http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/groups/GroupResourceIT.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/groups/GroupResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/groups/GroupResourceIT.java new file mode 100644 index 0000000..0dd6dc8 --- /dev/null +++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/groups/GroupResourceIT.java @@ -0,0 +1,295 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.usergrid.rest.applications.collection.groups; + + +import java.util.UUID; + +import javax.ws.rs.core.MediaType; + +import com.fasterxml.jackson.databind.JsonNode; +import java.io.IOException; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.usergrid.cassandra.Concurrent; +import org.apache.usergrid.java.client.Client.Query; +import org.apache.usergrid.java.client.response.ApiResponse; +import org.apache.usergrid.rest.AbstractRestIT; +import org.apache.usergrid.utils.UUIDUtils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + + +/** @author tnine */ +@Concurrent() +public class GroupResourceIT extends AbstractRestIT { + private static Logger log = LoggerFactory.getLogger( GroupResourceIT.class ); + + private static final String GROUP = "testGroup"; + + private static final String USER = "edanuff"; + + private static boolean groupCreated = false; + + + public GroupResourceIT() throws Exception { + + } + + + @Before + public void setupGroup() { + if ( groupCreated ) { + return; + } + + try { + client.createGroup( GROUP ); + groupCreated = true; + } + catch ( Exception e ) { + log.error( "Error creating group " + GROUP, e ); + } + refreshIndex("test-organization", "test-app"); + + } + + + @Test + public void failGroupNameValidation() { + + ApiResponse response = client.createGroup( "groupName/withslash" ); + assertNull( response.getError() ); + + refreshIndex("test-organization", "test-app"); + + { + boolean failed = false; + try { + ApiResponse groupResponse = client.createGroup( "groupName withspace" ); + failed = groupResponse.getError() != null; + } catch ( Exception e ) { + failed = true; + } + assertTrue( failed ); + } + } + + + @Test + public void postGroupActivity() { + + // don't populate the user, it will use the currently authenticated + // user. + + UUID id = UUIDUtils.newTimeUUID(); + + String groupPath = "groupPath" + id; + String groupTitle = "groupTitle " + id; + String groupName = "groupName" + id; + + ApiResponse response = client.createGroup( groupPath, groupTitle, groupName ); + + assertNull( "Error was: " + response.getErrorDescription(), response.getError() ); + + refreshIndex("test-organization", "test-app"); + + UUID newId = response.getEntities().get( 0 ).getUuid(); + + Query results = client.queryGroups( String.format( "name='%s'", groupName ) ); + + response = results.getResponse(); + + UUID entityId = response.getEntities().get( 0 ).getUuid(); + + assertEquals( newId, entityId ); + + results = client.queryGroups( String.format( "title='%s'", groupTitle ) ); + + response = results.getResponse(); + + entityId = response.getEntities().get( 0 ).getUuid(); + + assertEquals( newId, entityId ); + + results = client.queryGroups( String.format( "title contains '%s'", id ) ); + + response = results.getResponse(); + + entityId = response.getEntities().get( 0 ).getUuid(); + + assertEquals( newId, entityId ); + + results = client.queryGroups( String.format( "path='%s'", groupPath ) ); + + response = results.getResponse(); + + entityId = response.getEntities().get( 0 ).getUuid(); + + assertEquals( newId, entityId ); + } + + + @Test + public void addRemovePermission() throws IOException { + + UUID id = UUIDUtils.newTimeUUID(); + + String groupName = "groupname" + id; + + ApiResponse response = client.createGroup( groupName ); + assertNull( "Error was: " + response.getErrorDescription(), response.getError() ); + + refreshIndex("test-organization", "test-app"); + + UUID createdId = response.getEntities().get( 0 ).getUuid(); + + // add Permission + + String json = "{\"permission\":\"delete:/test\"}"; + JsonNode node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/permissions" ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, json )); + + // check it + assertNull( node.get( "errors" ) ); + assertEquals( node.get( "data" ).get( 0 ).asText(), "delete:/test" ); + + refreshIndex("test-organization", "test-app"); + + node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/permissions" ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + assertNull( node.get( "errors" ) ); + assertEquals( node.get( "data" ).get( 0 ).asText(), "delete:/test" ); + + + // remove Permission + + node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/permissions" ) + .queryParam( "access_token", access_token ).queryParam( "permission", "delete%3A%2Ftest" ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class )); + + // check it + assertNull( node.get( "errors" ) ); + assertTrue( node.get( "data" ).size() == 0 ); + + refreshIndex("test-organization", "test-app"); + + node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/permissions" ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + assertNull( node.get( "errors" ) ); + assertTrue( node.get( "data" ).size() == 0 ); + } + + + @Test + public void addRemoveRole() throws IOException { + + UUID id = UUIDUtils.newTimeUUID(); + + String groupName = "groupname" + id; + String roleName = "rolename" + id; + + ApiResponse response = client.createGroup( groupName ); + assertNull( "Error was: " + response.getErrorDescription(), response.getError() ); + + UUID createdId = response.getEntities().get( 0 ).getUuid(); + + refreshIndex("test-organization", "test-app"); + + // create Role + + String json = "{\"title\":\"" + roleName + "\",\"name\":\"" + roleName + "\"}"; + JsonNode node = mapper.readTree( resource().path( "/test-organization/test-app/roles" ).queryParam( "access_token", access_token ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ) + .post( String.class, json )); + + // check it + assertNull( node.get( "errors" ) ); + + + refreshIndex("test-organization", "test-app"); + + // add Role + + node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/roles/" + roleName ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class )); + + refreshIndex("test-organization", "test-app"); + + // check it + assertNull( node.get( "errors" ) ); + assertEquals( node.get( "entities" ).get( 0 ).get( "name" ).asText(), roleName ); + + node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/roles" ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + assertNull( node.get( "errors" ) ); + assertEquals( node.get( "entities" ).get( 0 ).get( "name" ).asText(), roleName ); + + // check root roles + node = mapper.readTree( resource().path( "/test-organization/test-app/roles" ).queryParam( "access_token", access_token ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + assertNull( node.get( "errors" ) ); + assertTrue( node.get( "entities" ).findValuesAsText( "name" ).contains( roleName ) ); + + refreshIndex("test-organization", "test-app"); + + // remove Role + + node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/roles/" + roleName ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class )); + assertNull( node.get( "errors" ) ); + + refreshIndex("test-organization", "test-app"); + + node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/roles" ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + assertNull( node.get( "errors" ) ); + assertTrue( node.get( "entities" ).size() == 0 ); + + // check root roles - role should remain + node = mapper.readTree( resource().path( "/test-organization/test-app/roles" ).queryParam( "access_token", access_token ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + assertNull( node.get( "errors" ) ); + assertTrue( node.get( "entities" ).findValuesAsText( "name" ).contains( roleName ) ); + + // now kill the root role + node = mapper.readTree( resource().path( "/test-organization/test-app/roles/" + roleName ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class )); + assertNull( node.get( "errors" ) ); + + refreshIndex("test-organization", "test-app"); + + // now it should be gone + node = mapper.readTree( resource().path( "/test-organization/test-app/roles" ).queryParam( "access_token", access_token ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + assertNull( node.get( "errors" ) ); + assertFalse( node.get( "entities" ).findValuesAsText( "name" ).contains( roleName ) ); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingEntitiesTest.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingEntitiesTest.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingEntitiesTest.java new file mode 100644 index 0000000..93a061d --- /dev/null +++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingEntitiesTest.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.usergrid.rest.applications.collection.paging; + + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.databind.JsonNode; +import java.io.IOException; +import org.junit.Rule; +import org.junit.Test; +import org.apache.usergrid.rest.AbstractRestIT; +import org.apache.usergrid.rest.TestContextSetup; +import org.apache.usergrid.rest.test.resource.CustomCollection; + +import org.apache.commons.lang.ArrayUtils; + +import static org.junit.Assert.assertEquals; +import static org.apache.usergrid.utils.MapUtils.hashMap; + + +/** + * // TODO: Document this + * + * @author ApigeeCorporation + * @since 4.0 + */ +public class PagingEntitiesTest extends AbstractRestIT { + + @Rule + public TestContextSetup context = new TestContextSetup( this ); + + + @Test //USERGRID-266 + public void pageThroughConnectedEntities() throws IOException { + + CustomCollection activities = context.collection( "activities" ); + + long created = 0; + int maxSize = 100; + long[] verifyCreated = new long[maxSize]; + Map actor = hashMap( "displayName", "Erin" ); + Map props = new HashMap(); + + + props.put( "actor", actor ); + props.put( "verb", "go" ); + + for ( int i = 0; i < maxSize; i++ ) { + + props.put( "ordinal", i ); + JsonNode activity = activities.create( props ); + verifyCreated[i] = activity.findValue( "created" ).longValue(); + if ( i == 0 ) { + created = activity.findValue( "created" ).longValue(); + } + } + ArrayUtils.reverse( verifyCreated ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + String query = "select * where created >= " + created; + + + JsonNode node = activities.query( query, "limit", "2" ); //activities.query(query,""); + int index = 0; + while ( node.get( "entities" ).get( "created" ) != null ) { + assertEquals( 2, node.get( "entities" ).size() ); + + if ( node.get( "cursor" ) != null ) { + node = activities.query( query, "cursor", node.get( "cursor" ).toString() ); + } + + else { + break; + } + } + } + + + @Test //USERGRID-1253 + public void pagingQueryReturnCorrectResults() throws Exception { + + CustomCollection activities = context.collection( "activities" ); + + long created = 0; + int maxSize = 23; + long[] verifyCreated = new long[maxSize]; + Map actor = hashMap( "displayName", "Erin" ); + Map props = new HashMap(); + + props.put( "actor", actor ); + props.put( "content", "bragh" ); + + for ( int i = 0; i < maxSize; i++ ) { + + if ( i > 17 && i < 23 ) { + props.put( "verb", "stop" ); + } + else { + props.put( "verb", "go" ); + } + props.put( "ordinal", i ); + JsonNode activity = activities.create( props ); + verifyCreated[i] = activity.findValue( "created" ).longValue(); + if ( i == 18 ) { + created = activity.findValue( "created" ).longValue(); + } + } + + refreshIndex(context.getOrgName(), context.getAppName()); + + String query = "select * where created >= " + created + " or verb = 'stop'"; + + JsonNode node = activities.withQuery( query ).get(); + + for ( int index = 0; index < 5; index++ ) { + assertEquals( verifyCreated[maxSize - 1 - index], + node.get( "entities" ).get( index ).get( "created" ).longValue() ); + } + + int totalEntitiesContained = activities.countEntities( query ); + + assertEquals( 5, totalEntitiesContained ); + } +} http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingResourceIT.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingResourceIT.java new file mode 100644 index 0000000..397dd0f --- /dev/null +++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingResourceIT.java @@ -0,0 +1,239 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.usergrid.rest.applications.collection.paging; + + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.apache.usergrid.cassandra.Concurrent; +import org.apache.usergrid.java.client.entities.Entity; +import org.apache.usergrid.java.client.response.ApiResponse; +import org.apache.usergrid.rest.AbstractRestIT; +import org.apache.usergrid.rest.TestContextSetup; +import org.apache.usergrid.rest.test.resource.CustomCollection; +import org.apache.usergrid.rest.test.resource.EntityResource; +import static org.apache.usergrid.utils.MapUtils.hashMap; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** Simple tests to test querying at the REST tier */ +@Concurrent() +public class PagingResourceIT extends AbstractRestIT { + + private static final Logger logger = LoggerFactory.getLogger( PagingResourceIT.class ); + + @Rule + public TestContextSetup context = new TestContextSetup( this ); + + + @Test + public void collectionPaging() throws Exception { + + CustomCollection things = context.application().collection( "test1things" ); + + int size = 40; + + List<Map<String, String>> created = new ArrayList<Map<String, String>>( size ); + + for ( int i = 0; i < size; i++ ) { + Map<String, String> entity = hashMap( "name", String.valueOf( i ) ); + things.create( entity ); + + created.add( entity ); + } + + refreshIndex(context.getOrgName(), context.getAppName()); + + // now page them all + ApiResponse response = null; + Iterator<Map<String, String>> entityItr = created.iterator(); + + do { + + response = parse( things.get() ); + + for ( Entity e : response.getEntities() ) { + assertTrue( entityItr.hasNext() ); + assertEquals( entityItr.next().get( "name" ), e.getProperties().get( "name" ).asText() ); + logger.debug("Got item value {}", e.getProperties().get( "name" ).asText()); + } + + logger.debug("response cursor: " + response.getCursor() ); + + things = things.withCursor( response.getCursor() ); + } + while ( response != null && response.getCursor() != null ); + + assertFalse("Should have paged them all", entityItr.hasNext() ); + } + + + @Test + @Ignore("ignored because currently startPaging is only be supported for queues and not for " + + "generic collections as this test assumes. " + + "see also: https://issues.apache.org/jira/browse/USERGRID-211 ") + public void startPaging() throws Exception { + + CustomCollection things = context.application().collection( "test2things" ); + + int size = 40; + + List<Map<String, String>> created = new ArrayList<Map<String, String>>( size ); + + for ( int i = 0; i < size; i++ ) { + Map<String, String> entity = hashMap( "name", String.valueOf( i ) ); + things.create( entity ); + + created.add( entity ); + } + + refreshIndex(context.getOrgName(), context.getAppName()); + + // now page them all + ApiResponse response = null; + + UUID start = null; + int index = 0; + + do { + + response = parse( things.get() ); + + for ( Entity e : response.getEntities() ) { + logger.debug("Getting item {} value {}", index, e.getProperties().get( "name" ).asText()); + assertEquals( created.get( index ).get( "name" ), e.getProperties().get( "name" ).asText() ); + index++; + } + + // decrement since we'll get this one again + index--; + + start = response.getEntities().get( response.getEntities().size() - 1 ).getUuid(); + + things = things.withStart( start ); + } + while ( response != null && response.getEntities().size() > 1 ); + + // we paged them all + assertEquals( created.size() - 1, index ); + } + + + @Test + public void collectionBatchDeleting() throws Exception { + + CustomCollection things = context.application().collection( "test3things" ); + + int size = 40; + + List<Map<String, String>> created = new ArrayList<Map<String, String>>( size ); + + for ( int i = 0; i < size; i++ ) { + Map<String, String> entity = hashMap( "name", String.valueOf( i ) ); + things.create( entity ); + + created.add( entity ); + } + + refreshIndex(context.getOrgName(), context.getAppName()); + + ApiResponse response; + int deletePageSize = 10; + + things = things.withLimit( deletePageSize ); + + for ( int i = 0; i < size / deletePageSize; i++ ) { + response = parse( things.delete() ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + assertEquals( "Only 10 entities should have been deleted", 10, response.getEntityCount() ); + } + + response = parse( things.get() ); + + assertEquals( "All entities should have been removed", 0, response.getEntityCount() ); + + //now do 1 more delete, we should get any results + + response = parse( things.delete() ); + + assertEquals( "No more entities deleted", 0, response.getEntityCount() ); + } + + + @Test + public void emptyQlandLimitIgnored() throws Exception { + + CustomCollection things = context.application().collection( "test4things" ); + + Map<String, String> data = hashMap( "name", "thing1" ); + JsonNode response = things.create( data ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + JsonNode entity = getEntity( response, 0 ); + + String uuid = entity.get( "uuid" ).asText(); + + EntityResource entityRequest = things.entity( "thing1" ).withParam( "ql", "" ).withParam( "limit", "" ); + + JsonNode returnedEntity = getEntity( entityRequest.get(), 0 ); + + assertEquals( entity, returnedEntity ); + + entityRequest = things.entity( uuid ).withParam( "ql", "" ).withParam( "limit", "" ); + + returnedEntity = getEntity( entityRequest.get(), 0 ); + + assertEquals( entity, returnedEntity ); + + // now do a delete + returnedEntity = getEntity( entityRequest.delete(), 0 ); + + assertEquals( entity, returnedEntity ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + // verify it's gone + returnedEntity = getEntity( things.entity( uuid ).get(), 0 ); + + assertNull( returnedEntity ); + } + + + private static ObjectMapper mapper = new ObjectMapper(); + + + private static final ApiResponse parse( JsonNode response ) throws Exception { + String jsonResponseString = mapper.writeValueAsString( response ); + return mapper.readValue( jsonResponseString, ApiResponse.class ); + } +} http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/ConnectionResourceTest.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/ConnectionResourceTest.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/ConnectionResourceTest.java new file mode 100644 index 0000000..e034443 --- /dev/null +++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/ConnectionResourceTest.java @@ -0,0 +1,271 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.usergrid.rest.applications.collection.users; + + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; + +import javax.ws.rs.core.MediaType; + +import com.fasterxml.jackson.databind.JsonNode; +import org.junit.Rule; +import org.junit.Test; +import org.apache.usergrid.rest.AbstractRestIT; +import org.apache.usergrid.rest.TestContextSetup; +import org.apache.usergrid.rest.test.resource.CustomCollection; + +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.UniformInterfaceException; +import java.io.IOException; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.apache.usergrid.utils.MapUtils.hashMap; + + +/** + * // TODO: Document this + * + * @author ApigeeCorporation + * @since 4.0 + */ +public class ConnectionResourceTest extends AbstractRestIT { + @Rule + public TestContextSetup context = new TestContextSetup( this ); + + + @Test + public void connectionsQueryTest() throws IOException { + + + CustomCollection activities = context.collection( "peeps" ); + + Map stuff = hashMap( "type", "chicken" ); + + activities.create( stuff ); + + + Map<String, Object> payload = new LinkedHashMap<String, Object>(); + payload.put( "username", "todd" ); + + Map<String, Object> objectOfDesire = new LinkedHashMap<String, Object>(); + objectOfDesire.put( "codingmunchies", "doritoes" ); + + resource().path( "/test-organization/test-app/users" ).queryParam( "access_token", access_token ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ) + .post( String.class, payload ); + + payload.put( "username", "scott" ); + + + resource().path( "/test-organization/test-app/users" ).queryParam( "access_token", access_token ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ) + .post( String.class, payload ); + /*finish setting up the two users */ + + + refreshIndex("test-organization", "test-app"); + + ClientResponse toddWant = resource().path( "/test-organization/test-app/users/todd/likes/peeps" ) + .queryParam( "access_token", access_token ).accept( MediaType.TEXT_HTML ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( ClientResponse.class, objectOfDesire ); + + assertEquals( 200, toddWant.getStatus() ); + + refreshIndex("test-organization", "test-app"); + + JsonNode node = mapper.readTree( resource().path( "/test-organization/test-app/peeps" ).queryParam( "access_token", access_token ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ) + .get( String.class )); + + String uuid = node.get( "entities" ).get( 0 ).get( "uuid" ).textValue(); + + + try { + node = mapper.readTree( resource().path( "/test-organization/test-app/users/scott/likes/" + uuid ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + assert ( false ); + } + catch ( UniformInterfaceException uie ) { + assertEquals( 404, uie.getResponse().getClientResponseStatus().getStatusCode() ); + } + } + + + @Test + public void connectionsLoopbackTest() throws IOException { + + CustomCollection things = context.collection( "things" ); + + UUID thing1Id = getEntityId( things.create( hashMap( "name", "thing1" ) ), 0 ); + + UUID thing2Id = getEntityId( things.create( hashMap( "name", "thing2" ) ), 0 ); + + + refreshIndex(context.getOrgName(), context.getAppName()); + + //create the connection + things.entity( thing1Id ).connection( "likes" ).entity( thing2Id ).post(); + + + refreshIndex(context.getOrgName(), context.getAppName()); + + //test we have the "likes" in our connection meta data response + + JsonNode response = things.entity( "thing1" ).get(); + + String url = getEntity( response, 0 ).get( "metadata" ).get( "connections" ).get( "likes" ).asText(); + + + assertNotNull( "Connection url returned in entity", url ); + + //trim off the start / + url = url.substring( 1 ); + + + //now that we know the URl is correct, follow it + + response = context.collection( url ).get(); + + UUID returnedUUID = getEntityId( response, 0 ); + + assertEquals( thing2Id, returnedUUID ); + + + //now follow the loopback, which should be pointers to the other entity + + url = getEntity( response, 0 ).get( "metadata" ).get( "connecting" ).get( "likes" ).asText(); + + assertNotNull( "Incoming edge URL provited", url ); + + //trim off the start / + url = url.substring( 1 ); + + //now we should get thing1 from the loopback url + + response = context.collection( url ).get(); + + UUID returned = getEntityId( response, 0 ); + + assertEquals( "Should point to thing1 as an incoming entity connection", thing1Id, returned ); + } + + + @Test + public void connectionsUUIDTest() throws IOException { + + CustomCollection things = context.collection( "things" ); + + UUID thing1Id = getEntityId( things.create( hashMap( "name", "thing1" ) ), 0 ); + + UUID thing2Id = getEntityId( things.create( hashMap( "name", "thing2" ) ), 0 ); + + + refreshIndex(context.getOrgName(), context.getAppName()); + + //create the connection + things.entity( thing1Id ).connection( "likes" ).entity( thing2Id ).post(); + + + refreshIndex(context.getOrgName(), context.getAppName()); + + //test we have the "likes" in our connection meta data response + + JsonNode response = things.entity( "thing1" ).get(); + + String url = getEntity( response, 0 ).get( "metadata" ).get( "connections" ).get( "likes" ).asText(); + + + assertNotNull( "Connection url returned in entity", url ); + + //trim off the start / + url = url.substring( 1 ); + + + //now that we know the URl is correct, follow it + + response = context.collection( url ).get(); + + UUID returnedUUID = getEntityId( response, 0 ); + + assertEquals( thing2Id, returnedUUID ); + + //get on the collection works, now get it directly by uuid + + //now we should get thing1 from the loopback url + + response = things.entity( thing1Id ).connection( "likes" ).entity( thing2Id ).get(); + + UUID returned = getEntityId( response, 0 ); + + assertEquals( "Should point to thing2 as an entity connection", thing2Id, returned ); + } + + @Test //USERGRID-3011 + public void connectionsDeleteSecondEntityInConnectionTest() throws IOException { + + CustomCollection things = context.collection( "things" ); + + UUID thing1Id = getEntityId( things.create( hashMap( "name", "thing1" ) ), 0 ); + + UUID thing2Id = getEntityId( things.create( hashMap( "name", "thing2" ) ), 0 ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + //create the connection + things.entity( thing1Id ).connection( "likes" ).entity( thing2Id ).post(); + + JsonNode response = things.entity( "thing2" ).delete(); + + refreshIndex(context.getOrgName(), context.getAppName()); + + JsonNode node = things.entity ( "thing2" ).get(); + + assertNull(node); + + } + + @Test //USERGRID-3011 + public void connectionsDeleteFirstEntityInConnectionTest() throws IOException { + + CustomCollection things = context.collection( "things" ); + + UUID thing1Id = getEntityId( things.create( hashMap( "name", "thing1" ) ), 0 ); + + UUID thing2Id = getEntityId( things.create( hashMap( "name", "thing2" ) ), 0 ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + //create the connection + things.entity( thing1Id ).connection( "likes" ).entity( thing2Id ).post(); + + JsonNode response = things.entity( "thing1" ).delete(); + + refreshIndex(context.getOrgName(), context.getAppName()); + + JsonNode node = things.entity ( "thing1" ).get(); + + assertNull(node); + + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/OwnershipResourceIT.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/OwnershipResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/OwnershipResourceIT.java new file mode 100644 index 0000000..a514781 --- /dev/null +++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/OwnershipResourceIT.java @@ -0,0 +1,379 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.usergrid.rest.applications.collection.users; + + +import com.fasterxml.jackson.databind.JsonNode; +import java.io.IOException; +import org.junit.Rule; +import org.junit.Test; +import org.apache.usergrid.cassandra.Concurrent; +import org.apache.usergrid.rest.AbstractRestIT; +import org.apache.usergrid.rest.TestContextSetup; +import org.apache.usergrid.rest.test.resource.Connection; +import org.apache.usergrid.rest.test.resource.CustomCollection; +import org.apache.usergrid.rest.test.resource.app.queue.DevicesCollection; +import org.apache.usergrid.rest.test.security.TestAppUser; +import org.apache.usergrid.rest.test.security.TestUser; +import org.apache.usergrid.utils.MapUtils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + + +/** + * + */ +@Concurrent() +public class OwnershipResourceIT extends AbstractRestIT { + + @Rule + public TestContextSetup context = new TestContextSetup( this ); + + + @Test + public void meVerify() throws Exception { + + context.clearUser(); + + String email = "[email protected]"; + TestUser user1 = new TestAppUser( email, "password", email ).create( context ); + refreshIndex(context.getOrgName(), context.getAppName()); + user1.login( context ).makeActive( context ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + String token = user1.getToken(); + JsonNode userNode = context.application().users().user( "me" ).get(); + assertNotNull( userNode ); + + String uuid = userNode.get( "entities" ).get( 0 ).get( "uuid" ).textValue(); + assertNotNull( uuid ); + + setup.getMgmtSvc().revokeAccessTokenForAppUser( token ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + try { + context.application().users().user( "me" ).get(); + fail(); + } + catch ( Exception ex ) { + ex.printStackTrace(); + assertTrue( ex.getMessage().contains( "401" ) ); + } + } + + + @Test + public void contextualPathOwnership() throws IOException { + + // anonymous user + context.clearUser(); + + refreshIndex(context.getOrgName(), context.getAppName()); + + TestUser user1 = new TestAppUser( "[email protected]", "password", "[email protected]" ).create( context ); + refreshIndex(context.getOrgName(), context.getAppName()); + user1.login( context ); + user1.makeActive( context ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + // create device 1 on user1 devices + context.application().users().user( "me" ).devices() + .create( MapUtils.hashMap( "name", "device1" ).map( "number", "5551112222" ) ); + + // anonymous user + context.clearUser(); + refreshIndex(context.getOrgName(), context.getAppName()); + + // create device 2 on user 2 + TestUser user2 = new TestAppUser( "[email protected]", "password", "[email protected]" ).create( context ); + refreshIndex(context.getOrgName(), context.getAppName()); + user2.login( context ); + user2.makeActive( context ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + context.application().users().user( "me" ).devices() + .create( MapUtils.hashMap( "name", "device2" ).map( "number", "5552223333" ) ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + // now query on user 1. + + DevicesCollection devices = context.withUser( user1 ).application().users().user( "me" ).devices(); + + JsonNode data = devices.device( "device1" ).get(); + assertNotNull( data ); + assertEquals( "device1", getEntity( data, 0 ).get( "name" ).asText() ); + + // check we can't see device2 + data = devices.device( "device2" ).get(); + assertNull( data ); + + // do a collection load, make sure we're not loading device 2 + data = devices.get(); + + assertEquals( "device1", getEntity( data, 0 ).get( "name" ).asText() ); + assertNull( getEntity( data, 1 ) ); + + // log in as user 2 and check it + devices = context.withUser( user2 ).application().users().user( "me" ).devices(); + + data = devices.device( "device2" ).get(); + assertNotNull( data ); + assertEquals( "device2", getEntity( data, 0 ).get( "name" ).asText() ); + + // check we can't see device1 + data = devices.device( "device1" ).get(); + assertNull( data ); + + // do a collection load, make sure we're not loading device 1 + data = devices.get(); + + assertEquals( "device2", getEntity( data, 0 ).get( "name" ).asText() ); + assertNull( getEntity( data, 1 ) ); + + // we should see both devices when loaded from the root application + + // test for user 1 + + devices = context.withUser( user1 ).application().devices(); + data = devices.device( "device1" ).get(); + + assertNotNull( data ); + assertEquals( "device1", getEntity( data, 0 ).get( "name" ).asText() ); + + data = devices.device( "device2" ).get(); + + assertNotNull( data ); + assertEquals( "device2", getEntity( data, 0 ).get( "name" ).asText() ); + + // test for user 2 + data = context.withUser( user2 ).application().devices().device( "device1" ).get(); + + assertNotNull( data ); + assertEquals( "device1", getEntity( data, 0 ).get( "name" ).asText() ); + + data = devices.device( "device2" ).get(); + + assertNotNull( data ); + assertEquals( "device2", getEntity( data, 0 ).get( "name" ).asText() ); + } + + + @Test + public void contextualConnectionOwnership() throws IOException { + + // anonymous user + context.clearUser(); + + refreshIndex(context.getOrgName(), context.getAppName()); + + String email = "[email protected]"; + TestUser user1 = new TestAppUser( email, "password", email ).create( context ); + refreshIndex(context.getOrgName(), context.getAppName()); + user1.login( context ).makeActive( context ); + + // create a 4peaks restaurant + JsonNode data = context.application() + .collection( "restaurants" ).create( MapUtils.hashMap( "name", "4peaks" ) ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + // create our connection + data = context.application().users().user( "me" ) + .connection( "likes" ).collection( "restaurants" ).entity( "4peaks" ).post(); + + refreshIndex(context.getOrgName(), context.getAppName()); + + String peaksId = getEntity( data, 0 ).get( "uuid" ).asText(); + + // anonymous user + context.clearUser(); + + // create a restaurant and link it to user 2 + email = "[email protected]"; + TestUser user2 = new TestAppUser( email, "password", email ).create( context ); + refreshIndex(context.getOrgName(), context.getAppName()); + + user2.login( context ).makeActive( context ); + refreshIndex(context.getOrgName(), context.getAppName()); + + data = context.application().collection( "restaurants" ) + .create( MapUtils.hashMap( "name", "arrogantbutcher" ) ); + refreshIndex(context.getOrgName(), context.getAppName()); + + data = context.application().users().user( "me" ).connection( "likes" ).collection( "restaurants" ) + .entity( "arrogantbutcher" ).post(); + refreshIndex(context.getOrgName(), context.getAppName()); + + String arrogantButcherId = getEntity( data, 0 ).get( "uuid" ).asText(); + + // now query on user 1. + + CustomCollection likeRestaurants = + context.withUser( user1 ).application().users().user( "me" ).connection( "likes" ) + .collection( "restaurants" ); + refreshIndex(context.getOrgName(), context.getAppName()); + + // check we can get it via id + data = likeRestaurants.entity( peaksId ).get(); + assertNotNull( data ); + assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() ); + + // check we can get it by name + data = likeRestaurants.entity( "4peaks" ).get(); + assertNotNull( data ); + assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() ); + + // check we can't see arrogantbutcher by name or id + data = likeRestaurants.entity( "arrogantbutcher" ).get(); + assertNull( data ); + + data = likeRestaurants.entity( arrogantButcherId ).get(); + assertNull( data ); + + // do a collection load, make sure we're not entities we shouldn't see + data = likeRestaurants.get(); + + assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() ); + assertNull( getEntity( data, 1 ) ); + + // log in as user 2 and check it + likeRestaurants = context.withUser( user2 ).application().users().user( "me" ).connection( "likes" ) + .collection( "restaurants" ); + + data = likeRestaurants.entity( arrogantButcherId ).get(); + assertNotNull( data ); + assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() ); + + data = likeRestaurants.entity( "arrogantbutcher" ).get(); + assertNotNull( data ); + assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() ); + + // check we can't see 4peaks + data = likeRestaurants.entity( "4peaks" ).get(); + assertNull( data ); + + data = likeRestaurants.entity( peaksId ).get(); + assertNull( data ); + + // do a collection load, make sure we're not loading device 1 + data = likeRestaurants.get(); + + assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() ); + assertNull( getEntity( data, 1 ) ); + + // we should see both devices when loaded from the root application + + // test for user 1 + + CustomCollection restaurants = context.withUser( user1 ).application().collection( "restaurants" ); + data = restaurants.entity( "4peaks" ).get(); + + assertNotNull( data ); + assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() ); + + data = restaurants.entity( "arrogantbutcher" ).get(); + + assertNotNull( data ); + assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() ); + + // test for user 2 + restaurants = context.withUser( user1 ).application().collection( "restaurants" ); + data = restaurants.entity( "4peaks" ).get(); + + assertNotNull( data ); + assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() ); + + data = restaurants.entity( "arrogantbutcher" ).get(); + + assertNotNull( data ); + assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() ); + } + + + @Test + public void contextualConnectionOwnershipGuestAccess() throws IOException { + + //set up full GET,PUT,POST,DELETE access for guests + context.application().collection( "roles" ).entity( "guest" ).collection( "permissions" ) + .create( MapUtils.hashMap( "permission", "get,put,post,delete:/**" ) ); + + + // anonymous user + context.clearUser(); + + + JsonNode city = context.application().collection( "cities" ).create( MapUtils.hashMap( "name", "tempe" ) ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + String cityId = getEntity( city, 0 ).get( "uuid" ).asText(); + + // create a 4peaks restaurant + JsonNode data = context.application().collection( "cities" ).entity( "tempe" ).connection( "likes" ) + .collection( "restaurants" ).create( MapUtils.hashMap( "name", "4peaks" ) ); + + String peaksId = getEntity( data, 0 ).get( "uuid" ).asText(); + + data = context.application().collection( "cities" ).entity( "tempe" ).connection( "likes" ) + .collection( "restaurants" ).create( MapUtils.hashMap( "name", "arrogantbutcher" ) ); + + String arrogantButcherId = getEntity( data, 0 ).get( "uuid" ).asText(); + + // now query on user 1. + + Connection likeRestaurants = + context.application().collection( "cities" ).entity( "tempe" ).connection( "likes" ); + + refreshIndex(context.getOrgName(), context.getAppName()); + + // check we can get it via id with no collection name + data = likeRestaurants.entity( peaksId ).get(); + assertNotNull( data ); + assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() ); + + data = likeRestaurants.entity( arrogantButcherId ).get(); + assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() ); + + // check we can get it via id with a collection name + data = likeRestaurants.collection( "restaurants" ).entity( peaksId ).get(); + assertNotNull( data ); + assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() ); + + data = likeRestaurants.collection( "restaurants" ).entity( arrogantButcherId ).get(); + assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() ); + + // do a delete either token should work + data = likeRestaurants.collection( "restaurants" ).entity( peaksId ).delete(); + + assertNotNull( data ); + assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() ); + + data = likeRestaurants.collection( "restaurants" ).entity( arrogantButcherId ).delete(); + + assertNotNull( data ); + assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() ); + } +} http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java new file mode 100644 index 0000000..a07622e --- /dev/null +++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java @@ -0,0 +1,768 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.usergrid.rest.applications.collection.users; + + +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; + +import javax.ws.rs.core.MediaType; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.junit.Ignore; +import org.junit.Test; +import org.apache.usergrid.cassandra.Concurrent; +import org.apache.usergrid.java.client.entities.Group; +import org.apache.usergrid.management.ApplicationInfo; +import org.apache.usergrid.management.OrganizationOwnerInfo; +import org.apache.usergrid.rest.AbstractRestIT; +import org.apache.usergrid.utils.UUIDUtils; + +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.ClientResponse.Status; +import com.sun.jersey.api.client.UniformInterfaceException; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; +import static org.apache.usergrid.utils.MapUtils.hashMap; + + +/** + * Tests permissions of adding and removing users from roles as well as groups + * + * @author tnine + */ +@Concurrent() +public class PermissionsResourceIT extends AbstractRestIT { + + private static final String ROLE = "permtestrole"; + + private static final String USER = "edanuff"; + + + public PermissionsResourceIT() throws Exception { + + } + + + @Test + public void deleteUserFromRole() throws IOException { + Map<String, String> data = hashMap( "name", ROLE ); + + JsonNode node = mapper.readTree( resource().path( "/test-organization/test-app/roles" ).queryParam( "access_token", access_token ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ) + .post( String.class, data )); + + assertNull( node.get( "error" ) ); + + assertEquals( ROLE, getEntity( node, 0 ).get( "name" ).asText() ); + + refreshIndex("test-organization", "test-app"); + + // add the user to the role + node = mapper.readTree( resource().path( "/test-organization/test-app/roles/" + ROLE + "/users/" + USER ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class )); + + assertNull( node.get( "error" ) ); + + refreshIndex("test-organization", "test-app"); + + // now check the user has the role + node = mapper.readTree( resource().path( "/test-organization/test-app/users/" + USER + "/roles" ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + + // check if the role was assigned + assertEquals( ROLE, getEntity( node, 0 ).get( "name" ).asText() ); + + // now delete the role + node = mapper.readTree( resource().path( "/test-organization/test-app/users/" + USER + "/roles/" + ROLE ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class )); + + refreshIndex("test-organization", "test-app"); + + // check if the role was deleted + + node = mapper.readTree( resource().path( "/test-organization/test-app/users/" + USER + "/roles" ) + .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + + // check if the role was assigned + assertNull( getEntity( node, 0 ) ); + } + + + @Test + public void deleteUserGroup() throws IOException { + + // don't populate the user, it will use the currently authenticated + // user. + + UUID id = UUIDUtils.newTimeUUID(); + + String groupPath = "groupPath" + id; + + Map<String, String> data = hashMap( "type", "group" ).map( "path", groupPath ); + + JsonNode node = mapper.readTree( resource().path( "/test-organization/test-app/groups" ) + .queryParam( "access_token", access_token ) + .accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ) + .post( String.class, data )); + + assertNull( node.get( "error" ) ); + + refreshIndex("test-organization", "test-app"); + + node = mapper.readTree( + resource().path( "/test-organization/test-app/groups/" + groupPath + "/users/" + USER ) + .queryParam( "access_token", access_token ) + .accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ) + .post( String.class )); + + assertNull( node.get( "error" ) ); + + refreshIndex("test-organization", "test-app"); + + Map<String, Group> groups = client.getGroupsForUser( USER ); + + assertNotNull( groups.get( groupPath ) ); + + // now delete the group + + node = mapper.readTree( + resource().path( "/test-organization/test-app/groups/" + groupPath + "/users/" + USER ) + .queryParam( "access_token", access_token ) + .accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ) + .delete( String.class )); + + assertNull( node.get( "error" ) ); + + refreshIndex("test-organization", "test-app"); + + groups = client.getGroupsForUser( USER ); + + assertNull( groups.get( groupPath ) ); + } + + + /** + * For the record, you should NEVER allow the guest role to add roles. This is a gaping security hole and a VERY BAD + * IDEA! That being said, this should technically work, and needs testing. + */ + @Test + public void dictionaryPermissions() throws Exception { + UUID id = UUIDUtils.newTimeUUID(); + + String applicationName = "testapp"; + String orgname = "dictionaryPermissions"; + String username = "permissionadmin" + id; + String password = "password"; + String email = String.format( "[email protected]", id ); + + OrganizationOwnerInfo orgs = setup.getMgmtSvc() + .createOwnerAndOrganization( orgname, username, "noname", email, password, + true, false ); + + // create the app + ApplicationInfo appInfo = + setup.getMgmtSvc().createApplication( orgs.getOrganization().getUuid(), applicationName ); + + String adminToken = setup.getMgmtSvc().getAccessTokenForAdminUser( orgs.getOwner().getUuid(), 0 ); + + // add the perms to the guest to allow users in the role to create roles + // themselves + addPermission( orgname, applicationName, adminToken, "guest", "get,put,post:/roles/**" ); + + Map<String, String> data = hashMap( "name", "usercreatedrole" ); + + // create a role as the user + JsonNode node = mapper.readTree( resource().path( String.format( "/%s/%s/roles", orgname, applicationName ) ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ) + .post( String.class, data )); + + assertNull( getError( node ) ); + + refreshIndex(orgname, applicationName); + + // now try to add permission as the user, this should work + addPermission( orgname, applicationName, "usercreatedrole", "get,put,post:/foo/**" ); + } + + + /** + * Tests a real world example with the following steps. Creates an application. + * <p/> + * Creates a new role "reviewer" + * <p/> + * Grants a permission to GET, POST, and PUT the reviews url for the reviewer role + * <p/> + * Grants a permission GET on the reviewer for the + * <p/> + * Create a user reviewer1 and add them to the reviewer role + * <p/> + * Test access with reviewer1 + * <p/> + * Create a group reviewergroup and add the "reviewer" group to it + * <p/> + * Create a user reviewer 2 and add them to the "reveiwergroup" + */ + @Test + public void applicationPermissions() throws Exception { + UUID id = UUIDUtils.newTimeUUID(); + + String applicationName = "test"; + String orgname = "applicationpermissions"; + String username = "permissionadmin" + id; + String password = "password"; + String email = String.format( "[email protected]", id ); + + OrganizationOwnerInfo orgs = setup.getMgmtSvc() + .createOwnerAndOrganization( orgname, username, "noname", email, password, + true, false ); + + // create the app + ApplicationInfo appInfo = + setup.getMgmtSvc().createApplication( orgs.getOrganization().getUuid(), applicationName ); + + // now create the new role + Map<String, String> data = hashMap( "name", "reviewer" ); + + String adminToken = setup.getMgmtSvc().getAccessTokenForAdminUser( orgs.getOwner().getUuid(), 0 ); + + JsonNode node = mapper.readTree( resource().path( String.format( "/%s/%s/roles", orgname, applicationName ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, data )); + + assertNull( getError( node ) ); + + // delete the default role to test permissions later + node = mapper.readTree( resource().path( String.format( "/%s/%s/roles/default", orgname, applicationName ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class )); + + assertNull( getError( node ) ); + refreshIndex(orgname, applicationName); + + // grant the perms to reviewer + addPermission( orgname, applicationName, adminToken, "reviewer", "get,put,post:/reviews/**" ); + + // grant get to guest + addPermission( orgname, applicationName, adminToken, "guest", "get:/reviews/**" ); + + UUID userId = createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "reviewer1", + "[email protected]" ); + + refreshIndex(orgname, applicationName); + + // grant this user the "reviewer" role + node = mapper.readTree( resource().path( String.format( "/%s/%s/users/reviewer1/roles/reviewer", orgname, applicationName ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class )); + + assertNull( getError( node ) ); + + refreshIndex(orgname, applicationName); + + String reviewer1Token = setup.getMgmtSvc().getAccessTokenForAppUser( appInfo.getId(), userId, 0 ); + + Map<String, String> review = + hashMap( "rating", "4" ).map( "name", "noca" ).map( "review", "Excellent service and food" ); + + // post a review as the reviewer1 user + resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) ) + .queryParam( "access_token", reviewer1Token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, review ); + + review = hashMap( "rating", "4" ).map( "name", "4peaks" ).map( "review", "Huge beer selection" ); + + refreshIndex(orgname, applicationName); + + // put a review as the reviewer1 user + resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) ) + .queryParam( "access_token", reviewer1Token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).put( String.class, review ); + + refreshIndex(orgname, applicationName); + + // get the reviews + + node = mapper.readTree( resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) ) + .queryParam( "access_token", reviewer1Token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + + assertEquals( "noca", getEntity( node, 0 ).get( "name" ).asText() ); + assertEquals( "4peaks", getEntity( node, 1 ).get( "name" ).asText() ); + + // can't delete, not in the grants + + ClientResponse.Status status = null; + + try { + resource().path( String.format( "/%s/%s/reviews/noca", orgname, applicationName ) ) + .queryParam( "access_token", reviewer1Token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class ); + } + catch ( UniformInterfaceException uie ) { + status = uie.getResponse().getClientResponseStatus(); + } + + assertEquals( Status.UNAUTHORIZED, status ); + + refreshIndex(orgname, applicationName); + + status = null; + + try { + resource().path( String.format( "/%s/%s/reviews/4peaks", orgname, applicationName ) ) + .queryParam( "access_token", reviewer1Token ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class ); + } + catch ( UniformInterfaceException uie ) { + status = uie.getResponse().getClientResponseStatus(); + } + + assertEquals( Status.UNAUTHORIZED, status ); + + refreshIndex(orgname, applicationName); + + // now test some groups + UUID secondUserId = createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "reviewer2", + "[email protected]" ); + + Map<String, String> group = hashMap( "path", "reviewergroup" ); + + // /now create the group + resource().path( String.format( "/%s/%s/groups", orgname, applicationName ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, group ); + + refreshIndex(orgname, applicationName); + + // link the group to the role + resource().path( String.format( "/%s/%s/groups/reviewergroup/roles/reviewer", orgname, applicationName ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, group ); + + refreshIndex(orgname, applicationName); + + // add the user to the group + resource().path( String.format( "/%s/%s/users/reviewer2/groups/reviewergroup", orgname, applicationName ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class ); + + refreshIndex(orgname, applicationName); + + // post 2 reviews. Should get permissions from the group + + String secondUserToken = setup.getMgmtSvc().getAccessTokenForAppUser( appInfo.getId(), secondUserId, 0 ); + + review = hashMap( "rating", "4" ).map( "name", "cowboyciao" ).map( "review", "Great atmosphoere" ); + + // post a review as the reviewer2 user + resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) ) + .queryParam( "access_token", secondUserToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, review ); + + review = hashMap( "rating", "4" ).map( "name", "currycorner" ).map( "review", "Authentic" ); + + refreshIndex(orgname, applicationName); + + // post a review as the reviewer2 user + resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) ) + .queryParam( "access_token", secondUserToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, review ); + + refreshIndex(orgname, applicationName); + + // get all reviews as a user + node = mapper.readTree( resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) ) + .queryParam( "access_token", secondUserToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + + assertEquals( "noca", getEntity( node, 0 ).get( "name" ).asText() ); + assertEquals( "4peaks", getEntity( node, 1 ).get( "name" ).asText() ); + assertEquals( "cowboyciao", getEntity( node, 2 ).get( "name" ).asText() ); + assertEquals( "currycorner", getEntity( node, 3 ).get( "name" ).asText() ); + + // issue a delete, it shouldn't work, no permissions + + status = null; + + try { + resource().path( String.format( "/%s/%s/reviews/cowboyciao", orgname, applicationName ) ) + .queryParam( "access_token", secondUserToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class ); + } + catch ( UniformInterfaceException uie ) { + status = uie.getResponse().getClientResponseStatus(); + } + + assertEquals( Status.UNAUTHORIZED, status ); + + refreshIndex(orgname, applicationName); + + status = null; + + try { + resource().path( String.format( "/%s/%s/reviews/currycorner", orgname, applicationName ) ) + .queryParam( "access_token", secondUserToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class ); + } + catch ( UniformInterfaceException uie ) { + status = uie.getResponse().getClientResponseStatus(); + } + + assertEquals( Status.UNAUTHORIZED, status ); + } + + + /** + * Tests the scenario where we have roles declarations such as: <ul> <li>GET /users/[star]/reviews "any user can + * read any others book review"</li> <li>POST /users/[user1]/reviews "cannot post as user2 to user1's reviews"</li> + * <ii>POST /users/[star]/reviews/feedback/* "can post as user2 to user1's feedback/good or /bad</ii> </ul> + * <p/> + * Scenario is as follows: Create an application + * <p/> + * Add two application users - user1 - user2 + * <p/> + * Create a book collection for user1 + */ + @Test + public void wildcardMiddlePermission() throws Exception { + + Map<String, String> params = buildOrgAppParams(); + String orgname =params.get( "orgName" ) ; + String applicationName = params.get( "appName" ) ; + + OrganizationOwnerInfo orgs = setup.getMgmtSvc().createOwnerAndOrganization( params.get( "orgName" ), + params.get( "username" ), "noname", params.get( "email" ), params.get( "password" ), true, false ); + + // create the app + ApplicationInfo appInfo = + setup.getMgmtSvc().createApplication( orgs.getOrganization().getUuid(), params.get( "appName" ) ); + assertNotNull( appInfo ); + + String adminToken = setup.getMgmtSvc().getAccessTokenForAdminUser( orgs.getOwner().getUuid(), 0 ); + + JsonNode node = mapper.readTree( resource() + .path( String.format( "/%s/%s/roles/default", params.get( "orgName" ), params.get( "appName" ) ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class )); + Map<String, String> data = hashMap( "name", "reviewer" ); + + node = mapper.readTree( resource().path( String.format( "/%s/%s/roles", params.get( "orgName" ), params.get( "appName" ) ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, data )); + assertNull( getError( node ) ); + + refreshIndex(orgname, applicationName); + + // allow access to reviews + addPermission( params.get( "orgName" ), params.get( "appName" ), adminToken, "reviewer", + "get,put,post:/reviews/**" ); + // allow access to all user's connections + addPermission( params.get( "orgName" ), params.get( "appName" ), adminToken, "reviewer", + "get,put,post:/users/${user}/**" ); + // allow access to the review relationship + addPermission( params.get( "orgName" ), params.get( "appName" ), adminToken, "reviewer", + "get,put,post:/books/*/review/*" ); + + assertNull( getError( node ) ); + // create userOne + UUID userOneId = + createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "wildcardpermuserone", + "[email protected]" ); + assertNotNull( userOneId ); + + // create userTwo + UUID userTwoId = + createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "wildcardpermusertwo", + "[email protected]" ); + assertNotNull( userTwoId ); + + refreshIndex(orgname, applicationName); + + // assign userOne the reviewer role + node = mapper.readTree( resource().path( String + .format( "/%s/%s/users/%s/roles/reviewer", params.get( "orgName" ), params.get( "appName" ), + userOneId.toString() ) ).queryParam( "access_token", adminToken ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).post( String.class )); + + refreshIndex(orgname, applicationName); + + Map<String, String> book = hashMap( "title", "Ready Player One" ).map( "author", "Earnest Cline" ); + + // create a book as admin + node = mapper.readTree( resource().path( String.format( "/%s/%s/books", params.get( "orgName" ), params.get( "appName" ) ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, book )); + + logNode( node ); + assertEquals( "Ready Player One", getEntity( node, 0 ).get( "title" ).textValue() ); + String bookId = getEntity( node, 0 ).get( "uuid" ).textValue(); + + refreshIndex(orgname, applicationName); + + String userOneToken = setup.getMgmtSvc().getAccessTokenForAppUser( appInfo.getId(), userOneId, 0 ); + // post a review of the book as user1 + // POST https://api.usergrid.com/my-org/my-app/users/$user1/reviewed/books/$uuid + Map<String, String> review = + hashMap( "heading", "Loved It" ).map( "body", "80s Awesomeness set in the future" ); + node = mapper.readTree( resource().path( String.format( "/%s/%s/reviews", params.get( "orgName" ), params.get( "appName" ) ) ) + .queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, review )); + String reviewId = getEntity( node, 0 ).get( "uuid" ).textValue(); + + refreshIndex(orgname, applicationName); + + // POST https://api.usergrid.com/my-org/my-app/users/me/wrote/review/${reviewId} + node = mapper.readTree( resource().path( String + .format( "/%s/%s/users/me/wrote/review/%s", params.get( "orgName" ), params.get( "appName" ), + reviewId ) ).queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class )); + + refreshIndex(orgname, applicationName); + + node = mapper.readTree( resource().path( String + .format( "/%s/%s/users/me/reviewed/books/%s", params.get( "orgName" ), params.get( "appName" ), + bookId ) ).queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class )); + logNode( node ); + + refreshIndex(orgname, applicationName); + + // POST https://api.usergrid.com/my-org/my-app/books/${bookId}/review/${reviewId} + node = mapper.readTree( resource().path( String + .format( "/%s/%s/books/%s/review/%s", params.get( "orgName" ), params.get( "appName" ), bookId, + reviewId ) ).queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class )); + logNode( node ); + + refreshIndex(orgname, applicationName); + + // now try to post the same thing to books to verify as userOne the failure + Status status = null; + try { + node = mapper.readTree( resource().path( String.format( "/%s/%s/books", params.get( "orgName" ), params.get( "appName" ) ) ) + .queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class )); + logNode( node ); + } + catch ( UniformInterfaceException uie ) { + status = uie.getResponse().getClientResponseStatus(); + } + assertEquals( Status.UNAUTHORIZED, status ); + + refreshIndex(orgname, applicationName); + + node = mapper.readTree( resource().path( String + .format( "/%s/%s/users/me/reviewed/books", params.get( "orgName" ), params.get( "appName" ) ) ) + .queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + logNode( node ); + + node = mapper.readTree( resource().path( String + .format( "/%s/%s/reviews/%s", params.get( "orgName" ), params.get( "appName" ), reviewId ) ) + .queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + logNode( node ); + + node = mapper.readTree( resource() + .path( String.format( "/%s/%s/users/me/wrote", params.get( "orgName" ), params.get( "appName" ) ) ) + .queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + logNode( node ); + } + + + /** + * Tests the scenario where we have role declaration such as: <ul> <li>POST /users/[star]/following/users/${user}" a + * user can add himself to any other user following list"</li> </ul> + * <p/> + * Scenario is as follows: Create an application + * <p/> + * Add two application users - examplepatient - exampledoctor + * <p/> + * examplepatient add himself to exampledoctor following list + */ + @Test + @Ignore("Why is this ignored?") + public void wildcardFollowingPermission() throws Exception { + UUID id = UUIDUtils.newTimeUUID(); + + String applicationName = "test"; + String orgname = "followingpermissions"; + String username = "permissionadmin" + id; + String password = "password"; + String email = String.format( "[email protected]", id ); + + OrganizationOwnerInfo orgs = setup.getMgmtSvc() + .createOwnerAndOrganization( orgname, username, "noname", email, password, + true, false ); + + // create the app + ApplicationInfo appInfo = + setup.getMgmtSvc().createApplication( orgs.getOrganization().getUuid(), applicationName ); + assertNotNull( appInfo ); + + String adminToken = setup.getMgmtSvc().getAccessTokenForAdminUser( orgs.getOwner().getUuid(), 0 ); + + JsonNode node = mapper.readTree( resource().path( String.format( "/%s/%s/roles/default", orgname, applicationName ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class )); + Map<String, String> data = hashMap( "name", "patient" ); + + node = mapper.readTree( resource().path( String.format( "/%s/%s/roles", orgname, applicationName ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, data )); + assertNull( getError( node ) ); + //allow patients to add doctors as their followers + addPermission( orgname, applicationName, adminToken, "patient", + "delete,post:/users/*/following/users/${user}" ); + + assertNull( getError( node ) ); + // create examplepatient + UUID patientId = + createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "examplepatient", + "[email protected]" ); + assertNotNull( patientId ); + + // create exampledoctor + UUID doctorId = createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "exampledoctor", + "[email protected]" ); + assertNotNull( doctorId ); + + + // assign examplepatient the patient role + node = mapper.readTree( resource().path( String + .format( "/%s/%s/users/%s/roles/patient", orgname, applicationName, patientId.toString() ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class )); + + String patientToken = setup.getMgmtSvc().getAccessTokenForAppUser( appInfo.getId(), patientId, 0 ); + + node = mapper.readTree( resource().path( String + .format( "/%s/%s/users/%s/following/users/%s", orgname, applicationName, "exampledoctor", + "examplepatient" ) ).queryParam( "access_token", patientToken ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).post( String.class )); + logNode( node ); + } + + + private Map<String, String> buildOrgAppParams() { + UUID id = UUIDUtils.newTimeUUID(); + Map<String, String> props = + hashMap( "username", "wcpermadmin" ).map( "orgName", "orgnamewcperm" ).map( "appName", "test" ) + .map( "password", "password" ) + .map( "email", String.format( "[email protected]", id.toString() ) ); + + return props; + } + + + /** + * Create the user, check there are no errors + * + * @return the userid + */ + private UUID createRoleUser( UUID orgId, UUID appId, String adminToken, String username, String email ) + throws Exception { + + Map<String, String> props = hashMap( "email", email ).map( "username", username ).map( "name", username ) + .map( "password", "password" ); + + JsonNode node = mapper.readTree( resource().path( String.format( "/%s/%s/users", orgId, appId ) ) + .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).put( String.class, props )); + + assertNull( getError( node ) ); + + UUID userId = UUID.fromString( getEntity( node, 0 ).get( "uuid" ).asText() ); + + // manually activate user + setup.getMgmtSvc().activateAppUser( appId, userId ); + + return userId; + } + + + /** Test adding the permission to the role */ + private void addPermission( String orgname, String appname, String adminToken, String rolename, String grant ) throws IOException { + Map<String, String> props = hashMap( "permission", grant ); + + String rolePath = String.format( "/%s/%s/roles/%s/permissions", orgname, appname, rolename ); + + JsonNode node = mapper.readTree( resource().path( rolePath ).queryParam( "access_token", adminToken ) + .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ) + .put( String.class, props )); + + assertNull( getError( node ) ); + + node = mapper.readTree( resource().path( rolePath ).queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON ) + .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class )); + + ArrayNode data = ( ArrayNode ) node.get( "data" ); + + Iterator<JsonNode> iterator = data.elements(); + + while ( iterator.hasNext() ) { + if ( grant.equals( iterator.next().asText() ) ) { + return; + } + } + + fail( String.format( "didn't find grant %s in the results", grant ) ); + } + + + /** Test adding the permission to the role */ + private void addPermission( String orgname, String appname, String rolename, String grant ) throws IOException { + Map<String, String> props = hashMap( "permission", grant ); + + String rolePath = String.format( "/%s/%s/roles/%s/permissions", orgname, appname, rolename ); + + JsonNode node = mapper.readTree( resource().path( rolePath ).accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ) + .put( String.class, props )); + + assertNull( getError( node ) ); + + node = mapper.readTree( resource().path( rolePath ).accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ) + .get( String.class )); + + ArrayNode data = ( ArrayNode ) node.get( "data" ); + + Iterator<JsonNode> iterator = data.elements(); + + while ( iterator.hasNext() ) { + if ( grant.equals( iterator.next().asText() ) ) { + return; + } + } + + fail( String.format( "didn't find grant %s in the results", grant ) ); + } +}
