Polish "Auto-configure a JwtAuthenticationConverter"
The JwtConverter bean is only supplied, if one of the following properties is there: * spring.security.oauth2.resourceserver.jwt.authority-prefix * spring.security.oauth2.resourceserver.jwt.principal-claim-name * spring.security.oauth2.resourceserver.jwt.authorities-claim-name See gh-38105
This commit is contained in:
@@ -26,6 +26,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -168,6 +169,7 @@ class ReactiveOAuth2ResourceServerJwkConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(ReactiveJwtAuthenticationConverter.class)
|
||||
@Conditional(JwtConverterPropertiesCondition.class)
|
||||
static class JwtConverterConfiguration {
|
||||
|
||||
private final OAuth2ResourceServerProperties.Jwt properties;
|
||||
@@ -212,4 +214,27 @@ class ReactiveOAuth2ResourceServerJwkConfiguration {
|
||||
|
||||
}
|
||||
|
||||
private static class JwtConverterPropertiesCondition extends AnyNestedCondition {
|
||||
|
||||
JwtConverterPropertiesCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "spring.security.oauth2.resourceserver.jwt", name = "authority-prefix")
|
||||
static class OnAuthorityPrefix {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "spring.security.oauth2.resourceserver.jwt", name = "principal-claim-name")
|
||||
static class OnPrincipalClaimName {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "spring.security.oauth2.resourceserver.jwt", name = "authorities-claim-name")
|
||||
static class OnAuthoritiesClaimName {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -179,6 +180,7 @@ class OAuth2ResourceServerJwtConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(JwtAuthenticationConverter.class)
|
||||
@Conditional(JwtConverterPropertiesCondition.class)
|
||||
static class JwtConverterConfiguration {
|
||||
|
||||
private final OAuth2ResourceServerProperties.Jwt properties;
|
||||
@@ -204,4 +206,27 @@ class OAuth2ResourceServerJwtConfiguration {
|
||||
|
||||
}
|
||||
|
||||
private static class JwtConverterPropertiesCondition extends AnyNestedCondition {
|
||||
|
||||
JwtConverterPropertiesCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "spring.security.oauth2.resourceserver.jwt", name = "authority-prefix")
|
||||
static class OnAuthorityPrefix {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "spring.security.oauth2.resourceserver.jwt", name = "principal-claim-name")
|
||||
static class OnPrincipalClaimName {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "spring.security.oauth2.resourceserver.jwt", name = "authorities-claim-name")
|
||||
static class OnAuthoritiesClaimName {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ public final class JwtConverterCustomizationsArgumentsProvider implements Argume
|
||||
String customDelimiter = "[~,#:]";
|
||||
String customAuthoritiesClaim = "custom_authorities";
|
||||
String customPrincipalClaim = "custom_principal";
|
||||
|
||||
String jwkSetUriProperty = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com";
|
||||
String authorityPrefixProperty = "spring.security.oauth2.resourceserver.jwt.authority-prefix=" + customPrefix;
|
||||
String authoritiesDelimiterProperty = "spring.security.oauth2.resourceserver.jwt.authorities-claim-delimiter="
|
||||
@@ -51,19 +50,15 @@ public final class JwtConverterCustomizationsArgumentsProvider implements Argume
|
||||
+ customAuthoritiesClaim;
|
||||
String principalClaimProperty = "spring.security.oauth2.resourceserver.jwt.principal-claim-name="
|
||||
+ customPrincipalClaim;
|
||||
|
||||
String[] noJwtConverterProps = { jwkSetUriProperty };
|
||||
String[] customPrefixProps = { jwkSetUriProperty, authorityPrefixProperty };
|
||||
String[] customDelimiterProps = { jwkSetUriProperty, authoritiesDelimiterProperty };
|
||||
String[] customDelimiterProps = { jwkSetUriProperty, authorityPrefixProperty, authoritiesDelimiterProperty };
|
||||
String[] customAuthoritiesClaimProps = { jwkSetUriProperty, authoritiesClaimProperty };
|
||||
String[] customPrincipalClaimProps = { jwkSetUriProperty, principalClaimProperty };
|
||||
String[] allJwtConverterProps = { jwkSetUriProperty, authorityPrefixProperty, authoritiesDelimiterProperty,
|
||||
authoritiesClaimProperty, principalClaimProperty };
|
||||
|
||||
String[] jwtScopes = { "custom_scope0", "custom_scope1" };
|
||||
String subjectValue = UUID.randomUUID().toString();
|
||||
String customPrincipalValue = UUID.randomUUID().toString();
|
||||
|
||||
Jwt.Builder jwtBuilder = Jwt.withTokenValue("token")
|
||||
.header("alg", "none")
|
||||
.expiresAt(Instant.MAX)
|
||||
@@ -73,7 +68,6 @@ public final class JwtConverterCustomizationsArgumentsProvider implements Argume
|
||||
.notBefore(Instant.MIN)
|
||||
.subject(subjectValue)
|
||||
.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)
|
||||
@@ -82,17 +76,13 @@ public final class JwtConverterCustomizationsArgumentsProvider implements Argume
|
||||
Jwt customAuthoritiesClaimAndDelimiterJwt = jwtBuilder.claim("scp", null)
|
||||
.claim(customAuthoritiesClaim, jwtScopes[0] + "~" + jwtScopes[1])
|
||||
.build();
|
||||
|
||||
String[] customPrefixAuthorities = { customPrefix + jwtScopes[0], customPrefix + jwtScopes[1] };
|
||||
String[] defaultPrefixAuthorities = { "SCOPE_" + jwtScopes[0], "SCOPE_" + jwtScopes[1] };
|
||||
|
||||
return Stream.of(
|
||||
Arguments.of(Named.named("No JWT converter customizations", noJwtConverterProps),
|
||||
noAuthoritiesCustomizationsJwt, subjectValue, defaultPrefixAuthorities),
|
||||
Arguments.of(Named.named("Custom prefix for GrantedAuthority", customPrefixProps),
|
||||
noAuthoritiesCustomizationsJwt, subjectValue, customPrefixAuthorities),
|
||||
Arguments.of(Named.named("Custom delimiter for JWT scopes", customDelimiterProps),
|
||||
customAuthoritiesDelimiterJwt, subjectValue, defaultPrefixAuthorities),
|
||||
customAuthoritiesDelimiterJwt, subjectValue, customPrefixAuthorities),
|
||||
Arguments.of(Named.named("Custom JWT authority claim name", customAuthoritiesClaimProps),
|
||||
customAuthoritiesClaimJwt, subjectValue, defaultPrefixAuthorities),
|
||||
Arguments.of(Named.named("Custom JWT principal claim name", customPrincipalClaimProps),
|
||||
|
||||
@@ -633,6 +633,30 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotConfigureJwtConverterIfNoPropertiesAreSet() {
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(ReactiveJwtAuthenticationConverter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConfigureJwtConverterIfPrincipalClaimNameIsSet() {
|
||||
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.principal-claim-name=dummy")
|
||||
.run((context) -> assertThat(context).hasSingleBean(ReactiveJwtAuthenticationConverter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConfigureJwtConverterIfAuthorityPrefixIsSet() {
|
||||
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.authority-prefix=dummy")
|
||||
.run((context) -> assertThat(context).hasSingleBean(ReactiveJwtAuthenticationConverter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConfigureJwtConverterIfAuthorityClaimsNameIsSet() {
|
||||
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.authorities-claim-name=dummy")
|
||||
.run((context) -> assertThat(context).hasSingleBean(ReactiveJwtAuthenticationConverter.class));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}")
|
||||
@ArgumentsSource(JwtConverterCustomizationsArgumentsProvider.class)
|
||||
void autoConfigurationShouldConfigureResourceServerWithJwtConverterCustomizations(String[] properties, Jwt jwt,
|
||||
|
||||
@@ -662,6 +662,29 @@ class OAuth2ResourceServerAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotConfigureJwtConverterIfNoPropertiesAreSet() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(JwtAuthenticationConverter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConfigureJwtConverterIfPrincipalClaimNameIsSet() {
|
||||
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.principal-claim-name=dummy")
|
||||
.run((context) -> assertThat(context).hasSingleBean(JwtAuthenticationConverter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConfigureJwtConverterIfAuthorityPrefixIsSet() {
|
||||
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.authority-prefix=dummy")
|
||||
.run((context) -> assertThat(context).hasSingleBean(JwtAuthenticationConverter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConfigureJwtConverterIfAuthorityClaimsNameIsSet() {
|
||||
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.authorities-claim-name=dummy")
|
||||
.run((context) -> assertThat(context).hasSingleBean(JwtAuthenticationConverter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void jwtAuthenticationConverterByJwtConfigIsConditionalOnMissingBean() {
|
||||
String propertiesPrincipalClaim = "principal_from_properties";
|
||||
|
||||
Reference in New Issue
Block a user