Skip to content

Commit 73a7b77

Browse files
committed
Polish "Reject unknown JWS algorithms configured on NimbusJwtDecoder"
See gh-50118
1 parent 3f32906 commit 73a7b77

4 files changed

Lines changed: 20 additions & 12 deletions

File tree

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@
5454
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
5555
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
5656
import org.springframework.security.web.SecurityFilterChain;
57+
import org.springframework.util.Assert;
5758
import org.springframework.util.CollectionUtils;
59+
import org.springframework.util.StringUtils;
5860

5961
import static org.springframework.security.config.Customizer.withDefaults;
6062

@@ -140,7 +142,7 @@ JwtDecoder jwtDecoderByPublicKeyValue() throws Exception {
140142
RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
141143
.generatePublic(new X509EncodedKeySpec(getKeySpec(this.properties.readPublicKey())));
142144
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey(publicKey)
143-
.signatureAlgorithm(SignatureAlgorithm.from(exactlyOneAlgorithm()))
145+
.signatureAlgorithm(exactlyOneAlgorithm())
144146
.build();
145147
jwtDecoder.setJwtValidator(getValidators(JwtValidators.createDefault()));
146148
return jwtDecoder;
@@ -151,15 +153,18 @@ private byte[] getKeySpec(String keyValue) {
151153
return Base64.getMimeDecoder().decode(keyValue);
152154
}
153155

154-
private String exactlyOneAlgorithm() {
156+
private SignatureAlgorithm exactlyOneAlgorithm() {
155157
List<String> algorithms = this.properties.getJwsAlgorithms();
156-
int count = (algorithms != null) ? algorithms.size() : 0;
157-
if (count != 1) {
158-
throw new IllegalStateException(
159-
"Creating a JWT decoder using a public key requires exactly one JWS algorithm but " + count
160-
+ " were configured");
158+
Assert.state(algorithms != null && algorithms.size() == 1,
159+
() -> "Creating a JWT decoder using a public key requires exactly one JWS algorithm but "
160+
+ algorithms.size() + " were configured");
161+
SignatureAlgorithm algorithm = SignatureAlgorithm.from(algorithms.get(0));
162+
if (algorithm == null) {
163+
throw new InvalidConfigurationPropertyValueException(
164+
"spring.security.oauth2.resourceserver.jwt.jws-algorithms",
165+
StringUtils.collectionToCommaDelimitedString(algorithms), "Unknown algorithm");
161166
}
162-
return algorithms.get(0);
167+
return algorithm;
163168
}
164169

165170
@Bean

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/JwtConverterCustomizationsArgumentsProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext extensionCo
7070
.claim(customPrincipalClaim, customPrincipalValue);
7171
Jwt noAuthoritiesCustomizationsJwt = jwtBuilder.claim("scp", jwtScopes[0] + " " + jwtScopes[1]).build();
7272
Jwt customAuthoritiesDelimiterJwt = jwtBuilder.claim("scp", jwtScopes[0] + "~" + jwtScopes[1]).build();
73-
Jwt customAuthoritiesClaimJwt = jwtBuilder.claim("scp", null)
73+
Jwt customAuthoritiesClaimJwt = jwtBuilder.claim("scp", "value")
7474
.claim(customAuthoritiesClaim, jwtScopes[0] + " " + jwtScopes[1])
7575
.build();
76-
Jwt customAuthoritiesClaimAndDelimiterJwt = jwtBuilder.claim("scp", null)
76+
Jwt customAuthoritiesClaimAndDelimiterJwt = jwtBuilder.claim("scp", "value")
7777
.claim(customAuthoritiesClaim, jwtScopes[0] + "~" + jwtScopes[1])
7878
.build();
7979
String[] customPrefixAuthorities = { customPrefix + jwtScopes[0], customPrefix + jwtScopes[1] };

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import org.springframework.boot.autoconfigure.AutoConfigurations;
5050
import org.springframework.boot.autoconfigure.security.oauth2.resource.JwtConverterCustomizationsArgumentsProvider;
5151
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
52+
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
5253
import org.springframework.boot.test.context.FilteredClassLoader;
5354
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
5455
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
@@ -333,7 +334,8 @@ void autoConfigurationShouldFailIfAlgorithmIsInvalid() {
333334
"spring.security.oauth2.resourceserver.jwt.jws-algorithms=NOT_VALID")
334335
.run((context) -> assertThat(context).hasFailed()
335336
.getFailure()
336-
.hasMessageContaining("signatureAlgorithm cannot be null"));
337+
.hasMessageContaining("Unknown algorithm")
338+
.hasRootCauseExactlyInstanceOf(InvalidConfigurationPropertyValueException.class));
337339
}
338340

339341
@Test

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/server/servlet/OAuth2AuthorizationServerJwtAutoConfigurationTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
3232

3333
import static org.assertj.core.api.Assertions.assertThat;
34+
import static org.mockito.Mockito.mock;
3435

3536
/**
3637
* Tests for {@link OAuth2AuthorizationServerJwtAutoConfiguration}.
@@ -96,7 +97,7 @@ static class TestJwtDecoderConfiguration {
9697

9798
@Bean
9899
JwtDecoder jwtDecoder() {
99-
return (token) -> null;
100+
return mock(JwtDecoder.class);
100101
}
101102

102103
}

0 commit comments

Comments
 (0)