added encryption/decryption to cached JWK-URI service

Conflicts:

	openid-connect-server/src/main/java/org/mitre/openid/connect/ConnectOAuth2RequestFactory.java
pull/650/head
Justin Richer 2013-09-20 11:29:46 -04:00
parent 672efa722c
commit b9f545d75b
4 changed files with 63 additions and 21 deletions

View File

@ -31,7 +31,7 @@ import javax.servlet.http.HttpSession;
import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultHttpClient;
import org.mitre.jwt.signer.service.JwtSigningAndValidationService; 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.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.model.IssuerServiceResponse; import org.mitre.openid.connect.client.model.IssuerServiceResponse;
import org.mitre.openid.connect.client.service.AuthRequestOptionsService; import org.mitre.openid.connect.client.service.AuthRequestOptionsService;
@ -85,7 +85,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
private int timeSkewAllowance = 300; private int timeSkewAllowance = 300;
@Autowired @Autowired
private JWKSetSigningAndValidationServiceCacheService validationServices; private JWKSetCacheService validationServices;
// modular services to build out client filter // modular services to build out client filter
private ServerConfigurationService servers; private ServerConfigurationService servers;
@ -355,7 +355,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
ReadOnlyJWTClaimsSet idClaims = idToken.getJWTClaimsSet(); ReadOnlyJWTClaimsSet idClaims = idToken.getJWTClaimsSet();
// check the signature // check the signature
JwtSigningAndValidationService jwtValidator = validationServices.get(serverConfig.getJwksUri()); JwtSigningAndValidationService jwtValidator = validationServices.getValidator(serverConfig.getJwksUri());
if (jwtValidator != null) { if (jwtValidator != null) {
if(!jwtValidator.validateSignature(idToken)) { if(!jwtValidator.validateSignature(idToken)) {
throw new AuthenticationServiceException("Signature validation failed"); throw new AuthenticationServiceException("Signature validation failed");
@ -543,14 +543,14 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
/** /**
* @return the validationServices * @return the validationServices
*/ */
public JWKSetSigningAndValidationServiceCacheService getValidationServices() { public JWKSetCacheService getValidationServices() {
return validationServices; return validationServices;
} }
/** /**
* @param validationServices the validationServices to set * @param validationServices the validationServices to set
*/ */
public void setValidationServices(JWKSetSigningAndValidationServiceCacheService validationServices) { public void setValidationServices(JWKSetCacheService validationServices) {
this.validationServices = validationServices; this.validationServices = validationServices;
} }

View File

@ -25,6 +25,8 @@ import java.util.concurrent.TimeUnit;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultHttpClient;
import org.mitre.jose.keystore.JWKSetKeyStore; 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.mitre.jwt.signer.service.JwtSigningAndValidationService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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. * Creates a caching map of JOSE signers/validators and encryptors/decryptors
* Dynamically loads JWK Sets to create the signing and validation services. * keyed on the JWK Set URI. Dynamically loads JWK Sets to create the services.
* *
* @author jricher * @author jricher
* *
*/ */
@Service @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 // map of jwk set uri -> signing/validation service built on the keys found in that jwk set
private LoadingCache<String, JwtSigningAndValidationService> cache; private LoadingCache<String, JwtSigningAndValidationService> validators;
// map of jwk set uri -> encryption/decryption service built on the keys found in that jwk set
private LoadingCache<String, JwtEncryptionAndDecryptionService> encryptors;
public JWKSetSigningAndValidationServiceCacheService() { public JWKSetCacheService() {
this.cache = CacheBuilder.newBuilder() this.validators = CacheBuilder.newBuilder()
.expireAfterWrite(1, TimeUnit.HOURS) // expires 1 hour after fetch .expireAfterWrite(1, TimeUnit.HOURS) // expires 1 hour after fetch
.maximumSize(100) .maximumSize(100)
.build(new JWKSetVerifierFetcher()); .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 * @throws ExecutionException
* @see com.google.common.cache.Cache#get(java.lang.Object) * @see com.google.common.cache.Cache#get(java.lang.Object)
*/ */
public JwtSigningAndValidationService get(String jwksUri) { public JwtSigningAndValidationService getValidator(String jwksUri) {
try { try {
return cache.get(jwksUri); return validators.get(jwksUri);
} catch (ExecutionException e) { } catch (ExecutionException e) {
logger.warn("Couldn't load JWK Set from " + jwksUri, e); logger.warn("Couldn't load JWK Set from " + jwksUri, e);
return null; 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 * @author jricher
* *
@ -103,4 +121,28 @@ public class JWKSetSigningAndValidationServiceCacheService {
} }
/**
* @author jricher
*
*/
private class JWKSetEncryptorFetcher extends CacheLoader<String, JwtEncryptionAndDecryptionService> {
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;
}
}
} }

View File

@ -25,7 +25,7 @@ import java.util.Set;
import net.minidev.json.JSONObject; import net.minidev.json.JSONObject;
import org.mitre.jwt.signer.service.JwtSigningAndValidationService; 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.exception.NonceReuseException; import org.mitre.oauth2.exception.NonceReuseException;
import org.mitre.oauth2.model.ClientDetailsEntity; import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.service.ClientDetailsEntityService; import org.mitre.oauth2.service.ClientDetailsEntityService;
@ -62,7 +62,7 @@ public class ConnectAuthorizationRequestManager implements AuthorizationRequestM
private ClientDetailsEntityService clientDetailsService; private ClientDetailsEntityService clientDetailsService;
@Autowired @Autowired
private JWKSetSigningAndValidationServiceCacheService validators; private JWKSetCacheService validators;
/** /**
* Constructor with arguments * Constructor with arguments
@ -162,7 +162,7 @@ public class ConnectAuthorizationRequestManager implements AuthorizationRequestM
} }
// check JWT signature // check JWT signature
JwtSigningAndValidationService validator = validators.get(client.getJwksUri()); JwtSigningAndValidationService validator = validators.getValidator(client.getJwksUri());
if (validator == null) { if (validator == null) {
throw new InvalidClientException("Unable to create signature validator for client's JWKS URI: " + client.getJwksUri()); throw new InvalidClientException("Unable to create signature validator for client's JWKS URI: " + client.getJwksUri());
} }

View File

@ -23,7 +23,7 @@ import java.text.ParseException;
import java.util.Date; import java.util.Date;
import org.mitre.jwt.signer.service.JwtSigningAndValidationService; 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.model.ClientDetailsEntity;
import org.mitre.oauth2.service.ClientDetailsEntityService; import org.mitre.oauth2.service.ClientDetailsEntityService;
import org.mitre.openid.connect.config.ConfigurationPropertiesBean; import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
@ -51,7 +51,7 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
// map of verifiers, load keys for clients // map of verifiers, load keys for clients
@Autowired @Autowired
private JWKSetSigningAndValidationServiceCacheService validators; private JWKSetCacheService validators;
// Allow for time sync issues by having a window of X seconds. // Allow for time sync issues by having a window of X seconds.
private int timeSkewAllowance = 300; private int timeSkewAllowance = 300;
@ -82,7 +82,7 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
// check the signature with nimbus // check the signature with nimbus
if (jwt instanceof SignedJWT) { if (jwt instanceof SignedJWT) {
SignedJWT jws = (SignedJWT)jwt; SignedJWT jws = (SignedJWT)jwt;
JwtSigningAndValidationService validator = validators.get(client.getJwksUri()); JwtSigningAndValidationService validator = validators.getValidator(client.getJwksUri());
if (validator == null || !validator.validateSignature(jws)) { if (validator == null || !validator.validateSignature(jws)) {
throw new AuthenticationServiceException("Invalid signature"); throw new AuthenticationServiceException("Invalid signature");
} }