| /* |
| * 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.management; |
| |
| |
| import com.fasterxml.jackson.databind.JsonNode; |
| import com.sun.jersey.api.client.ClientResponse.Status; |
| import com.sun.jersey.api.client.UniformInterfaceException; |
| import com.sun.jersey.api.representation.Form; |
| import org.apache.commons.lang.RandomStringUtils; |
| |
| import org.apache.usergrid.persistence.index.utils.UUIDUtils; |
| import org.apache.usergrid.rest.management.organizations.OrganizationsResource; |
| import org.apache.usergrid.rest.test.resource2point0.AbstractRestIT; |
| import org.apache.usergrid.rest.test.resource2point0.model.*; |
| import org.apache.usergrid.rest.test.resource2point0.model.Collection; |
| import org.junit.Before; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import javax.ws.rs.core.MediaType; |
| import java.io.IOException; |
| import java.util.*; |
| |
| import static org.apache.usergrid.rest.AbstractRestIT.logNode; |
| import static org.apache.usergrid.rest.management.ManagementResource.USERGRID_CENTRAL_URL; |
| import static org.apache.usergrid.utils.MapUtils.hashMap; |
| import static org.junit.Assert.*; |
| |
| /** |
| * @author tnine |
| */ |
| public class ManagementResourceIT extends AbstractRestIT { |
| |
| private static final Logger logger = LoggerFactory.getLogger(ManagementResourceIT.class); |
| private org.apache.usergrid.rest.test.resource2point0.endpoints.mgmt.ManagementResource management; |
| |
| public ManagementResourceIT() throws Exception { |
| |
| } |
| |
| |
| @Before |
| public void setup() { |
| management= clientSetup.getRestClient().management(); |
| Token token = management.token().get(new QueryParameters().addParam("grant_type", "password").addParam("username", clientSetup.getEmail()).addParam("password", clientSetup.getPassword())); |
| management.token().setToken(token); |
| } |
| |
| /** |
| * Test if we can reset our password as an admin |
| */ |
| @Test |
| public void setSelfAdminPasswordAsAdwmin() { |
| UUID uuid = UUIDUtils.newTimeUUID(); |
| management.token().setToken(clientSetup.getSuperuserToken()); |
| management.orgs().org( clientSetup.getOrganizationName() ).users().post(ApiResponse.class, new User("test" + uuid, "test" + uuid, "test" + uuid + "@email.com", "test")); |
| Map<String, Object> data = new HashMap<>(); |
| data.put( "newpassword", "foo" ); |
| data.put( "oldpassword", "test" ); |
| management.users().user("test"+uuid).password().post(Entity.class, data); |
| Token token = management.token().post(Token.class, new Token( "test"+uuid, "foo" ) ); |
| management.token().setToken( token ); |
| data.clear(); |
| data.put( "oldpassword", "foo" ); |
| data.put( "newpassword", "test" ); |
| management.users().user("test"+uuid).password().post(Entity.class,data); |
| } |
| |
| |
| /** |
| * Test that admins can't view organizations they're not authorized to view. |
| */ |
| @Test |
| public void crossOrgsNotViewable() throws Exception { |
| |
| String username = "test" + UUIDUtils.newTimeUUID(); |
| String name = "someguy2"; |
| String email = "someguy" + "@usergrid.com"; |
| String password = "password"; |
| String orgName = "someneworg"; |
| |
| Entity payload = |
| new Entity().chainPut("company", "Apigee" ); |
| |
| Organization organization = new Organization(orgName,username,email,name,password,payload); |
| |
| Organization node = management().orgs().post( organization ); |
| management.token().get(clientSetup.getUsername(),clientSetup.getPassword()); |
| |
| // check that the test admin cannot access the new org info |
| |
| Status status = null; |
| String returnVal = ""; |
| |
| try { |
| returnVal = this.management().orgs().org( orgName ).get(String.class); |
| } |
| catch ( UniformInterfaceException uie ) { |
| status = uie.getResponse().getClientResponseStatus(); |
| } |
| |
| assertNotNull( status ); |
| assertEquals( Status.UNAUTHORIZED, status ); |
| |
| // this admin should have access to test org |
| status = null; |
| try { |
| this.management().orgs().org( this.clientSetup.getOrganizationName() ).get( String.class ); |
| } |
| catch ( UniformInterfaceException uie ) { |
| status = uie.getResponse().getClientResponseStatus(); |
| } |
| |
| assertNull( status ); |
| |
| //test getting the organization by org |
| |
| status = null; |
| try { |
| this.management().orgs().org( this.clientSetup.getOrganizationName() ).get( String.class ); |
| } |
| catch ( UniformInterfaceException uie ) { |
| status = uie.getResponse().getClientResponseStatus(); |
| } |
| |
| assertNull( status ); |
| } |
| |
| |
| /** |
| * Test that we can support over 10 items in feed. |
| */ |
| @Test |
| public void mgmtFollowsUserFeed() throws Exception { |
| List<String> users1 = new ArrayList<String>(); |
| int i; |
| //try with 10 users |
| for ( i = 0; i < 10; i++ ) { |
| users1.add( "follower" + Integer.toString( i ) ); |
| } |
| |
| refreshIndex( ); |
| |
| checkFeed( "leader1", users1 ); |
| //try with 11 |
| List<String> users2 = new ArrayList<String>(); |
| for ( i = 20; i < 31; i++ ) { |
| users2.add( "follower" + Integer.toString( i ) ); |
| } |
| checkFeed( "leader2", users2 ); |
| } |
| |
| |
| private void checkFeed( String leader, List<String> followers ) throws IOException { |
| List<Entity> userFeed; |
| |
| //create user |
| createUser( leader ); |
| refreshIndex( ); |
| |
| String preFollowContent = leader + ": pre-something to look for " + UUID.randomUUID().toString(); |
| |
| addActivity( leader, leader + " " + leader + "son", preFollowContent ); |
| refreshIndex( ); |
| |
| String lastUser = followers.get( followers.size() - 1 ); |
| int i = 0; |
| for ( String user : followers ) { |
| createUser( user ); |
| refreshIndex( ); |
| follow( user, leader ); |
| refreshIndex( ); |
| } |
| userFeed = getUserFeed( lastUser ); |
| assertTrue( userFeed.size() == 1 ); |
| |
| //retrieve feed |
| userFeed = getUserFeed( lastUser ); |
| assertTrue( userFeed.size() == 1 ); |
| String postFollowContent = leader + ": something to look for " + UUID.randomUUID().toString(); |
| addActivity( leader, leader + " " + leader + "son", postFollowContent ); |
| |
| refreshIndex( ); |
| |
| //check feed |
| userFeed = getUserFeed( lastUser ); |
| assertNotNull( userFeed ); |
| assertTrue( userFeed.size() > 1 ); |
| String serialized = ((Entity)userFeed.get(0)).get("content").toString()+ ((Entity)userFeed.get(1)).get("content").toString(); |
| assertTrue( serialized.indexOf( postFollowContent ) >= 0 ); |
| assertTrue( serialized.indexOf( preFollowContent ) >= 0 ); |
| } |
| |
| |
| private void createUser( String username ) { |
| Map<String, Object> payload = new LinkedHashMap<String, Object>(); |
| payload.put( "username", username ); |
| this.app().collection("users").post(String.class, payload); |
| } |
| |
| |
| private List<Entity> getUserFeed( String username ) throws IOException { |
| Collection collection = this.app().collection("users").entity(username).collection("feed").get(); |
| return collection.getResponse().getEntities(); |
| } |
| |
| |
| private void follow( String user, String followUser ) { |
| //post follow |
| Entity entity = this.app().collection("users").entity(user).collection("following").collection("users").entity(followUser).post(); |
| } |
| |
| |
| private void addActivity( String user, String name, String content ) { |
| Map<String, Object> activityPayload = new HashMap<String, Object>(); |
| activityPayload.put( "content", content ); |
| activityPayload.put( "verb", "post" ); |
| Map<String, String> actorMap = new HashMap<String, String>(); |
| actorMap.put( "displayName", name ); |
| actorMap.put( "username", user ); |
| activityPayload.put("actor", actorMap); |
| Entity entity = this.app().collection("users").entity(user).collection("activities").post(new Entity(activityPayload)); |
| } |
| |
| |
| @Test |
| public void mgmtCreateAndGetApplication() throws Exception { |
| |
| |
| |
| // POST /applications |
| ApiResponse apiResponse = management().orgs().org( clientSetup.getOrganizationName() ).app().post(new Application("mgmt-org-app")); |
| |
| |
| refreshIndex(); |
| |
| Entity appdata = apiResponse.getEntities().get(0); |
| assertEquals((clientSetup.getOrganizationName() + "/mgmt-org-app").toLowerCase(), appdata.get("name").toString().toLowerCase()); |
| assertNotNull(appdata.get("metadata")); |
| Map metadata =(Map) appdata.get( "metadata" ); |
| assertNotNull(metadata.get("collections")); |
| Map collections = ((Map)metadata.get("collections")); |
| assertNotNull(collections.get("roles")); |
| Map roles =(Map) collections.get("roles"); |
| assertNotNull(roles.get("title")); |
| assertEquals("Roles", roles.get("title").toString()); |
| assertEquals(4, roles.size()); |
| |
| refreshIndex( ); |
| |
| // GET /applications/mgmt-org-app |
| |
| |
| Entity app = management().orgs().org( clientSetup.getOrganizationName() ).app().addToPath("mgmt-org-app").get(); |
| |
| |
| assertEquals(this.clientSetup.getOrganizationName().toLowerCase(), app.get("organizationName").toString()); |
| assertEquals( "mgmt-org-app", app.get( "applicationName" ).toString() ); |
| |
| assertEquals( clientSetup.getOrganizationName().toLowerCase() + "/mgmt-org-app", app.get( "name" ).toString() ); |
| metadata =(Map) appdata.get( "metadata" ); |
| collections = ((Map)metadata.get("collections")); |
| roles =(Map) collections.get("roles"); |
| |
| assertEquals( "Roles", roles.get("title").toString() ); |
| assertEquals(4, roles.size()); |
| } |
| |
| @Test |
| public void tokenTtl() throws Exception { |
| |
| long ttl = 2000; |
| |
| Token token = management.token().get(new QueryParameters().addParam("grant_type", "password").addParam("username", clientSetup.getEmail()).addParam("password", clientSetup.getPassword()).addParam("ttl", String.valueOf(ttl))); |
| |
| |
| long startTime = System.currentTimeMillis(); |
| |
| |
| assertNotNull( token ); |
| |
| Entity userdata = management.users().entity(clientSetup.getEmail()).get(token); |
| |
| assertNotNull(userdata.get("email").toString()); |
| |
| // wait for the token to expire |
| Thread.sleep( (System.currentTimeMillis() - startTime) + ttl ); |
| |
| Status responseStatus = null; |
| try { |
| userdata = management.users().user(clientSetup.getEmail()).get(); |
| } |
| catch ( UniformInterfaceException uie ) { |
| responseStatus = uie.getResponse().getClientResponseStatus(); |
| } |
| |
| assertEquals( Status.UNAUTHORIZED, responseStatus ); |
| } |
| |
| |
| @Test |
| public void token() throws Exception { |
| Token myToken = management.token().get(new QueryParameters().addParam("grant_type", "password").addParam("username", clientSetup.getEmail()).addParam("password", clientSetup.getPassword())); |
| |
| String token = myToken.getAccessToken(); |
| assertNotNull( token ); |
| |
| // set an organization property |
| Organization payload = new Organization(); |
| Map<String, Object> properties = new HashMap<String, Object>(); |
| properties.put( "securityLevel", 5 ); |
| payload.put( OrganizationsResource.ORGANIZATION_PROPERTIES, properties ); |
| management.orgs().org( clientSetup.getOrganizationName() ) |
| .put(payload); |
| |
| |
| // ensure the organization property is included |
| String obj = management.token().get(String.class,new QueryParameters().addParam("access_token", token)); |
| assertTrue(obj.indexOf("securityLevel")>0); |
| } |
| |
| |
| @Test |
| public void meToken() throws Exception { |
| QueryParameters queryParameters = new QueryParameters().addParam("grant_type", "password") |
| .addParam("username", clientSetup.getUsername()).addParam("password",clientSetup.getPassword()); |
| Token myToken = management.me().get(Token.class,queryParameters); |
| |
| |
| String token = myToken.getAccessToken(); |
| assertNotNull( token ); |
| |
| Entity entity = management.me().get( Entity.class ); |
| |
| assertNotNull( entity.get( "passwordChanged" ) ); |
| assertNotNull( entity.get( "access_token" ) ); |
| assertNotNull( entity.get( "expires_in" ) ); |
| Map<String,Object> userNode =(Map<String,Object>) entity.get( "user" ); |
| assertNotNull( userNode ); |
| assertNotNull( userNode.get( "uuid" ) ); |
| assertNotNull( userNode.get( "username" ) ); |
| assertNotNull( userNode.get( "email" ) ); |
| assertNotNull( userNode.get( "name" ) ); |
| assertNotNull( userNode.get( "properties" ) ); |
| Map<String,Object> orgsNode = (Map<String,Object>) userNode.get( "organizations" ); |
| assertNotNull( orgsNode ); |
| Map<String,Object> orgNode =(Map<String,Object>) orgsNode.entrySet().iterator().next().getValue(); |
| assertNotNull( orgNode ); |
| assertNotNull( orgNode.get( "name" ) ); |
| assertNotNull( orgNode.get( "properties" ) ); |
| } |
| |
| |
| @Test |
| public void meTokenPost() throws Exception { |
| Map<String, String> payload = |
| hashMap( "grant_type", "password" ).map( "username", clientSetup.getUsername() ).map( "password",clientSetup.getPassword() ); |
| |
| JsonNode node = management.me().post(JsonNode.class, payload); |
| |
| logNode( node ); |
| String token = node.get( "access_token" ).textValue(); |
| |
| assertNotNull( token ); |
| |
| node = management.me().get( JsonNode.class ); |
| } |
| |
| |
| @Test |
| public void meTokenPostForm() { |
| |
| Form form = new Form(); |
| form.add( "grant_type", "password" ); |
| form.add( "username", clientSetup.getUsername() ); |
| form.add( "password", clientSetup.getPassword() ); |
| |
| JsonNode node = management.me().post( JsonNode.class, form ); |
| |
| logNode( node ); |
| String token = node.get( "access_token" ).textValue(); |
| |
| assertNotNull( token ); |
| |
| node = resource().path( "/management/me" ).queryParam( "access_token", token ) |
| .accept( MediaType.APPLICATION_JSON ).get( JsonNode.class ); |
| logNode( node ); |
| } |
| |
| |
| @Test |
| public void ttlNan() throws Exception { |
| |
| Map<String, String> payload = |
| hashMap( "grant_type", "password" ).map("username", clientSetup.getUsername()).map( "password",clientSetup.getPassword() ) |
| .map("ttl", "derp"); |
| |
| Status responseStatus = null; |
| try { |
| management.token().post(JsonNode.class, payload); |
| } |
| catch ( UniformInterfaceException uie ) { |
| responseStatus = uie.getResponse().getClientResponseStatus(); |
| } |
| |
| assertEquals( Status.BAD_REQUEST, responseStatus ); |
| } |
| |
| |
| @Test |
| public void ttlOverMax() throws Exception { |
| |
| Map<String, String> payload = |
| hashMap( "grant_type", "password" ).map( "username", clientSetup.getUsername()).map( "password", clientSetup.getPassword() ) |
| .map( "ttl", Long.MAX_VALUE + "" ); |
| |
| Status responseStatus = null; |
| |
| try { |
| management.token().post(JsonNode.class, payload); |
| } |
| catch ( UniformInterfaceException uie ) { |
| responseStatus = uie.getResponse().getClientResponseStatus(); |
| } |
| |
| assertEquals( Status.BAD_REQUEST, responseStatus ); |
| } |
| |
| |
| @Test |
| public void revokeToken() throws Exception { |
| Token token1 = management.token().get(clientSetup.getUsername(),clientSetup.getPassword()); |
| |
| Entity response = management.users().user(clientSetup.getUsername()).get(); |
| |
| assertNotNull(response.get("email").toString()); |
| |
| response = management.users().user(clientSetup.getUsername()).get(); |
| |
| assertNotNull(response.get("email").toString()); |
| |
| // now revoke the tokens |
| response = management.users().user(clientSetup.getUsername()).revokeTokens().post(true,Entity.class,null, null,false); |
| |
| // the tokens shouldn't work |
| |
| Status status = null; |
| |
| try { |
| response = management.users().user(clientSetup.getUsername()).get(); |
| } |
| catch ( UniformInterfaceException uie ) { |
| status = uie.getResponse().getClientResponseStatus(); |
| } |
| |
| assertEquals( Status.UNAUTHORIZED, status ); |
| |
| Token token3 = management.token().get(clientSetup.getUsername(), clientSetup.getPassword()); |
| |
| response = management.users().user(clientSetup.getUsername()).get(); |
| assertNotNull(response.get("email").toString()); |
| |
| // now revoke the token3 |
| QueryParameters queryParameters = new QueryParameters(); |
| queryParameters.addParam( "token", token3.getAccessToken() ); |
| management.users().user(clientSetup.getUsername()).revokeToken().post( false, Entity.class,null,queryParameters ); |
| |
| // the token3 shouldn't work |
| status = null; |
| |
| try { |
| management.users().user(clientSetup.getUsername()).get(); |
| } |
| catch ( UniformInterfaceException uie ) { |
| status = uie.getResponse().getClientResponseStatus(); |
| } |
| |
| assertEquals( Status.UNAUTHORIZED, status ); |
| |
| } |
| |
| |
| @Test |
| @Ignore |
| public void testValidateExternalToken() throws Exception { |
| |
| // create a new admin user, get access token |
| |
| String rand = RandomStringUtils.randomAlphanumeric(10); |
| final String username = "user_" + rand; |
| management().orgs().post( |
| new Organization( username, username, username+"@example.com", username, "password", null ) ); |
| |
| refreshIndex(); |
| QueryParameters queryParams = new QueryParameters().addParam("username", username ).addParam("password", "password").addParam("grant_type", "password"); |
| Token accessInfoNode = management.token().get(queryParams); |
| String accessToken = accessInfoNode.getAccessToken(); |
| |
| // set the Usergrid Central SSO URL because Tomcat port is dynamically assigned |
| |
| String suToken = clientSetup.getSuperuserToken().getAccessToken(); |
| Map<String, String> props = new HashMap<String, String>(); |
| props.put( USERGRID_CENTRAL_URL, getBaseURI().toURL().toExternalForm() ); |
| resource().path( "/testproperties" ) |
| .queryParam("access_token", suToken) |
| .accept( MediaType.APPLICATION_JSON ) |
| .type( MediaType.APPLICATION_JSON_TYPE ) |
| .post( props ); |
| |
| // attempt to validate the token, must be valid |
| queryParams = new QueryParameters().addParam("access_token", suToken ).addParam("ext_access_token", accessToken).addParam("ttl", "1000"); |
| |
| Entity validatedNode = management.externaltoken().get(Entity.class,queryParams); |
| String validatedAccessToken = validatedNode.get( "access_token" ).toString(); |
| assertEquals( accessToken, validatedAccessToken ); |
| |
| // attempt to validate an invalid token, must fail |
| |
| try { |
| queryParams = new QueryParameters().addParam("access_token", suToken ).addParam("ext_access_token", "rubbish_token").addParam("ttl", "1000"); |
| |
| validatedNode = management.externaltoken().get(Entity.class,queryParams); |
| |
| fail("Validation should have failed"); |
| } catch ( UniformInterfaceException actual ) { |
| assertEquals( 404, actual.getResponse().getStatus() ); |
| String errorMsg = actual.getResponse().getEntity( JsonNode.class ).get( "error_description" ).toString(); |
| logger.error( "ERROR: " + errorMsg ); |
| assertTrue( errorMsg.contains( "Cannot find Admin User" ) ); |
| } |
| |
| |
| |
| // TODO: how do we test the create new user and organization case? |
| |
| |
| |
| // unset the Usergrid Central SSO URL so it does not interfere with other tests |
| |
| props.put( USERGRID_CENTRAL_URL, "" ); |
| resource().path( "/testproperties" ) |
| .queryParam( "access_token", suToken) |
| .accept( MediaType.APPLICATION_JSON ) |
| .type( MediaType.APPLICATION_JSON_TYPE ) |
| .post( props ); |
| |
| } |
| |
| |
| @Test |
| @Ignore |
| public void testSuperuserOnlyWhenValidateExternalTokensEnabled() throws Exception { |
| |
| // create an org and an admin user |
| |
| String rand = RandomStringUtils.randomAlphanumeric( 10 ); |
| final String username = "user_" + rand; |
| management().orgs().post( |
| new Organization( username, username, username+"@example.com", username, "password", null ) ); |
| |
| // turn on validate external tokens by setting the usergrid.central.url |
| |
| String suToken = clientSetup.getSuperuserToken().getAccessToken(); |
| Map<String, String> props = new HashMap<String, String>(); |
| props.put( USERGRID_CENTRAL_URL, getBaseURI().toURL().toExternalForm()); |
| resource().path( "/testproperties" ) |
| .queryParam( "access_token", suToken) |
| .accept( MediaType.APPLICATION_JSON ) |
| .type( MediaType.APPLICATION_JSON_TYPE ) |
| .post( props ); |
| |
| // calls to login as an Admin User must now fail |
| |
| try { |
| |
| Map<String, Object> loginInfo = new HashMap<String, Object>() {{ |
| put("username", username ); |
| put("password", "password"); |
| put("grant_type", "password"); |
| }}; |
| JsonNode accessInfoNode = resource().path("/management/token") |
| .type( MediaType.APPLICATION_JSON_TYPE ) |
| .post( JsonNode.class, loginInfo ); |
| fail("Login as Admin User must fail when validate external tokens is enabled"); |
| |
| } catch ( UniformInterfaceException actual ) { |
| assertEquals( 400, actual.getResponse().getStatus() ); |
| String errorMsg = actual.getResponse().getEntity( JsonNode.class ).get( "error_description" ).toString(); |
| logger.error( "ERROR: " + errorMsg ); |
| assertTrue( errorMsg.contains( "Admin Users must login via" )); |
| |
| } catch ( Exception e ) { |
| fail( "We expected a UniformInterfaceException" ); |
| } |
| |
| // login as superuser must succeed |
| |
| Map<String, Object> loginInfo = new HashMap<String, Object>() {{ |
| put("username", "superuser"); |
| put("password", "superpassword"); |
| put("grant_type", "password"); |
| }}; |
| JsonNode accessInfoNode = resource().path("/management/token") |
| .type( MediaType.APPLICATION_JSON_TYPE ) |
| .post( JsonNode.class, loginInfo ); |
| String accessToken = accessInfoNode.get( "access_token" ).textValue(); |
| assertNotNull( accessToken ); |
| |
| // turn off validate external tokens by un-setting the usergrid.central.url |
| |
| props.put( USERGRID_CENTRAL_URL, "" ); |
| resource().path( "/testproperties" ) |
| .queryParam( "access_token", suToken) |
| .accept( MediaType.APPLICATION_JSON ) |
| .type( MediaType.APPLICATION_JSON_TYPE ) |
| .post( props ); |
| } |
| |
| } |