cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From serg...@apache.org
Subject cxf git commit: [CXF-5607] Introducing an sso-oidc module
Date Fri, 07 Nov 2014 16:53:40 GMT
Repository: cxf
Updated Branches:
  refs/heads/master 4915ce370 -> be9694b4c


[CXF-5607] Introducing an sso-oidc module


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

Branch: refs/heads/master
Commit: be9694b4c269f2a6d95e4787e08a58d03c4e3296
Parents: 4915ce3
Author: Sergey Beryozkin <sberyozkin@talend.com>
Authored: Fri Nov 7 16:53:22 2014 +0000
Committer: Sergey Beryozkin <sberyozkin@talend.com>
Committed: Fri Nov 7 16:53:22 2014 +0000

----------------------------------------------------------------------
 rt/pom.xml                                      |   1 +
 rt/rs/security/sso/oidc/pom.xml                 |  51 ++++++++
 .../rs/security/oidc/common/UserProfile.java    |  25 ++++
 .../rs/security/oidc/rp/IdTokenValidator.java   | 121 +++++++++++++++++++
 .../cxf/rs/security/oidc/rp/OidcUtils.java      |  64 ++++++++++
 5 files changed, 262 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/be9694b4/rt/pom.xml
----------------------------------------------------------------------
diff --git a/rt/pom.xml b/rt/pom.xml
index b76a3c9..06f725b 100644
--- a/rt/pom.xml
+++ b/rt/pom.xml
@@ -65,6 +65,7 @@
         <module>rs/security/jose</module>
         <module>rs/security/oauth-parent</module>
         <module>rs/security/sso/saml</module>
+        <module>rs/security/sso/oidc</module>
         <module>rs/security/cors</module>
         <module>management</module>
         <module>management-web</module>

http://git-wip-us.apache.org/repos/asf/cxf/blob/be9694b4/rt/rs/security/sso/oidc/pom.xml
----------------------------------------------------------------------
diff --git a/rt/rs/security/sso/oidc/pom.xml b/rt/rs/security/sso/oidc/pom.xml
new file mode 100644
index 0000000..566caef
--- /dev/null
+++ b/rt/rs/security/sso/oidc/pom.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>cxf-rt-rs-security-sso-oidc</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache CXF Runtime OpenId Connect</name>
+    <description>Apache CXF Runtime OpenId Connect</description>
+    <url>http://cxf.apache.org</url>
+    <parent>
+        <groupId>org.apache.cxf</groupId>
+        <artifactId>cxf-parent</artifactId>
+        <version>3.1.0-SNAPSHOT</version>
+        <relativePath>../../../../../parent/pom.xml</relativePath>
+    </parent>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-rs-security-oauth2</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <!--test dependencies-->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/cxf/blob/be9694b4/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/common/UserProfile.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/common/UserProfile.java
b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/common/UserProfile.java
new file mode 100644
index 0000000..9f519cf
--- /dev/null
+++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/common/UserProfile.java
@@ -0,0 +1,25 @@
+/**
+ * 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.cxf.rs.security.oidc.common;
+
+import org.apache.cxf.jaxrs.provider.json.JsonMapObject;
+
+public class UserProfile extends JsonMapObject {
+
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/be9694b4/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenValidator.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenValidator.java
b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenValidator.java
new file mode 100644
index 0000000..eb16698
--- /dev/null
+++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenValidator.java
@@ -0,0 +1,121 @@
+/**
+ * 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.cxf.rs.security.oidc.rp;
+
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.rs.security.jose.jwe.JweDecryptionProvider;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKeys;
+import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer;
+import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier;
+import org.apache.cxf.rs.security.jose.jws.JwsUtils;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken;
+
+public class IdTokenValidator {
+    private JweDecryptionProvider jweDecryptor;
+    private JwsSignatureVerifier jwsVerifier;
+    private String issuerId;
+    private int issuedAtRange;
+
+    private WebClient jwkSetClient;
+
+    public JwtToken validateIdToken(ClientAccessToken at, String clientId) {
+        String idToken = at.getParameters().get("id_token");
+        if (idToken == null) {
+            throw new SecurityException("ID Token is missing");
+        }
+        // Decrypt the token if needed
+        if (jweDecryptor != null) {
+            idToken = new String(jweDecryptor.decrypt(idToken).getContentText());
+        }
+
+        // read id_token into JwtToken
+        JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(idToken);
+        JwtToken jwt = jwtConsumer.getJwtToken();
+        System.out.println("JWT claims" + jwtConsumer.getDecodedJsonToken().getClaimsJson());
+        // validate token signature
+        JwsSignatureVerifier theJwsVerifier = loadJwkSignatureVerifier(jwt);
+        if (!jwtConsumer.verifySignatureWith(theJwsVerifier)) {
+            throw new SecurityException("ID Token signature verification failed");
+        }
+
+        // validate audience
+        if (!clientId.equals(jwt.getClaims().getAudience())) {
+            throw new SecurityException("Invalid audience");
+        }
+
+        // validate the provider
+        if (!issuerId.equals(jwt.getClaims().getIssuer())) {
+            throw new SecurityException("Invalid provider");
+        }
+        long currentTimeInSecs = System.currentTimeMillis() / 1000;
+        long expiryTimeInSecs = jwt.getClaims().getExpiryTime();
+        if (currentTimeInSecs > expiryTimeInSecs) {
+            throw new SecurityException("The token expired");
+        }
+        long issuedAtInSecs = jwt.getClaims().getIssuedAt();
+        if (issuedAtInSecs > currentTimeInSecs || issuedAtRange > 0
+            && issuedAtInSecs < currentTimeInSecs - issuedAtRange) {
+            throw new SecurityException("Invalid issuedAt");
+        }
+        // validate at_hash
+        OidcUtils.validateAccessTokenHash(at, jwt);
+        return jwt;
+    }
+
+    private JwsSignatureVerifier loadJwkSignatureVerifier(JwtToken jwt) {
+        if (jwsVerifier != null) {
+            return jwsVerifier;
+        }
+        if (jwkSetClient == null) {
+            throw new SecurityException("Provider Jwk Set Client is not available");
+        }
+        String keyId = jwt.getHeaders().getKeyId();
+        if (keyId == null) {
+            throw new SecurityException("Provider JWK key id is null");
+        }
+        JsonWebKeys keys = jwkSetClient.get(JsonWebKeys.class);
+        JsonWebKey key = keys.getKey(keyId);
+        if (key == null) {
+            throw new SecurityException("JWK key with the key id: \"" + keyId + "\" is not
available");
+        }
+        return JwsUtils.getSignatureVerifier(key);
+    }
+
+    public void setJweDecryptor(JweDecryptionProvider jweDecryptor) {
+        this.jweDecryptor = jweDecryptor;
+    }
+
+    public void setJweVerifier(JwsSignatureVerifier theJwsVerifier) {
+        this.jwsVerifier = theJwsVerifier;
+    }
+
+    public void setIssuerId(String issuerId) {
+        this.issuerId = issuerId;
+    }
+
+    public void setJwkSetClient(WebClient jwkSetClient) {
+        this.jwkSetClient = jwkSetClient;
+    }
+
+    public void setIssuedAtRange(int issuedAtRange) {
+        this.issuedAtRange = issuedAtRange;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/be9694b4/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcUtils.java
b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcUtils.java
new file mode 100644
index 0000000..0a2e71d
--- /dev/null
+++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcUtils.java
@@ -0,0 +1,64 @@
+/**
+ * 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.cxf.rs.security.oidc.rp;
+
+import java.security.NoSuchAlgorithmException;
+
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.common.util.crypto.MessageDigestUtils;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken;
+
+public final class OidcUtils {
+    private OidcUtils() {
+        
+    }
+    
+    public static void validateAccessTokenHash(ClientAccessToken at, JwtToken jwt) {
+        validateHash(at.getTokenKey(),
+                     (String)jwt.getClaims().getClaim("at_hash"),
+                     jwt.getHeaders().getAlgorithm());
+    }
+    public static void validateCodeHash(String code, JwtToken jwt) {
+        validateHash(code,
+                     (String)jwt.getClaims().getClaim("c_hash"),
+                     jwt.getHeaders().getAlgorithm());
+    }
+    private static void validateHash(String value, String theHash, String joseAlgo) {
+        String hash = calculateHash(value, joseAlgo);
+        if (!hash.equals(theHash)) {
+            throw new SecurityException("Invalid hash");
+        }
+    }
+    public static String calculateHash(String value, String joseAlgo) {
+        //TODO: map from the JOSE alg to a signature alg, 
+        // for example, RS256 -> SHA-256 
+        // and calculate the chunk size based on the algo key size
+        // for example SHA-256 -> 256/8 = 32 and 32/2 = 16 bytes
+        try {
+            byte[] atBytes = StringUtils.toBytesASCII(value);
+            byte[] digest = MessageDigestUtils.createDigest(atBytes,  MessageDigestUtils.ALGO_SHA_256);
+            return Base64UrlUtility.encodeChunk(digest, 0, 16);
+        } catch (NoSuchAlgorithmException ex) {
+            throw new SecurityException(ex);
+        }
+    }
+    
+}


Mime
View raw message