Repository: usergrid
Updated Branches:
  refs/heads/apigee-sso-provider ead9e89c2 -> b21e47780


initial commit for ApogeeSSO2-Usergrid integration. Added an interface for 
ExternalToken providers and ApigeeSSO2Provider class which validates the jwt 
tokens.


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

Branch: refs/heads/apigee-sso-provider
Commit: c23f16a350d6c653c61884406a3fabbfcf06254a
Parents: f212608
Author: Ayesha Dastagiri <[email protected]>
Authored: Thu Jun 23 03:54:13 2016 -0700
Committer: Ayesha Dastagiri <[email protected]>
Committed: Thu Jun 23 03:54:13 2016 -0700

----------------------------------------------------------------------
 .../main/resources/usergrid-default.properties  |   4 +
 stack/services/pom.xml                          |   7 ++
 .../tokens/cassandra/TokenServiceImpl.java      |  31 +++++-
 .../externalProviders/ApigeeSSO2Provider.java   | 106 +++++++++++++++++++
 .../ExternalTokenProvider.java                  |  13 +++
 .../resources/usergrid-services-context.xml     |   3 +
 6 files changed, 160 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/c23f16a3/stack/config/src/main/resources/usergrid-default.properties
----------------------------------------------------------------------
diff --git a/stack/config/src/main/resources/usergrid-default.properties 
b/stack/config/src/main/resources/usergrid-default.properties
index d2141cf..2758bfb 100644
--- a/stack/config/src/main/resources/usergrid-default.properties
+++ b/stack/config/src/main/resources/usergrid-default.properties
@@ -491,6 +491,10 @@ usergrid.central.read.timeout=10000
 
 
 
+###############################   Usergrid SSO2   #############################
+usergrid.external.sso.enabled=true
+usergrid.external.sso.provider=apigee
+usergrid.external.sso.publicKeyUrl=https://login.apigee.com/token_key
 
 ###############################  Usergrid Assets  #############################
 #

http://git-wip-us.apache.org/repos/asf/usergrid/blob/c23f16a3/stack/services/pom.xml
----------------------------------------------------------------------
diff --git a/stack/services/pom.xml b/stack/services/pom.xml
index 06ae5d8..fdbd9c9 100644
--- a/stack/services/pom.xml
+++ b/stack/services/pom.xml
@@ -175,6 +175,13 @@
             <artifactId>shiro-core</artifactId>
         </dependency>
 
+        <!-- http://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.2</version>
+        </dependency>
+
         <dependency>
             <groupId>org.apache.shiro</groupId>
             <artifactId>shiro-spring</artifactId>

http://git-wip-us.apache.org/repos/asf/usergrid/blob/c23f16a3/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 5c71b1b..c07bb15 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
@@ -42,6 +42,7 @@ import org.apache.usergrid.security.tokens.TokenService;
 import org.apache.usergrid.security.tokens.exceptions.BadTokenException;
 import org.apache.usergrid.security.tokens.exceptions.ExpiredTokenException;
 import org.apache.usergrid.security.tokens.exceptions.InvalidTokenException;
+import 
org.apache.usergrid.security.tokens.externalProviders.ApigeeSSO2Provider;
 import org.apache.usergrid.utils.ConversionUtils;
 import org.apache.usergrid.utils.JsonUtils;
 import org.apache.usergrid.utils.UUIDUtils;
@@ -326,21 +327,28 @@ public class TokenServiceImpl implements TokenService {
     @Override
     public TokenInfo getTokenInfo( String token, boolean updateAccessTime ) 
throws Exception {
 
+        if(isApigeeSSO2Enabled()) {
+            //TODO: pass the correct token ttl.
+            return validateExternalToken(token,maxPersistenceTokenAge 
,properties.getProperty(USERGRID_EXTERNAL_PROVIDER));
+        }
+
+
         UUID uuid = getUUIDForToken( token );
 
         long ssoTtl = 1000000L; // TODO: property for this
 
         if ( uuid == null ) {
-            return isSSOEnabled() ? validateExternalToken( token, ssoTtl ) : 
null;
+            return isSSOEnabled() ? validateExternalToken( token, ssoTtl, "" ) 
: null;
         }
 
+
         TokenInfo tokenInfo;
         try {
             tokenInfo = getTokenInfo( uuid );
         } catch (InvalidTokenException e){
             // now try from central sso
             if ( isSSOEnabled() ){
-                return validateExternalToken( token, maxPersistenceTokenAge );
+                return validateExternalToken( token, maxPersistenceTokenAge,"" 
);
             }else{
                 throw e; // re-throw the error
             }
@@ -748,12 +756,19 @@ public class TokenServiceImpl implements TokenService {
     public static final String CENTRAL_CONNECTION_TIMEOUT =   
"usergrid.central.connection.timeout";
     public static final String CENTRAL_READ_TIMEOUT =         
"usergrid.central.read.timeout";
 
+
     // names for metrics to be collected
     private static final String SSO_TOKENS_REJECTED =         
"sso.tokens_rejected";
     private static final String SSO_TOKENS_VALIDATED =        
"sso.tokens_validated";
     private static final String SSO_CREATED_LOCAL_ADMINS =    
"sso.created_local_admins";
     private static final String SSO_PROCESSING_TIME =         
"sso.processing_time";
 
+    //SSO2 implementation
+    public static final String USERGRID_EXTERNAL_SSO_ENABLED = 
"usergrid.external.sso.enabled";
+    public static final String USERGRID_EXTERNAL_PROVIDER =    
"usergrid.external.sso.provider";
+
+
+
     private static Client jerseyClient = null;
 
     @Autowired
@@ -770,6 +785,9 @@ public class TokenServiceImpl implements TokenService {
         return !StringUtils.isEmpty( properties.getProperty( 
USERGRID_CENTRAL_URL ));
     }
 
+    private boolean isApigeeSSO2Enabled() {
+        return Boolean.valueOf(properties.getProperty( 
USERGRID_EXTERNAL_SSO_ENABLED ));
+    }
 
     /**
      * <p>
@@ -788,10 +806,16 @@ public class TokenServiceImpl implements TokenService {
      * @param extAccessToken Access token from external Usergrid system.
      * @param ttl            Time to live for token.
      */
-    public TokenInfo validateExternalToken(String extAccessToken, long ttl) 
throws Exception {
+    public TokenInfo validateExternalToken(String extAccessToken, long ttl, 
String provider) throws Exception {
 
         TokenInfo tokenInfo = null;
 
+        //todo: based on provider call the appropriate method.
+        if(provider.equalsIgnoreCase("apigee")){
+            ApigeeSSO2Provider apigeeProvider = 
((CpEntityManagerFactory)emf).getApplicationContext().getBean( 
ApigeeSSO2Provider.class );
+            return apigeeProvider.validateAndReturnUserInfo(extAccessToken);
+        }
+
         if (!isSSOEnabled()) {
             throw new NotImplementedException( "External Token Validation 
Service not enabled" );
         }
@@ -892,7 +916,6 @@ public class TokenServiceImpl implements TokenService {
         return tokenInfo;
     }
 
-
     /**
      * Look up Admin User via UG Central's /management/me endpoint.
      *

http://git-wip-us.apache.org/repos/asf/usergrid/blob/c23f16a3/stack/services/src/main/java/org/apache/usergrid/security/tokens/externalProviders/ApigeeSSO2Provider.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/main/java/org/apache/usergrid/security/tokens/externalProviders/ApigeeSSO2Provider.java
 
b/stack/services/src/main/java/org/apache/usergrid/security/tokens/externalProviders/ApigeeSSO2Provider.java
new file mode 100644
index 0000000..028d244
--- /dev/null
+++ 
b/stack/services/src/main/java/org/apache/usergrid/security/tokens/externalProviders/ApigeeSSO2Provider.java
@@ -0,0 +1,106 @@
+package org.apache.usergrid.security.tokens.externalProviders;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jws;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureException;
+import org.apache.usergrid.corepersistence.util.CpNamingUtils;
+import org.apache.usergrid.management.ManagementService;
+import org.apache.usergrid.management.UserInfo;
+import org.apache.usergrid.security.AuthPrincipalInfo;
+import org.apache.usergrid.security.AuthPrincipalType;
+import org.apache.usergrid.security.tokens.TokenInfo;
+import org.apache.usergrid.utils.UUIDUtils;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.jackson.JacksonFeature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.apache.commons.codec.binary.Base64.decodeBase64;
+
+/**
+ * Created by ayeshadastagiri on 6/22/16.
+ */
+public class ApigeeSSO2Provider implements ExternalTokenProvider {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(ApigeeSSO2Provider.class);
+    private static final String RESPONSE_PUBLICKEY_VALUE = "value";
+
+    protected Properties properties;
+
+    protected ManagementService management;
+
+    protected Client client;
+
+    protected String publicKey;
+
+    public static final String USERGRID_EXTERNAL_PUBLICKEY_URL = 
"usergrid.external.sso.publicKeyUrl";
+
+    public ApigeeSSO2Provider() {
+        ClientConfig clientConfig = new ClientConfig();
+        clientConfig.register(new JacksonFeature());
+        client = ClientBuilder.newClient(clientConfig);
+    }
+
+    private String getPublicKey() {
+        return 
client.target(properties.getProperty(USERGRID_EXTERNAL_PUBLICKEY_URL)).request().get(Map.class).
+            get(RESPONSE_PUBLICKEY_VALUE).toString();
+    }
+
+    @Override
+    public TokenInfo validateAndReturnUserInfo(String token) throws Exception {
+
+
+        //todo:// check cache , if its invalid retrieve from the 
USERGRID_EXTERNAL_PUBLICKEY_URL
+        String key = 
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0w+/0m5ENuLEAUxPxTMm\nXrJ8bhkyPunC2VCLTaA+2dkYhR0pfPM4RtCO9tqkjc63Raos3OTph9I9gE7RMBiU\n0GVMBDYe74OLZjpGeI7OO8TmQhaOeLzX/ej9QBvq1gbhHt1QGP3m43/g1bN64Ggt\nBq4NCXm1Ie80NvdxWDsKifhYi4fgo+zhcMBaSE2Hhyc3TIg1oEKfh+EmHL/4LhPd\n7CYl4PxqR+DVNbJrdGeGOteWX4p5sW79t/8CsnvJ4St5Yv3sGK5JuBbmGiKW8wWE\nn+9bDg5i3SPlimMBdySH+wMbFULyfVSvJHeMmEAMHKDq+PVGdM+znNkPCCVIkHZG\nRQIDAQAB";
+        byte[] publicBytes = decodeBase64(key);
+        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+        PublicKey pubKey = keyFactory.generatePublic(keySpec);
+        Jws<Claims> payload = null;
+        try {
+            payload = 
Jwts.parser().setSigningKey(pubKey).parseClaimsJws(token);
+            System.out.println(payload.getBody());
+            //todo : construct the jsonNode object - or should we construct 
the Tokeninfo??
+            UserInfo userInfo = 
management.getAdminUserByEmail(payload.getBody().get("email").toString());
+            TokenInfo tokeninfo = new TokenInfo(UUIDUtils.newTimeUUID(), 
"access", 1, 1, 1, 1,
+                new AuthPrincipalInfo(AuthPrincipalType.ADMIN_USER, 
userInfo.getUuid(),
+                    CpNamingUtils.MANAGEMENT_APPLICATION_ID), null);
+            return tokeninfo;
+        } catch (SignatureException se) {
+            //if this exception is thrown, first check if the token is 
expired. Else retirve the public key from the EXTERNAL_URL
+            try{
+                getPublicKey();
+            }
+            catch(Exception e){
+
+            }
+            logger.debug("signature did not match");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+
+    @Autowired
+    public void setManagement(ManagementService management) {
+        this.management = management;
+    }
+
+    @Autowired
+    public void setProperties( Properties properties ) {
+        this.properties = properties;
+        this.publicKey = getPublicKey();
+    }
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/c23f16a3/stack/services/src/main/java/org/apache/usergrid/security/tokens/externalProviders/ExternalTokenProvider.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/main/java/org/apache/usergrid/security/tokens/externalProviders/ExternalTokenProvider.java
 
b/stack/services/src/main/java/org/apache/usergrid/security/tokens/externalProviders/ExternalTokenProvider.java
new file mode 100644
index 0000000..cd00cdf
--- /dev/null
+++ 
b/stack/services/src/main/java/org/apache/usergrid/security/tokens/externalProviders/ExternalTokenProvider.java
@@ -0,0 +1,13 @@
+package org.apache.usergrid.security.tokens.externalProviders;
+
+import org.apache.usergrid.security.tokens.TokenInfo;
+
+/**
+ * Created by ayeshadastagiri on 6/22/16.
+ */
+public interface ExternalTokenProvider {
+
+    /** Authenticate a userId and external token against this provider */
+    TokenInfo validateAndReturnUserInfo(String token) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/c23f16a3/stack/services/src/main/resources/usergrid-services-context.xml
----------------------------------------------------------------------
diff --git a/stack/services/src/main/resources/usergrid-services-context.xml 
b/stack/services/src/main/resources/usergrid-services-context.xml
index c064f60..29a4b7c 100644
--- a/stack/services/src/main/resources/usergrid-services-context.xml
+++ b/stack/services/src/main/resources/usergrid-services-context.xml
@@ -78,6 +78,9 @@
     <bean id="saltProvider" 
class="org.apache.usergrid.security.salt.NoOpSaltProvider"/>
 
 
+    <bean id="apigeeSSO2Provider" 
class="org.apache.usergrid.security.tokens.externalProviders.ApigeeSSO2Provider">
+        <property name="management" ref="managementService" />
+    </bean>
 
     <bean id="serviceManagerFactory" 
class="org.apache.usergrid.services.ServiceManagerFactory">
         <constructor-arg ref="entityManagerFactory"/>

Reply via email to