Repository: cxf Updated Branches: refs/heads/master 9fc3be7e5 -> b32c5d0cb
More work on the abstract jose support code Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/b32c5d0c Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/b32c5d0c Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/b32c5d0c Branch: refs/heads/master Commit: b32c5d0cbf61ae599c33e401679066d92b8e2024 Parents: 9fc3be7 Author: Sergey Beryozkin <[email protected]> Authored: Wed Jul 29 17:36:18 2015 +0300 Committer: Sergey Beryozkin <[email protected]> Committed: Wed Jul 29 17:36:18 2015 +0300 ---------------------------------------------------------------------- .../main/webapp/WEB-INF/applicationContext.xml | 13 ++-- .../jose/jwt/AbstractJoseJwtConsumer.java | 9 ++- .../jose/jwt/AbstractJoseJwtProducer.java | 2 +- .../oidc/rp/AbstractTokenValidator.java | 74 +++----------------- .../cxf/rs/security/oidc/rp/IdTokenReader.java | 2 +- .../oidc/rp/OidcClientCodeRequestFilter.java | 7 +- .../cxf/rs/security/oidc/rp/UserInfoClient.java | 19 +++-- 7 files changed, 36 insertions(+), 90 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/b32c5d0c/distribution/src/main/release/samples/jax_rs/big_query/src/main/webapp/WEB-INF/applicationContext.xml ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/big_query/src/main/webapp/WEB-INF/applicationContext.xml b/distribution/src/main/release/samples/jax_rs/big_query/src/main/webapp/WEB-INF/applicationContext.xml index e099c28..08e0d23 100644 --- a/distribution/src/main/release/samples/jax_rs/big_query/src/main/webapp/WEB-INF/applicationContext.xml +++ b/distribution/src/main/release/samples/jax_rs/big_query/src/main/webapp/WEB-INF/applicationContext.xml @@ -116,7 +116,8 @@ <property name="clientCodeStateManager" ref="rpClientCodeStateManager"/> <property name="scopes" value="openid email profile https://www.googleapis.com/auth/bigquery.readonly"/> <property name="accessTokenServiceClient" ref="atServiceClient"/> - <property name="idTokenReader" ref="userInfoClient"/> + <property name="idTokenReader" ref="idTokenReader"/> + <property name="userInfoClient" ref="userInfoClient"/> <property name="consumer" ref="consumer"/> <property name="authorizationServiceUri" value="https://accounts.google.com/o/oauth2/auth"/> <property name="startUri" value="rp"/> @@ -144,16 +145,12 @@ </jaxrsclient:features> </jaxrsclient:client> - <!-- The RP filter uses this client to read OIDC IdToken from OAuth2 access token and - request OIDC UserInfo. If OIDC IdToken only is required then registering - org.apache.cxf.rs.security.oidc.rp.IdTokenReader is enough. - --> - <bean id="userInfoClient" class="org.apache.cxf.rs.security.oidc.rp.UserInfoClient"> - <!-- these properties are needed to validate IdToken --> + <bean id="idTokenReader" class="org.apache.cxf.rs.security.oidc.rp.IdTokenReader"> <property name="jwkSetClient" ref="jwkSetClient"/> <property name="issuerId" value="accounts.google.com"/> <property name="clockOffset" value="10"/> - <!-- this one is needed to get OIDC UserInfo --> + </bean> + <bean id="userInfoClient" class="org.apache.cxf.rs.security.oidc.rp.UserInfoClient"> <property name="userInfoServiceClient" ref="userInfoServiceClient"/> </bean> http://git-wip-us.apache.org/repos/asf/cxf/blob/b32c5d0c/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java index fc00c81..0708cac 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtConsumer.java @@ -27,7 +27,7 @@ import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier; public abstract class AbstractJoseJwtConsumer extends AbstractJoseConsumer { private boolean jwsRequired = true; - private boolean jweRequired = true; + private boolean jweRequired; protected JwtToken getJwtToken(String wrappedJwtToken) { if (!isJwsRequired() && !isJweRequired()) { @@ -42,14 +42,17 @@ public abstract class AbstractJoseJwtConsumer extends AbstractJoseConsumer { } JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(wrappedJwtToken); - JwsSignatureVerifier theSigVerifier = getInitializedSignatureVerifier(isJwsRequired()); + JwtToken jwt = jwtConsumer.getJwtToken(); + JwsSignatureVerifier theSigVerifier = getInitializedSignatureVerifier(jwt); if (!jwtConsumer.verifySignatureWith(theSigVerifier)) { throw new SecurityException("Invalid Signature"); } - JwtToken jwt = jwtConsumer.getJwtToken(); validateToken(jwt); return jwt; } + protected JwsSignatureVerifier getInitializedSignatureVerifier(JwtToken jwt) { + return super.getInitializedSignatureVerifier(isJwsRequired()); + } protected void validateToken(JwtToken jwt) { } public boolean isJwsRequired() { http://git-wip-us.apache.org/repos/asf/cxf/blob/b32c5d0c/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java index bd2e1da..6ec4b44 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/AbstractJoseJwtProducer.java @@ -28,7 +28,7 @@ import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider; public abstract class AbstractJoseJwtProducer extends AbstractJoseProducer { private boolean jwsRequired = true; - private boolean jweRequired = true; + private boolean jweRequired; protected String processJwt(JwtToken jwt) { if (!isJwsRequired() && !isJweRequired()) { http://git-wip-us.apache.org/repos/asf/cxf/blob/b32c5d0c/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/AbstractTokenValidator.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/AbstractTokenValidator.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/AbstractTokenValidator.java index 0b271e8..e79c4f0 100644 --- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/AbstractTokenValidator.java +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/AbstractTokenValidator.java @@ -21,48 +21,25 @@ package org.apache.cxf.rs.security.oidc.rp; import java.util.concurrent.ConcurrentHashMap; import org.apache.cxf.jaxrs.client.WebClient; -import org.apache.cxf.rs.security.jose.jwe.JweDecryptionProvider; -import org.apache.cxf.rs.security.jose.jwe.JweJwtCompactConsumer; -import org.apache.cxf.rs.security.jose.jwe.JweUtils; 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.jwk.JwkUtils; -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.AbstractJoseJwtConsumer; import org.apache.cxf.rs.security.jose.jwt.JwtClaims; import org.apache.cxf.rs.security.jose.jwt.JwtToken; import org.apache.cxf.rs.security.jose.jwt.JwtUtils; -public abstract class AbstractTokenValidator { +public abstract class AbstractTokenValidator extends AbstractJoseJwtConsumer { private static final String SELF_ISSUED_ISSUER = "https://self-issued.me"; - private JweDecryptionProvider jweDecryptor; - private JwsSignatureVerifier jwsVerifier; private String issuerId; private int issuedAtRange; private int clockOffset; private WebClient jwkSetClient; private boolean supportSelfIssuedProvider; private ConcurrentHashMap<String, JsonWebKey> keyMap = new ConcurrentHashMap<String, JsonWebKey>(); - protected JwtToken getJwtToken(String wrappedJwtToken, boolean jweOnly) { - if (wrappedJwtToken == null) { - throw new SecurityException("ID Token is missing"); - } - JweDecryptionProvider theJweDecryptor = getInitializedDecryptionProvider(jweOnly); - if (theJweDecryptor != null) { - if (jweOnly) { - return new JweJwtCompactConsumer(wrappedJwtToken).decryptWith(jweDecryptor); - } - wrappedJwtToken = jweDecryptor.decrypt(wrappedJwtToken).getContentText(); - } - - JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(wrappedJwtToken); - JwtToken jwt = jwtConsumer.getJwtToken(); - JwsSignatureVerifier theSigVerifier = getInitializedSignatureVerifier(jwt); - return validateToken(jwtConsumer, jwt, theSigVerifier); - } - protected void validateJwtClaims(JwtClaims claims, String clientId, boolean validateClaimsAlways) { // validate the issuer String issuer = claims.getIssuer(); @@ -90,21 +67,6 @@ public abstract class AbstractTokenValidator { } } - - protected JwtToken validateToken(JwsJwtCompactConsumer consumer, JwtToken jwt, JwsSignatureVerifier jws) { - if (!consumer.verifySignatureWith(jws)) { - throw new SecurityException("Invalid Signature"); - } - return jwt; - } - public void setJweDecryptor(JweDecryptionProvider jweDecryptor) { - this.jweDecryptor = jweDecryptor; - } - - public void setJwsVerifier(JwsSignatureVerifier theJwsVerifier) { - this.jwsVerifier = theJwsVerifier; - } - public void setIssuerId(String issuerId) { this.issuerId = issuerId; } @@ -117,21 +79,8 @@ public abstract class AbstractTokenValidator { this.issuedAtRange = issuedAtRange; } - protected JweDecryptionProvider getInitializedDecryptionProvider(boolean jweOnly) { - if (jweDecryptor != null) { - return jweDecryptor; - } - return JweUtils.loadDecryptionProvider(jweOnly); - } + @Override protected JwsSignatureVerifier getInitializedSignatureVerifier(JwtToken jwt) { - if (jwsVerifier != null) { - return jwsVerifier; - } - JwsSignatureVerifier theJwsVerifier = JwsUtils.loadSignatureVerifier(false); - if (theJwsVerifier != null) { - return theJwsVerifier; - } - JsonWebKey key = null; if (supportSelfIssuedProvider && SELF_ISSUED_ISSUER.equals(jwt.getClaim("issuer"))) { String publicKeyJson = (String)jwt.getClaim("sub_jwk"); @@ -148,10 +97,7 @@ public abstract class AbstractTokenValidator { } else { String keyId = jwt.getHeaders().getKeyId(); key = keyId != null ? keyMap.get(keyId) : null; - if (key == null) { - if (jwkSetClient == null) { - throw new SecurityException("Provider Jwk Set Client is not available"); - } + if (key == null && jwkSetClient != null) { JsonWebKeys keys = jwkSetClient.get(JsonWebKeys.class); if (keyId != null) { key = keys.getKey(keyId); @@ -160,13 +106,13 @@ public abstract class AbstractTokenValidator { } keyMap.putAll(keys.getKeyIdMap()); } - if (key == null) { - throw new SecurityException("JWK key with the key id: \"" + keyId + "\" is not available"); - } } - - theJwsVerifier = JwsUtils.getSignatureVerifier(key); - + JwsSignatureVerifier theJwsVerifier = null; + if (key != null) { + theJwsVerifier = JwsUtils.getSignatureVerifier(key); + } else { + theJwsVerifier = super.getInitializedSignatureVerifier(jwt); + } if (theJwsVerifier == null) { throw new SecurityException("JWS Verifier is not available"); } http://git-wip-us.apache.org/repos/asf/cxf/blob/b32c5d0c/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenReader.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenReader.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenReader.java index ff633a1..63161d5 100644 --- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenReader.java +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenReader.java @@ -40,7 +40,7 @@ public class IdTokenReader extends AbstractTokenValidator { return jwt; } public JwtToken getIdJwtToken(String idJwtToken, String clientId) { - JwtToken jwt = getJwtToken(idJwtToken, false); + JwtToken jwt = getJwtToken(idJwtToken); validateJwtClaims(jwt.getClaims(), clientId, true); return jwt; } http://git-wip-us.apache.org/repos/asf/cxf/blob/b32c5d0c/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClientCodeRequestFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClientCodeRequestFilter.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClientCodeRequestFilter.java index 6406e3b..aa34cf1 100644 --- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClientCodeRequestFilter.java +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClientCodeRequestFilter.java @@ -41,6 +41,7 @@ public class OidcClientCodeRequestFilter extends ClientCodeRequestFilter { private static final String MAX_AGE_PARAMETER = "max_age"; private static final List<String> PROMPTS = Arrays.asList("none", "consent", "login", "select_account"); private IdTokenReader idTokenReader; + private UserInfoClient userInfoClient; private List<String> authenticationContextRef; private String promptLogin; private Long maxAgeOffset; @@ -64,8 +65,7 @@ public class OidcClientCodeRequestFilter extends ClientCodeRequestFilter { validateIdToken(idToken, state); ctx.setIdToken(idToken); - if (idTokenReader instanceof UserInfoClient) { - UserInfoClient userInfoClient = (UserInfoClient)idTokenReader; + if (userInfoClient != null) { ctx.setUserInfo(userInfoClient.getUserInfo(at, ctx.getIdToken())); } rc.setSecurityContext(new OidcSecurityContext(ctx)); @@ -106,6 +106,9 @@ public class OidcClientCodeRequestFilter extends ClientCodeRequestFilter { public void setIdTokenReader(IdTokenReader idTokenReader) { this.idTokenReader = idTokenReader; } + public void setUserInfoClient(UserInfoClient userInfoClient) { + this.userInfoClient = userInfoClient; + } @Override protected void checkSecurityContextStart(ContainerRequestContext rc) { http://git-wip-us.apache.org/repos/asf/cxf/blob/b32c5d0c/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/UserInfoClient.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/UserInfoClient.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/UserInfoClient.java index f1d0998..058867c 100644 --- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/UserInfoClient.java +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/UserInfoClient.java @@ -27,17 +27,14 @@ import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken; import org.apache.cxf.rs.security.oidc.common.IdToken; import org.apache.cxf.rs.security.oidc.common.UserInfo; -public class UserInfoClient extends IdTokenReader { - private boolean encryptedOnly; +public class UserInfoClient extends AbstractTokenValidator { private boolean sendTokenAsFormParameter; private WebClient profileClient; + private boolean getUserInfoFromJwt; public UserInfo getUserInfo(ClientAccessToken at, IdToken idToken) { - return getUserInfo(at, idToken, false); - } - public UserInfo getUserInfo(ClientAccessToken at, IdToken idToken, boolean asJwt) { if (!sendTokenAsFormParameter) { OAuthClientUtils.setAuthorizationHeader(profileClient, at); - if (asJwt) { + if (getUserInfoFromJwt) { String jwt = profileClient.get(String.class); return getUserInfoFromJwt(jwt, idToken); } else { @@ -47,7 +44,7 @@ public class UserInfoClient extends IdTokenReader { } } else { Form form = new Form().param("access_token", at.getTokenKey()); - if (asJwt) { + if (getUserInfoFromJwt) { String jwt = profileClient.form(form).readEntity(String.class); return getUserInfoFromJwt(jwt, idToken); } else { @@ -67,7 +64,7 @@ public class UserInfoClient extends IdTokenReader { return profile; } public JwtToken getUserInfoJwt(String profileJwtToken) { - return getJwtToken(profileJwtToken, encryptedOnly); + return getJwtToken(profileJwtToken); } public void validateUserInfo(UserInfo profile, IdToken idToken) { validateJwtClaims(profile, idToken.getAudience(), false); @@ -76,14 +73,14 @@ public class UserInfoClient extends IdTokenReader { throw new SecurityException("Invalid subject"); } } - public void setEncryptedOnly(boolean encryptedOnly) { - this.encryptedOnly = encryptedOnly; - } public void setUserInfoServiceClient(WebClient client) { this.profileClient = client; } public void setSendTokenAsFormParameter(boolean sendTokenAsFormParameter) { this.sendTokenAsFormParameter = sendTokenAsFormParameter; } + public void setGetUserInfoFromJwt(boolean getUserInfoFromJwt) { + this.getUserInfoFromJwt = getUserInfoFromJwt; + } }
