usergrid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From g...@apache.org
Subject [9/9] incubator-usergrid git commit: An additional test for validate external tokens logic, plus some related fixes to superuser-only login logic.
Date Thu, 16 Apr 2015 18:09:33 GMT
An additional test for validate external tokens logic, plus some related fixes to superuser-only
login logic.


Project: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/commit/25d0077e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/25d0077e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/25d0077e

Branch: refs/heads/master
Commit: 25d0077edd0b69607459ef3b0c87d276498adac9
Parents: 6ae492e
Author: Dave Johnson <dmjohnson@apigee.com>
Authored: Thu Apr 16 11:22:07 2015 -0400
Committer: Dave Johnson <dmjohnson@apigee.com>
Committed: Thu Apr 16 11:22:07 2015 -0400

----------------------------------------------------------------------
 .../rest/management/ManagementResource.java     | 161 ++++++++++---------
 .../rest/management/ManagementResourceIT.java   | 108 +++++++++++--
 2 files changed, 176 insertions(+), 93 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/25d0077e/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
b/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
index 73963fe..2bbcfd9 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
@@ -37,6 +37,7 @@ import org.apache.usergrid.exception.NotImplementedException;
 import org.apache.usergrid.management.ApplicationCreator;
 import org.apache.usergrid.management.OrganizationInfo;
 import org.apache.usergrid.management.OrganizationOwnerInfo;
+import org.apache.usergrid.persistence.entities.User;
 import org.apache.usergrid.persistence.exceptions.EntityNotFoundException;
 import org.codehaus.jackson.JsonNode;
 import org.slf4j.Logger;
@@ -87,6 +88,8 @@ import static org.apache.usergrid.utils.StringUtils.stringOrSubstringBeforeFirst
 } )
 public class ManagementResource extends AbstractContextResource {
 
+    private static final Logger logger = LoggerFactory.getLogger( ManagementResource.class
);
+
     /*-
      * New endpoints:
      * 
@@ -99,32 +102,17 @@ public class ManagementResource extends AbstractContextResource {
      * 
      */
 
-    private static final Logger logger = LoggerFactory.getLogger( ManagementResource.class
);
-
     @Autowired
     private ApplicationCreator applicationCreator;
 
     public static final String USERGRID_CENTRAL_URL = "usergrid.central.url";
 
-    private boolean superuserAllowed;
-
-    private boolean externalTokensEnabled;
+    public static final String USERGRID_SYSADMIN_LOGIN_NAME = "usergrid.sysadmin.login.name";
 
-    private String superuserName;
+    public static final String USERGRID_SYSADMIN_LOGIN_ALLOWED = "usergrid.sysadmin.login.allowed";
 
 
     public ManagementResource() {
-
-        String superuserAllowedStr =  properties.getProperty( "usergrid.sysadmin.login.allowed"
);
-
-        superuserName = properties.getProperty( "usergrid.sysadmin.login.name" );
-
-        superuserAllowed = !StringUtils.isEmpty( superuserAllowedStr )
-                && superuserAllowedStr.trim().equalsIgnoreCase( "true" );
-
-        externalTokensEnabled =
-                !StringUtils.isEmpty( properties.getProperty( USERGRID_CENTRAL_URL ));
-
         logger.info( "ManagementResource initialized" );
     }
 
@@ -196,20 +184,11 @@ public class ManagementResource extends AbstractContextResource {
     }
 
 
-    private Response getAccessTokenInternal( UriInfo ui, String authorization, String grant_type,
String username,
+   private Response getAccessTokenInternal( UriInfo ui, String authorization, String grant_type,
String username,
                                              String password, String client_id, String client_secret,
long ttl,
                                              String callback, boolean loadAdminData ) throws
Exception {
 
 
-        // when external tokens (Usergrid Central SSO) are enabled only superuser can login
as Admin User.
-        if ( externalTokensEnabled &&
-                superuserAllowed && !username.equalsIgnoreCase( superuserName ))
{
-
-            // cause an HTTP 400 response with a useful message
-            throw  new IllegalArgumentException("Admin Users must login via " +
-                properties.getProperty( USERGRID_CENTRAL_URL ));
-        }
-
         UserInfo user = null;
 
         try {
@@ -222,6 +201,11 @@ public class ManagementResource extends AbstractContextResource {
             String errorDescription = "invalid username or password";
 
             if ( user == null ) {
+
+                // make sure authentication is allowed considering
+                // external token validation configuration (UG Central SSO)
+                ensureAuthenticationAllowed( username, grant_type );
+
                 if ( authorization != null ) {
                     String type = stringOrSubstringBeforeFirst( authorization, ' ' ).toUpperCase();
 
@@ -482,15 +466,7 @@ public class ManagementResource extends AbstractContextResource {
 
     /**
      * <p>
-     * Validates access token from other or "external" Usergrid system.
-     * Calls other system's /management/me endpoint to get the User associated with the access
token.
-     * If user does not exist locally, then user and organization with the same name of user
is created.
-     * If no user is returned from the other cluster, then this endpoint will return 401.
-     * <p>
-     *
-     * <p>
-     * See <a href="https://issues.apache.org/jira/browse/USERGRID-567">USERGRID-567</a>
-     * for details about Usergrid Central SSO.
+     * Allows call to validateExternalToken() (see below) with a POST of a JSON object.
      * </p>
      *
      * @param ui             Information about calling URI.
@@ -573,71 +549,74 @@ public class ManagementResource extends AbstractContextResource {
         if ( ttl == -1 ) {
             throw new IllegalArgumentException("ttl must be specified");
         }
+        AccessInfo accessInfo = null;
 
-        // look up user via UG Central's /management/me endpoint.
-
-        JsonNode accessInfoNode = getMeFromUgCentral( extAccessToken );
-
-        JsonNode userNode = accessInfoNode.get( "user" );
-        String username = userNode.get( "username" ).getTextValue();
+        try {
+            // look up user via UG Central's /management/me endpoint.
 
-        // if user does not exist locally then we need to fix that
+            JsonNode accessInfoNode = getMeFromUgCentral( extAccessToken );
 
-        UUID userId = management.getAdminUserByUsername( username ).getUuid();
+            JsonNode userNode = accessInfoNode.get( "user" );
+            String username = userNode.get( "username" ).getTextValue();
 
-        if ( userId == null ) {
+            // if user does not exist locally then we need to fix that
 
-            // create local user and and organizations they have on the central Usergrid
instance
+            UserInfo userInfo = management.getAdminUserByUsername( username );
+            UUID userId = userInfo == null ? null : userInfo.getUuid();
 
-            String name     = userNode.get( "name" ).getTextValue();
-            String email    = userNode.get( "email" ).getTextValue();
+            if ( userId == null ) {
 
-            // set dummy password to random string that nobody can guess, in central SSO
setup
-            // admin users should never be able to login directly to this Usergrid system
-            String dummyPassword = RandomStringUtils.randomAlphanumeric( 40 );
+                // create local user and and organizations they have on the central Usergrid
instance
 
-            JsonNode orgsNode = userNode.get( "organizations" );
-            final Iterator<String> fieldNames = orgsNode.getFieldNames();
+                String name  = userNode.get( "name" ).getTextValue();
+                String email = userNode.get( "email" ).getTextValue();
+                String dummyPassword = RandomStringUtils.randomAlphanumeric( 40 );
 
-            UserInfo userInfo = null;
+                JsonNode orgsNode = userNode.get( "organizations" );
+                final Iterator<String> fieldNames = orgsNode.getFieldNames();
 
-            // create user and any organizations that user is supposed to have
+                // create user and any organizations that user is supposed to have
 
-            while ( fieldNames.hasNext() ) {
+                while ( fieldNames.hasNext() ) {
 
-                String orgName = fieldNames.next();
+                    String orgName = fieldNames.next();
 
-                if ( userId == null ) {
+                    if ( userId == null ) {
 
-                    // haven't created user yet so do that now
-                    OrganizationOwnerInfo ownerOrgInfo = management.createOwnerAndOrganization(
-                            orgName, username, name, email, dummyPassword, true, true );
+                        // haven't created user yet so do that now
+                        OrganizationOwnerInfo ownerOrgInfo = management.createOwnerAndOrganization(
+                                orgName, username, name, email, dummyPassword, true, true
);
 
-                    management.activateOrganization( ownerOrgInfo.getOrganization() ); //
redundant?
-                    applicationCreator.createSampleFor( ownerOrgInfo.getOrganization() );
+                        management.activateOrganization( ownerOrgInfo.getOrganization() );
// redundant?
+                        applicationCreator.createSampleFor( ownerOrgInfo.getOrganization()
);
 
-                    userId = ownerOrgInfo.getOwner().getUuid();
-                    userInfo = ownerOrgInfo.getOwner();
+                        userId = ownerOrgInfo.getOwner().getUuid();
+                        userInfo = ownerOrgInfo.getOwner();
 
-                } else {
+                    } else {
 
-                    // already created user, so just create an org
-                    final OrganizationInfo organization = management.createOrganization(
orgName, userInfo, true );
+                        // already created user, so just create an org
+                        final OrganizationInfo organization = management.createOrganization(
orgName, userInfo, true );
 
-                    management.activateOrganization( organization ); // redundant?
-                    applicationCreator.createSampleFor( organization );
+                        management.activateOrganization( organization ); // redundant?
+                        applicationCreator.createSampleFor( organization );
+                    }
                 }
+
             }
 
-        }
+            // store the external access_token as if it were one of our own
+            management.importTokenForAdminUser( userId, extAccessToken, ttl );
 
-        // store the external access_token as if it were one of our own
-        management.importTokenForAdminUser( userId, extAccessToken, ttl );
+            // success! return JSON object with access_token field
+            accessInfo = new AccessInfo()
+                    .withExpiresIn( tokens.getMaxTokenAgeInSeconds( extAccessToken ) )
+                    .withAccessToken( extAccessToken );
 
-        // success! return JSON object with access_token field
-        AccessInfo accessInfo = new AccessInfo()
-                .withExpiresIn( tokens.getMaxTokenAgeInSeconds(extAccessToken ) )
-                .withAccessToken( extAccessToken );
+        } catch (Exception e) {
+            logger.debug("Error validating external token", e);
+            throw e;
+        }
 
         return Response.status( SC_OK ).type( jsonMediaType( callback ) ).entity( accessInfo
).build();
     }
@@ -680,6 +659,34 @@ public class ManagementResource extends AbstractContextResource {
     }
 
 
+    /**
+     * Check that authentication is allowed. If external token validation is enabled (Central
Usergrid SSO)
+     * then only superusers should be allowed to login directly to this Usergrid instance.
+     */
+    private void ensureAuthenticationAllowed( String username, String grant_type ) {
+
+        final boolean externalTokensEnabled =
+                !StringUtils.isEmpty( properties.getProperty( USERGRID_CENTRAL_URL ) );
+
+        if ( externalTokensEnabled ) {
+
+            // when external tokens enabled then only superuser can obtain an access token
+
+            final String superuserName = properties.getProperty( USERGRID_SYSADMIN_LOGIN_NAME
);
+            final String superuserAllowedStr = properties.getProperty( USERGRID_SYSADMIN_LOGIN_ALLOWED
);
+            final boolean superuserAllowed = !StringUtils.isEmpty( superuserAllowedStr )
+                    && superuserAllowedStr.trim().equalsIgnoreCase( "true" );
+
+            if ( superuserAllowed && !superuserName.equalsIgnoreCase( username ))
{
+
+                // this guy is not the superuser
+                throw new IllegalArgumentException( "Admin Users must login via " +
+                        properties.getProperty( USERGRID_CENTRAL_URL ) );
+            }
+        }
+    }
+
+
     String errorMsg = "";
     String responseType;
     String clientId;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/25d0077e/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
b/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
index b18614d..d6b507e 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
@@ -381,7 +381,7 @@ public class ManagementResourceIT extends AbstractRestIT {
         assertEquals( "test@usergrid.com", userdata.get( "data" ).get( "email" ).asText()
);
 
         // wait for the token to expire
-        Thread.sleep( ttl - ( System.currentTimeMillis() - startTime ) + 1000 );
+        Thread.sleep( ttl - (System.currentTimeMillis() - startTime) + 1000 );
 
         Status responseStatus = null;
         try {
@@ -646,19 +646,7 @@ public class ManagementResourceIT extends AbstractRestIT {
 
 
     @Test
-    public void validateExternalToken() throws Exception {
-
-        // set the Usergrid Central SSO URL becuase Tomcat port is dynamically assigned
-
-        String suToken = superAdminToken();
-
-        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 );
+    public void testValidateExternalToken() throws Exception {
 
         // create a new admin user, get access token
 
@@ -677,6 +665,17 @@ public class ManagementResourceIT extends AbstractRestIT {
             .post( JsonNode.class, loginInfo );
         String accessToken = accessInfoNode.get( "access_token" ).getTextValue();
 
+        // set the Usergrid Central SSO URL because Tomcat port is dynamically assigned
+
+        String suToken = superAdminToken();
+        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
 
         JsonNode validatedNode = resource().path( "/management/externaltoken" )
@@ -690,17 +689,94 @@ public class ManagementResourceIT extends AbstractRestIT {
         // attempt to validate an invalid token, must fail
 
         try {
-            JsonNode invalidNode = resource().path( "/management/externaltoken" )
+            resource().path( "/management/externaltoken" )
                 .queryParam( "access_token", suToken ) // as superuser
                 .queryParam( "ext_access_token", "rubbish_token")
                 .queryParam( "ttl", "1000" )
                 .get( JsonNode.class );
             fail("Validation should have failed");
-        } catch ( Exception expected ) {}
+        } catch ( Exception actual ) {
+            logger.debug( "error", actual );
+        }
+
 
 
         // 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
+    public void testSuperuserOnlyWhenValidateExternalTokensEnabled() throws Exception {
+
+        // create an org and an admin user
+
+        String rand = RandomStringUtils.randomAlphanumeric(10);
+        final String username = "user_" + rand;
+        OrganizationOwnerInfo orgInfo = setup.getMgmtSvc().createOwnerAndOrganization(
+                username, username, "Test User", username + "@example.com", "password" );
+
+        // turn on validate external tokens by setting the usergrid.central.url
+
+        String suToken = superAdminToken();
+        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 ( Exception actual ) {
+            logger.debug( "error", actual );
+        }
+
+        // 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" ).getTextValue();
+        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 );
     }
 
 }


Mime
View raw message