added encryption/decryption to cached JWK-URI service
parent
2b0d02dc72
commit
6605877a1b
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<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() {
|
||||
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<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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue