added system wide cache for all symmetric validators, closes # 557
parent
ca333d256b
commit
e4d5f4a540
|
@ -16,19 +16,18 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.openid.connect.client;
|
package org.mitre.openid.connect.client;
|
||||||
|
|
||||||
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.*;
|
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.PRIVATE_KEY;
|
||||||
|
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_BASIC;
|
||||||
|
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_JWT;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
@ -37,9 +36,8 @@ import javax.servlet.http.HttpSession;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.impl.client.SystemDefaultHttpClient;
|
import org.apache.http.impl.client.SystemDefaultHttpClient;
|
||||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||||
import org.mitre.jwt.signer.service.impl.DefaultJwtSigningAndValidationService;
|
|
||||||
import org.mitre.jwt.signer.service.impl.JWKSetCacheService;
|
import org.mitre.jwt.signer.service.impl.JWKSetCacheService;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
import org.mitre.jwt.signer.service.impl.SymmetricCacheService;
|
||||||
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;
|
||||||
|
@ -65,18 +63,13 @@ import org.springframework.web.client.HttpClientErrorException;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.nimbusds.jose.JWSAlgorithm;
|
import com.nimbusds.jose.JWSAlgorithm;
|
||||||
import com.nimbusds.jose.JWSHeader;
|
import com.nimbusds.jose.JWSHeader;
|
||||||
import com.nimbusds.jose.jwk.JWK;
|
|
||||||
import com.nimbusds.jose.jwk.OctetSequenceKey;
|
|
||||||
import com.nimbusds.jose.jwk.Use;
|
|
||||||
import com.nimbusds.jose.util.Base64;
|
import com.nimbusds.jose.util.Base64;
|
||||||
import com.nimbusds.jose.util.Base64URL;
|
|
||||||
import com.nimbusds.jwt.JWTClaimsSet;
|
import com.nimbusds.jwt.JWTClaimsSet;
|
||||||
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
|
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
|
||||||
import com.nimbusds.jwt.SignedJWT;
|
import com.nimbusds.jwt.SignedJWT;
|
||||||
|
@ -104,6 +97,9 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
@Autowired
|
@Autowired
|
||||||
private JWKSetCacheService validationServices;
|
private JWKSetCacheService validationServices;
|
||||||
|
|
||||||
|
@Autowired(required=false)
|
||||||
|
private SymmetricCacheService symmetricCacheService;
|
||||||
|
|
||||||
@Autowired(required=false)
|
@Autowired(required=false)
|
||||||
private JwtSigningAndValidationService authenticationSignerService;
|
private JwtSigningAndValidationService authenticationSignerService;
|
||||||
|
|
||||||
|
@ -131,6 +127,17 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
super.afterPropertiesSet();
|
super.afterPropertiesSet();
|
||||||
|
|
||||||
|
// if our JOSE validators don't get wired in, drop defaults into place
|
||||||
|
|
||||||
|
if (validationServices == null) {
|
||||||
|
validationServices = new JWKSetCacheService();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symmetricCacheService == null) {
|
||||||
|
symmetricCacheService = new SymmetricCacheService();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -324,7 +331,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
|| alg.equals(JWSAlgorithm.HS512))) {
|
|| alg.equals(JWSAlgorithm.HS512))) {
|
||||||
|
|
||||||
// generate one based on client secret
|
// generate one based on client secret
|
||||||
signer = getSymmetricValidtor(clientConfig.getClient());
|
signer = symmetricCacheService.getSymmetricValidtor(clientConfig.getClient());
|
||||||
|
|
||||||
} else if (PRIVATE_KEY.equals(clientConfig.getTokenEndpointAuthMethod())) {
|
} else if (PRIVATE_KEY.equals(clientConfig.getTokenEndpointAuthMethod())) {
|
||||||
|
|
||||||
|
@ -744,41 +751,4 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
this.authOptions = authOptions;
|
this.authOptions = authOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a symmetric signing and validation service for the given client
|
|
||||||
*
|
|
||||||
* @param client
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private JwtSigningAndValidationService getSymmetricValidtor(ClientDetailsEntity client) {
|
|
||||||
|
|
||||||
// TODO: cache
|
|
||||||
|
|
||||||
if (client == null) {
|
|
||||||
logger.error("Couldn't create symmetric validator for null client");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(client.getClientSecret())) {
|
|
||||||
logger.error("Couldn't create symmetric validator for client " + client.getClientId() + " without a client secret");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
JWK jwk = new OctetSequenceKey(Base64URL.encode(client.getClientSecret()), Use.SIGNATURE, null, client.getClientId(), null, null, null);
|
|
||||||
Map<String, JWK> keys = ImmutableMap.of(client.getClientId(), jwk);
|
|
||||||
JwtSigningAndValidationService service = new DefaultJwtSigningAndValidationService(keys);
|
|
||||||
|
|
||||||
return service;
|
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
logger.error("Couldn't create symmetric validator for client " + client.getClientId(), e);
|
|
||||||
} catch (InvalidKeySpecException e) {
|
|
||||||
logger.error("Couldn't create symmetric validator for client " + client.getClientId(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
package org.mitre.jwt.signer.service.impl;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||||
|
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||||
|
import com.nimbusds.jose.jwk.JWK;
|
||||||
|
import com.nimbusds.jose.jwk.OctetSequenceKey;
|
||||||
|
import com.nimbusds.jose.jwk.Use;
|
||||||
|
import com.nimbusds.jose.util.Base64URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and caches symmetrical validators for clients based on client secrets.
|
||||||
|
*
|
||||||
|
* @author jricher
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class SymmetricCacheService {
|
||||||
|
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(SymmetricCacheService.class);
|
||||||
|
|
||||||
|
private LoadingCache<String, JwtSigningAndValidationService> validators;
|
||||||
|
|
||||||
|
|
||||||
|
public SymmetricCacheService() {
|
||||||
|
validators = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterAccess(24, TimeUnit.HOURS)
|
||||||
|
.maximumSize(100)
|
||||||
|
.build(new SymmetricValidatorBuilder());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a symmetric signing and validation service for the given client
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public JwtSigningAndValidationService getSymmetricValidtor(ClientDetailsEntity client) {
|
||||||
|
|
||||||
|
if (client == null) {
|
||||||
|
logger.error("Couldn't create symmetric validator for null client");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Strings.isNullOrEmpty(client.getClientSecret())) {
|
||||||
|
logger.error("Couldn't create symmetric validator for client " + client.getClientId() + " without a client secret");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return validators.get(client.getClientSecret());
|
||||||
|
} catch (UncheckedExecutionException ue) {
|
||||||
|
logger.error("Problem loading client validator", ue);
|
||||||
|
return null;
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
logger.error("Problem loading client validator", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SymmetricValidatorBuilder extends CacheLoader<String, JwtSigningAndValidationService> {
|
||||||
|
@Override
|
||||||
|
public JwtSigningAndValidationService load(String key) throws Exception {
|
||||||
|
try {
|
||||||
|
|
||||||
|
String id = "SYMMETRIC-KEY";
|
||||||
|
|
||||||
|
JWK jwk = new OctetSequenceKey(Base64URL.encode(key), Use.SIGNATURE, null, id, null, null, null);
|
||||||
|
Map<String, JWK> keys = ImmutableMap.of(id, jwk);
|
||||||
|
JwtSigningAndValidationService service = new DefaultJwtSigningAndValidationService(keys);
|
||||||
|
|
||||||
|
return service;
|
||||||
|
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
logger.error("Couldn't create symmetric validator for client", e);
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
logger.error("Couldn't create symmetric validator for client", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Couldn't create symmetric validator for client");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,8 +16,6 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.openid.connect;
|
package org.mitre.openid.connect;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -26,8 +24,8 @@ import java.util.UUID;
|
||||||
|
|
||||||
import org.mitre.jwt.encryption.service.JwtEncryptionAndDecryptionService;
|
import org.mitre.jwt.encryption.service.JwtEncryptionAndDecryptionService;
|
||||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||||
import org.mitre.jwt.signer.service.impl.DefaultJwtSigningAndValidationService;
|
|
||||||
import org.mitre.jwt.signer.service.impl.JWKSetCacheService;
|
import org.mitre.jwt.signer.service.impl.JWKSetCacheService;
|
||||||
|
import org.mitre.jwt.signer.service.impl.SymmetricCacheService;
|
||||||
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.oauth2.service.SystemScopeService;
|
import org.mitre.oauth2.service.SystemScopeService;
|
||||||
|
@ -35,23 +33,18 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
||||||
|
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||||
import org.springframework.security.oauth2.common.util.OAuth2Utils;
|
import org.springframework.security.oauth2.common.util.OAuth2Utils;
|
||||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.provider.DefaultOAuth2RequestFactory;
|
import org.springframework.security.oauth2.provider.DefaultOAuth2RequestFactory;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.nimbusds.jose.Algorithm;
|
import com.nimbusds.jose.Algorithm;
|
||||||
import com.nimbusds.jose.JWEObject.State;
|
import com.nimbusds.jose.JWEObject.State;
|
||||||
import com.nimbusds.jose.JWSAlgorithm;
|
import com.nimbusds.jose.JWSAlgorithm;
|
||||||
import com.nimbusds.jose.jwk.JWK;
|
|
||||||
import com.nimbusds.jose.jwk.OctetSequenceKey;
|
|
||||||
import com.nimbusds.jose.jwk.Use;
|
|
||||||
import com.nimbusds.jose.util.Base64URL;
|
|
||||||
import com.nimbusds.jwt.EncryptedJWT;
|
import com.nimbusds.jwt.EncryptedJWT;
|
||||||
import com.nimbusds.jwt.JWT;
|
import com.nimbusds.jwt.JWT;
|
||||||
import com.nimbusds.jwt.JWTParser;
|
import com.nimbusds.jwt.JWTParser;
|
||||||
|
@ -68,6 +61,9 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JWKSetCacheService validators;
|
private JWKSetCacheService validators;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SymmetricCacheService symmetricCacheService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SystemScopeService systemScopes;
|
private SystemScopeService systemScopes;
|
||||||
|
@ -126,15 +122,19 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.getClientId() != null) {
|
if (request.getClientId() != null) {
|
||||||
ClientDetailsEntity client = clientDetailsService.loadClientByClientId(request.getClientId());
|
try {
|
||||||
|
ClientDetailsEntity client = clientDetailsService.loadClientByClientId(request.getClientId());
|
||||||
if ((request.getScope() == null || request.getScope().isEmpty())) {
|
|
||||||
Set<String> clientScopes = client.getScope();
|
if ((request.getScope() == null || request.getScope().isEmpty())) {
|
||||||
request.setScope(clientScopes);
|
Set<String> clientScopes = client.getScope();
|
||||||
}
|
request.setScope(clientScopes);
|
||||||
|
}
|
||||||
if (request.getExtensions().get("max_age") == null && client.getDefaultMaxAge() != null) {
|
|
||||||
request.getExtensions().put("max_age", client.getDefaultMaxAge().toString());
|
if (request.getExtensions().get("max_age") == null && client.getDefaultMaxAge() != null) {
|
||||||
|
request.getExtensions().put("max_age", client.getDefaultMaxAge().toString());
|
||||||
|
}
|
||||||
|
} catch (OAuth2Exception e) {
|
||||||
|
logger.error("Caught OAuth2 exception trying to test client scopes and max age:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory {
|
||||||
|
|
||||||
// it's HMAC, we need to make a validator based on the client secret
|
// it's HMAC, we need to make a validator based on the client secret
|
||||||
|
|
||||||
JwtSigningAndValidationService validator = getSymmetricValidtor(client);
|
JwtSigningAndValidationService validator = symmetricCacheService.getSymmetricValidtor(client);
|
||||||
|
|
||||||
if (validator == null) {
|
if (validator == null) {
|
||||||
throw new InvalidClientException("Unable to create signature validator for client's secret: " + client.getClientSecret());
|
throw new InvalidClientException("Unable to create signature validator for client's secret: " + client.getClientSecret());
|
||||||
|
@ -366,40 +366,4 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a symmetric signing and validation service for the given client
|
|
||||||
*
|
|
||||||
* @param client
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private JwtSigningAndValidationService getSymmetricValidtor(ClientDetailsEntity client) {
|
|
||||||
|
|
||||||
if (client == null) {
|
|
||||||
logger.error("Couldn't create symmetric validator for null client");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(client.getClientSecret())) {
|
|
||||||
logger.error("Couldn't create symmetric validator for client " + client.getClientId() + " without a client secret");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
JWK jwk = new OctetSequenceKey(Base64URL.encode(client.getClientSecret()), Use.SIGNATURE, null, client.getClientId(), null, null, null);
|
|
||||||
Map<String, JWK> keys = ImmutableMap.of(client.getClientId(), jwk);
|
|
||||||
JwtSigningAndValidationService service = new DefaultJwtSigningAndValidationService(keys);
|
|
||||||
|
|
||||||
return service;
|
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
logger.error("Couldn't create symmetric validator for client " + client.getClientId(), e);
|
|
||||||
} catch (InvalidKeySpecException e) {
|
|
||||||
logger.error("Couldn't create symmetric validator for client " + client.getClientId(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,15 +19,12 @@
|
||||||
*/
|
*/
|
||||||
package org.mitre.openid.connect.assertion;
|
package org.mitre.openid.connect.assertion;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||||
import org.mitre.jwt.signer.service.impl.DefaultJwtSigningAndValidationService;
|
|
||||||
import org.mitre.jwt.signer.service.impl.JWKSetCacheService;
|
import org.mitre.jwt.signer.service.impl.JWKSetCacheService;
|
||||||
|
import org.mitre.jwt.signer.service.impl.SymmetricCacheService;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
|
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
|
||||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||||
|
@ -42,13 +39,7 @@ import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.nimbusds.jose.JWSAlgorithm;
|
import com.nimbusds.jose.JWSAlgorithm;
|
||||||
import com.nimbusds.jose.jwk.JWK;
|
|
||||||
import com.nimbusds.jose.jwk.OctetSequenceKey;
|
|
||||||
import com.nimbusds.jose.jwk.Use;
|
|
||||||
import com.nimbusds.jose.util.Base64URL;
|
|
||||||
import com.nimbusds.jwt.JWT;
|
import com.nimbusds.jwt.JWT;
|
||||||
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
|
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
|
||||||
import com.nimbusds.jwt.SignedJWT;
|
import com.nimbusds.jwt.SignedJWT;
|
||||||
|
@ -64,6 +55,10 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
||||||
// map of verifiers, load keys for clients
|
// map of verifiers, load keys for clients
|
||||||
@Autowired
|
@Autowired
|
||||||
private JWKSetCacheService validators;
|
private JWKSetCacheService validators;
|
||||||
|
|
||||||
|
// map of symmetric verifiers for client secrets
|
||||||
|
@Autowired
|
||||||
|
private SymmetricCacheService symmetricCacheService;
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -123,7 +118,7 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
|
||||||
// it's HMAC, we need to make a validator based on the client secret
|
// it's HMAC, we need to make a validator based on the client secret
|
||||||
|
|
||||||
JwtSigningAndValidationService validator = getSymmetricValidtor(client);
|
JwtSigningAndValidationService validator = symmetricCacheService.getSymmetricValidtor(client);
|
||||||
|
|
||||||
if (validator == null) {
|
if (validator == null) {
|
||||||
throw new AuthenticationServiceException("Unable to create signature validator for client's secret: " + client.getClientSecret());
|
throw new AuthenticationServiceException("Unable to create signature validator for client's secret: " + client.getClientSecret());
|
||||||
|
@ -199,43 +194,4 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
||||||
return (JwtBearerAssertionAuthenticationToken.class.isAssignableFrom(authentication));
|
return (JwtBearerAssertionAuthenticationToken.class.isAssignableFrom(authentication));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a symmetric signing and validation service for the given client
|
|
||||||
*
|
|
||||||
* @param client
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private JwtSigningAndValidationService getSymmetricValidtor(ClientDetailsEntity client) {
|
|
||||||
|
|
||||||
// TODO: cache
|
|
||||||
|
|
||||||
if (client == null) {
|
|
||||||
logger.error("Couldn't create symmetric validator for null client");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(client.getClientSecret())) {
|
|
||||||
logger.error("Couldn't create symmetric validator for client " + client.getClientId() + " without a client secret");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
JWK jwk = new OctetSequenceKey(Base64URL.encode(client.getClientSecret()), Use.SIGNATURE, null, client.getClientId(), null, null, null);
|
|
||||||
Map<String, JWK> keys = ImmutableMap.of(client.getClientId(), jwk);
|
|
||||||
JwtSigningAndValidationService service = new DefaultJwtSigningAndValidationService(keys);
|
|
||||||
|
|
||||||
return service;
|
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
logger.error("Couldn't create symmetric validator for client " + client.getClientId(), e);
|
|
||||||
} catch (InvalidKeySpecException e) {
|
|
||||||
logger.error("Couldn't create symmetric validator for client " + client.getClientId(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue