Polish "Reject unknown JWS algorithms configured on NimbusJwtDecoder"

See gh-50118
This commit is contained in:
Stéphane Nicoll
2026-04-27 10:19:00 +02:00
parent 3f32906b05
commit 73a7b7727d
4 changed files with 20 additions and 12 deletions
@@ -54,7 +54,9 @@ import org.springframework.security.oauth2.jwt.SupplierJwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import static org.springframework.security.config.Customizer.withDefaults;
@@ -140,7 +142,7 @@ class OAuth2ResourceServerJwtConfiguration {
RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(getKeySpec(this.properties.readPublicKey())));
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey(publicKey)
.signatureAlgorithm(SignatureAlgorithm.from(exactlyOneAlgorithm()))
.signatureAlgorithm(exactlyOneAlgorithm())
.build();
jwtDecoder.setJwtValidator(getValidators(JwtValidators.createDefault()));
return jwtDecoder;
@@ -151,15 +153,18 @@ class OAuth2ResourceServerJwtConfiguration {
return Base64.getMimeDecoder().decode(keyValue);
}
private String exactlyOneAlgorithm() {
private SignatureAlgorithm exactlyOneAlgorithm() {
List<String> algorithms = this.properties.getJwsAlgorithms();
int count = (algorithms != null) ? algorithms.size() : 0;
if (count != 1) {
throw new IllegalStateException(
"Creating a JWT decoder using a public key requires exactly one JWS algorithm but " + count
+ " were configured");
Assert.state(algorithms != null && algorithms.size() == 1,
() -> "Creating a JWT decoder using a public key requires exactly one JWS algorithm but "
+ algorithms.size() + " were configured");
SignatureAlgorithm algorithm = SignatureAlgorithm.from(algorithms.get(0));
if (algorithm == null) {
throw new InvalidConfigurationPropertyValueException(
"spring.security.oauth2.resourceserver.jwt.jws-algorithms",
StringUtils.collectionToCommaDelimitedString(algorithms), "Unknown algorithm");
}
return algorithms.get(0);
return algorithm;
}
@Bean
@@ -70,10 +70,10 @@ public final class JwtConverterCustomizationsArgumentsProvider implements Argume
.claim(customPrincipalClaim, customPrincipalValue);
Jwt noAuthoritiesCustomizationsJwt = jwtBuilder.claim("scp", jwtScopes[0] + " " + jwtScopes[1]).build();
Jwt customAuthoritiesDelimiterJwt = jwtBuilder.claim("scp", jwtScopes[0] + "~" + jwtScopes[1]).build();
Jwt customAuthoritiesClaimJwt = jwtBuilder.claim("scp", null)
Jwt customAuthoritiesClaimJwt = jwtBuilder.claim("scp", "value")
.claim(customAuthoritiesClaim, jwtScopes[0] + " " + jwtScopes[1])
.build();
Jwt customAuthoritiesClaimAndDelimiterJwt = jwtBuilder.claim("scp", null)
Jwt customAuthoritiesClaimAndDelimiterJwt = jwtBuilder.claim("scp", "value")
.claim(customAuthoritiesClaim, jwtScopes[0] + "~" + jwtScopes[1])
.build();
String[] customPrefixAuthorities = { customPrefix + jwtScopes[0], customPrefix + jwtScopes[1] };
@@ -49,6 +49,7 @@ import org.mockito.InOrder;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.security.oauth2.resource.JwtConverterCustomizationsArgumentsProvider;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
@@ -333,7 +334,8 @@ class OAuth2ResourceServerAutoConfigurationTests {
"spring.security.oauth2.resourceserver.jwt.jws-algorithms=NOT_VALID")
.run((context) -> assertThat(context).hasFailed()
.getFailure()
.hasMessageContaining("signatureAlgorithm cannot be null"));
.hasMessageContaining("Unknown algorithm")
.hasRootCauseExactlyInstanceOf(InvalidConfigurationPropertyValueException.class));
}
@Test
@@ -31,6 +31,7 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link OAuth2AuthorizationServerJwtAutoConfiguration}.
@@ -96,7 +97,7 @@ class OAuth2AuthorizationServerJwtAutoConfigurationTests {
@Bean
JwtDecoder jwtDecoder() {
return (token) -> null;
return mock(JwtDecoder.class);
}
}