Merge pull request #17952 from htztomic
* pr/17952: Polish "Configure Issuer Validator for Resource Server" Configure Issuer Validator for Resource Server Closes gh-17952
This commit is contained in:
@@ -22,6 +22,7 @@ import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2Res
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.oauth2.jwt.JwtValidators;
|
||||
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders;
|
||||
@@ -31,6 +32,7 @@ import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders;
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Artsiom Yudovin
|
||||
* @author HaiTao Zhang
|
||||
*/
|
||||
@Configuration
|
||||
class ReactiveOAuth2ResourceServerJwkConfiguration {
|
||||
@@ -45,7 +47,13 @@ class ReactiveOAuth2ResourceServerJwkConfiguration {
|
||||
@ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri")
|
||||
@ConditionalOnMissingBean
|
||||
public ReactiveJwtDecoder jwtDecoder() {
|
||||
return new NimbusReactiveJwtDecoder(this.properties.getJwt().getJwkSetUri());
|
||||
NimbusReactiveJwtDecoder nimbusReactiveJwtDecoder = new NimbusReactiveJwtDecoder(
|
||||
this.properties.getJwt().getJwkSetUri());
|
||||
String issuerUri = this.properties.getJwt().getIssuerUri();
|
||||
if (issuerUri != null) {
|
||||
nimbusReactiveJwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuerUri));
|
||||
}
|
||||
return nimbusReactiveJwtDecoder;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoders;
|
||||
import org.springframework.security.oauth2.jwt.JwtValidators;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
|
||||
|
||||
/**
|
||||
@@ -32,6 +33,7 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Artsiom Yudovin
|
||||
* @author HaiTao Zhang
|
||||
*/
|
||||
@Configuration
|
||||
class OAuth2ResourceServerJwtConfiguration {
|
||||
@@ -46,7 +48,13 @@ class OAuth2ResourceServerJwtConfiguration {
|
||||
@ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri")
|
||||
@ConditionalOnMissingBean
|
||||
public JwtDecoder jwtDecoderByJwkKeySetUri() {
|
||||
return new NimbusJwtDecoderJwkSupport(this.properties.getJwt().getJwkSetUri());
|
||||
NimbusJwtDecoderJwkSupport nimbusJwtDecoder = new NimbusJwtDecoderJwkSupport(
|
||||
this.properties.getJwt().getJwkSetUri());
|
||||
String issuerUri = this.properties.getJwt().getIssuerUri();
|
||||
if (issuerUri != null) {
|
||||
nimbusJwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuerUri));
|
||||
}
|
||||
return nimbusJwtDecoder;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource.reactive;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -42,6 +43,10 @@ import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
|
||||
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.jwt.JwtIssuerValidator;
|
||||
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
||||
@@ -60,6 +65,7 @@ import static org.mockito.Mockito.mock;
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Artsiom Yudovin
|
||||
* @author HaiTao Zhang
|
||||
*/
|
||||
public class ReactiveOAuth2ResourceServerAutoConfigurationTests {
|
||||
|
||||
@@ -163,6 +169,30 @@ public class ReactiveOAuth2ResourceServerAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void autoConfigurationShouldConfigureResourceServerUsingJwkSetUriAndIssuerUri() throws Exception {
|
||||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
String path = "test";
|
||||
String issuer = this.server.url(path).toString();
|
||||
String cleanIssuerPath = cleanIssuerPath(issuer);
|
||||
setupMockResponse(cleanIssuerPath);
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com",
|
||||
"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" + this.server.getHostName() + ":"
|
||||
+ this.server.getPort() + "/" + path)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ReactiveJwtDecoder.class);
|
||||
ReactiveJwtDecoder reactiveJwtDecoder = context.getBean(ReactiveJwtDecoder.class);
|
||||
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator) ReflectionTestUtils
|
||||
.getField(reactiveJwtDecoder, "jwtValidator");
|
||||
Collection<OAuth2TokenValidator<Jwt>> tokenValidators = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
|
||||
.getField(jwtValidator, "tokenValidators");
|
||||
assertThat(tokenValidators.stream()).hasAtLeastOneElementOfType(JwtIssuerValidator.class);
|
||||
});
|
||||
}
|
||||
|
||||
private void assertFilterConfiguredWithJwtAuthenticationManager(AssertableReactiveWebApplicationContext context) {
|
||||
MatcherSecurityWebFilterChain filterChain = (MatcherSecurityWebFilterChain) context
|
||||
.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -40,12 +41,17 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtIssuerValidator;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -55,6 +61,7 @@ import static org.mockito.Mockito.mock;
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Artsiom Yudovin
|
||||
* @author HaiTao Zhang
|
||||
*/
|
||||
public class OAuth2ResourceServerAutoConfigurationTests {
|
||||
|
||||
@@ -148,6 +155,30 @@ public class OAuth2ResourceServerAutoConfigurationTests {
|
||||
.run((context) -> assertThat(getBearerTokenFilter(context)).isNull());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void autoConfigurationShouldConfigureResourceServerUsingJwkSetUriAndIssuerUri() throws Exception {
|
||||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
String path = "test";
|
||||
String issuer = this.server.url(path).toString();
|
||||
String cleanIssuerPath = cleanIssuerPath(issuer);
|
||||
setupMockResponse(cleanIssuerPath);
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com",
|
||||
"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" + this.server.getHostName() + ":"
|
||||
+ this.server.getPort() + "/" + path)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(JwtDecoder.class);
|
||||
JwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);
|
||||
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator) ReflectionTestUtils
|
||||
.getField(jwtDecoder, "jwtValidator");
|
||||
Collection<OAuth2TokenValidator<Jwt>> tokenValidators = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
|
||||
.getField(jwtValidator, "tokenValidators");
|
||||
assertThat(tokenValidators.stream()).hasAtLeastOneElementOfType(JwtIssuerValidator.class);
|
||||
});
|
||||
}
|
||||
|
||||
private Filter getBearerTokenFilter(AssertableWebApplicationContext context) {
|
||||
FilterChainProxy filterChain = (FilterChainProxy) context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
List<SecurityFilterChain> filterChains = filterChain.getFilterChains();
|
||||
|
||||
Reference in New Issue
Block a user