You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2016/02/05 15:20:53 UTC
cxf git commit: Adding the renamed resources
Repository: cxf
Updated Branches:
refs/heads/master 5c8c5f5b0 -> dcf440746
Adding the renamed resources
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/dcf44074
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/dcf44074
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/dcf44074
Branch: refs/heads/master
Commit: dcf4407466d5c307feb5f3be387ed8667dba6e32
Parents: 5c8c5f5
Author: Sergey Beryozkin <sb...@gmail.com>
Authored: Fri Feb 5 14:20:40 2016 +0000
Committer: Sergey Beryozkin <sb...@gmail.com>
Committed: Fri Feb 5 14:20:40 2016 +0000
----------------------------------------------------------------------
.../rs/security/jose/jwt/JoseJwtConsumer.java | 107 +++++++++++
.../rs/security/jose/jwt/JoseJwtProducer.java | 91 +++++++++
.../oauth2/provider/OAuthJoseJwtConsumer.java | 60 ++++++
.../oauth2/provider/OAuthJoseJwtProducer.java | 71 +++++++
.../provider/OAuthServerJoseJwtProducer.java | 65 +++++++
.../security/oidc/rp/OidcClaimsValidator.java | 192 +++++++++++++++++++
6 files changed, 586 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cxf/blob/dcf44074/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JoseJwtConsumer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JoseJwtConsumer.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JoseJwtConsumer.java
new file mode 100644
index 0000000..35a6eee
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JoseJwtConsumer.java
@@ -0,0 +1,107 @@
+/**
+ * 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.jose.jwt;
+
+import org.apache.cxf.rs.security.jose.common.AbstractJoseConsumer;
+import org.apache.cxf.rs.security.jose.jwe.JweDecryptionOutput;
+import org.apache.cxf.rs.security.jose.jwe.JweDecryptionProvider;
+import org.apache.cxf.rs.security.jose.jwe.JweHeaders;
+import org.apache.cxf.rs.security.jose.jwe.JweJwtCompactConsumer;
+import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer;
+import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier;
+
+public class JoseJwtConsumer extends AbstractJoseConsumer {
+ private boolean jwsRequired = true;
+ private boolean jweRequired;
+
+ public JwtToken getJwtToken(String wrappedJwtToken) {
+ return getJwtToken(wrappedJwtToken, null, null);
+ }
+ public JwtToken getJwtToken(String wrappedJwtToken,
+ JweDecryptionProvider theDecryptor,
+ JwsSignatureVerifier theSigVerifier) {
+ if (!isJwsRequired() && !isJweRequired()) {
+ throw new JwtException("Unable to process JWT");
+ }
+
+ JweHeaders jweHeaders = new JweHeaders();
+ if (isJweRequired()) {
+ JweJwtCompactConsumer jwtConsumer = new JweJwtCompactConsumer(wrappedJwtToken);
+
+ if (theDecryptor == null) {
+ theDecryptor = getInitializedDecryptionProvider(jwtConsumer.getHeaders());
+ }
+ if (theDecryptor == null) {
+ throw new JwtException("Unable to decrypt JWT");
+ }
+
+ if (!isJwsRequired()) {
+ return jwtConsumer.decryptWith(theDecryptor);
+ }
+
+ JweDecryptionOutput decOutput = theDecryptor.decrypt(wrappedJwtToken);
+ wrappedJwtToken = decOutput.getContentText();
+ jweHeaders = decOutput.getHeaders();
+ }
+
+ JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(wrappedJwtToken);
+ JwtToken jwt = jwtConsumer.getJwtToken();
+ // Store the encryption headers as well
+ jwt = new JwtToken(jwt.getJwsHeaders(), jweHeaders, jwt.getClaims());
+
+ if (isJwsRequired()) {
+ if (theSigVerifier == null) {
+ theSigVerifier = getInitializedSignatureVerifier(jwt);
+ }
+ if (theSigVerifier == null) {
+ throw new JwtException("Unable to validate JWT");
+ }
+
+ if (!jwtConsumer.verifySignatureWith(theSigVerifier)) {
+ throw new JwtException("Invalid Signature");
+ }
+ }
+
+ validateToken(jwt);
+ return jwt;
+ }
+
+ protected JwsSignatureVerifier getInitializedSignatureVerifier(JwtToken jwt) {
+ return super.getInitializedSignatureVerifier(jwt.getJwsHeaders());
+ }
+
+ protected void validateToken(JwtToken jwt) {
+ }
+ public boolean isJwsRequired() {
+ return jwsRequired;
+ }
+
+ public void setJwsRequired(boolean jwsRequired) {
+ this.jwsRequired = jwsRequired;
+ }
+
+ public boolean isJweRequired() {
+ return jweRequired;
+ }
+
+ public void setJweRequired(boolean jweRequired) {
+ this.jweRequired = jweRequired;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/dcf44074/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JoseJwtProducer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JoseJwtProducer.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JoseJwtProducer.java
new file mode 100644
index 0000000..c729cbe
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JoseJwtProducer.java
@@ -0,0 +1,91 @@
+/**
+ * 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.jose.jwt;
+
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.rs.security.jose.common.AbstractJoseProducer;
+import org.apache.cxf.rs.security.jose.jwe.JweEncryptionProvider;
+import org.apache.cxf.rs.security.jose.jwe.JweJwtCompactProducer;
+import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactProducer;
+import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider;
+
+public class JoseJwtProducer extends AbstractJoseProducer {
+ private boolean jwsRequired = true;
+ private boolean jweRequired;
+
+ public String processJwt(JwtToken jwt) {
+ return processJwt(jwt, null, null);
+ }
+ public String processJwt(JwtToken jwt,
+ JweEncryptionProvider theEncProvider,
+ JwsSignatureProvider theSigProvider) {
+ if (!isJwsRequired() && !isJweRequired()) {
+ throw new JwtException("Unable to secure JWT");
+ }
+ String data = null;
+
+ if (isJweRequired() && theEncProvider == null) {
+ theEncProvider = getInitializedEncryptionProvider(jwt.getJweHeaders());
+ if (theEncProvider == null) {
+ throw new JwtException("Unable to encrypt JWT");
+ }
+ }
+
+ if (isJwsRequired()) {
+ JwsJwtCompactProducer jws = new JwsJwtCompactProducer(jwt);
+ if (jws.isPlainText()) {
+ data = jws.getSignedEncodedJws();
+ } else {
+ if (theSigProvider == null) {
+ theSigProvider = getInitializedSignatureProvider(jwt.getJwsHeaders());
+ }
+
+ if (theSigProvider == null) {
+ throw new JwtException("Unable to sign JWT");
+ }
+
+ data = jws.signWith(theSigProvider);
+ }
+ if (theEncProvider != null) {
+ data = theEncProvider.encrypt(StringUtils.toBytesUTF8(data), null);
+ }
+ } else {
+ JweJwtCompactProducer jwe = new JweJwtCompactProducer(jwt);
+ data = jwe.encryptWith(theEncProvider);
+ }
+ return data;
+ }
+
+ public boolean isJwsRequired() {
+ return jwsRequired;
+ }
+
+ public void setJwsRequired(boolean jwsRequired) {
+ this.jwsRequired = jwsRequired;
+ }
+
+ public boolean isJweRequired() {
+ return jweRequired;
+ }
+
+ public void setJweRequired(boolean jweRequired) {
+ this.jweRequired = jweRequired;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/dcf44074/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthJoseJwtConsumer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthJoseJwtConsumer.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthJoseJwtConsumer.java
new file mode 100644
index 0000000..a6e4541
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthJoseJwtConsumer.java
@@ -0,0 +1,60 @@
+/**
+ * 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.oauth2.provider;
+
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.rs.security.jose.jwe.JweDecryptionProvider;
+import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier;
+import org.apache.cxf.rs.security.jose.jwt.JoseJwtConsumer;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthUtils;
+
+public class OAuthJoseJwtConsumer extends JoseJwtConsumer {
+
+ private boolean decryptWithClientSecret;
+ private boolean verifyWithClientSecret;
+
+ public JwtToken getJwtToken(String wrappedJwtToken, String clientSecret) {
+ return getJwtToken(wrappedJwtToken,
+ getInitializedDecryptionProvider(clientSecret),
+ getInitializedSignatureVerifier(clientSecret));
+ }
+
+ protected JwsSignatureVerifier getInitializedSignatureVerifier(String clientSecret) {
+ if (verifyWithClientSecret && !StringUtils.isEmpty(clientSecret)) {
+ return OAuthUtils.getClientSecretSignatureVerifier(clientSecret);
+ } else {
+ return null;
+ }
+ }
+ protected JweDecryptionProvider getInitializedDecryptionProvider(String clientSecret) {
+ if (decryptWithClientSecret && !StringUtils.isEmpty(clientSecret)) {
+ return OAuthUtils.getClientSecretDecryptionProvider(clientSecret);
+ } else {
+ return null;
+ }
+ }
+
+ public void setDecryptWithClientSecret(boolean decryptWithClientSecret) {
+ this.decryptWithClientSecret = verifyWithClientSecret;
+ }
+ public void setVerifyWithClientSecret(boolean verifyWithClientSecret) {
+ this.verifyWithClientSecret = verifyWithClientSecret;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/dcf44074/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthJoseJwtProducer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthJoseJwtProducer.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthJoseJwtProducer.java
new file mode 100644
index 0000000..506e826
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthJoseJwtProducer.java
@@ -0,0 +1,71 @@
+/**
+ * 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.oauth2.provider;
+
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.rs.security.jose.jwe.JweEncryptionProvider;
+import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider;
+import org.apache.cxf.rs.security.jose.jwt.JoseJwtProducer;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthUtils;
+
+public class OAuthJoseJwtProducer extends JoseJwtProducer {
+ private boolean encryptWithClientSecret;
+ private boolean signWithClientSecret;
+
+ public String processJwt(JwtToken jwt, String clientSecret) {
+ return processJwt(jwt,
+ getInitializedEncryptionProvider(clientSecret),
+ getInitializedSignatureProvider(clientSecret));
+ }
+
+ protected JwsSignatureProvider getInitializedSignatureProvider(String clientSecret) {
+ if (signWithClientSecret && !StringUtils.isEmpty(clientSecret)) {
+ return OAuthUtils.getClientSecretSignatureProvider(clientSecret);
+ } else {
+ return null;
+ }
+ }
+ protected JweEncryptionProvider getInitializedEncryptionProvider(String clientSecret) {
+ if (encryptWithClientSecret && !StringUtils.isEmpty(clientSecret)) {
+ return OAuthUtils.getClientSecretEncryptionProvider(clientSecret);
+ } else {
+ return null;
+ }
+ }
+
+ public void setEncryptWithClientSecret(boolean encryptWithClientSecret) {
+ if (signWithClientSecret) {
+ throw new SecurityException();
+ }
+ this.encryptWithClientSecret = encryptWithClientSecret;
+ }
+ public void setSignWithClientSecret(boolean signWithClientSecret) {
+ if (encryptWithClientSecret) {
+ throw new SecurityException();
+ }
+ this.signWithClientSecret = signWithClientSecret;
+ }
+ public boolean isSignWithClientSecret() {
+ return signWithClientSecret;
+ }
+ public boolean isEncryptWithClientSecret() {
+ return encryptWithClientSecret;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/dcf44074/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthServerJoseJwtProducer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthServerJoseJwtProducer.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthServerJoseJwtProducer.java
new file mode 100644
index 0000000..24e6a16
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthServerJoseJwtProducer.java
@@ -0,0 +1,65 @@
+/**
+ * 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.oauth2.provider;
+
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+
+import org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
+import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm;
+import org.apache.cxf.rs.security.jose.jwe.JweEncryptionProvider;
+import org.apache.cxf.rs.security.jose.jwe.JweUtils;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.cxf.rs.security.oauth2.common.Client;
+import org.apache.cxf.rt.security.crypto.CryptoUtils;
+
+public class OAuthServerJoseJwtProducer extends OAuthJoseJwtProducer {
+ private boolean encryptWithClientCertificates;
+
+ public String processJwt(JwtToken jwt, Client client) {
+ return processJwt(jwt,
+ getInitializedEncryptionProvider(client),
+ getInitializedSignatureProvider(client.getClientSecret()));
+ }
+
+ protected JweEncryptionProvider getInitializedEncryptionProvider(Client c) {
+ JweEncryptionProvider theEncryptionProvider = null;
+ if (encryptWithClientCertificates) {
+ X509Certificate cert =
+ (X509Certificate)CryptoUtils.decodeCertificate(c.getApplicationCertificates().get(0));
+ theEncryptionProvider = JweUtils.createJweEncryptionProvider((RSAPublicKey)cert.getPublicKey(),
+ KeyAlgorithm.RSA_OAEP,
+ ContentAlgorithm.A128GCM,
+ null);
+ }
+ if (theEncryptionProvider == null) {
+ theEncryptionProvider = super.getInitializedEncryptionProvider(c.getClientSecret());
+ }
+ return theEncryptionProvider;
+
+ }
+
+ public void setEncryptWithClientCertificates(boolean encryptWithClientCertificates) {
+ if (isEncryptWithClientSecret()) {
+ throw new SecurityException();
+ }
+ this.encryptWithClientCertificates = encryptWithClientCertificates;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/dcf44074/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClaimsValidator.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClaimsValidator.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClaimsValidator.java
new file mode 100644
index 0000000..31a3111
--- /dev/null
+++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClaimsValidator.java
@@ -0,0 +1,192 @@
+/**
+ * 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.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.jaxrs.client.WebClient;
+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.JwsSignatureVerifier;
+import org.apache.cxf.rs.security.jose.jws.JwsUtils;
+import org.apache.cxf.rs.security.jose.jwt.JwtClaims;
+import org.apache.cxf.rs.security.jose.jwt.JwtException;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.cxf.rs.security.jose.jwt.JwtUtils;
+import org.apache.cxf.rs.security.oauth2.provider.OAuthJoseJwtConsumer;
+import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
+import org.apache.cxf.rs.security.oidc.common.IdToken;
+
+public class OidcClaimsValidator extends OAuthJoseJwtConsumer {
+ private static final String SELF_ISSUED_ISSUER = "https://self-issued.me";
+ private String issuerId;
+ private int clockOffset;
+ private int ttl;
+ private WebClient jwkSetClient;
+ private boolean supportSelfIssuedProvider;
+ private boolean strictTimeValidation;
+ private ConcurrentHashMap<String, JsonWebKey> keyMap = new ConcurrentHashMap<String, JsonWebKey>();
+
+ /**
+ * Validate core JWT claims
+ * @param claims the claims
+ * @param clientId OAuth2 client id
+ * @param validateClaimsAlways if set to true then enforce that the claims
+ * to be validated must be set
+ */
+ public void validateJwtClaims(JwtClaims claims, String clientId, boolean validateClaimsAlways) {
+ // validate the issuer
+ String issuer = claims.getIssuer();
+ if (issuer == null && validateClaimsAlways) {
+ throw new OAuthServiceException("Invalid issuer");
+ }
+ if (supportSelfIssuedProvider && issuerId == null
+ && issuer != null && SELF_ISSUED_ISSUER.equals(issuer)) {
+ validateSelfIssuedProvider(claims, clientId, validateClaimsAlways);
+ } else {
+ if (issuer != null && !issuer.equals(issuerId)) {
+ throw new OAuthServiceException("Invalid issuer");
+ }
+ // validate subject
+ if (claims.getSubject() == null) {
+ throw new OAuthServiceException("Invalid subject");
+ }
+
+ // validate authorized party
+ String authorizedParty = (String)claims.getClaim(IdToken.AZP_CLAIM);
+ if (authorizedParty != null && !authorizedParty.equals(clientId)) {
+ throw new OAuthServiceException("Invalid authorized party");
+ }
+ // validate audience
+ List<String> audiences = claims.getAudiences();
+ if (StringUtils.isEmpty(audiences) && validateClaimsAlways
+ || !StringUtils.isEmpty(audiences) && !audiences.contains(clientId)) {
+ throw new OAuthServiceException("Invalid audience");
+ }
+
+ // If strict time validation: if no issuedTime claim is set then an expiresAt claim must be set
+ // Otherwise: validate only if expiresAt claim is set
+ boolean expiredRequired =
+ validateClaimsAlways || strictTimeValidation && claims.getIssuedAt() == null;
+ try {
+ JwtUtils.validateJwtExpiry(claims, clockOffset, expiredRequired);
+ } catch (JwtException ex) {
+ throw new OAuthServiceException("ID Token has expired", ex);
+ }
+
+ // If strict time validation: If no expiresAt claim is set then an issuedAt claim must be set
+ // Otherwise: validate only if issuedAt claim is set
+ boolean issuedAtRequired =
+ validateClaimsAlways || strictTimeValidation && claims.getExpiryTime() == null;
+ try {
+ JwtUtils.validateJwtIssuedAt(claims, ttl, clockOffset, issuedAtRequired);
+ } catch (JwtException ex) {
+ throw new OAuthServiceException("Invalid issuedAt claim", ex);
+ }
+ if (strictTimeValidation) {
+ try {
+ JwtUtils.validateJwtNotBefore(claims, clockOffset, strictTimeValidation);
+ } catch (JwtException ex) {
+ throw new OAuthServiceException("ID Token can not be used yet", ex);
+ }
+ }
+ }
+ }
+
+ private void validateSelfIssuedProvider(JwtClaims claims, String clientId, boolean validateClaimsAlways) {
+ }
+
+ public void setIssuerId(String issuerId) {
+ this.issuerId = issuerId;
+ }
+
+ public void setJwkSetClient(WebClient jwkSetClient) {
+ this.jwkSetClient = jwkSetClient;
+ }
+
+ @Override
+ protected JwsSignatureVerifier getInitializedSignatureVerifier(JwtToken jwt) {
+ JsonWebKey key = null;
+ if (supportSelfIssuedProvider && SELF_ISSUED_ISSUER.equals(jwt.getClaim("issuer"))) {
+ String publicKeyJson = (String)jwt.getClaim("sub_jwk");
+ if (publicKeyJson != null) {
+ JsonWebKey publicKey = JwkUtils.readJwkKey(publicKeyJson);
+ String thumbprint = JwkUtils.getThumbprint(publicKey);
+ if (thumbprint.equals(jwt.getClaim("sub"))) {
+ key = publicKey;
+ }
+ }
+ if (key == null) {
+ throw new SecurityException("Self-issued JWK key is invalid or not available");
+ }
+ } else {
+ String keyId = jwt.getJwsHeaders().getKeyId();
+ key = keyId != null ? keyMap.get(keyId) : null;
+ if (key == null && jwkSetClient != null) {
+ JsonWebKeys keys = jwkSetClient.get(JsonWebKeys.class);
+ if (keyId != null) {
+ key = keys.getKey(keyId);
+ } else if (keys.getKeys().size() == 1) {
+ key = keys.getKeys().get(0);
+ }
+ //jwkSetClient returns the most up-to-date keys
+ keyMap.clear();
+ keyMap.putAll(keys.getKeyIdMap());
+ }
+ }
+ JwsSignatureVerifier theJwsVerifier = null;
+ if (key != null) {
+ theJwsVerifier = JwsUtils.getSignatureVerifier(key);
+ } else {
+ theJwsVerifier = super.getInitializedSignatureVerifier(jwt.getJwsHeaders());
+ }
+ if (theJwsVerifier == null) {
+ throw new SecurityException("JWS Verifier is not available");
+ }
+
+ return theJwsVerifier;
+ }
+
+ public void setSupportSelfIssuedProvider(boolean supportSelfIssuedProvider) {
+ this.supportSelfIssuedProvider = supportSelfIssuedProvider;
+ }
+
+ public int getClockOffset() {
+ return clockOffset;
+ }
+
+ public void setClockOffset(int clockOffset) {
+ this.clockOffset = clockOffset;
+ }
+
+ public void setStrictTimeValidation(boolean strictTimeValidation) {
+ this.strictTimeValidation = strictTimeValidation;
+ }
+
+ public int getTtl() {
+ return ttl;
+ }
+
+ public void setTtl(int ttl) {
+ this.ttl = ttl;
+ }
+}