Polish spring-security-oauth2-jose main code

Manually polish `spring-security-oauth-jose` following the
formatting and checkstyle fixes.

Issue gh-8945
This commit is contained in:
Phillip Webb 2020-07-31 22:16:50 -07:00 committed by Rob Winch
parent a577871bca
commit 20aa8bef25
15 changed files with 96 additions and 175 deletions

View File

@ -55,6 +55,15 @@ public enum MacAlgorithm implements JwsAlgorithm {
this.name = name;
}
/**
* Returns the algorithm name.
* @return the algorithm name
*/
@Override
public String getName() {
return this.name;
}
/**
* Attempt to resolve the provided algorithm name to a {@code MacAlgorithm}.
* @param name the algorithm name
@ -69,13 +78,4 @@ public enum MacAlgorithm implements JwsAlgorithm {
return null;
}
/**
* Returns the algorithm name.
* @return the algorithm name
*/
@Override
public String getName() {
return this.name;
}
}

View File

@ -85,6 +85,15 @@ public enum SignatureAlgorithm implements JwsAlgorithm {
this.name = name;
}
/**
* Returns the algorithm name.
* @return the algorithm name
*/
@Override
public String getName() {
return this.name;
}
/**
* Attempt to resolve the provided algorithm name to a {@code SignatureAlgorithm}.
* @param name the algorithm name
@ -99,13 +108,4 @@ public enum SignatureAlgorithm implements JwsAlgorithm {
return null;
}
/**
* Returns the algorithm name.
* @return the algorithm name
*/
@Override
public String getName() {
return this.name;
}
}

View File

@ -58,9 +58,6 @@ public final class JwtClaimValidator<T> implements OAuth2TokenValidator<Jwt> {
"https://tools.ietf.org/html/rfc6750#section-3.1");
}
/**
* {@inheritDoc}
*/
@Override
public OAuth2TokenValidatorResult validate(Jwt token) {
Assert.notNull(token, "token cannot be null");
@ -68,10 +65,8 @@ public final class JwtClaimValidator<T> implements OAuth2TokenValidator<Jwt> {
if (this.test.test(claimValue)) {
return OAuth2TokenValidatorResult.success();
}
else {
this.logger.debug(this.error.getDescription());
return OAuth2TokenValidatorResult.failure(this.error);
}
}
}

View File

@ -23,6 +23,7 @@ import java.util.Map;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
@ -46,7 +47,7 @@ final class JwtDecoderProviderConfigurationUtils {
private static final RestTemplate rest = new RestTemplate();
private static final ParameterizedTypeReference<Map<String, Object>> typeReference = new ParameterizedTypeReference<Map<String, Object>>() {
private static final ParameterizedTypeReference<Map<String, Object>> STRING_OBJECT_MAP = new ParameterizedTypeReference<Map<String, Object>>() {
};
private JwtDecoderProviderConfigurationUtils() {
@ -62,14 +63,16 @@ final class JwtDecoderProviderConfigurationUtils {
}
static void validateIssuer(Map<String, Object> configuration, String issuer) {
String metadataIssuer = "(unavailable)";
if (configuration.containsKey("issuer")) {
metadataIssuer = configuration.get("issuer").toString();
}
if (!issuer.equals(metadataIssuer)) {
throw new IllegalStateException("The Issuer \"" + metadataIssuer
String metadataIssuer = getMetadataIssuer(configuration);
Assert.state(issuer.equals(metadataIssuer), () -> "The Issuer \"" + metadataIssuer
+ "\" provided in the configuration did not " + "match the requested issuer \"" + issuer + "\"");
}
private static String getMetadataIssuer(Map<String, Object> configuration) {
if (configuration.containsKey("issuer")) {
return configuration.get("issuer").toString();
}
return "(unavailable)";
}
private static Map<String, Object> getConfiguration(String issuer, URI... uris) {
@ -77,13 +80,9 @@ final class JwtDecoderProviderConfigurationUtils {
for (URI uri : uris) {
try {
RequestEntity<Void> request = RequestEntity.get(uri).build();
ResponseEntity<Map<String, Object>> response = rest.exchange(request, typeReference);
ResponseEntity<Map<String, Object>> response = rest.exchange(request, STRING_OBJECT_MAP);
Map<String, Object> configuration = response.getBody();
if (configuration.get("jwks_uri") == null) {
throw new IllegalArgumentException("The public JWK set URI must not be null");
}
Assert.isTrue(configuration.get("jwks_uri") != null, "The public JWK set URI must not be null");
return configuration;
}
catch (IllegalArgumentException ex) {

View File

@ -34,6 +34,9 @@ import org.springframework.util.Assert;
*/
public final class JwtDecoders {
private JwtDecoders() {
}
/**
* Creates a {@link JwtDecoder} using the provided <a href=
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
@ -105,11 +108,7 @@ public final class JwtDecoders {
OAuth2TokenValidator<Jwt> jwtValidator = JwtValidators.createDefaultWithIssuer(issuer);
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(configuration.get("jwks_uri").toString()).build();
jwtDecoder.setJwtValidator(jwtValidator);
return jwtDecoder;
}
private JwtDecoders() {
}
}

View File

@ -39,9 +39,6 @@ public final class JwtIssuerValidator implements OAuth2TokenValidator<Jwt> {
this.validator = new JwtClaimValidator(JwtClaimNames.ISS, issuer::equals);
}
/**
* {@inheritDoc}
*/
@Override
public OAuth2TokenValidatorResult validate(Jwt token) {
Assert.notNull(token, "token cannot be null");

View File

@ -68,31 +68,23 @@ public final class JwtTimestampValidator implements OAuth2TokenValidator<Jwt> {
this.clockSkew = clockSkew;
}
/**
* {@inheritDoc}
*/
@Override
public OAuth2TokenValidatorResult validate(Jwt jwt) {
Assert.notNull(jwt, "jwt cannot be null");
Instant expiry = jwt.getExpiresAt();
if (expiry != null) {
if (Instant.now(this.clock).minus(this.clockSkew).isAfter(expiry)) {
OAuth2Error oAuth2Error = createOAuth2Error(String.format("Jwt expired at %s", jwt.getExpiresAt()));
return OAuth2TokenValidatorResult.failure(oAuth2Error);
}
}
Instant notBefore = jwt.getNotBefore();
if (notBefore != null) {
if (Instant.now(this.clock).plus(this.clockSkew).isBefore(notBefore)) {
OAuth2Error oAuth2Error = createOAuth2Error(String.format("Jwt used before %s", jwt.getNotBefore()));
return OAuth2TokenValidatorResult.failure(oAuth2Error);
}
}
return OAuth2TokenValidatorResult.success();
}
@ -103,8 +95,7 @@ public final class JwtTimestampValidator implements OAuth2TokenValidator<Jwt> {
}
/**
* ' Use this {@link Clock} with {@link Instant#now()} for assessing timestamp
* validity
* Use this {@link Clock} with {@link Instant#now()} for assessing timestamp validity
* @param clock
*/
public void setClock(Clock clock) {

View File

@ -54,7 +54,6 @@ public class JwtValidationException extends BadJwtException {
*/
public JwtValidationException(String message, Collection<OAuth2Error> errors) {
super(message);
Assert.notEmpty(errors, "errors cannot be empty");
this.errors = new ArrayList<>(errors);
}

View File

@ -32,6 +32,9 @@ import org.springframework.security.oauth2.core.OAuth2TokenValidator;
*/
public final class JwtValidators {
private JwtValidators() {
}
/**
* <p>
* Create a {@link Jwt} Validator that contains all standard validators when an issuer
@ -69,7 +72,4 @@ public final class JwtValidators {
return new DelegatingOAuth2TokenValidator<>(Arrays.asList(new JwtTimestampValidator()));
}
private JwtValidators() {
}
}

View File

@ -93,11 +93,9 @@ public final class MappedJwtClaimSetConverter implements Converter<Map<String, O
*/
public static MappedJwtClaimSetConverter withDefaults(Map<String, Converter<Object, ?>> claimTypeConverters) {
Assert.notNull(claimTypeConverters, "claimTypeConverters cannot be null");
Converter<Object, ?> stringConverter = getConverter(STRING_TYPE_DESCRIPTOR);
Converter<Object, ?> collectionStringConverter = getConverter(
TypeDescriptor.collection(Collection.class, STRING_TYPE_DESCRIPTOR));
Map<String, Converter<Object, ?>> claimNameToConverter = new HashMap<>();
claimNameToConverter.put(JwtClaimNames.AUD, collectionStringConverter);
claimNameToConverter.put(JwtClaimNames.EXP, MappedJwtClaimSetConverter::convertInstant);
@ -107,7 +105,6 @@ public final class MappedJwtClaimSetConverter implements Converter<Map<String, O
claimNameToConverter.put(JwtClaimNames.NBF, MappedJwtClaimSetConverter::convertInstant);
claimNameToConverter.put(JwtClaimNames.SUB, stringConverter);
claimNameToConverter.putAll(claimTypeConverters);
return new MappedJwtClaimSetConverter(claimNameToConverter);
}
@ -120,9 +117,7 @@ public final class MappedJwtClaimSetConverter implements Converter<Map<String, O
return null;
}
Instant result = (Instant) CONVERSION_SERVICE.convert(source, OBJECT_TYPE_DESCRIPTOR, INSTANT_TYPE_DESCRIPTOR);
if (result == null) {
throw new IllegalStateException("Could not coerce " + source + " into an Instant");
}
Assert.state(result != null, () -> "Could not coerce " + source + " into an Instant");
return result;
}
@ -145,24 +140,17 @@ public final class MappedJwtClaimSetConverter implements Converter<Map<String, O
return (String) CONVERSION_SERVICE.convert(source, OBJECT_TYPE_DESCRIPTOR, STRING_TYPE_DESCRIPTOR);
}
/**
* {@inheritDoc}
*/
@Override
public Map<String, Object> convert(Map<String, Object> claims) {
Assert.notNull(claims, "claims cannot be null");
Map<String, Object> mappedClaims = this.delegate.convert(claims);
mappedClaims = removeClaims(mappedClaims);
mappedClaims = addClaims(mappedClaims);
Instant issuedAt = (Instant) mappedClaims.get(JwtClaimNames.IAT);
Instant expiresAt = (Instant) mappedClaims.get(JwtClaimNames.EXP);
if (issuedAt == null && expiresAt != null) {
mappedClaims.put(JwtClaimNames.IAT, expiresAt.minusSeconds(1));
}
return mappedClaims;
}

View File

@ -145,20 +145,16 @@ public final class NimbusJwtDecoder implements JwtDecoder {
try {
// Verify the signature
JWTClaimsSet jwtClaimsSet = this.jwtProcessor.process(parsedJwt, null);
Map<String, Object> headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject());
Map<String, Object> claims = this.claimSetConverter.convert(jwtClaimsSet.getClaims());
return Jwt.withTokenValue(token).headers((h) -> h.putAll(headers)).claims((c) -> c.putAll(claims)).build();
}
catch (RemoteKeySourceException ex) {
if (ex.getCause() instanceof ParseException) {
throw new JwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, "Malformed Jwk set"));
}
else {
throw new JwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, ex.getMessage()), ex);
}
}
catch (JOSEException ex) {
throw new JwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, ex.getMessage()), ex);
}
@ -166,28 +162,27 @@ public final class NimbusJwtDecoder implements JwtDecoder {
if (ex.getCause() instanceof ParseException) {
throw new BadJwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, "Malformed payload"));
}
else {
throw new BadJwtException(String.format(DECODING_ERROR_MESSAGE_TEMPLATE, ex.getMessage()), ex);
}
}
}
private Jwt validateJwt(Jwt jwt) {
OAuth2TokenValidatorResult result = this.jwtValidator.validate(jwt);
if (result.hasErrors()) {
Collection<OAuth2Error> errors = result.getErrors();
String validationErrorString = "Unable to validate Jwt";
for (OAuth2Error oAuth2Error : errors) {
if (!StringUtils.isEmpty(oAuth2Error.getDescription())) {
validationErrorString = String.format(DECODING_ERROR_MESSAGE_TEMPLATE,
oAuth2Error.getDescription());
break;
String validationErrorString = getJwtValidationExceptionMessage(errors);
throw new JwtValidationException(validationErrorString, errors);
}
}
throw new JwtValidationException(validationErrorString, result.getErrors());
return jwt;
}
return jwt;
private String getJwtValidationExceptionMessage(Collection<OAuth2Error> errors) {
for (OAuth2Error oAuth2Error : errors) {
if (!StringUtils.isEmpty(oAuth2Error.getDescription())) {
return String.format(DECODING_ERROR_MESSAGE_TEMPLATE, oAuth2Error.getDescription());
}
}
return "Unable to validate Jwt";
}
/**
@ -316,7 +311,6 @@ public final class NimbusJwtDecoder implements JwtDecoder {
if (this.signatureAlgorithms.isEmpty()) {
return new JWSVerificationKeySelector<>(JWSAlgorithm.RS256, jwkSource);
}
else {
Set<JWSAlgorithm> jwsAlgorithms = new HashSet<>();
for (SignatureAlgorithm signatureAlgorithm : this.signatureAlgorithms) {
JWSAlgorithm jwsAlgorithm = JWSAlgorithm.parse(signatureAlgorithm.getName());
@ -324,7 +318,6 @@ public final class NimbusJwtDecoder implements JwtDecoder {
}
return new JWSVerificationKeySelector<>(jwsAlgorithms, jwkSource);
}
}
JWKSource<SecurityContext> jwkSource(ResourceRetriever jwkSetRetriever) {
if (this.cache == null) {
@ -339,13 +332,10 @@ public final class NimbusJwtDecoder implements JwtDecoder {
JWKSource<SecurityContext> jwkSource = jwkSource(jwkSetRetriever);
ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
jwtProcessor.setJWSKeySelector(jwsKeySelector(jwkSource));
// Spring Security validates the claim set independent from Nimbus
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
});
this.jwtProcessorCustomizer.accept(jwtProcessor);
return jwtProcessor;
}
@ -397,10 +387,10 @@ public final class NimbusJwtDecoder implements JwtDecoder {
@Override
public Resource retrieveResource(URL url) throws IOException {
String jwkSet;
try {
jwkSet = this.cache.get(url.toString(),
String jwkSet = this.cache.get(url.toString(),
() -> this.resourceRetriever.retrieveResource(url).getContent());
return new Resource(jwkSet, "UTF-8");
}
catch (Cache.ValueRetrievalException ex) {
Throwable thrownByValueLoader = ex.getCause();
@ -412,8 +402,6 @@ public final class NimbusJwtDecoder implements JwtDecoder {
catch (Exception ex) {
throw new IOException(ex);
}
return new Resource(jwkSet, "UTF-8");
}
}
@ -433,21 +421,21 @@ public final class NimbusJwtDecoder implements JwtDecoder {
public Resource retrieveResource(URL url) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON, APPLICATION_JWK_SET_JSON));
ResponseEntity<String> response = getResponse(url, headers);
if (response.getStatusCodeValue() != 200) {
throw new IOException(response.toString());
}
return new Resource(response.getBody(), "UTF-8");
}
ResponseEntity<String> response;
private ResponseEntity<String> getResponse(URL url, HttpHeaders headers) throws IOException {
try {
RequestEntity<Void> request = new RequestEntity<>(headers, HttpMethod.GET, url.toURI());
response = this.restOperations.exchange(request, String.class);
return this.restOperations.exchange(request, String.class);
}
catch (Exception ex) {
throw new IOException(ex);
}
if (response.getStatusCodeValue() != 200) {
throw new IOException(response.toString());
}
return new Resource(response.getBody(), "UTF-8");
}
}
@ -506,22 +494,16 @@ public final class NimbusJwtDecoder implements JwtDecoder {
}
JWTProcessor<SecurityContext> processor() {
if (!JWSAlgorithm.Family.RSA.contains(this.jwsAlgorithm)) {
throw new IllegalStateException(
"The provided key is of type RSA; " + "however the signature algorithm is of some other type: "
Assert.state(JWSAlgorithm.Family.RSA.contains(this.jwsAlgorithm),
() -> "The provided key is of type RSA; however the signature algorithm is of some other type: "
+ this.jwsAlgorithm + ". Please indicate one of RS256, RS384, or RS512.");
}
JWSKeySelector<SecurityContext> jwsKeySelector = new SingleKeyJWSKeySelector<>(this.jwsAlgorithm, this.key);
DefaultJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
jwtProcessor.setJWSKeySelector(jwsKeySelector);
// Spring Security validates the claim set independent from Nimbus
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
});
this.jwtProcessorCustomizer.accept(jwtProcessor);
return jwtProcessor;
}
@ -599,13 +581,10 @@ public final class NimbusJwtDecoder implements JwtDecoder {
this.secretKey);
DefaultJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
jwtProcessor.setJWSKeySelector(jwsKeySelector);
// Spring Security validates the claim set independent from Nimbus
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
});
this.jwtProcessorCustomizer.accept(jwtProcessor);
return jwtProcessor;
}

View File

@ -79,7 +79,6 @@ public final class NimbusJwtDecoderJwkSupport implements JwtDecoder {
public NimbusJwtDecoderJwkSupport(String jwkSetUrl, String jwsAlgorithm) {
Assert.hasText(jwkSetUrl, "jwkSetUrl cannot be empty");
Assert.hasText(jwsAlgorithm, "jwsAlgorithm cannot be empty");
this.jwtDecoderBuilder = NimbusJwtDecoder.withJwkSetUri(jwkSetUrl)
.jwsAlgorithm(SignatureAlgorithm.from(jwsAlgorithm));
this.delegate = makeDelegate();

View File

@ -161,8 +161,8 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
try {
return this.jwtProcessor.convert(parsedToken).map((set) -> createJwt(parsedToken, set))
.map(this::validateJwt)
.onErrorMap((e) -> !(e instanceof IllegalStateException) && !(e instanceof JwtException),
(e) -> new JwtException("An error occurred while attempting to decode the Jwt: ", e));
.onErrorMap((ex) -> !(ex instanceof IllegalStateException) && !(ex instanceof JwtException),
(ex) -> new JwtException("An error occurred while attempting to decode the Jwt: ", ex));
}
catch (JwtException ex) {
throw ex;
@ -176,7 +176,6 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
try {
Map<String, Object> headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject());
Map<String, Object> claims = this.claimSetConverter.convert(jwtClaimsSet.getClaims());
return Jwt.withTokenValue(parsedJwt.getParsedString()).headers((h) -> h.putAll(headers))
.claims((c) -> c.putAll(claims)).build();
}
@ -189,19 +188,21 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
OAuth2TokenValidatorResult result = this.jwtValidator.validate(jwt);
if (result.hasErrors()) {
Collection<OAuth2Error> errors = result.getErrors();
String validationErrorString = "Unable to validate Jwt";
for (OAuth2Error oAuth2Error : errors) {
if (!StringUtils.isEmpty(oAuth2Error.getDescription())) {
validationErrorString = oAuth2Error.getDescription();
break;
}
}
String validationErrorString = getJwtValidationExceptionMessage(errors);
throw new JwtValidationException(validationErrorString, errors);
}
return jwt;
}
private String getJwtValidationExceptionMessage(Collection<OAuth2Error> errors) {
for (OAuth2Error oAuth2Error : errors) {
if (!StringUtils.isEmpty(oAuth2Error.getDescription())) {
return oAuth2Error.getDescription();
}
}
return "Unable to validate Jwt";
}
/**
* Use the given <a href="https://tools.ietf.org/html/rfc7517#section-5">JWK Set</a>
* uri to validate JWTs.
@ -353,7 +354,6 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
if (this.signatureAlgorithms.isEmpty()) {
return new JWSVerificationKeySelector<>(JWSAlgorithm.RS256, jwkSource);
}
else {
Set<JWSAlgorithm> jwsAlgorithms = new HashSet<>();
for (SignatureAlgorithm signatureAlgorithm : this.signatureAlgorithms) {
JWSAlgorithm jwsAlgorithm = JWSAlgorithm.parse(signatureAlgorithm.getName());
@ -361,7 +361,6 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
}
return new JWSVerificationKeySelector<>(jwsAlgorithms, jwkSource);
}
}
Converter<JWT, Mono<JWTClaimsSet>> processor() {
JWKSecurityContextJWKSet jwkSource = new JWKSecurityContextJWKSet();
@ -370,16 +369,14 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
jwtProcessor.setJWSKeySelector(jwsKeySelector);
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
});
this.jwtProcessorCustomizer.accept(jwtProcessor);
ReactiveRemoteJWKSource source = new ReactiveRemoteJWKSource(this.jwkSetUri);
source.setWebClient(this.webClient);
Function<JWSAlgorithm, Boolean> expectedJwsAlgorithms = getExpectedJwsAlgorithms(jwsKeySelector);
return (jwt) -> {
JWKSelector selector = createSelector(expectedJwsAlgorithms, jwt.getHeader());
return source.get(selector).onErrorMap((e) -> new IllegalStateException("Could not obtain the keys", e))
return source.get(selector)
.onErrorMap((ex) -> new IllegalStateException("Could not obtain the keys", ex))
.map((jwkList) -> createClaimsSet(jwtProcessor, jwt, new JWKSecurityContext(jwkList)));
};
}
@ -396,7 +393,6 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
if (!expectedJwsAlgorithms.apply(jwsHeader.getAlgorithm())) {
throw new BadJwtException("Unsupported algorithm of " + header.getAlgorithm());
}
return new JWKSelector(JWKMatcher.forJWSHeader(jwsHeader));
}
@ -463,22 +459,16 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
}
Converter<JWT, Mono<JWTClaimsSet>> processor() {
if (!JWSAlgorithm.Family.RSA.contains(this.jwsAlgorithm)) {
throw new IllegalStateException(
"The provided key is of type RSA; " + "however the signature algorithm is of some other type: "
Assert.state(JWSAlgorithm.Family.RSA.contains(this.jwsAlgorithm),
() -> "The provided key is of type RSA; however the signature algorithm is of some other type: "
+ this.jwsAlgorithm + ". Please indicate one of RS256, RS384, or RS512.");
}
JWSKeySelector<SecurityContext> jwsKeySelector = new SingleKeyJWSKeySelector<>(this.jwsAlgorithm, this.key);
DefaultJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
jwtProcessor.setJWSKeySelector(jwsKeySelector);
// Spring Security validates the claim set independent from Nimbus
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
});
this.jwtProcessorCustomizer.accept(jwtProcessor);
return (jwt) -> Mono.just(createClaimsSet(jwtProcessor, jwt, null));
}
@ -550,13 +540,10 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
this.secretKey);
DefaultJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
jwtProcessor.setJWSKeySelector(jwsKeySelector);
// Spring Security validates the claim set independent from Nimbus
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
});
this.jwtProcessorCustomizer.accept(jwtProcessor);
return (jwt) -> Mono.just(createClaimsSet(jwtProcessor, jwt, null));
}
@ -626,9 +613,7 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
jwtProcessor.setJWSKeySelector(jwsKeySelector);
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
});
this.jwtProcessorCustomizer.accept(jwtProcessor);
return (jwt) -> {
if (jwt instanceof SignedJWT) {
return this.jwkSource.apply((SignedJWT) jwt)

View File

@ -33,6 +33,9 @@ import org.springframework.util.Assert;
*/
public final class ReactiveJwtDecoders {
private ReactiveJwtDecoders() {
}
/**
* Creates a {@link ReactiveJwtDecoder} using the provided <a href=
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
@ -106,11 +109,7 @@ public final class ReactiveJwtDecoders {
NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder
.withJwkSetUri(configuration.get("jwks_uri").toString()).build();
jwtDecoder.setJwtValidator(jwtValidator);
return jwtDecoder;
}
private ReactiveJwtDecoders() {
}
}

View File

@ -63,29 +63,23 @@ class ReactiveRemoteJWKSource implements ReactiveJWKSource {
return Mono.defer(() -> {
// Run the selector on the JWK set
List<JWK> matches = jwkSelector.select(jwkSet);
if (!matches.isEmpty()) {
// Success
return Mono.just(matches);
}
// Refresh the JWK set if the sought key ID is not in the cached JWK set
// Looking for JWK with specific ID?
String soughtKeyID = getFirstSpecifiedKeyID(jwkSelector.getMatcher());
if (soughtKeyID == null) {
// No key ID specified, return no matches
return Mono.just(Collections.emptyList());
}
if (jwkSet.getKeyByKeyId(soughtKeyID) != null) {
// The key ID exists in the cached JWK set, matching
// failed for some other reason, return no matches
return Mono.just(Collections.emptyList());
}
return Mono.empty();
});
}
@ -114,13 +108,10 @@ class ReactiveRemoteJWKSource implements ReactiveJWKSource {
* @return The first key ID, {@code null} if none.
*/
protected static String getFirstSpecifiedKeyID(final JWKMatcher jwkMatcher) {
Set<String> keyIDs = jwkMatcher.getKeyIDs();
if (keyIDs == null || keyIDs.isEmpty()) {
return null;
}
for (String id : keyIDs) {
if (id != null) {
return id;