diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java index 9f7a052cb21b..1c55f23b1fdd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java @@ -19,6 +19,7 @@ import java.security.interfaces.RSAPublicKey; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; +import java.util.Optional; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -37,6 +38,7 @@ import org.springframework.security.oauth2.jwt.JwtDecoders; import org.springframework.security.oauth2.jwt.JwtValidators; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; +import org.springframework.web.client.RestTemplate; /** * Configures a {@link JwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI or Public @@ -63,9 +65,14 @@ static class JwtDecoderConfiguration { @Bean @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri") - JwtDecoder jwtDecoderByJwkKeySetUri() { - NimbusJwtDecoder nimbusJwtDecoder = NimbusJwtDecoder.withJwkSetUri(this.properties.getJwkSetUri()) - .jwsAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build(); + JwtDecoder jwtDecoderByJwkKeySetUri(Optional configuredRestTemplate) { + NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder jwtDecoderBuilder = NimbusJwtDecoder + .withJwkSetUri(this.properties.getJwkSetUri()) + .jwsAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())); + + configuredRestTemplate.ifPresent(jwtDecoderBuilder::restOperations); + NimbusJwtDecoder nimbusJwtDecoder = jwtDecoderBuilder.build(); + String issuerUri = this.properties.getIssuerUri(); if (issuerUri != null) { nimbusJwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuerUri)); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java index 66251e6400fa..5a28a6fd82e2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java @@ -54,6 +54,7 @@ import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.client.RestTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -90,6 +91,23 @@ void autoConfigurationShouldConfigureResourceServer() { }); } + @Test + void autoConfigurationShouldUseApplicationsRestTemplate() { + this.contextRunner + .withPropertyValues("spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com") + .withUserConfiguration(RestTemplateConfig.class).run((context) -> { + assertThat(context).hasSingleBean(JwtDecoder.class); + JwtDecoder jwtDecoder = context.getBean(JwtDecoder.class); + Object processor = ReflectionTestUtils.getField(jwtDecoder, "jwtProcessor"); + Object keySelector = ReflectionTestUtils.getField(processor, "jwsKeySelector"); + Object jwkSource = ReflectionTestUtils.getField(keySelector, "jwkSource"); + Object jwkSetRetriever = ReflectionTestUtils.getField(jwkSource, "jwkSetRetriever"); + Object restOperations = ReflectionTestUtils.getField(jwkSetRetriever, "restOperations"); + assertThat(restOperations).isNotNull(); + assertThat(restOperations).isEqualTo(RestTemplateConfig.configuredRestTemplate); + }); + } + @Test void autoConfigurationShouldMatchDefaultJwsAlgorithm() { this.contextRunner @@ -424,6 +442,19 @@ JwtDecoder decoder() { } + @Configuration(proxyBeanMethods = false) + @EnableWebSecurity + static class RestTemplateConfig { + + private static RestTemplate configuredRestTemplate = new RestTemplate(); + + @Bean + RestTemplate restTemplate() { + return configuredRestTemplate; + } + + } + @Configuration(proxyBeanMethods = false) @EnableWebSecurity static class OpaqueTokenIntrospectorConfig {