usergrid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From g...@apache.org
Subject [1/9] incubator-usergrid git commit: First cut of Usergrid Central SSO feature, with tests.
Date Thu, 16 Apr 2015 18:09:25 GMT
Repository: incubator-usergrid
Updated Branches:
  refs/heads/master 6d962b7fe -> 25d0077ed


First cut of Usergrid Central SSO feature, with tests.


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

Branch: refs/heads/master
Commit: 098355f8521a7528fe0fa44e9ce959f7c4c603d8
Parents: 9ef73e7
Author: Dave Johnson <dmjohnson@apigee.com>
Authored: Mon Apr 13 11:24:53 2015 -0400
Committer: Dave Johnson <dmjohnson@apigee.com>
Committed: Mon Apr 13 11:24:53 2015 -0400

----------------------------------------------------------------------
 .../rest/management/ManagementResource.java     | 170 ++++++++++++++++++-
 .../OAuth2AccessTokenSecurityFilter.java        |   5 +
 .../rest/management/ManagementResourceIT.java   |  71 +++++++-
 .../rest/test/PropertiesResourceIT.java         |  23 +--
 .../usergrid/management/ManagementService.java  |   5 +-
 .../cassandra/ManagementServiceImpl.java        |   7 +
 .../apache/usergrid/security/shiro/Realm.java   |  10 +-
 .../usergrid/security/tokens/TokenService.java  |   3 +
 .../tokens/cassandra/TokenServiceImpl.java      |  44 ++++-
 .../security/tokens/TokenServiceIT.java         |  42 +++++
 10 files changed, 354 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/098355f8/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 c590140..c1c0be5 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
@@ -19,21 +19,25 @@ package org.apache.usergrid.rest.management;
 
 import java.net.URLEncoder;
 import java.util.Map;
+import java.util.UUID;
 
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.GET;
-import javax.ws.rs.HeaderParam;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
+import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+import com.sun.jersey.api.json.JSONConfiguration;
+import org.apache.commons.lang.RandomStringUtils;
+import org.apache.usergrid.management.OrganizationInfo;
+import org.apache.usergrid.management.OrganizationOwnerInfo;
+import org.apache.usergrid.persistence.exceptions.EntityNotFoundException;
+import org.apache.usergrid.rest.security.annotations.RequireSystemAccess;
+import org.apache.usergrid.utils.UUIDUtils;
+import org.codehaus.jackson.JsonNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.context.annotation.Scope;
@@ -95,6 +99,8 @@ public class ManagementResource extends AbstractContextResource {
 
     private static final Logger logger = LoggerFactory.getLogger( ManagementResource.class
);
 
+    public static final String USERGRID_CENTRAL_URL = "usergrid.central.url";
+
 
     public ManagementResource() {
         logger.info( "ManagementResource initialized" );
@@ -441,6 +447,152 @@ 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.
+     * </p>
+     *
+     * @param ui             Information about calling URI.
+     * @param json           JSON object with fields: ext_access_token, ttl
+     * @param callback       For JSONP support.
+     * @return               Returns JSON object with access_token field.
+     * @throws Exception     Returns 401 if access token cannot be validated
+     */
+    @POST
+    @Path( "/externaltoken" )
+    //@RequireSystemAccess TODO: should this be required
+    public Response validateExternalToken(
+            @Context UriInfo ui,
+            Map<String, Object> json,
+            @QueryParam( "callback" ) @DefaultValue( "" ) String callback )  throws Exception
{
+
+        Object extAccessTokenObj = json.get("ext_access_token");
+        if ( extAccessTokenObj == null ) {
+            throw new IllegalArgumentException("ext_access_token must be specified");
+        }
+        String extAccessToken = json.get("ext_access_token").toString();
+
+        Object ttlObj = json.get("ttl");
+        if ( ttlObj == null ) {
+            throw new IllegalArgumentException("ttl must be specified");
+        }
+        long ttl;
+        try {
+            ttl = Long.parseLong(ttlObj.toString());
+        } catch ( NumberFormatException e ) {
+            throw new IllegalArgumentException("ttl must be specified as a long");
+        }
+
+        return validateExternalToken( ui, extAccessToken, ttl, callback );
+    }
+
+
+    /**
+     * <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> Part of Usergrid Central SSO feature.
+     * See <a href="https://issues.apache.org/jira/browse/USERGRID-567">USERGRID-567</a>
+     * for details about Usergrid Central SSO.
+     * </p>
+     *
+     * @param ui             Information about calling URI.
+     * @param extAccessToken Access token from external Usergrid system.
+     * @param ttl            Time to live for token.
+     * @param callback       For JSONP support.
+     * @return               Returns JSON object with access_token field.
+     * @throws Exception     Returns 401 if access token cannot be validated
+     */
+    @GET
+    @Path( "/externaltoken" )
+    //@RequireSystemAccess TODO: should this be required
+    public Response validateExternalToken(
+                                @Context UriInfo ui,
+                                @QueryParam( "ext_access_token" ) String extAccessToken,
+                                @QueryParam( "ttl" ) @DefaultValue("-1") long ttl,
+                                @QueryParam( "callback" ) @DefaultValue( "" ) String callback
)
+            throws Exception {
+
+
+        if ( extAccessToken == null ) {
+            throw new IllegalArgumentException("ext_access_token must be specified");
+        }
+
+        if ( ttl == -1 ) {
+            throw new IllegalArgumentException("ttl must be specified");
+        }
+
+        // create URL of central Usergrid's /management/me endpoint
+
+        String externalUrl = properties.getProperty( USERGRID_CENTRAL_URL ).trim();
+        // be lenient about trailing slash
+        externalUrl = !externalUrl.endsWith( "/" ) ? externalUrl + "/" : externalUrl;
+        String me = externalUrl + "management/me?access_token=" + extAccessToken;
+
+        // use our favorite HTTP client to GET /management/me
+
+        ClientConfig clientConfig = new DefaultClientConfig();
+        clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
+        Client client = Client.create(clientConfig);
+        final JsonNode accessInfoNode;
+        try {
+            accessInfoNode = client.resource( me )
+                    .type(MediaType.APPLICATION_JSON_TYPE)
+                    .get(JsonNode.class);
+
+        } catch ( Exception e ) {
+            // user not found 404
+            String msg = "Cannot find Admin User associated with " + extAccessToken;
+            throw new EntityNotFoundException( msg, e );
+        }
+
+        // good. user was found in central Usergrid
+
+        JsonNode userNode = accessInfoNode.get( "user" );
+        UUID userId     = UUIDUtils.tryExtractUUID( userNode.get( "uuid" ).getTextValue()
);
+        String username = userNode.get( "username" ).getTextValue();
+        String name     = userNode.get( "name" ).getTextValue();
+        String email    = userNode.get( "email" ).getTextValue();
+
+        // set dummy password to random string that nobody can guess, in SSO setup
+        // admin users should never be able to login directly to this Usergrid system
+        String dummyPassword = RandomStringUtils.randomAlphanumeric( 40 );
+
+        // if user does not exist locally then we need to fix that
+
+        final OrganizationInfo organizationInfo = management.getOrganizationByName(username);
+        if ( organizationInfo == null ) {
+
+            // create local user and personal organization, activate user.
+
+            OrganizationOwnerInfo ownerOrgInfo = management.createOwnerAndOrganization(
+                    username, username, name, email, dummyPassword, true, true);
+        }
+
+        // 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 accessInfo = new AccessInfo()
+                .withExpiresIn( tokens.getMaxTokenAgeInSeconds(extAccessToken ) )
+                .withAccessToken( extAccessToken );
+
+        return Response.status( SC_OK ).type( jsonMediaType( callback ) ).entity( accessInfo
).build();
+    }
+
+
     String errorMsg = "";
     String responseType;
     String clientId;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/098355f8/stack/rest/src/main/java/org/apache/usergrid/rest/security/shiro/filters/OAuth2AccessTokenSecurityFilter.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/security/shiro/filters/OAuth2AccessTokenSecurityFilter.java
b/stack/rest/src/main/java/org/apache/usergrid/rest/security/shiro/filters/OAuth2AccessTokenSecurityFilter.java
index f4c4fc5..e3a7d54 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/security/shiro/filters/OAuth2AccessTokenSecurityFilter.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/security/shiro/filters/OAuth2AccessTokenSecurityFilter.java
@@ -104,7 +104,12 @@ public class OAuth2AccessTokenSecurityFilter extends SecurityFilter {
                 catch ( InvalidTokenException ite ) {
                     throw mappableSecurityException( INVALID_AUTH_ERROR );
                 }
+                catch ( IndexOutOfBoundsException ioobe ) {
+                    // token is just some rubbish string
+                    throw mappableSecurityException( BAD_ACCESS_TOKEN_ERROR );
+                }
                 catch ( Exception e ) {
+                    // unexpected so we log it
                     LOG.error( "unable to verify oauth token", e );
                     throw mappableSecurityException( UNVERIFIED_OAUTH_ERROR );
                 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/098355f8/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 13cb2ae..b18614d 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
@@ -26,6 +26,7 @@ import java.util.UUID;
 
 import javax.ws.rs.core.MediaType;
 
+import org.apache.commons.lang.RandomStringUtils;
 import org.codehaus.jackson.JsonNode;
 import org.junit.Test;
 
@@ -40,12 +41,13 @@ import org.apache.usergrid.rest.management.organizations.OrganizationsResource;
 import com.sun.jersey.api.client.ClientResponse.Status;
 import com.sun.jersey.api.client.UniformInterfaceException;
 import com.sun.jersey.api.representation.Form;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static org.apache.usergrid.utils.MapUtils.hashMap;
-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.apache.usergrid.rest.management.ManagementResource.USERGRID_CENTRAL_URL;
+import static org.junit.Assert.*;
 
 
 /**
@@ -54,6 +56,8 @@ import static org.junit.Assert.assertTrue;
 @Concurrent()
 public class ManagementResourceIT extends AbstractRestIT {
 
+    private static final Logger logger = LoggerFactory.getLogger(ManagementResourceIT.class);
+
     public ManagementResourceIT() throws Exception {
 
     }
@@ -640,4 +644,63 @@ public class ManagementResourceIT extends AbstractRestIT {
         assertEquals( Status.OK, status );
     }
 
+
+    @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 );
+
+        // create a new admin user, get access token
+
+        String rand = RandomStringUtils.randomAlphanumeric(10);
+        final String username = "user_" + rand;
+        OrganizationOwnerInfo orgInfo = setup.getMgmtSvc().createOwnerAndOrganization(
+                username, username, "Test User", username + "@example.com", "password" );
+
+        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 );
+        String accessToken = accessInfoNode.get( "access_token" ).getTextValue();
+
+        // attempt to validate the token, must be valid
+
+        JsonNode validatedNode = resource().path( "/management/externaltoken" )
+            .queryParam( "access_token", suToken ) // as superuser
+            .queryParam( "ext_access_token", accessToken )
+            .queryParam( "ttl", "1000" )
+            .get( JsonNode.class );
+        String validatedAccessToken = validatedNode.get( "access_token" ).getTextValue();
+        assertEquals( accessToken, validatedAccessToken );
+
+        // attempt to validate an invalid token, must fail
+
+        try {
+            JsonNode invalidNode = 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 ) {}
+
+
+        // TODO: how do we test the create new user and organization case?
+
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/098355f8/stack/rest/src/test/java/org/apache/usergrid/rest/test/PropertiesResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/test/PropertiesResourceIT.java
b/stack/rest/src/test/java/org/apache/usergrid/rest/test/PropertiesResourceIT.java
index ebd6f9e..db3f046 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/test/PropertiesResourceIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/test/PropertiesResourceIT.java
@@ -36,9 +36,6 @@ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_ADM
 public class PropertiesResourceIT extends AbstractRestIT {
     static final Logger logger = LoggerFactory.getLogger( PropertiesResourceIT.class );
 
-    @Autowired
-    protected ServiceManagerFactory smf;
-
 
     @Test
     public void testBasicOperation() {
@@ -51,25 +48,31 @@ public class PropertiesResourceIT extends AbstractRestIT {
 
         // verify that is is not set in Jetty
         {
-            Map<String, String> map = resource().path( "/testproperties" ).queryParam(
"access_token", access_token )
-                    .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE
).get( Map.class );
-            Assert.assertFalse( Boolean.parseBoolean( map.get( PROPERTIES_ADMIN_USERS_REQUIRE_CONFIRMATION
) ) );
+            Map map = resource().path( "/testproperties" )
+                    .queryParam( "access_token", access_token )
+                    .accept( MediaType.APPLICATION_JSON )
+                    .type( MediaType.APPLICATION_JSON_TYPE ).get(Map.class);
+            Assert.assertFalse( Boolean.parseBoolean(
+                    map.get( PROPERTIES_ADMIN_USERS_REQUIRE_CONFIRMATION ).toString() ) );
         }
 
         // set property in Jetty
         {
             Map<String, String> props = new HashMap<String, String>();
             props.put( PROPERTIES_ADMIN_USERS_REQUIRE_CONFIRMATION, "true" );
-            resource().path( "/testproperties" ).queryParam( "access_token", access_token
)
-                    .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE
).post( props );
+            resource().path( "/testproperties" )
+                    .queryParam( "access_token", access_token )
+                    .accept( MediaType.APPLICATION_JSON )
+                    .type( MediaType.APPLICATION_JSON_TYPE ).post( props );
         }
 
         // verify that it is set in Jetty
         {
-            Map<String, String> map = resource().path( "/testproperties" ).queryParam(
"access_token", access_token )
+            Map map = resource().path( "/testproperties" ).queryParam( "access_token", access_token
)
                     .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE
).get( Map.class );
 
-            Assert.assertTrue( Boolean.parseBoolean( map.get( PROPERTIES_ADMIN_USERS_REQUIRE_CONFIRMATION
) ) );
+            Assert.assertTrue( Boolean.parseBoolean(
+                    map.get( PROPERTIES_ADMIN_USERS_REQUIRE_CONFIRMATION ).toString() ) );
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/098355f8/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
b/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
index 865f296..56343d4 100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
@@ -109,7 +109,7 @@ public interface ManagementService {
 
     public String getAccessTokenForAdminUser( UUID userId, long duration ) throws Exception;
 
-    /** Revoke all active access tokens for this admin user */
+   /** Revoke all active access tokens for this admin user */
     public void revokeAccessTokensForAdminUser( UUID userId ) throws Exception;
 
     public void revokeAccessTokenForAdminUser( UUID userId, String token ) throws Exception;
@@ -120,6 +120,9 @@ public interface ManagementService {
 
     public String getActivationTokenForOrganization( UUID organizationId, long ttl ) throws
Exception;
 
+    /** Import an Admin User token generated by some other system */
+    public void importTokenForAdminUser( UUID userId, String token, long ttl ) throws Exception;
+
     public ServiceResults getAdminUserActivities( UserInfo user ) throws Exception;
 
     public ServiceResults getAdminUserActivity( UserInfo user ) throws Exception;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/098355f8/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
index a2e1271..5b77534 100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
@@ -1391,6 +1391,13 @@ public class ManagementServiceImpl implements ManagementService {
     }
 
 
+    @Override
+    public void importTokenForAdminUser(UUID userId, String token, long ttl) throws Exception
{
+        tokens.importToken( token, TokenCategory.ACCESS, null,
+                new AuthPrincipalInfo( ADMIN_USER, userId, MANAGEMENT_APPLICATION_ID ), null,
ttl );
+    }
+
+
     /*
    * (non-Javadoc)
    * 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/098355f8/stack/services/src/main/java/org/apache/usergrid/security/shiro/Realm.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/shiro/Realm.java b/stack/services/src/main/java/org/apache/usergrid/security/shiro/Realm.java
index 84f4fe5..0f1f9e8 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/shiro/Realm.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/shiro/Realm.java
@@ -235,8 +235,16 @@ public class Realm extends AuthorizingRealm {
 
         for ( PrincipalIdentifier principal : principals.byType( PrincipalIdentifier.class
) ) {
 
+            // TODO: refactor so that this whole instanceof mess can be replaced with this:
+            // principle.addRolesAndPermissionsToInfo( info );
+            // principle.addApplicationsToSet( applicationsSet );
+            // principle.addOrganizationsToSet( applicationsSet );
+            // organization = principle.getOrganization();
+            // application = principle.getApplication();
+
             if ( principal instanceof OrganizationPrincipal ) {
-                // OrganizationPrincipals are usually only through OAuth
+
+                // OrganizationPricipals are usually only through OAuth
                 // They have access to a single organization
 
                 organization = ( ( OrganizationPrincipal ) principal ).getOrganization();

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/098355f8/stack/services/src/main/java/org/apache/usergrid/security/tokens/TokenService.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/tokens/TokenService.java
b/stack/services/src/main/java/org/apache/usergrid/security/tokens/TokenService.java
index 8b5863f..36decce 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/tokens/TokenService.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/tokens/TokenService.java
@@ -31,6 +31,9 @@ public interface TokenService {
     public String createToken( TokenCategory tokenCategory, String type, AuthPrincipalInfo
principal,
                                Map<String, Object> state, long duration ) throws Exception;
 
+    public void importToken( String token, TokenCategory tokenCategory, String type, AuthPrincipalInfo
principal,
+                               Map<String, Object> state, long duration ) throws Exception;
+
     /** Get the token info for the string version of this token */
     public TokenInfo getTokenInfo( String token ) throws Exception;
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/098355f8/stack/services/src/main/java/org/apache/usergrid/security/tokens/cassandra/TokenServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/tokens/cassandra/TokenServiceImpl.java
b/stack/services/src/main/java/org/apache/usergrid/security/tokens/cassandra/TokenServiceImpl.java
index 50156b5..7ea2af3 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/tokens/cassandra/TokenServiceImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/tokens/cassandra/TokenServiceImpl.java
@@ -230,14 +230,56 @@ public class TokenServiceImpl implements TokenService {
             Assert.notNull( principal.getUuid() );
         }
 
+        // create UUID that we will use to store token info in our database
         UUID uuid = UUIDUtils.newTimeUUID( creationTimestamp );
+
         long timestamp = getTimestampInMillis( uuid );
         if ( type == null ) {
             type = TOKEN_TYPE_ACCESS;
         }
         TokenInfo tokenInfo = new TokenInfo( uuid, type, timestamp, timestamp, 0, duration,
principal, state );
         putTokenInfo( tokenInfo );
-        return getTokenForUUID( tokenInfo, tokenCategory, uuid );
+
+        // generate token from the UUID that we created
+        return getTokenForUUID(tokenInfo, tokenCategory, uuid);
+    }
+
+
+    @Override
+    public void importToken(String token, TokenCategory tokenCategory, String type, AuthPrincipalInfo
principal,
+                            Map<String, Object> state, long duration) throws Exception
{
+
+        // same logic as create token
+
+        long maxTokenTtl = getMaxTtl( tokenCategory, principal );
+
+        if ( duration > maxTokenTtl ) {
+            throw new IllegalArgumentException(
+                    String.format( "Your token age cannot be more than the maximum age of
%d milliseconds",
+                            maxTokenTtl ) );
+        }
+
+        if ( duration == 0 ) {
+            duration = maxTokenTtl;
+        }
+
+        if ( principal != null ) {
+            Assert.notNull( principal.getType() );
+            Assert.notNull( principal.getApplicationId() );
+            Assert.notNull( principal.getUuid() );
+        }
+
+        // except that we generate the UUID based on the token
+
+        UUID uuid = getUUIDForToken(token);
+
+        long timestamp = getTimestampInMillis( uuid );
+        if ( type == null ) {
+            type = TOKEN_TYPE_ACCESS;
+        }
+
+        TokenInfo tokenInfo = new TokenInfo( uuid, type, timestamp, timestamp, 0, duration,
principal, state );
+        putTokenInfo( tokenInfo );
     }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/098355f8/stack/services/src/test/java/org/apache/usergrid/security/tokens/TokenServiceIT.java
----------------------------------------------------------------------
diff --git a/stack/services/src/test/java/org/apache/usergrid/security/tokens/TokenServiceIT.java
b/stack/services/src/test/java/org/apache/usergrid/security/tokens/TokenServiceIT.java
index 0141c9b..58ab3e6 100644
--- a/stack/services/src/test/java/org/apache/usergrid/security/tokens/TokenServiceIT.java
+++ b/stack/services/src/test/java/org/apache/usergrid/security/tokens/TokenServiceIT.java
@@ -454,4 +454,46 @@ public class TokenServiceIT {
 
         assertTrue( invalidTokenException );
     }
+
+    @Test
+    public void testImportToken() throws Exception {
+
+        // create admin user token and make sure it is working
+
+        AuthPrincipalInfo adminPrincipal = new AuthPrincipalInfo(
+                AuthPrincipalType.ADMIN_USER, adminUser.getUuid(), UUIDUtils.newTimeUUID()
);
+
+        String tokenStr = setup.getTokenSvc().createToken(
+                TokenCategory.ACCESS, null, adminPrincipal, null, 0 );
+
+        log.info("token: " + tokenStr);
+
+        // revoke token and check to make sure it is no longer valid
+
+        setup.getTokenSvc().revokeToken( tokenStr );
+
+        boolean invalidTokenException = false;
+        try {
+            setup.getTokenSvc().getTokenInfo( tokenStr );
+        }
+        catch ( InvalidTokenException ite ) {
+            invalidTokenException = true;
+        }
+        assertTrue(invalidTokenException);
+
+        // import same token and make sure it works again
+
+        setup.getTokenSvc().importToken( tokenStr, TokenCategory.ACCESS, null, adminPrincipal,
null, 0 );
+
+        TokenInfo tokenInfo = setup.getTokenSvc().getTokenInfo( tokenStr );
+
+        long last_access = tokenInfo.getAccessed();
+
+        assertEquals( "access", tokenInfo.getType() );
+        assertEquals( adminUser.getUuid(), tokenInfo.getPrincipal().getUuid() );
+
+        tokenInfo = setup.getTokenSvc().getTokenInfo( tokenStr );
+
+        assertTrue(last_access < tokenInfo.getAccessed());
+    }
 }


Mime
View raw message