Polish "Add Spring Authorization Server support"

See gh-34003
pull/34729/head
Madhura Bhave 2 years ago
parent 25d77ee70b
commit e6f602cec0

@ -31,7 +31,6 @@ import org.springframework.security.oauth2.server.authorization.client.Registere
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.util.CollectionUtils;
/**
* Adapter class to convert {@link Client} to a {@link RegisteredClient}.
@ -58,66 +57,23 @@ public final class OAuth2AuthorizationServerPropertiesRegistrationAdapter {
map.from(registration::getClientId).to(builder::clientId);
map.from(registration::getClientSecret).to(builder::clientSecret);
map.from(registration::getClientName).to(builder::clientName);
if (!CollectionUtils.isEmpty(registration.getClientAuthenticationMethods())) {
registration.getClientAuthenticationMethods()
.forEach((clientAuthenticationMethod) -> map.from(clientAuthenticationMethod)
.as(OAuth2AuthorizationServerPropertiesRegistrationAdapter::clientAuthenticationMethod)
.to(builder::clientAuthenticationMethod));
}
if (!CollectionUtils.isEmpty(registration.getAuthorizationGrantTypes())) {
registration.getAuthorizationGrantTypes()
.forEach((authorizationGrantType) -> map.from(authorizationGrantType)
.as(OAuth2AuthorizationServerPropertiesRegistrationAdapter::authorizationGrantType)
.to(builder::authorizationGrantType));
}
if (!CollectionUtils.isEmpty(registration.getRedirectUris())) {
registration.getRedirectUris().forEach((redirectUri) -> map.from(redirectUri).to(builder::redirectUri));
}
if (!CollectionUtils.isEmpty(registration.getPostLogoutRedirectUris())) {
registration.getPostLogoutRedirectUris()
.forEach((redirectUri) -> map.from(redirectUri).to(builder::postLogoutRedirectUri));
}
if (!CollectionUtils.isEmpty(registration.getScopes())) {
registration.getScopes().forEach((scope) -> map.from(scope).to(builder::scope));
}
registration.getClientAuthenticationMethods()
.forEach((clientAuthenticationMethod) -> map.from(clientAuthenticationMethod)
.as(ClientAuthenticationMethod::new)
.to(builder::clientAuthenticationMethod));
registration.getAuthorizationGrantTypes()
.forEach((authorizationGrantType) -> map.from(authorizationGrantType)
.as(AuthorizationGrantType::new)
.to(builder::authorizationGrantType));
registration.getRedirectUris().forEach((redirectUri) -> map.from(redirectUri).to(builder::redirectUri));
registration.getPostLogoutRedirectUris()
.forEach((redirectUri) -> map.from(redirectUri).to(builder::postLogoutRedirectUri));
registration.getScopes().forEach((scope) -> map.from(scope).to(builder::scope));
builder.clientSettings(getClientSettings(client, map));
builder.tokenSettings(getTokenSettings(client, map));
return builder.build();
}
private static ClientAuthenticationMethod clientAuthenticationMethod(String clientAuthenticationMethod) {
if (ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue().equals(clientAuthenticationMethod)) {
return ClientAuthenticationMethod.CLIENT_SECRET_BASIC;
}
else if (ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue().equals(clientAuthenticationMethod)) {
return ClientAuthenticationMethod.CLIENT_SECRET_POST;
}
else if (ClientAuthenticationMethod.CLIENT_SECRET_JWT.getValue().equals(clientAuthenticationMethod)) {
return ClientAuthenticationMethod.CLIENT_SECRET_JWT;
}
else if (ClientAuthenticationMethod.PRIVATE_KEY_JWT.getValue().equals(clientAuthenticationMethod)) {
return ClientAuthenticationMethod.PRIVATE_KEY_JWT;
}
else if (ClientAuthenticationMethod.NONE.getValue().equals(clientAuthenticationMethod)) {
return ClientAuthenticationMethod.NONE;
}
else {
return new ClientAuthenticationMethod(clientAuthenticationMethod);
}
}
private static AuthorizationGrantType authorizationGrantType(String authorizationGrantType) {
if (AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(authorizationGrantType)) {
return AuthorizationGrantType.AUTHORIZATION_CODE;
}
else if (AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equals(authorizationGrantType)) {
return AuthorizationGrantType.CLIENT_CREDENTIALS;
}
else {
return new AuthorizationGrantType(authorizationGrantType);
}
}
private static ClientSettings getClientSettings(Client client, PropertyMapper map) {
ClientSettings.Builder builder = ClientSettings.builder();
map.from(client::isRequireProofKey).to(builder::requireProofKey);

@ -21,10 +21,9 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
/**
@ -43,11 +42,11 @@ import org.springframework.security.oauth2.server.authorization.OAuth2Authorizat
* @since 3.1.0
* @see OAuth2AuthorizationServerJwtAutoConfiguration
*/
@AutoConfiguration(before = { OAuth2ResourceServerAutoConfiguration.class, SecurityFilterAutoConfiguration.class })
@AutoConfiguration(before = { OAuth2ResourceServerAutoConfiguration.class, SecurityAutoConfiguration.class,
UserDetailsServiceAutoConfiguration.class })
@ConditionalOnClass(OAuth2Authorization.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@Import({ OAuth2AuthorizationServerPropertiesConfiguration.class,
OAuth2AuthorizationServerWebSecurityConfiguration.class, ObjectPostProcessorConfiguration.class })
@Import({ OAuth2AuthorizationServerConfiguration.class, OAuth2AuthorizationServerWebSecurityConfiguration.class })
public class OAuth2AuthorizationServerAutoConfiguration {
}

@ -40,7 +40,7 @@ import org.springframework.security.oauth2.server.authorization.settings.Authori
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(OAuth2AuthorizationServerProperties.class)
class OAuth2AuthorizationServerPropertiesConfiguration {
class OAuth2AuthorizationServerConfiguration {
@Bean
@ConditionalOnMissingBean

@ -16,13 +16,30 @@
package org.springframework.boot.autoconfigure.security.oauth2.server.servlet;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Role;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
/**
* {@link EnableAutoConfiguration Auto-configuration} for JWT support for endpoints of the
@ -30,12 +47,52 @@ import org.springframework.security.oauth2.server.authorization.OAuth2Authorizat
*
* @author Steve Riesenberg
* @since 3.1.0
* @see OAuth2AuthorizationServerAutoConfiguration
*/
@AutoConfiguration(after = { UserDetailsServiceAutoConfiguration.class })
@AutoConfiguration(after = UserDetailsServiceAutoConfiguration.class)
@ConditionalOnClass(OAuth2Authorization.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@Import(OAuth2AuthorizationServerJwtConfiguration.class)
public class OAuth2AuthorizationServerJwtAutoConfiguration {
@Bean
@ConditionalOnClass(JwtDecoder.class)
@ConditionalOnMissingBean
JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnMissingBean
JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = getRsaKey();
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}
private static RSAKey getRsaKey() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// @formatter:off
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
// @formatter:on
return rsaKey;
}
private static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
}

@ -1,87 +0,0 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.security.oauth2.server.servlet;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
/**
* {@link Configuration @Configuration} for JWT support for endpoints of the OAuth2
* authorization server that require it (e.g. User Info, Client Registration).
*
* @author Steve Riesenberg
*/
@Configuration(proxyBeanMethods = false)
class OAuth2AuthorizationServerJwtConfiguration {
@Bean
@ConditionalOnClass(JwtDecoder.class)
@ConditionalOnMissingBean
JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnClass(JWKSource.class)
@ConditionalOnMissingBean
JWKSource<SecurityContext> jwkSource() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// @formatter:off
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
// @formatter:on
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}
private static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
}

@ -16,6 +16,7 @@
package org.springframework.boot.autoconfigure.security.oauth2.server.servlet;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.security.ConditionalOnDefaultWebSecurity;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
@ -25,8 +26,10 @@ import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
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.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
@ -37,6 +40,7 @@ import org.springframework.security.web.authentication.LoginUrlAuthenticationEnt
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnDefaultWebSecurity
@ConditionalOnBean({ RegisteredClientRepository.class, AuthorizationServerSettings.class })
class OAuth2AuthorizationServerWebSecurityConfiguration {
@Bean

@ -37,7 +37,7 @@ import org.springframework.security.authentication.DefaultAuthenticationEventPub
* @author Madhura Bhave
* @since 1.0.0
*/
@AutoConfiguration
@AutoConfiguration(before = UserDetailsServiceAutoConfiguration.class)
@ConditionalOnClass(DefaultAuthenticationEventPublisher.class)
@EnableConfigurationProperties(SecurityProperties.class)
@Import({ SpringBootWebSecurityConfiguration.class, SecurityDataConfiguration.class })

@ -34,18 +34,16 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Steve Riesenberg
*/
public class OAuth2AuthorizationServerPropertiesRegistrationAdapterTests {
class OAuth2AuthorizationServerPropertiesRegistrationAdapterTests {
@Test
void getRegisteredClientsWhenValidParametersShouldAdapt() {
OAuth2AuthorizationServerProperties properties = new OAuth2AuthorizationServerProperties();
OAuth2AuthorizationServerProperties.Client client = createClient();
properties.getClient().put("foo", client);
List<RegisteredClient> registeredClients = OAuth2AuthorizationServerPropertiesRegistrationAdapter
.getRegisteredClients(properties);
assertThat(registeredClients).hasSize(1);
RegisteredClient registeredClient = registeredClients.get(0);
assertThat(registeredClient.getClientId()).isEqualTo("foo");
assertThat(registeredClient.getClientSecret()).isEqualTo("secret");
@ -56,13 +54,11 @@ public class OAuth2AuthorizationServerPropertiesRegistrationAdapterTests {
assertThat(registeredClient.getRedirectUris()).containsExactly("https://example.com/redirect");
assertThat(registeredClient.getPostLogoutRedirectUris()).containsExactly("https://example.com/logout");
assertThat(registeredClient.getScopes()).containsExactly("user.read");
assertThat(registeredClient.getClientSettings().isRequireProofKey()).isTrue();
assertThat(registeredClient.getClientSettings().isRequireAuthorizationConsent()).isTrue();
assertThat(registeredClient.getClientSettings().getJwkSetUrl()).isEqualTo("https://example.com/jwks");
assertThat(registeredClient.getClientSettings().getTokenEndpointAuthenticationSigningAlgorithm())
.isEqualTo(SignatureAlgorithm.RS256);
assertThat(registeredClient.getTokenSettings().getAccessTokenFormat()).isEqualTo(OAuth2TokenFormat.REFERENCE);
assertThat(registeredClient.getTokenSettings().getAccessTokenTimeToLive()).isEqualTo(Duration.ofSeconds(300));
assertThat(registeredClient.getTokenSettings().getRefreshTokenTimeToLive()).isEqualTo(Duration.ofHours(24));
@ -77,7 +73,6 @@ public class OAuth2AuthorizationServerPropertiesRegistrationAdapterTests {
client.setRequireAuthorizationConsent(true);
client.setJwkSetUri("https://example.com/jwks");
client.setTokenEndpointAuthenticationSigningAlgorithm("rs256");
OAuth2AuthorizationServerProperties.Registration registration = client.getRegistration();
registration.setClientId("foo");
registration.setClientSecret("secret");
@ -86,14 +81,12 @@ public class OAuth2AuthorizationServerPropertiesRegistrationAdapterTests {
registration.getRedirectUris().add("https://example.com/redirect");
registration.getPostLogoutRedirectUris().add("https://example.com/logout");
registration.getScopes().add("user.read");
OAuth2AuthorizationServerProperties.Token token = client.getToken();
token.setAccessTokenFormat("reference");
token.setAccessTokenTimeToLive(Duration.ofSeconds(300));
token.setRefreshTokenTimeToLive(Duration.ofHours(24));
token.setReuseRefreshTokens(true);
token.setIdTokenSignatureAlgorithm("rs512");
return client;
}

@ -27,12 +27,11 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Steve Riesenberg
*/
public class OAuth2AuthorizationServerPropertiesSettingsAdapterTests {
class OAuth2AuthorizationServerPropertiesSettingsAdapterTests {
@Test
void getAuthorizationServerSettingsWhenValidParametersShouldAdapt() {
OAuth2AuthorizationServerProperties properties = createAuthorizationServerProperties();
AuthorizationServerSettings settings = OAuth2AuthorizationServerPropertiesSettingsAdapter
.getAuthorizationServerSettings(properties);
assertThat(settings.getIssuer()).isEqualTo("https://example.com");
@ -49,14 +48,12 @@ public class OAuth2AuthorizationServerPropertiesSettingsAdapterTests {
private OAuth2AuthorizationServerProperties createAuthorizationServerProperties() {
OAuth2AuthorizationServerProperties properties = new OAuth2AuthorizationServerProperties();
properties.setIssuer("https://example.com");
OAuth2AuthorizationServerProperties.Endpoint endpoints = properties.getEndpoint();
endpoints.setAuthorizationUri("/authorize");
endpoints.setTokenUri("/token");
endpoints.setJwkSetUri("/jwks");
endpoints.setTokenRevocationUri("/revoke");
endpoints.setTokenIntrospectionUri("/introspect");
OAuth2AuthorizationServerProperties.OidcEndpoint oidc = endpoints.getOidc();
oidc.setLogoutUri("/logout");
oidc.setClientRegistrationUri("/register");

@ -25,7 +25,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
*
* @author Steve Riesenberg
*/
public class OAuth2AuthorizationServerPropertiesTests {
class OAuth2AuthorizationServerPropertiesTests {
private final OAuth2AuthorizationServerProperties properties = new OAuth2AuthorizationServerProperties();

@ -0,0 +1,184 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.security.oauth2.server.servlet;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test for {@link OAuth2AuthorizationServerAutoConfiguration}.
*
* @author Steve Riesenberg
* @author Madhura Bhave
*/
class OAuth2AuthorizationServerAutoConfigurationTests {
private static final String PROPERTIES_PREFIX = "spring.security.oauth2.authorizationserver";
private static final String CLIENT_PREFIX = PROPERTIES_PREFIX + ".client";
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(OAuth2AuthorizationServerAutoConfiguration.class,
OAuth2AuthorizationServerJwtAutoConfiguration.class, SecurityAutoConfiguration.class,
UserDetailsServiceAutoConfiguration.class));
@Test
void autoConfigurationConditionalOnClassOauth2Authorization() {
this.contextRunner.withClassLoader(new FilteredClassLoader(OAuth2Authorization.class))
.run((context) -> assertThat(context).doesNotHaveBean(OAuth2AuthorizationServerAutoConfiguration.class));
}
@Test
void autoConfigurationDoesNotCauseUserDetailsServiceToBackOff() {
this.contextRunner.run((context) -> assertThat(context).hasBean("inMemoryUserDetailsManager"));
}
@Test
void registeredClientRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(RegisteredClientRepository.class));
}
@Test
void registeredClientRepositoryBeanShouldBeCreatedWhenPropertiesPresent() {
this.contextRunner
.withPropertyValues(CLIENT_PREFIX + ".foo.registration.client-id=abcd",
CLIENT_PREFIX + ".foo.registration.client-secret=secret",
CLIENT_PREFIX + ".foo.registration.client-authentication-methods=client_secret_basic",
CLIENT_PREFIX + ".foo.registration.authorization-grant-types=client_credentials",
CLIENT_PREFIX + ".foo.registration.scopes=test")
.run((context) -> {
RegisteredClientRepository registeredClientRepository = context
.getBean(RegisteredClientRepository.class);
RegisteredClient registeredClient = registeredClientRepository.findById("foo");
assertThat(registeredClient).isNotNull();
assertThat(registeredClient.getClientId()).isEqualTo("abcd");
assertThat(registeredClient.getClientSecret()).isEqualTo("secret");
assertThat(registeredClient.getClientAuthenticationMethods())
.containsOnly(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
assertThat(registeredClient.getAuthorizationGrantTypes())
.containsOnly(AuthorizationGrantType.CLIENT_CREDENTIALS);
assertThat(registeredClient.getScopes()).containsOnly("test");
});
}
@Test
void registeredClientRepositoryBacksOffWhenRegisteredClientRepositoryBeanPresent() {
this.contextRunner.withUserConfiguration(TestRegisteredClientRepositoryConfiguration.class)
.withPropertyValues(CLIENT_PREFIX + ".foo.registration.client-id=abcd",
CLIENT_PREFIX + ".foo.registration.client-secret=secret",
CLIENT_PREFIX + ".foo.registration.client-authentication-methods=client_secret_basic",
CLIENT_PREFIX + ".foo.registration.authorization-grant-types=client_credentials",
CLIENT_PREFIX + ".foo.registration.scope=test")
.run((context) -> {
RegisteredClientRepository registeredClientRepository = context
.getBean(RegisteredClientRepository.class);
RegisteredClient registeredClient = registeredClientRepository.findById("test");
assertThat(registeredClient).isNotNull();
assertThat(registeredClient.getClientId()).isEqualTo("abcd");
assertThat(registeredClient.getClientSecret()).isEqualTo("secret");
assertThat(registeredClient.getClientAuthenticationMethods())
.containsOnly(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
assertThat(registeredClient.getAuthorizationGrantTypes())
.containsOnly(AuthorizationGrantType.CLIENT_CREDENTIALS);
assertThat(registeredClient.getScopes()).containsOnly("test");
});
}
@Test
void authorizationServerSettingsBeanShouldBeCreatedWhenPropertiesAbsent() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(AuthorizationServerSettings.class));
}
@Test
void authorizationServerSettingsBeanShouldBeCreatedWhenPropertiesPresent() {
this.contextRunner
.withPropertyValues(PROPERTIES_PREFIX + ".issuer=https://example.com",
PROPERTIES_PREFIX + ".endpoint.authorization-uri=/authorize",
PROPERTIES_PREFIX + ".endpoint.token-uri=/token", PROPERTIES_PREFIX + ".endpoint.jwk-set-uri=/jwks",
PROPERTIES_PREFIX + ".endpoint.token-revocation-uri=/revoke",
PROPERTIES_PREFIX + ".endpoint.token-introspection-uri=/introspect",
PROPERTIES_PREFIX + ".endpoint.oidc.logout-uri=/logout",
PROPERTIES_PREFIX + ".endpoint.oidc.client-registration-uri=/register",
PROPERTIES_PREFIX + ".endpoint.oidc.user-info-uri=/user")
.run((context) -> {
AuthorizationServerSettings settings = context.getBean(AuthorizationServerSettings.class);
assertThat(settings.getIssuer()).isEqualTo("https://example.com");
assertThat(settings.getAuthorizationEndpoint()).isEqualTo("/authorize");
assertThat(settings.getTokenEndpoint()).isEqualTo("/token");
assertThat(settings.getJwkSetEndpoint()).isEqualTo("/jwks");
assertThat(settings.getTokenRevocationEndpoint()).isEqualTo("/revoke");
assertThat(settings.getTokenIntrospectionEndpoint()).isEqualTo("/introspect");
assertThat(settings.getOidcLogoutEndpoint()).isEqualTo("/logout");
assertThat(settings.getOidcClientRegistrationEndpoint()).isEqualTo("/register");
assertThat(settings.getOidcUserInfoEndpoint()).isEqualTo("/user");
});
}
@Test
void authorizationServerSettingsBacksOffWhenAuthorizationServerSettingsBeanPresent() {
this.contextRunner.withUserConfiguration(TestAuthorizationServerSettingsConfiguration.class)
.withPropertyValues(PROPERTIES_PREFIX + ".issuer=https://test.com")
.run((context) -> {
AuthorizationServerSettings settings = context.getBean(AuthorizationServerSettings.class);
assertThat(settings.getIssuer()).isEqualTo("https://example.com");
});
}
@Configuration
static class TestRegisteredClientRepositoryConfiguration {
@Bean
RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId("test")
.clientId("abcd")
.clientSecret("secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.scope("test")
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
}
@Configuration
static class TestAuthorizationServerSettingsConfiguration {
@Bean
AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().issuer("https://example.com").build();
}
}
}

@ -0,0 +1,107 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.security.oauth2.server.servlet;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link OAuth2AuthorizationServerJwtAutoConfiguration}.
*
* @author Steve Riesenberg
*/
class OAuth2AuthorizationServerJwtAutoConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(OAuth2AuthorizationServerJwtAutoConfiguration.class));
@Test
void autoConfigurationConditionalOnClassOauth2Authorization() {
this.contextRunner.withClassLoader(new FilteredClassLoader(OAuth2Authorization.class))
.run((context) -> assertThat(context).doesNotHaveBean(OAuth2AuthorizationServerJwtAutoConfiguration.class));
}
@Test
void jwtDecoderConditionalOnClassJwtDecoder() {
this.contextRunner.withClassLoader(new FilteredClassLoader(JwtDecoder.class))
.run((context) -> assertThat(context).doesNotHaveBean("jwtDecoder"));
}
@Test
void jwtConfigurationConfiguresJwtDecoderWithGeneratedKey() {
this.contextRunner.run((context) -> {
assertThat(context).hasBean("jwtDecoder");
assertThat(context.getBean("jwtDecoder")).isInstanceOf(NimbusJwtDecoder.class);
assertThat(context).hasBean("jwkSource");
assertThat(context.getBean("jwkSource")).isInstanceOf(ImmutableJWKSet.class);
});
}
@Test
void jwtDecoderBacksOffWhenBeanPresent() {
this.contextRunner.withUserConfiguration(TestJwtDecoderConfiguration.class).run((context) -> {
assertThat(context).hasBean("jwtDecoder");
assertThat(context.getBean("jwtDecoder")).isNotInstanceOf(NimbusJwtDecoder.class);
assertThat(context).hasBean("jwkSource");
assertThat(context.getBean("jwkSource")).isInstanceOf(ImmutableJWKSet.class);
});
}
@Test
void jwkSourceBacksOffWhenBeanPresent() {
this.contextRunner.withUserConfiguration(TestJwkSourceConfiguration.class).run((context) -> {
assertThat(context).hasBean("jwtDecoder");
assertThat(context.getBean("jwtDecoder")).isInstanceOf(NimbusJwtDecoder.class);
assertThat(context).hasBean("jwkSource");
assertThat(context.getBean("jwkSource")).isNotInstanceOf(ImmutableJWKSet.class);
});
}
@Configuration
static class TestJwtDecoderConfiguration {
@Bean
JwtDecoder jwtDecoder() {
return (token) -> null;
}
}
@Configuration
static class TestJwkSourceConfiguration {
@Bean
JWKSource<SecurityContext> jwkSource() {
return (jwkSelector, context) -> null;
}
}
}

@ -1,110 +0,0 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.security.oauth2.server.servlet;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link OAuth2AuthorizationServerJwtConfiguration}.
*
* @author Steve Riesenberg
*/
public class OAuth2AuthorizationServerJwtConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
@Test
void jwtConfigurationConfiguresJwtDecoderWithGeneratedKey() {
// @formatter:off
this.contextRunner.withUserConfiguration(TestJwtConfiguration.class)
.run((context) -> {
assertThat(context).hasBean("jwtDecoder");
assertThat(context).hasBean("jwkSource");
assertThat(context.getBean("jwtDecoder")).isInstanceOf(NimbusJwtDecoder.class);
assertThat(context.getBean("jwkSource")).isInstanceOf(ImmutableJWKSet.class);
});
// @formatter:on
}
@Test
void jwtDecoderBacksOffWhenBeanPresent() {
// @formatter:off
this.contextRunner.withUserConfiguration(TestJwtDecoderConfiguration.class, TestJwtConfiguration.class)
.run((context) -> {
assertThat(context).hasBean("jwtDecoder");
assertThat(context).hasBean("jwkSource");
assertThat(context.getBean("jwtDecoder")).isNotInstanceOf(NimbusJwtDecoder.class);
assertThat(context.getBean("jwkSource")).isInstanceOf(ImmutableJWKSet.class);
});
// @formatter:on
}
@Test
void jwkSourceBacksOffWhenBeanPresent() {
// @formatter:off
this.contextRunner.withUserConfiguration(TestJwkSourceConfiguration.class, TestJwtConfiguration.class)
.run((context) -> {
assertThat(context).hasBean("jwtDecoder");
assertThat(context).hasBean("jwkSource");
assertThat(context.getBean("jwtDecoder")).isInstanceOf(NimbusJwtDecoder.class);
assertThat(context.getBean("jwkSource")).isNotInstanceOf(ImmutableJWKSet.class);
});
// @formatter:on
}
@Configuration
@Import(OAuth2AuthorizationServerJwtConfiguration.class)
static class TestJwtConfiguration {
}
@Configuration
static class TestJwtDecoderConfiguration {
@Bean
JwtDecoder jwtDecoder() {
return (token) -> null;
}
}
@Configuration
static class TestJwkSourceConfiguration {
@Bean
JWKSource<SecurityContext> jwkSource() {
return (jwkSelector, context) -> null;
}
}
}

@ -1,189 +0,0 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.security.oauth2.server.servlet;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Steve Riesenberg
*/
public class OAuth2AuthorizationServerPropertiesConfigurationTests {
private static final String PROPERTIES_PREFIX = "spring.security.oauth2.authorizationserver";
private static final String CLIENT_PREFIX = PROPERTIES_PREFIX + ".client";
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
@Test
void registeredClientRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() {
// @formatter:off
this.contextRunner.withUserConfiguration(TestOAuth2AuthorizationServerConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean(RegisteredClientRepository.class));
// @formatter:on
}
@Test
void registeredClientRepositoryBeanShouldBeCreatedWhenPropertiesPresent() {
// @formatter:off
this.contextRunner.withUserConfiguration(TestOAuth2AuthorizationServerConfiguration.class)
.withPropertyValues(
CLIENT_PREFIX + ".foo.registration.client-id=abcd",
CLIENT_PREFIX + ".foo.registration.client-secret=secret",
CLIENT_PREFIX + ".foo.registration.client-authentication-methods=client_secret_basic",
CLIENT_PREFIX + ".foo.registration.authorization-grant-types=client_credentials",
CLIENT_PREFIX + ".foo.registration.scopes=test")
.run((context) -> {
RegisteredClientRepository registeredClientRepository = context.getBean(RegisteredClientRepository.class);
RegisteredClient registeredClient = registeredClientRepository.findById("foo");
assertThat(registeredClient).isNotNull();
assertThat(registeredClient.getClientId()).isEqualTo("abcd");
assertThat(registeredClient.getClientSecret()).isEqualTo("secret");
assertThat(registeredClient.getClientAuthenticationMethods())
.containsOnly(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
assertThat(registeredClient.getAuthorizationGrantTypes())
.containsOnly(AuthorizationGrantType.CLIENT_CREDENTIALS);
assertThat(registeredClient.getScopes()).containsOnly("test");
});
// @formatter:on
}
@Test
void registeredClientRepositoryBacksOffWhenRegisteredClientRepositoryBeanPresent() {
// @formatter:off
this.contextRunner.withUserConfiguration(TestRegisteredClientRepositoryConfiguration.class,
TestOAuth2AuthorizationServerConfiguration.class)
.withPropertyValues(
CLIENT_PREFIX + ".foo.registration.client-id=abcd",
CLIENT_PREFIX + ".foo.registration.client-secret=secret",
CLIENT_PREFIX + ".foo.registration.client-authentication-methods=client_secret_basic",
CLIENT_PREFIX + ".foo.registration.authorization-grant-types=client_credentials",
CLIENT_PREFIX + ".foo.registration.scope=test")
.run((context) -> {
RegisteredClientRepository registeredClientRepository = context.getBean(RegisteredClientRepository.class);
RegisteredClient registeredClient = registeredClientRepository.findById("test");
assertThat(registeredClient).isNotNull();
assertThat(registeredClient.getClientId()).isEqualTo("abcd");
assertThat(registeredClient.getClientSecret()).isEqualTo("secret");
assertThat(registeredClient.getClientAuthenticationMethods())
.containsOnly(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
assertThat(registeredClient.getAuthorizationGrantTypes())
.containsOnly(AuthorizationGrantType.CLIENT_CREDENTIALS);
assertThat(registeredClient.getScopes()).containsOnly("test");
});
// @formatter:on
}
@Test
void authorizationServerSettingsBeanShouldBeCreatedWhenPropertiesAbsent() {
// @formatter:off
this.contextRunner.withUserConfiguration(TestOAuth2AuthorizationServerConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(AuthorizationServerSettings.class));
// @formatter:on
}
@Test
void authorizationServerSettingsBeanShouldBeCreatedWhenPropertiesPresent() {
// @formatter:off
this.contextRunner.withUserConfiguration(TestOAuth2AuthorizationServerConfiguration.class)
.withPropertyValues(
PROPERTIES_PREFIX + ".issuer=https://example.com",
PROPERTIES_PREFIX + ".endpoint.authorization-uri=/authorize",
PROPERTIES_PREFIX + ".endpoint.token-uri=/token",
PROPERTIES_PREFIX + ".endpoint.jwk-set-uri=/jwks",
PROPERTIES_PREFIX + ".endpoint.token-revocation-uri=/revoke",
PROPERTIES_PREFIX + ".endpoint.token-introspection-uri=/introspect",
PROPERTIES_PREFIX + ".endpoint.oidc.logout-uri=/logout",
PROPERTIES_PREFIX + ".endpoint.oidc.client-registration-uri=/register",
PROPERTIES_PREFIX + ".endpoint.oidc.user-info-uri=/user")
.run((context) -> {
AuthorizationServerSettings settings = context.getBean(AuthorizationServerSettings.class);
assertThat(settings.getIssuer()).isEqualTo("https://example.com");
assertThat(settings.getAuthorizationEndpoint()).isEqualTo("/authorize");
assertThat(settings.getTokenEndpoint()).isEqualTo("/token");
assertThat(settings.getJwkSetEndpoint()).isEqualTo("/jwks");
assertThat(settings.getTokenRevocationEndpoint()).isEqualTo("/revoke");
assertThat(settings.getTokenIntrospectionEndpoint()).isEqualTo("/introspect");
assertThat(settings.getOidcLogoutEndpoint()).isEqualTo("/logout");
assertThat(settings.getOidcClientRegistrationEndpoint()).isEqualTo("/register");
assertThat(settings.getOidcUserInfoEndpoint()).isEqualTo("/user");
});
// @formatter:on
}
@Test
void authorizationServerSettingsBacksOffWhenAuthorizationServerSettingsBeanPresent() {
// @formatter:off
this.contextRunner.withUserConfiguration(TestAuthorizationServerSettingsConfiguration.class,
TestOAuth2AuthorizationServerConfiguration.class)
.withPropertyValues(PROPERTIES_PREFIX + ".issuer=https://test.com")
.run((context) -> {
AuthorizationServerSettings settings = context.getBean(AuthorizationServerSettings.class);
assertThat(settings.getIssuer()).isEqualTo("https://example.com");
});
// @formatter:on
}
@Configuration
@EnableWebSecurity
@Import({ OAuth2AuthorizationServerPropertiesConfiguration.class })
static class TestOAuth2AuthorizationServerConfiguration {
}
@Configuration
static class TestRegisteredClientRepositoryConfiguration {
@Bean
RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId("test")
.clientId("abcd")
.clientSecret("secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.scope("test")
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
}
@Configuration
static class TestAuthorizationServerSettingsConfiguration {
@Bean
AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().issuer("https://example.com").build();
}
}
}

@ -21,8 +21,8 @@ import java.util.List;
import jakarta.servlet.Filter;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -31,10 +31,16 @@ import org.springframework.security.config.BeanIds;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.oidc.web.OidcClientRegistrationEndpointFilter;
import org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter;
import org.springframework.security.oauth2.server.authorization.oidc.web.OidcUserInfoEndpointFilter;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter;
import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter;
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter;
@ -49,74 +55,69 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageGenera
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link OAuth2AuthorizationServerWebSecurityConfiguration}.
*
* @author Steve Riesenberg
*/
public class OAuth2AuthorizationServerWebSecurityConfigurationTests {
class OAuth2AuthorizationServerWebSecurityConfigurationTests {
private static final String PROPERTIES_PREFIX = "spring.security.oauth2.authorizationserver";
private static final String CLIENT_PREFIX = PROPERTIES_PREFIX + ".client";
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner();
@Test
void webSecurityConfigurationConfiguresAuthorizationServerWithFormLogin() {
// @formatter:off
this.contextRunner.withUserConfiguration(TestOAuth2AuthorizationServerConfiguration.class)
.withPropertyValues(
CLIENT_PREFIX + ".foo.registration.client-id=abcd",
CLIENT_PREFIX + ".foo.registration.client-secret=secret",
CLIENT_PREFIX + ".foo.registration.client-authentication-methods=client_secret_basic",
CLIENT_PREFIX + ".foo.registration.authorization-grant-types=client_credentials",
CLIENT_PREFIX + ".foo.registration.scopes=test")
.run((context) -> {
assertThat(context).hasBean("authorizationServerSecurityFilterChain");
assertThat(context).hasBean("defaultSecurityFilterChain");
assertThat(context).hasBean("registeredClientRepository");
assertThat(context).hasBean("authorizationServerSettings");
assertThat(findFilter(context, OAuth2AuthorizationEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OAuth2TokenEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OAuth2TokenIntrospectionEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OAuth2TokenRevocationEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OAuth2AuthorizationServerMetadataEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OidcProviderConfigurationEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OidcUserInfoEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, BearerTokenAuthenticationFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OidcClientRegistrationEndpointFilter.class, 0)).isNull();
assertThat(findFilter(context, UsernamePasswordAuthenticationFilter.class, 0)).isNull();
assertThat(findFilter(context, DefaultLoginPageGeneratingFilter.class, 1)).isNotNull();
assertThat(findFilter(context, UsernamePasswordAuthenticationFilter.class, 1)).isNotNull();
});
// @formatter:on
.withPropertyValues(CLIENT_PREFIX + ".foo.registration.client-id=abcd",
CLIENT_PREFIX + ".foo.registration.client-secret=secret",
CLIENT_PREFIX + ".foo.registration.client-authentication-methods=client_secret_basic",
CLIENT_PREFIX + ".foo.registration.authorization-grant-types=client_credentials",
CLIENT_PREFIX + ".foo.registration.scopes=test")
.run((context) -> {
assertThat(context).hasBean("authorizationServerSecurityFilterChain");
assertThat(context).hasBean("defaultSecurityFilterChain");
assertThat(context).hasBean("registeredClientRepository");
assertThat(context).hasBean("authorizationServerSettings");
assertThat(findFilter(context, OAuth2AuthorizationEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OAuth2TokenEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OAuth2TokenIntrospectionEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OAuth2TokenRevocationEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OAuth2AuthorizationServerMetadataEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OidcProviderConfigurationEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OidcUserInfoEndpointFilter.class, 0)).isNotNull();
assertThat(findFilter(context, BearerTokenAuthenticationFilter.class, 0)).isNotNull();
assertThat(findFilter(context, OidcClientRegistrationEndpointFilter.class, 0)).isNull();
assertThat(findFilter(context, UsernamePasswordAuthenticationFilter.class, 0)).isNull();
assertThat(findFilter(context, DefaultLoginPageGeneratingFilter.class, 1)).isNotNull();
assertThat(findFilter(context, UsernamePasswordAuthenticationFilter.class, 1)).isNotNull();
});
}
@Test
void securityFilterChainsBackOffWhenSecurityFilterChainBeanPresent() {
// @formatter:off
this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfiguration.class,
TestOAuth2AuthorizationServerConfiguration.class)
.withPropertyValues(
CLIENT_PREFIX + ".foo.registration.client-id=abcd",
CLIENT_PREFIX + ".foo.registration.client-secret=secret",
CLIENT_PREFIX + ".foo.registration.client-authentication-methods=client_secret_basic",
CLIENT_PREFIX + ".foo.registration.authorization-grant-types=client_credentials",
CLIENT_PREFIX + ".foo.registration.scopes=test")
.run((context) -> {
assertThat(context).hasBean("authServerSecurityFilterChain");
assertThat(context).doesNotHaveBean("authorizationServerSecurityFilterChain");
assertThat(context).hasBean("securityFilterChain");
assertThat(context).doesNotHaveBean("defaultSecurityFilterChain");
assertThat(context).hasBean("registeredClientRepository");
assertThat(context).hasBean("authorizationServerSettings");
assertThat(findFilter(context, BearerTokenAuthenticationFilter.class, 0)).isNull();
assertThat(findFilter(context, UsernamePasswordAuthenticationFilter.class, 1)).isNull();
});
// @formatter:on
this.contextRunner
.withUserConfiguration(TestSecurityFilterChainConfiguration.class,
TestOAuth2AuthorizationServerConfiguration.class)
.withPropertyValues(CLIENT_PREFIX + ".foo.registration.client-id=abcd",
CLIENT_PREFIX + ".foo.registration.client-secret=secret",
CLIENT_PREFIX + ".foo.registration.client-authentication-methods=client_secret_basic",
CLIENT_PREFIX + ".foo.registration.authorization-grant-types=client_credentials",
CLIENT_PREFIX + ".foo.registration.scopes=test")
.run((context) -> {
assertThat(context).hasBean("authServerSecurityFilterChain");
assertThat(context).doesNotHaveBean("authorizationServerSecurityFilterChain");
assertThat(context).hasBean("securityFilterChain");
assertThat(context).doesNotHaveBean("defaultSecurityFilterChain");
assertThat(context).hasBean("registeredClientRepository");
assertThat(context).hasBean("authorizationServerSettings");
assertThat(findFilter(context, BearerTokenAuthenticationFilter.class, 0)).isNull();
assertThat(findFilter(context, UsernamePasswordAuthenticationFilter.class, 1)).isNull();
});
}
private Filter findFilter(AssertableApplicationContext context, Class<? extends Filter> filter,
private Filter findFilter(AssertableWebApplicationContext context, Class<? extends Filter> filter,
int filterChainIndex) {
FilterChainProxy filterChain = (FilterChainProxy) context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
List<SecurityFilterChain> filterChains = filterChain.getFilterChains();
@ -126,12 +127,35 @@ public class OAuth2AuthorizationServerWebSecurityConfigurationTests {
@Configuration
@EnableWebSecurity
@Import({ OAuth2AuthorizationServerPropertiesConfiguration.class,
OAuth2AuthorizationServerWebSecurityConfiguration.class, OAuth2AuthorizationServerJwtConfiguration.class })
@Import({ TestRegisteredClientRepositoryConfiguration.class,
OAuth2AuthorizationServerWebSecurityConfiguration.class,
OAuth2AuthorizationServerJwtAutoConfiguration.class })
static class TestOAuth2AuthorizationServerConfiguration {
}
@Configuration
static class TestRegisteredClientRepositoryConfiguration {
@Bean
RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId("test")
.clientId("abcd")
.clientSecret("secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.scope("test")
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
@Bean
AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().issuer("https://example.com").build();
}
}
@Configuration
@EnableWebSecurity
static class TestSecurityFilterChainConfiguration {

@ -1336,7 +1336,7 @@ bom {
]
}
}
library("Spring Authorization Server", "1.1.0-M1") {
library("Spring Authorization Server", "1.1.0-M2") {
group("org.springframework.security") {
modules = [
"spring-security-oauth2-authorization-server"

@ -102,18 +102,14 @@ class SampleOAuth2AuthorizationServerApplicationTests {
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("messaging-client", "secret");
HttpEntity<Object> request = new HttpEntity<>(headers);
// @formatter:off
String requestUri = UriComponentsBuilder.fromUriString("/token")
.queryParam(OAuth2ParameterNames.CLIENT_ID, "messaging-client")
.queryParam(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
.queryParam(OAuth2ParameterNames.SCOPE, "message.read+message.write")
.toUriString();
// @formatter:on
.queryParam(OAuth2ParameterNames.CLIENT_ID, "messaging-client")
.queryParam(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
.queryParam(OAuth2ParameterNames.SCOPE, "message.read+message.write")
.toUriString();
ResponseEntity<Map<String, Object>> entity = this.restTemplate.exchange(requestUri, HttpMethod.POST, request,
MAP_TYPE_REFERENCE);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
Map<String, Object> tokenResponse = Objects.requireNonNull(entity.getBody());
assertThat(tokenResponse.get(OAuth2ParameterNames.ACCESS_TOKEN)).isNotNull();
assertThat(tokenResponse.get(OAuth2ParameterNames.EXPIRES_IN)).isNotNull();

Loading…
Cancel
Save