From 6605877a1b3b395b0690b945a1f2f7ab8a6c6e9b Mon Sep 17 00:00:00 2001 From: Justin Richer Date: Mon, 16 Sep 2013 15:59:30 -0400 Subject: [PATCH] added encryption/decryption to cached JWK-URI service --- .../client/OIDCAuthenticationFilter.java | 10 +-- ...heService.java => JWKSetCacheService.java} | 62 ++++++++++++++++--- .../connect/ConnectOAuth2RequestFactory.java | 6 +- .../JwtBearerAuthenticationProvider.java | 6 +- 4 files changed, 63 insertions(+), 21 deletions(-) rename openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/{JWKSetSigningAndValidationServiceCacheService.java => JWKSetCacheService.java} (57%) diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java index 3ed486b7c..4e73cad39 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java @@ -31,7 +31,7 @@ import javax.servlet.http.HttpSession; import org.apache.http.impl.client.DefaultHttpClient; import org.mitre.jwt.signer.service.JwtSigningAndValidationService; -import org.mitre.jwt.signer.service.impl.JWKSetSigningAndValidationServiceCacheService; +import org.mitre.jwt.signer.service.impl.JWKSetCacheService; import org.mitre.oauth2.model.RegisteredClient; import org.mitre.openid.connect.client.model.IssuerServiceResponse; import org.mitre.openid.connect.client.service.AuthRequestOptionsService; @@ -85,7 +85,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi private int timeSkewAllowance = 300; @Autowired - private JWKSetSigningAndValidationServiceCacheService validationServices; + private JWKSetCacheService validationServices; // modular services to build out client filter private ServerConfigurationService servers; @@ -355,7 +355,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi ReadOnlyJWTClaimsSet idClaims = idToken.getJWTClaimsSet(); // check the signature - JwtSigningAndValidationService jwtValidator = validationServices.get(serverConfig.getJwksUri()); + JwtSigningAndValidationService jwtValidator = validationServices.getValidator(serverConfig.getJwksUri()); if (jwtValidator != null) { if(!jwtValidator.validateSignature(idToken)) { throw new AuthenticationServiceException("Signature validation failed"); @@ -542,14 +542,14 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi /** * @return the validationServices */ - public JWKSetSigningAndValidationServiceCacheService getValidationServices() { + public JWKSetCacheService getValidationServices() { return validationServices; } /** * @param validationServices the validationServices to set */ - public void setValidationServices(JWKSetSigningAndValidationServiceCacheService validationServices) { + public void setValidationServices(JWKSetCacheService validationServices) { this.validationServices = validationServices; } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JWKSetSigningAndValidationServiceCacheService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JWKSetCacheService.java similarity index 57% rename from openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JWKSetSigningAndValidationServiceCacheService.java rename to openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JWKSetCacheService.java index 9170310db..b6677e8e3 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JWKSetSigningAndValidationServiceCacheService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JWKSetCacheService.java @@ -25,6 +25,8 @@ import java.util.concurrent.TimeUnit; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.DefaultHttpClient; import org.mitre.jose.keystore.JWKSetKeyStore; +import org.mitre.jwt.encryption.service.JwtEncryptionAndDecryptionService; +import org.mitre.jwt.encryption.service.impl.DefaultJwtEncryptionAndDecryptionService; import org.mitre.jwt.signer.service.JwtSigningAndValidationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,25 +41,32 @@ import com.nimbusds.jose.jwk.JWKSet; /** * - * Creates a caching map of JOSE signers and validators keyed on the JWK Set URI. - * Dynamically loads JWK Sets to create the signing and validation services. + * Creates a caching map of JOSE signers/validators and encryptors/decryptors + * keyed on the JWK Set URI. Dynamically loads JWK Sets to create the services. * * @author jricher - * + * */ @Service -public class JWKSetSigningAndValidationServiceCacheService { +public class JWKSetCacheService { - private static Logger logger = LoggerFactory.getLogger(JWKSetSigningAndValidationServiceCacheService.class); + private static Logger logger = LoggerFactory.getLogger(JWKSetCacheService.class); // map of jwk set uri -> signing/validation service built on the keys found in that jwk set - private LoadingCache cache; + private LoadingCache validators; + + // map of jwk set uri -> encryption/decryption service built on the keys found in that jwk set + private LoadingCache encryptors; - public JWKSetSigningAndValidationServiceCacheService() { - this.cache = CacheBuilder.newBuilder() + public JWKSetCacheService() { + this.validators = CacheBuilder.newBuilder() .expireAfterWrite(1, TimeUnit.HOURS) // expires 1 hour after fetch .maximumSize(100) .build(new JWKSetVerifierFetcher()); + this.encryptors = CacheBuilder.newBuilder() + .expireAfterWrite(1, TimeUnit.HOURS) // expires 1 hour after fetch + .maximumSize(100) + .build(new JWKSetEncryptorFetcher()); } /** @@ -66,15 +75,24 @@ public class JWKSetSigningAndValidationServiceCacheService { * @throws ExecutionException * @see com.google.common.cache.Cache#get(java.lang.Object) */ - public JwtSigningAndValidationService get(String jwksUri) { + public JwtSigningAndValidationService getValidator(String jwksUri) { try { - return cache.get(jwksUri); + return validators.get(jwksUri); } catch (ExecutionException e) { logger.warn("Couldn't load JWK Set from " + jwksUri, e); return null; } } + public JwtEncryptionAndDecryptionService getEncrypter(String jwksUri) { + try { + return encryptors.get(jwksUri); + } catch (ExecutionException e) { + logger.warn("Couldn't load JWK Set from " + jwksUri, e); + return null; + } + } + /** * @author jricher * @@ -103,4 +121,28 @@ public class JWKSetSigningAndValidationServiceCacheService { } + /** + * @author jricher + * + */ + private class JWKSetEncryptorFetcher extends CacheLoader { + private HttpClient httpClient = new DefaultHttpClient(); + private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + private RestTemplate restTemplate = new RestTemplate(httpFactory); + /* (non-Javadoc) + * @see com.google.common.cache.CacheLoader#load(java.lang.Object) + */ + @Override + public JwtEncryptionAndDecryptionService load(String key) throws Exception { + String jsonString = restTemplate.getForObject(key, String.class); + JWKSet jwkSet = JWKSet.parse(jsonString); + + JWKSetKeyStore keyStore = new JWKSetKeyStore(jwkSet); + + JwtEncryptionAndDecryptionService service = new DefaultJwtEncryptionAndDecryptionService(keyStore); + + return service; + } + } + } diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/ConnectOAuth2RequestFactory.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/ConnectOAuth2RequestFactory.java index a32602ff4..47ef55e5b 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/ConnectOAuth2RequestFactory.java +++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/ConnectOAuth2RequestFactory.java @@ -27,7 +27,7 @@ import java.util.Set; import org.mitre.jwt.encryption.service.JwtEncryptionAndDecryptionService; import org.mitre.jwt.signer.service.JwtSigningAndValidationService; import org.mitre.jwt.signer.service.impl.DefaultJwtSigningAndValidationService; -import org.mitre.jwt.signer.service.impl.JWKSetSigningAndValidationServiceCacheService; +import org.mitre.jwt.signer.service.impl.JWKSetCacheService; import org.mitre.oauth2.model.ClientDetailsEntity; import org.mitre.oauth2.service.ClientDetailsEntityService; import org.mitre.oauth2.service.SystemScopeService; @@ -67,7 +67,7 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { private ClientDetailsEntityService clientDetailsService; @Autowired - private JWKSetSigningAndValidationServiceCacheService validators; + private JWKSetCacheService validators; @Autowired private SystemScopeService systemScopes; @@ -192,7 +192,7 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory { } // check JWT signature - JwtSigningAndValidationService validator = validators.get(client.getJwksUri()); + JwtSigningAndValidationService validator = validators.getValidator(client.getJwksUri()); if (validator == null) { throw new InvalidClientException("Unable to create signature validator for client's JWKS URI: " + client.getJwksUri()); diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JwtBearerAuthenticationProvider.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JwtBearerAuthenticationProvider.java index b6da5284e..64db6e214 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JwtBearerAuthenticationProvider.java +++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/assertion/JwtBearerAuthenticationProvider.java @@ -23,7 +23,7 @@ import java.text.ParseException; import java.util.Date; import org.mitre.jwt.signer.service.JwtSigningAndValidationService; -import org.mitre.jwt.signer.service.impl.JWKSetSigningAndValidationServiceCacheService; +import org.mitre.jwt.signer.service.impl.JWKSetCacheService; import org.mitre.oauth2.model.ClientDetailsEntity; import org.mitre.oauth2.service.ClientDetailsEntityService; import org.mitre.openid.connect.config.ConfigurationPropertiesBean; @@ -51,7 +51,7 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider { // map of verifiers, load keys for clients @Autowired - private JWKSetSigningAndValidationServiceCacheService validators; + private JWKSetCacheService validators; // Allow for time sync issues by having a window of X seconds. private int timeSkewAllowance = 300; @@ -82,7 +82,7 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider { // check the signature with nimbus if (jwt instanceof SignedJWT) { SignedJWT jws = (SignedJWT)jwt; - JwtSigningAndValidationService validator = validators.get(client.getJwksUri()); + JwtSigningAndValidationService validator = validators.getValidator(client.getJwksUri()); if (validator == null || !validator.validateSignature(jws)) { throw new AuthenticationServiceException("Invalid signature"); }