mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-05-04 05:01:06 +01:00
Merge branch '2.7.x'
This commit is contained in:
+16
@@ -19,6 +19,8 @@ package org.springframework.boot.autoconfigure.security.oauth2.resource;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
|
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
|
||||||
@@ -31,6 +33,7 @@ import org.springframework.util.StreamUtils;
|
|||||||
*
|
*
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @author Artsiom Yudovin
|
* @author Artsiom Yudovin
|
||||||
|
* @author Mushtaq Ahmed
|
||||||
* @since 2.1.0
|
* @since 2.1.0
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties(prefix = "spring.security.oauth2.resourceserver")
|
@ConfigurationProperties(prefix = "spring.security.oauth2.resourceserver")
|
||||||
@@ -71,6 +74,11 @@ public class OAuth2ResourceServerProperties {
|
|||||||
*/
|
*/
|
||||||
private Resource publicKeyLocation;
|
private Resource publicKeyLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifies the recipients that the JWT is intended for.
|
||||||
|
*/
|
||||||
|
private List<String> audiences = new ArrayList<>();
|
||||||
|
|
||||||
public String getJwkSetUri() {
|
public String getJwkSetUri() {
|
||||||
return this.jwkSetUri;
|
return this.jwkSetUri;
|
||||||
}
|
}
|
||||||
@@ -103,6 +111,14 @@ public class OAuth2ResourceServerProperties {
|
|||||||
this.publicKeyLocation = publicKeyLocation;
|
this.publicKeyLocation = publicKeyLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getAudiences() {
|
||||||
|
return this.audiences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAudiences(List<String> audiences) {
|
||||||
|
this.audiences = audiences;
|
||||||
|
}
|
||||||
|
|
||||||
public String readPublicKey() throws IOException {
|
public String readPublicKey() throws IOException {
|
||||||
String key = "spring.security.oauth2.resourceserver.public-key-location";
|
String key = "spring.security.oauth2.resourceserver.public-key-location";
|
||||||
Assert.notNull(this.publicKeyLocation, "PublicKeyLocation must not be null");
|
Assert.notNull(this.publicKeyLocation, "PublicKeyLocation must not be null");
|
||||||
|
|||||||
+37
-6
@@ -19,7 +19,11 @@ package org.springframework.boot.autoconfigure.security.oauth2.resource.reactive
|
|||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
import java.security.interfaces.RSAPublicKey;
|
import java.security.interfaces.RSAPublicKey;
|
||||||
import java.security.spec.X509EncodedKeySpec;
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
@@ -32,13 +36,19 @@ import org.springframework.context.annotation.Conditional;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||||
import org.springframework.security.config.web.server.ServerHttpSecurity.OAuth2ResourceServerSpec;
|
import org.springframework.security.config.web.server.ServerHttpSecurity.OAuth2ResourceServerSpec;
|
||||||
|
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
||||||
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
||||||
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtClaimNames;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtClaimValidator;
|
||||||
import org.springframework.security.oauth2.jwt.JwtValidators;
|
import org.springframework.security.oauth2.jwt.JwtValidators;
|
||||||
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
|
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
|
||||||
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
|
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
|
||||||
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders;
|
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders;
|
||||||
import org.springframework.security.oauth2.jwt.SupplierReactiveJwtDecoder;
|
import org.springframework.security.oauth2.jwt.SupplierReactiveJwtDecoder;
|
||||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures a {@link ReactiveJwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI
|
* Configures a {@link ReactiveJwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI
|
||||||
@@ -49,6 +59,7 @@ import org.springframework.security.web.server.SecurityWebFilterChain;
|
|||||||
* @author Artsiom Yudovin
|
* @author Artsiom Yudovin
|
||||||
* @author HaiTao Zhang
|
* @author HaiTao Zhang
|
||||||
* @author Anastasiia Losieva
|
* @author Anastasiia Losieva
|
||||||
|
* @author Mushtaq Ahmed
|
||||||
*/
|
*/
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
class ReactiveOAuth2ResourceServerJwkConfiguration {
|
class ReactiveOAuth2ResourceServerJwkConfiguration {
|
||||||
@@ -70,19 +81,34 @@ class ReactiveOAuth2ResourceServerJwkConfiguration {
|
|||||||
.withJwkSetUri(this.properties.getJwkSetUri())
|
.withJwkSetUri(this.properties.getJwkSetUri())
|
||||||
.jwsAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
|
.jwsAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
|
||||||
String issuerUri = this.properties.getIssuerUri();
|
String issuerUri = this.properties.getIssuerUri();
|
||||||
if (issuerUri != null) {
|
Supplier<OAuth2TokenValidator<Jwt>> defaultValidator = (issuerUri != null)
|
||||||
nimbusReactiveJwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuerUri));
|
? () -> JwtValidators.createDefaultWithIssuer(issuerUri) : JwtValidators::createDefault;
|
||||||
}
|
nimbusReactiveJwtDecoder.setJwtValidator(getValidators(defaultValidator));
|
||||||
return nimbusReactiveJwtDecoder;
|
return nimbusReactiveJwtDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OAuth2TokenValidator<Jwt> getValidators(Supplier<OAuth2TokenValidator<Jwt>> defaultValidator) {
|
||||||
|
OAuth2TokenValidator<Jwt> defaultValidators = defaultValidator.get();
|
||||||
|
List<String> audiences = this.properties.getAudiences();
|
||||||
|
if (CollectionUtils.isEmpty(audiences)) {
|
||||||
|
return defaultValidators;
|
||||||
|
}
|
||||||
|
List<OAuth2TokenValidator<Jwt>> validators = new ArrayList<>();
|
||||||
|
validators.add(defaultValidators);
|
||||||
|
validators.add(new JwtClaimValidator<List<String>>(JwtClaimNames.AUD,
|
||||||
|
(aud) -> aud != null && !Collections.disjoint(aud, audiences)));
|
||||||
|
return new DelegatingOAuth2TokenValidator<>(validators);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Conditional(KeyValueCondition.class)
|
@Conditional(KeyValueCondition.class)
|
||||||
NimbusReactiveJwtDecoder jwtDecoderByPublicKeyValue() throws Exception {
|
NimbusReactiveJwtDecoder jwtDecoderByPublicKeyValue() throws Exception {
|
||||||
RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
|
RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
|
||||||
.generatePublic(new X509EncodedKeySpec(getKeySpec(this.properties.readPublicKey())));
|
.generatePublic(new X509EncodedKeySpec(getKeySpec(this.properties.readPublicKey())));
|
||||||
return NimbusReactiveJwtDecoder.withPublicKey(publicKey)
|
NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder.withPublicKey(publicKey)
|
||||||
.signatureAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
|
.signatureAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
|
||||||
|
jwtDecoder.setJwtValidator(getValidators(JwtValidators::createDefault));
|
||||||
|
return jwtDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] getKeySpec(String keyValue) {
|
private byte[] getKeySpec(String keyValue) {
|
||||||
@@ -93,8 +119,13 @@ class ReactiveOAuth2ResourceServerJwkConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
@Conditional(IssuerUriCondition.class)
|
@Conditional(IssuerUriCondition.class)
|
||||||
SupplierReactiveJwtDecoder jwtDecoderByIssuerUri() {
|
SupplierReactiveJwtDecoder jwtDecoderByIssuerUri() {
|
||||||
return new SupplierReactiveJwtDecoder(
|
return new SupplierReactiveJwtDecoder(() -> {
|
||||||
() -> ReactiveJwtDecoders.fromIssuerLocation(this.properties.getIssuerUri()));
|
NimbusReactiveJwtDecoder jwtDecoder = (NimbusReactiveJwtDecoder) ReactiveJwtDecoders
|
||||||
|
.fromIssuerLocation(this.properties.getIssuerUri());
|
||||||
|
jwtDecoder.setJwtValidator(
|
||||||
|
getValidators(() -> JwtValidators.createDefaultWithIssuer(this.properties.getIssuerUri())));
|
||||||
|
return jwtDecoder;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-5
@@ -19,7 +19,11 @@ package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
|
|||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
import java.security.interfaces.RSAPublicKey;
|
import java.security.interfaces.RSAPublicKey;
|
||||||
import java.security.spec.X509EncodedKeySpec;
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
@@ -33,13 +37,19 @@ import org.springframework.context.annotation.Conditional;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
|
||||||
|
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
||||||
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
||||||
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtClaimNames;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtClaimValidator;
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoders;
|
import org.springframework.security.oauth2.jwt.JwtDecoders;
|
||||||
import org.springframework.security.oauth2.jwt.JwtValidators;
|
import org.springframework.security.oauth2.jwt.JwtValidators;
|
||||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||||
import org.springframework.security.oauth2.jwt.SupplierJwtDecoder;
|
import org.springframework.security.oauth2.jwt.SupplierJwtDecoder;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures a {@link JwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI or Public
|
* Configures a {@link JwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI or Public
|
||||||
@@ -49,6 +59,7 @@ import org.springframework.security.web.SecurityFilterChain;
|
|||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @author Artsiom Yudovin
|
* @author Artsiom Yudovin
|
||||||
* @author HaiTao Zhang
|
* @author HaiTao Zhang
|
||||||
|
* @author Mushtaq Ahmed
|
||||||
*/
|
*/
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
class OAuth2ResourceServerJwtConfiguration {
|
class OAuth2ResourceServerJwtConfiguration {
|
||||||
@@ -69,19 +80,34 @@ class OAuth2ResourceServerJwtConfiguration {
|
|||||||
NimbusJwtDecoder nimbusJwtDecoder = NimbusJwtDecoder.withJwkSetUri(this.properties.getJwkSetUri())
|
NimbusJwtDecoder nimbusJwtDecoder = NimbusJwtDecoder.withJwkSetUri(this.properties.getJwkSetUri())
|
||||||
.jwsAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
|
.jwsAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
|
||||||
String issuerUri = this.properties.getIssuerUri();
|
String issuerUri = this.properties.getIssuerUri();
|
||||||
if (issuerUri != null) {
|
Supplier<OAuth2TokenValidator<Jwt>> defaultValidator = (issuerUri != null)
|
||||||
nimbusJwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuerUri));
|
? () -> JwtValidators.createDefaultWithIssuer(issuerUri) : JwtValidators::createDefault;
|
||||||
}
|
nimbusJwtDecoder.setJwtValidator(getValidators(defaultValidator));
|
||||||
return nimbusJwtDecoder;
|
return nimbusJwtDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OAuth2TokenValidator<Jwt> getValidators(Supplier<OAuth2TokenValidator<Jwt>> defaultValidator) {
|
||||||
|
OAuth2TokenValidator<Jwt> defaultValidators = defaultValidator.get();
|
||||||
|
List<String> audiences = this.properties.getAudiences();
|
||||||
|
if (CollectionUtils.isEmpty(audiences)) {
|
||||||
|
return defaultValidators;
|
||||||
|
}
|
||||||
|
List<OAuth2TokenValidator<Jwt>> validators = new ArrayList<>();
|
||||||
|
validators.add(defaultValidators);
|
||||||
|
validators.add(new JwtClaimValidator<List<String>>(JwtClaimNames.AUD,
|
||||||
|
(aud) -> aud != null && !Collections.disjoint(aud, audiences)));
|
||||||
|
return new DelegatingOAuth2TokenValidator<>(validators);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Conditional(KeyValueCondition.class)
|
@Conditional(KeyValueCondition.class)
|
||||||
JwtDecoder jwtDecoderByPublicKeyValue() throws Exception {
|
JwtDecoder jwtDecoderByPublicKeyValue() throws Exception {
|
||||||
RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
|
RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
|
||||||
.generatePublic(new X509EncodedKeySpec(getKeySpec(this.properties.readPublicKey())));
|
.generatePublic(new X509EncodedKeySpec(getKeySpec(this.properties.readPublicKey())));
|
||||||
return NimbusJwtDecoder.withPublicKey(publicKey)
|
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey(publicKey)
|
||||||
.signatureAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
|
.signatureAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
|
||||||
|
jwtDecoder.setJwtValidator(getValidators(JwtValidators::createDefault));
|
||||||
|
return jwtDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] getKeySpec(String keyValue) {
|
private byte[] getKeySpec(String keyValue) {
|
||||||
@@ -92,7 +118,12 @@ class OAuth2ResourceServerJwtConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
@Conditional(IssuerUriCondition.class)
|
@Conditional(IssuerUriCondition.class)
|
||||||
SupplierJwtDecoder jwtDecoderByIssuerUri() {
|
SupplierJwtDecoder jwtDecoderByIssuerUri() {
|
||||||
return new SupplierJwtDecoder(() -> JwtDecoders.fromIssuerLocation(this.properties.getIssuerUri()));
|
return new SupplierJwtDecoder(() -> {
|
||||||
|
String issuerUri = this.properties.getIssuerUri();
|
||||||
|
NimbusJwtDecoder jwtDecoder = JwtDecoders.fromIssuerLocation(issuerUri);
|
||||||
|
jwtDecoder.setJwtValidator(getValidators(() -> JwtValidators.createDefaultWithIssuer(issuerUri)));
|
||||||
|
return jwtDecoder;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+157
@@ -17,7 +17,10 @@
|
|||||||
package org.springframework.boot.autoconfigure.security.oauth2.resource.reactive;
|
package org.springframework.boot.autoconfigure.security.oauth2.resource.reactive;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -51,7 +54,9 @@ import org.springframework.security.core.userdetails.MapReactiveUserDetailsServi
|
|||||||
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
|
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
|
||||||
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
||||||
import org.springframework.security.oauth2.jwt.Jwt;
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtClaimValidator;
|
||||||
import org.springframework.security.oauth2.jwt.JwtIssuerValidator;
|
import org.springframework.security.oauth2.jwt.JwtIssuerValidator;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
|
||||||
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
|
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
|
||||||
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
|
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
|
||||||
import org.springframework.security.oauth2.jwt.SupplierReactiveJwtDecoder;
|
import org.springframework.security.oauth2.jwt.SupplierReactiveJwtDecoder;
|
||||||
@@ -75,6 +80,7 @@ import static org.mockito.Mockito.mock;
|
|||||||
* @author Artsiom Yudovin
|
* @author Artsiom Yudovin
|
||||||
* @author HaiTao Zhang
|
* @author HaiTao Zhang
|
||||||
* @author Anastasiia Losieva
|
* @author Anastasiia Losieva
|
||||||
|
* @author Mushtaq Ahmed
|
||||||
*/
|
*/
|
||||||
class ReactiveOAuth2ResourceServerAutoConfigurationTests {
|
class ReactiveOAuth2ResourceServerAutoConfigurationTests {
|
||||||
|
|
||||||
@@ -390,6 +396,144 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
void autoConfigurationShouldNotConfigureIssuerUriAndAudienceJwtValidatorIfPropertyNotConfigured() 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")
|
||||||
|
.run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(ReactiveJwtDecoder.class);
|
||||||
|
ReactiveJwtDecoder reactiveJwtDecoder = context.getBean(ReactiveJwtDecoder.class);
|
||||||
|
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils
|
||||||
|
.getField(reactiveJwtDecoder, "jwtValidator");
|
||||||
|
Collection<OAuth2TokenValidator<Jwt>> tokenValidators = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
|
||||||
|
.getField(jwtValidator, "tokenValidators");
|
||||||
|
assertThat(tokenValidators).hasExactlyElementsOfTypes(JwtTimestampValidator.class);
|
||||||
|
assertThat(tokenValidators).doesNotHaveAnyElementsOfTypes(JwtClaimValidator.class);
|
||||||
|
assertThat(tokenValidators).doesNotHaveAnyElementsOfTypes(JwtIssuerValidator.class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
void autoConfigurationShouldConfigureIssuerAndAudienceJwtValidatorIfPropertyProvided() 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);
|
||||||
|
String issuerUri = "http://" + this.server.getHostName() + ":" + this.server.getPort() + "/" + path;
|
||||||
|
this.contextRunner.withPropertyValues(
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com",
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.issuer-uri=" + issuerUri,
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com")
|
||||||
|
.run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(ReactiveJwtDecoder.class);
|
||||||
|
ReactiveJwtDecoder reactiveJwtDecoder = context.getBean(ReactiveJwtDecoder.class);
|
||||||
|
validate(issuerUri, reactiveJwtDecoder);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void validate(String issuerUri, ReactiveJwtDecoder jwtDecoder) throws MalformedURLException {
|
||||||
|
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils
|
||||||
|
.getField(jwtDecoder, "jwtValidator");
|
||||||
|
Jwt.Builder builder = jwt().claim("aud", Collections.singletonList("https://test-audience.com"));
|
||||||
|
if (issuerUri != null) {
|
||||||
|
builder.claim("iss", new URL(issuerUri));
|
||||||
|
}
|
||||||
|
Jwt jwt = builder.build();
|
||||||
|
assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse();
|
||||||
|
Collection<OAuth2TokenValidator<Jwt>> delegates = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
|
||||||
|
.getField(jwtValidator, "tokenValidators");
|
||||||
|
validateDelegates(issuerUri, delegates);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void validateDelegates(String issuerUri, Collection<OAuth2TokenValidator<Jwt>> delegates) {
|
||||||
|
assertThat(delegates).hasAtLeastOneElementOfType(JwtClaimValidator.class);
|
||||||
|
OAuth2TokenValidator<Jwt> delegatingValidator = delegates.stream()
|
||||||
|
.filter((v) -> v instanceof DelegatingOAuth2TokenValidator).findFirst().get();
|
||||||
|
Collection<OAuth2TokenValidator<Jwt>> nestedDelegates = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
|
||||||
|
.getField(delegatingValidator, "tokenValidators");
|
||||||
|
if (issuerUri != null) {
|
||||||
|
assertThat(nestedDelegates).hasAtLeastOneElementOfType(JwtIssuerValidator.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
void autoConfigurationShouldConfigureAudienceValidatorIfPropertyProvidedAndIssuerUri() 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);
|
||||||
|
String issuerUri = "http://" + this.server.getHostName() + ":" + this.server.getPort() + "/" + path;
|
||||||
|
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=" + issuerUri,
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com")
|
||||||
|
.run((context) -> {
|
||||||
|
SupplierReactiveJwtDecoder supplierJwtDecoderBean = context
|
||||||
|
.getBean(SupplierReactiveJwtDecoder.class);
|
||||||
|
Mono<ReactiveJwtDecoder> jwtDecoderSupplier = (Mono<ReactiveJwtDecoder>) ReflectionTestUtils
|
||||||
|
.getField(supplierJwtDecoderBean, "jwtDecoderMono");
|
||||||
|
ReactiveJwtDecoder jwtDecoder = jwtDecoderSupplier.block();
|
||||||
|
validate(issuerUri, jwtDecoder);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
void autoConfigurationShouldConfigureAudienceValidatorIfPropertyProvidedAndPublicKey() 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.public-key-location=classpath:public-key-location",
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com")
|
||||||
|
.run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(ReactiveJwtDecoder.class);
|
||||||
|
ReactiveJwtDecoder jwtDecoder = context.getBean(ReactiveJwtDecoder.class);
|
||||||
|
validate(null, jwtDecoder);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
void audienceValidatorWhenAudienceInvalid() 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);
|
||||||
|
String issuerUri = "http://" + this.server.getHostName() + ":" + this.server.getPort() + "/" + path;
|
||||||
|
this.contextRunner.withPropertyValues(
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com",
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.issuer-uri=" + issuerUri,
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com")
|
||||||
|
.run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(ReactiveJwtDecoder.class);
|
||||||
|
ReactiveJwtDecoder jwtDecoder = context.getBean(ReactiveJwtDecoder.class);
|
||||||
|
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils
|
||||||
|
.getField(jwtDecoder, "jwtValidator");
|
||||||
|
Jwt jwt = jwt().claim("iss", new URL(issuerUri))
|
||||||
|
.claim("aud", Collections.singletonList("https://other-audience.com")).build();
|
||||||
|
assertThat(jwtValidator.validate(jwt).hasErrors()).isTrue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void assertFilterConfiguredWithJwtAuthenticationManager(AssertableReactiveWebApplicationContext context) {
|
private void assertFilterConfiguredWithJwtAuthenticationManager(AssertableReactiveWebApplicationContext context) {
|
||||||
MatcherSecurityWebFilterChain filterChain = (MatcherSecurityWebFilterChain) context
|
MatcherSecurityWebFilterChain filterChain = (MatcherSecurityWebFilterChain) context
|
||||||
.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||||
@@ -458,6 +602,19 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Jwt.Builder jwt() {
|
||||||
|
// @formatter:off
|
||||||
|
return Jwt.withTokenValue("token")
|
||||||
|
.header("alg", "none")
|
||||||
|
.expiresAt(Instant.MAX)
|
||||||
|
.issuedAt(Instant.MIN)
|
||||||
|
.issuer("https://issuer.example.org")
|
||||||
|
.jti("jti")
|
||||||
|
.notBefore(Instant.MIN)
|
||||||
|
.subject("mock-test-subject");
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
@EnableWebFluxSecurity
|
@EnableWebFluxSecurity
|
||||||
static class TestConfig {
|
static class TestConfig {
|
||||||
|
|
||||||
|
|||||||
+156
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
|
package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -47,8 +50,10 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
|||||||
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
|
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
|
||||||
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
||||||
import org.springframework.security.oauth2.jwt.Jwt;
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtClaimValidator;
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
import org.springframework.security.oauth2.jwt.JwtIssuerValidator;
|
import org.springframework.security.oauth2.jwt.JwtIssuerValidator;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
|
||||||
import org.springframework.security.oauth2.jwt.SupplierJwtDecoder;
|
import org.springframework.security.oauth2.jwt.SupplierJwtDecoder;
|
||||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
|
||||||
@@ -67,6 +72,7 @@ import static org.mockito.Mockito.mock;
|
|||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @author Artsiom Yudovin
|
* @author Artsiom Yudovin
|
||||||
* @author HaiTao Zhang
|
* @author HaiTao Zhang
|
||||||
|
* @author Mushtaq Ahmed
|
||||||
*/
|
*/
|
||||||
class OAuth2ResourceServerAutoConfigurationTests {
|
class OAuth2ResourceServerAutoConfigurationTests {
|
||||||
|
|
||||||
@@ -403,6 +409,143 @@ class OAuth2ResourceServerAutoConfigurationTests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
void autoConfigurationShouldNotConfigureIssuerUriAndAudienceJwtValidatorIfPropertyNotConfigured() 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")
|
||||||
|
.run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(JwtDecoder.class);
|
||||||
|
JwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);
|
||||||
|
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils
|
||||||
|
.getField(jwtDecoder, "jwtValidator");
|
||||||
|
Collection<OAuth2TokenValidator<Jwt>> tokenValidators = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
|
||||||
|
.getField(jwtValidator, "tokenValidators");
|
||||||
|
assertThat(tokenValidators).hasExactlyElementsOfTypes(JwtTimestampValidator.class);
|
||||||
|
assertThat(tokenValidators).doesNotHaveAnyElementsOfTypes(JwtClaimValidator.class);
|
||||||
|
assertThat(tokenValidators).doesNotHaveAnyElementsOfTypes(JwtIssuerValidator.class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
void autoConfigurationShouldConfigureAudienceAndIssuerJwtValidatorIfPropertyProvided() 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);
|
||||||
|
String issuerUri = "http://" + this.server.getHostName() + ":" + this.server.getPort() + "/" + path;
|
||||||
|
this.contextRunner.withPropertyValues(
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com",
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.issuer-uri=" + issuerUri,
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com")
|
||||||
|
.run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(JwtDecoder.class);
|
||||||
|
JwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);
|
||||||
|
validate(issuerUri, jwtDecoder);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
void autoConfigurationShouldConfigureAudienceValidatorIfPropertyProvidedAndIssuerUri() 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);
|
||||||
|
String issuerUri = "http://" + this.server.getHostName() + ":" + this.server.getPort() + "/" + path;
|
||||||
|
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=" + issuerUri,
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com")
|
||||||
|
.run((context) -> {
|
||||||
|
SupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);
|
||||||
|
Supplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils
|
||||||
|
.getField(supplierJwtDecoderBean, "jwtDecoderSupplier");
|
||||||
|
JwtDecoder jwtDecoder = jwtDecoderSupplier.get();
|
||||||
|
validate(issuerUri, jwtDecoder);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void validate(String issuerUri, JwtDecoder jwtDecoder) throws MalformedURLException {
|
||||||
|
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils
|
||||||
|
.getField(jwtDecoder, "jwtValidator");
|
||||||
|
Jwt.Builder builder = jwt().claim("aud", Collections.singletonList("https://test-audience.com"));
|
||||||
|
if (issuerUri != null) {
|
||||||
|
builder.claim("iss", new URL(issuerUri));
|
||||||
|
}
|
||||||
|
Jwt jwt = builder.build();
|
||||||
|
assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse();
|
||||||
|
Collection<OAuth2TokenValidator<Jwt>> delegates = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
|
||||||
|
.getField(jwtValidator, "tokenValidators");
|
||||||
|
validateDelegates(issuerUri, delegates);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void validateDelegates(String issuerUri, Collection<OAuth2TokenValidator<Jwt>> delegates) {
|
||||||
|
assertThat(delegates).hasAtLeastOneElementOfType(JwtClaimValidator.class);
|
||||||
|
OAuth2TokenValidator<Jwt> delegatingValidator = delegates.stream()
|
||||||
|
.filter((v) -> v instanceof DelegatingOAuth2TokenValidator).findFirst().get();
|
||||||
|
Collection<OAuth2TokenValidator<Jwt>> nestedDelegates = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
|
||||||
|
.getField(delegatingValidator, "tokenValidators");
|
||||||
|
if (issuerUri != null) {
|
||||||
|
assertThat(nestedDelegates).hasAtLeastOneElementOfType(JwtIssuerValidator.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
void autoConfigurationShouldConfigureAudienceValidatorIfPropertyProvidedAndPublicKey() 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.public-key-location=classpath:public-key-location",
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,http://test-audience1.com")
|
||||||
|
.run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(JwtDecoder.class);
|
||||||
|
JwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);
|
||||||
|
validate(null, jwtDecoder);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
void audienceValidatorWhenAudienceInvalid() 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);
|
||||||
|
String issuerUri = "http://" + this.server.getHostName() + ":" + this.server.getPort() + "/" + path;
|
||||||
|
this.contextRunner.withPropertyValues(
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com",
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.issuer-uri=" + issuerUri,
|
||||||
|
"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com")
|
||||||
|
.run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(JwtDecoder.class);
|
||||||
|
JwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);
|
||||||
|
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils
|
||||||
|
.getField(jwtDecoder, "jwtValidator");
|
||||||
|
Jwt jwt = jwt().claim("iss", new URL(issuerUri))
|
||||||
|
.claim("aud", Collections.singletonList("https://other-audience.com")).build();
|
||||||
|
assertThat(jwtValidator.validate(jwt).hasErrors()).isTrue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void jwtSecurityConfigurerBacksOffWhenSecurityFilterChainBeanIsPresent() {
|
void jwtSecurityConfigurerBacksOffWhenSecurityFilterChainBeanIsPresent() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
@@ -471,6 +614,19 @@ class OAuth2ResourceServerAutoConfigurationTests {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Jwt.Builder jwt() {
|
||||||
|
// @formatter:off
|
||||||
|
return Jwt.withTokenValue("token")
|
||||||
|
.header("alg", "none")
|
||||||
|
.expiresAt(Instant.MAX)
|
||||||
|
.issuedAt(Instant.MIN)
|
||||||
|
.issuer("https://issuer.example.org")
|
||||||
|
.jti("jti")
|
||||||
|
.notBefore(Instant.MIN)
|
||||||
|
.subject("mock-test-subject");
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
static class TestConfig {
|
static class TestConfig {
|
||||||
|
|||||||
Reference in New Issue
Block a user