Restructure OAuth2 client auto-configuration
Previously, OAuth2 client auto-configuration was managed by a single class: - OAuth2ClientAutoConfiguration for servlet apps - ReactiveOAuth2ClientAutoConfiguration for reactive apps OAuth2ClientAutoConfiguration being for servlet apps meant that a blocking OAuth2 client was not availabile in a non-web application. The auto-configuration classes did two things: - Auto-configured beans that are specific to server-side web security that uses an OAuth2 client - Auto-configured OAuth2 client beans that may be used client- or server-side Combining these two things into a single auto-configuration class meant that you could not choose to use one or the other. For example, you may want to make use of an OAuth2 client in a web application without also using OAuth2 client-based web security. This commit restructures the auto-configuration to address these problems. There are now two auto-configurations for non-reactive apps: - OAuth2ClientAutoConfiguration - OAuth2ClientWebSecurityAutoConfiguration and two auto-configurations for reactive apps: - ReactiveOAuth2ClientAutoConfiguration - ReactiveOAuth2ClientWebSecurityAutoConfiguration This separation allows one to be used without the other. Furthermore, the conditions have been updated so that, for example, the blocking OAuth2 client is available in a non-web application. Closes gh-40997 Closes gh-44906 Co-authored-by: Moritz Halbritter <moritz.halbritter@broadcom.com>
This commit is contained in:
@@ -28,7 +28,7 @@ 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.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientWebSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration;
|
||||
@@ -57,7 +57,7 @@ import static org.springframework.security.config.Customizer.withDefaults;
|
||||
*/
|
||||
@AutoConfiguration(before = ReactiveSecurityAutoConfiguration.class,
|
||||
after = { HealthEndpointAutoConfiguration.class, InfoEndpointAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, ReactiveOAuth2ClientAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, ReactiveOAuth2ClientWebSecurityAutoConfiguration.class,
|
||||
ReactiveOAuth2ResourceServerAutoConfiguration.class,
|
||||
ReactiveUserDetailsServiceAutoConfiguration.class })
|
||||
@ConditionalOnClass({ EnableWebFluxSecurity.class, WebFilterChainProxy.class })
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -26,7 +26,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.security.ConditionalOnDefaultWebSecurity;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientWebSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
@@ -53,7 +53,7 @@ import static org.springframework.security.config.Customizer.withDefaults;
|
||||
*/
|
||||
@AutoConfiguration(before = SecurityAutoConfiguration.class,
|
||||
after = { HealthEndpointAutoConfiguration.class, InfoEndpointAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, OAuth2ClientAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, OAuth2ClientWebSecurityAutoConfiguration.class,
|
||||
OAuth2ResourceServerAutoConfiguration.class, Saml2RelyingPartyAutoConfiguration.class })
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@ConditionalOnDefaultWebSecurity
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.client;
|
||||
|
||||
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.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.NoneNestedConditions;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration.NonReactiveWebApplicationCondition;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for OAuth client support.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @since 3.5.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@Conditional(NonReactiveWebApplicationCondition.class)
|
||||
@ConditionalOnClass(ClientRegistration.class)
|
||||
@Import({ OAuth2ClientConfigurations.ClientRegistrationRepositoryConfiguration.class,
|
||||
OAuth2ClientConfigurations.OAuth2AuthorizedClientServiceConfiguration.class })
|
||||
public class OAuth2ClientAutoConfiguration {
|
||||
|
||||
static class NonReactiveWebApplicationCondition extends NoneNestedConditions {
|
||||
|
||||
NonReactiveWebApplicationCondition() {
|
||||
super(ConfigurationPhase.PARSE_CONFIGURATION);
|
||||
}
|
||||
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||
static class ReactiveWebApplicationCondition {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,39 +14,56 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client.servlet;
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.ConditionalOnOAuth2ClientRegistrationProperties;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesMapper;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||
|
||||
/**
|
||||
* {@link Configuration @Configuration} used to map {@link OAuth2ClientProperties} to
|
||||
* client registrations.
|
||||
* Configurations related to auto-configuration of OAuth2 client support.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(OAuth2ClientProperties.class)
|
||||
@ConditionalOnOAuth2ClientRegistrationProperties
|
||||
class OAuth2ClientRegistrationRepositoryConfiguration {
|
||||
class OAuth2ClientConfigurations {
|
||||
|
||||
@Bean
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnOAuth2ClientRegistrationProperties
|
||||
@EnableConfigurationProperties(OAuth2ClientProperties.class)
|
||||
@ConditionalOnMissingBean(ClientRegistrationRepository.class)
|
||||
InMemoryClientRegistrationRepository clientRegistrationRepository(OAuth2ClientProperties properties) {
|
||||
List<ClientRegistration> registrations = new ArrayList<>(
|
||||
new OAuth2ClientPropertiesMapper(properties).asClientRegistrations().values());
|
||||
return new InMemoryClientRegistrationRepository(registrations);
|
||||
static class ClientRegistrationRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
InMemoryClientRegistrationRepository clientRegistrationRepository(OAuth2ClientProperties properties) {
|
||||
List<ClientRegistration> registrations = new ArrayList<>(
|
||||
new OAuth2ClientPropertiesMapper(properties).asClientRegistrations().values());
|
||||
return new InMemoryClientRegistrationRepository(registrations);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(ClientRegistrationRepository.class)
|
||||
static class OAuth2AuthorizedClientServiceConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
OAuth2AuthorizedClientService authorizedClientService(
|
||||
ClientRegistrationRepository clientRegistrationRepository) {
|
||||
return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -23,12 +23,8 @@ 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.condition.NoneNestedConditions;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
|
||||
/**
|
||||
@@ -38,12 +34,11 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
|
||||
* @author Madhura Bhave
|
||||
* @since 2.1.0
|
||||
*/
|
||||
@AutoConfiguration(before = ReactiveSecurityAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(OAuth2ClientProperties.class)
|
||||
@AutoConfiguration
|
||||
@Conditional(ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition.class)
|
||||
@ConditionalOnClass({ Flux.class, EnableWebFluxSecurity.class, ClientRegistration.class })
|
||||
@ConditionalOnClass({ Flux.class, ClientRegistration.class })
|
||||
@Import({ ReactiveOAuth2ClientConfigurations.ReactiveClientRegistrationRepositoryConfiguration.class,
|
||||
ReactiveOAuth2ClientConfigurations.ReactiveOAuth2ClientConfiguration.class })
|
||||
ReactiveOAuth2ClientConfigurations.ReactiveOAuth2AuthorizedClientServiceConfiguration.class })
|
||||
public class ReactiveOAuth2ClientAutoConfiguration {
|
||||
|
||||
static class NonServletApplicationCondition extends NoneNestedConditions {
|
||||
|
||||
@@ -21,23 +21,17 @@ import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.ConditionalOnOAuth2ClientRegistrationProperties;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesMapper;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
|
||||
/**
|
||||
* Reactive OAuth2 Client configurations.
|
||||
@@ -47,12 +41,14 @@ import static org.springframework.security.config.Customizer.withDefaults;
|
||||
class ReactiveOAuth2ClientConfigurations {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(OAuth2ClientProperties.class)
|
||||
@ConditionalOnOAuth2ClientRegistrationProperties
|
||||
@ConditionalOnMissingBean(ReactiveClientRegistrationRepository.class)
|
||||
static class ReactiveClientRegistrationRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
InMemoryReactiveClientRegistrationRepository clientRegistrationRepository(OAuth2ClientProperties properties) {
|
||||
InMemoryReactiveClientRegistrationRepository reactiveClientRegistrationRepository(
|
||||
OAuth2ClientProperties properties) {
|
||||
List<ClientRegistration> registrations = new ArrayList<>(
|
||||
new OAuth2ClientPropertiesMapper(properties).asClientRegistrations().values());
|
||||
return new InMemoryReactiveClientRegistrationRepository(registrations);
|
||||
@@ -62,37 +58,15 @@ class ReactiveOAuth2ClientConfigurations {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(ReactiveClientRegistrationRepository.class)
|
||||
static class ReactiveOAuth2ClientConfiguration {
|
||||
static class ReactiveOAuth2AuthorizedClientServiceConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ReactiveOAuth2AuthorizedClientService authorizedClientService(
|
||||
ReactiveOAuth2AuthorizedClientService reactiveAuthorizedClientService(
|
||||
ReactiveClientRegistrationRepository clientRegistrationRepository) {
|
||||
return new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ServerOAuth2AuthorizedClientRepository authorizedClientRepository(
|
||||
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
|
||||
return new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||
static class SecurityWebFilterChainConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||
http.authorizeExchange((exchange) -> exchange.anyExchange().authenticated());
|
||||
http.oauth2Login(withDefaults());
|
||||
http.oauth2Client(withDefaults());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.client.reactive;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
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.reactive.ReactiveSecurityAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.web.server.AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
|
||||
/**
|
||||
* Auto-configuration for reactive web security that uses an OAuth 2 client.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 3.5.0
|
||||
*/
|
||||
@AutoConfiguration(before = ReactiveSecurityAutoConfiguration.class,
|
||||
after = ReactiveOAuth2ClientAutoConfiguration.class)
|
||||
@ConditionalOnClass({ Flux.class, EnableWebFluxSecurity.class, ServerOAuth2AuthorizedClientRepository.class })
|
||||
@ConditionalOnBean(ReactiveOAuth2AuthorizedClientService.class)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||
public class ReactiveOAuth2ClientWebSecurityAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ServerOAuth2AuthorizedClientRepository authorizedClientRepository(
|
||||
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
|
||||
return new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||
http.authorizeExchange((exchange) -> exchange.anyExchange().authenticated());
|
||||
http.oauth2Login(withDefaults());
|
||||
http.oauth2Client(withDefaults());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -16,14 +16,7 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client.servlet;
|
||||
|
||||
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.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for OAuth client support.
|
||||
@@ -31,11 +24,10 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
* @deprecated since 3.5.0 for removal in 4.0.0 in favor of
|
||||
* {@link org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration}
|
||||
*/
|
||||
@AutoConfiguration(before = SecurityAutoConfiguration.class)
|
||||
@ConditionalOnClass({ EnableWebSecurity.class, ClientRegistration.class })
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@Import({ OAuth2ClientRegistrationRepositoryConfiguration.class, OAuth2WebSecurityConfiguration.class })
|
||||
@Deprecated(since = "3.5.0", forRemoval = true)
|
||||
public class OAuth2ClientAutoConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -16,15 +16,19 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client.servlet;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
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.ConditionalOnDefaultWebSecurity;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
@@ -32,20 +36,18 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
|
||||
/**
|
||||
* {@link SecurityFilterChain} to add OAuth client support.
|
||||
* Auto-configuration for web security that uses an OAuth 2 client.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 3.5.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(ClientRegistrationRepository.class)
|
||||
class OAuth2WebSecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
OAuth2AuthorizedClientService authorizedClientService(ClientRegistrationRepository clientRegistrationRepository) {
|
||||
return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
|
||||
}
|
||||
@AutoConfiguration(before = SecurityAutoConfiguration.class, after = OAuth2ClientAutoConfiguration.class)
|
||||
@ConditionalOnClass({ EnableWebSecurity.class, OAuth2AuthorizedClientRepository.class })
|
||||
@ConditionalOnBean(OAuth2AuthorizedClientService.class)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
public class OAuth2ClientWebSecurityAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@@ -115,8 +115,10 @@ org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfi
|
||||
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientWebSecurityAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientWebSecurityAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.server.servlet.OAuth2AuthorizationServerAutoConfiguration
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration=org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -17,8 +17,6 @@
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client.reactive;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
@@ -26,34 +24,16 @@ import reactor.core.publisher.Flux;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.OAuth2AuthorizationCodeGrantWebFilter;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.authentication.OAuth2LoginAuthenticationWebFilter;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link ReactiveOAuth2ClientAutoConfiguration}.
|
||||
@@ -62,12 +42,12 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
class ReactiveOAuth2ClientAutoConfigurationTests {
|
||||
|
||||
private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration";
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ClientAutoConfiguration.class,
|
||||
ReactiveSecurityAutoConfiguration.class));
|
||||
|
||||
private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration";
|
||||
|
||||
@Test
|
||||
void autoConfigurationShouldBackOffForServletEnvironments() {
|
||||
new WebApplicationContextRunner()
|
||||
@@ -76,16 +56,20 @@ class ReactiveOAuth2ClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void clientRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ClientRegistrationRepository.class));
|
||||
void beansShouldNotBeCreatedWhenPropertiesAbsent() {
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(ReactiveClientRegistrationRepository.class)
|
||||
.doesNotHaveBean(ReactiveOAuth2AuthorizedClientService.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void clientRegistrationRepositoryBeanShouldBeCreatedWhenPropertiesPresent() {
|
||||
void beansAreCreatedWhenPropertiesPresent() {
|
||||
this.contextRunner
|
||||
.withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd",
|
||||
REGISTRATION_PREFIX + ".foo.client-secret=secret", REGISTRATION_PREFIX + ".foo.provider=github")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ReactiveClientRegistrationRepository.class);
|
||||
assertThat(context).hasSingleBean(ReactiveOAuth2AuthorizedClientService.class);
|
||||
ReactiveClientRegistrationRepository repository = context
|
||||
.getBean(ReactiveClientRegistrationRepository.class);
|
||||
ClientRegistration registration = repository.findByRegistrationId("foo").block(Duration.ofSeconds(30));
|
||||
@@ -95,24 +79,10 @@ class ReactiveOAuth2ClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void authorizedClientServiceAndRepositoryBeansAreConditionalOnClientRegistrationRepository() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(ReactiveOAuth2AuthorizedClientService.class);
|
||||
assertThat(context).doesNotHaveBean(ServerOAuth2AuthorizedClientRepository.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configurationRegistersAuthorizedClientServiceAndRepositoryBeans() {
|
||||
this.contextRunner.withUserConfiguration(ReactiveClientRepositoryConfiguration.class).run((context) -> {
|
||||
assertThat(context).hasSingleBean(InMemoryReactiveOAuth2AuthorizedClientService.class);
|
||||
assertThat(context).hasSingleBean(AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void authorizedClientServiceBeanIsConditionalOnMissingBean() {
|
||||
this.contextRunner.withUserConfiguration(ReactiveOAuth2AuthorizedClientRepositoryConfiguration.class)
|
||||
void clientServiceBeanIsConditionalOnMissingBean() {
|
||||
this.contextRunner
|
||||
.withBean("testAuthorizedClientService", ReactiveOAuth2AuthorizedClientService.class,
|
||||
() -> mock(ReactiveOAuth2AuthorizedClientService.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ReactiveOAuth2AuthorizedClientService.class);
|
||||
assertThat(context).hasBean("testAuthorizedClientService");
|
||||
@@ -120,43 +90,11 @@ class ReactiveOAuth2ClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void authorizedClientRepositoryBeanIsConditionalOnAuthorizedClientService() {
|
||||
void clientServiceBeanIsCreatedWithUserDefinedClientRegistrationRepository() {
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(ServerOAuth2AuthorizedClientRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configurationRegistersAuthorizedClientRepositoryBean() {
|
||||
this.contextRunner.withUserConfiguration(ReactiveOAuth2AuthorizedClientServiceConfiguration.class)
|
||||
.run((context) -> assertThat(context)
|
||||
.hasSingleBean(AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void authorizedClientRepositoryBeanIsConditionalOnMissingBean() {
|
||||
this.contextRunner.withUserConfiguration(ReactiveOAuth2AuthorizedClientRepositoryConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ServerOAuth2AuthorizedClientRepository.class);
|
||||
assertThat(context).hasBean("testAuthorizedClientRepository");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityWebFilterChainBeanConditionalOnWebApplication() {
|
||||
this.contextRunner.withUserConfiguration(ReactiveOAuth2AuthorizedClientRepositoryConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(SecurityWebFilterChain.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configurationRegistersSecurityWebFilterChainBean() { // gh-17949
|
||||
new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ClientAutoConfiguration.class))
|
||||
.withUserConfiguration(ReactiveOAuth2AuthorizedClientServiceConfiguration.class,
|
||||
ServerHttpSecurityConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(hasFilter(context, OAuth2LoginAuthenticationWebFilter.class)).isTrue();
|
||||
assertThat(hasFilter(context, OAuth2AuthorizationCodeGrantWebFilter.class)).isTrue();
|
||||
});
|
||||
.withBean(InMemoryReactiveClientRegistrationRepository.class,
|
||||
() -> new InMemoryReactiveClientRegistrationRepository(getClientRegistration("test", "test")))
|
||||
.run((context) -> assertThat(context).hasSingleBean(ReactiveOAuth2AuthorizedClientService.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -164,11 +102,6 @@ class ReactiveOAuth2ClientAutoConfigurationTests {
|
||||
assertWhenClassNotPresent(Flux.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigurationConditionalOnClassEnableWebFluxSecurity() {
|
||||
assertWhenClassNotPresent(EnableWebFluxSecurity.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigurationConditionalOnClassClientRegistration() {
|
||||
assertWhenClassNotPresent(ClientRegistration.class);
|
||||
@@ -182,86 +115,21 @@ class ReactiveOAuth2ClientAutoConfigurationTests {
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(ReactiveOAuth2ClientAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean hasFilter(AssertableReactiveWebApplicationContext context, Class<? extends WebFilter> filter) {
|
||||
SecurityWebFilterChain filterChain = (SecurityWebFilterChain) context
|
||||
.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
List<WebFilter> filters = (List<WebFilter>) ReflectionTestUtils.getField(filterChain, "filters");
|
||||
return filters.stream().anyMatch(filter::isInstance);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class ReactiveClientRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
ReactiveClientRegistrationRepository clientRegistrationRepository() {
|
||||
List<ClientRegistration> registrations = new ArrayList<>();
|
||||
registrations.add(getClientRegistration("first", "https://user-info-uri.com"));
|
||||
registrations.add(getClientRegistration("second", "https://other-user-info"));
|
||||
return new InMemoryReactiveClientRegistrationRepository(registrations);
|
||||
}
|
||||
|
||||
private ClientRegistration getClientRegistration(String id, String userInfoUri) {
|
||||
ClientRegistration.Builder builder = ClientRegistration.withRegistrationId(id);
|
||||
builder.clientName("foo")
|
||||
.clientId("foo")
|
||||
.clientAuthenticationMethod(
|
||||
org.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.scope("read")
|
||||
.clientSecret("secret")
|
||||
.redirectUri("https://redirect-uri.com")
|
||||
.authorizationUri("https://authorization-uri.com")
|
||||
.tokenUri("https://token-uri.com")
|
||||
.userInfoUri(userInfoUri)
|
||||
.userNameAttributeName("login");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ReactiveClientRepositoryConfiguration.class)
|
||||
static class ReactiveOAuth2AuthorizedClientServiceConfiguration {
|
||||
|
||||
@Bean
|
||||
ReactiveOAuth2AuthorizedClientService testAuthorizedClientService(
|
||||
ReactiveClientRegistrationRepository clientRegistrationRepository) {
|
||||
return new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ReactiveOAuth2AuthorizedClientServiceConfiguration.class)
|
||||
static class ReactiveOAuth2AuthorizedClientRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
ServerOAuth2AuthorizedClientRepository testAuthorizedClientRepository(
|
||||
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
|
||||
return new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class ServerHttpSecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
ServerHttpSecurity http() {
|
||||
TestServerHttpSecurity httpSecurity = new TestServerHttpSecurity();
|
||||
return httpSecurity;
|
||||
}
|
||||
|
||||
static class TestServerHttpSecurity extends ServerHttpSecurity implements ApplicationContextAware {
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
super.setApplicationContext(applicationContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ClientRegistration getClientRegistration(String id, String userInfoUri) {
|
||||
ClientRegistration.Builder builder = ClientRegistration.withRegistrationId(id);
|
||||
builder.clientName("foo")
|
||||
.clientId("foo")
|
||||
.clientAuthenticationMethod(
|
||||
org.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.scope("read")
|
||||
.clientSecret("secret")
|
||||
.redirectUri("https://redirect-uri.com")
|
||||
.authorizationUri("https://authorization-uri.com")
|
||||
.tokenUri("https://token-uri.com")
|
||||
.userInfoUri(userInfoUri)
|
||||
.userNameAttributeName("login");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.client.reactive;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
|
||||
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.OAuth2AuthorizationCodeGrantWebFilter;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.authentication.OAuth2LoginAuthenticationWebFilter;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ReactiveOAuth2ClientWebSecurityAutoConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ReactiveOAuth2ClientWebSecurityAutoConfigurationTests {
|
||||
|
||||
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ClientWebSecurityAutoConfiguration.class,
|
||||
ReactiveSecurityAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void autoConfigurationShouldBackOffForServletEnvironments() {
|
||||
new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ClientWebSecurityAutoConfiguration.class))
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(ReactiveOAuth2ClientWebSecurityAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigurationIsConditionalOnAuthorizedClientService() {
|
||||
this.contextRunner.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(ReactiveOAuth2ClientWebSecurityAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configurationRegistersAuthorizedClientRepositoryBean() {
|
||||
this.contextRunner.withUserConfiguration(ReactiveOAuth2AuthorizedClientServiceConfiguration.class)
|
||||
.run((context) -> assertThat(context)
|
||||
.hasSingleBean(AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void authorizedClientRepositoryBeanIsConditionalOnMissingBean() {
|
||||
this.contextRunner.withUserConfiguration(ReactiveOAuth2AuthorizedClientRepositoryConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ServerOAuth2AuthorizedClientRepository.class);
|
||||
assertThat(context).hasBean("testAuthorizedClientRepository");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configurationRegistersSecurityWebFilterChainBean() { // gh-17949
|
||||
this.contextRunner
|
||||
.withUserConfiguration(ReactiveOAuth2AuthorizedClientServiceConfiguration.class,
|
||||
ServerHttpSecurityConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(hasFilter(context, OAuth2LoginAuthenticationWebFilter.class)).isTrue();
|
||||
assertThat(hasFilter(context, OAuth2AuthorizationCodeGrantWebFilter.class)).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityWebFilterChainBeanConditionalOnWebApplication() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ClientWebSecurityAutoConfiguration.class,
|
||||
ReactiveSecurityAutoConfiguration.class))
|
||||
.withUserConfiguration(ReactiveOAuth2AuthorizedClientRepositoryConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(SecurityWebFilterChain.class));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean hasFilter(AssertableReactiveWebApplicationContext context, Class<? extends WebFilter> filter) {
|
||||
SecurityWebFilterChain filterChain = (SecurityWebFilterChain) context
|
||||
.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
List<WebFilter> filters = (List<WebFilter>) ReflectionTestUtils.getField(filterChain, "filters");
|
||||
return filters.stream().anyMatch(filter::isInstance);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ReactiveClientRepositoryConfiguration.class)
|
||||
static class ReactiveOAuth2AuthorizedClientServiceConfiguration {
|
||||
|
||||
@Bean
|
||||
InMemoryReactiveOAuth2AuthorizedClientService testAuthorizedClientService(
|
||||
ReactiveClientRegistrationRepository clientRegistrationRepository) {
|
||||
return new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ReactiveOAuth2AuthorizedClientServiceConfiguration.class)
|
||||
static class ReactiveOAuth2AuthorizedClientRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
ServerOAuth2AuthorizedClientRepository testAuthorizedClientRepository(
|
||||
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
|
||||
return new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class ReactiveClientRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
ReactiveClientRegistrationRepository clientRegistrationRepository() {
|
||||
List<ClientRegistration> registrations = new ArrayList<>();
|
||||
registrations.add(getClientRegistration("first", "https://user-info-uri.com"));
|
||||
registrations.add(getClientRegistration("second", "https://other-user-info"));
|
||||
return new InMemoryReactiveClientRegistrationRepository(registrations);
|
||||
}
|
||||
|
||||
private ClientRegistration getClientRegistration(String id, String userInfoUri) {
|
||||
ClientRegistration.Builder builder = ClientRegistration.withRegistrationId(id);
|
||||
builder.clientName("foo")
|
||||
.clientId("foo")
|
||||
.clientAuthenticationMethod(
|
||||
org.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.scope("read")
|
||||
.clientSecret("secret")
|
||||
.redirectUri("https://redirect-uri.com")
|
||||
.authorizationUri("https://authorization-uri.com")
|
||||
.tokenUri("https://token-uri.com")
|
||||
.userInfoUri(userInfoUri)
|
||||
.userNameAttributeName("login");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class ServerHttpSecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
ServerHttpSecurity http() {
|
||||
TestServerHttpSecurity httpSecurity = new TestServerHttpSecurity();
|
||||
return httpSecurity;
|
||||
}
|
||||
|
||||
static class TestServerHttpSecurity extends ServerHttpSecurity implements ApplicationContextAware {
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
super.setApplicationContext(applicationContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.client.servlet;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2ClientAutoConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class OAuth2ClientAutoConfigurationTests {
|
||||
|
||||
private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration";
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(OAuth2ClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void beansShouldNotBeCreatedWhenPropertiesAbsent() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ClientRegistrationRepository.class)
|
||||
.doesNotHaveBean(OAuth2AuthorizedClientService.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void beansAreCreatedWhenPropertiesPresent() {
|
||||
this.contextRunner
|
||||
.withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd",
|
||||
REGISTRATION_PREFIX + ".foo.client-secret=secret", REGISTRATION_PREFIX + ".foo.provider=github")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ClientRegistrationRepository.class);
|
||||
assertThat(context).hasSingleBean(OAuth2AuthorizedClientService.class);
|
||||
ClientRegistrationRepository repository = context.getBean(ClientRegistrationRepository.class);
|
||||
ClientRegistration registration = repository.findByRegistrationId("foo");
|
||||
assertThat(registration).isNotNull();
|
||||
assertThat(registration.getClientSecret()).isEqualTo("secret");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void clientServiceBeanIsConditionalOnMissingBean() {
|
||||
this.contextRunner
|
||||
.withBean("testAuthorizedClientService", OAuth2AuthorizedClientService.class,
|
||||
() -> mock(OAuth2AuthorizedClientService.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(OAuth2AuthorizedClientService.class);
|
||||
assertThat(context).hasBean("testAuthorizedClientService");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void clientServiceBeanIsCreatedWithUserDefinedClientRegistrationRepository() {
|
||||
this.contextRunner
|
||||
.withBean(ClientRegistrationRepository.class,
|
||||
() -> new InMemoryClientRegistrationRepository(getClientRegistration("test", "test")))
|
||||
.run((context) -> assertThat(context).hasSingleBean(OAuth2AuthorizedClientService.class));
|
||||
}
|
||||
|
||||
private ClientRegistration getClientRegistration(String id, String userInfoUri) {
|
||||
ClientRegistration.Builder builder = ClientRegistration.withRegistrationId(id);
|
||||
builder.clientName("foo")
|
||||
.clientId("foo")
|
||||
.clientAuthenticationMethod(
|
||||
org.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.scope("read")
|
||||
.clientSecret("secret")
|
||||
.redirectUri("https://redirect-uri.com")
|
||||
.authorizationUri("https://authorization-uri.com")
|
||||
.tokenUri("https://token-uri.com")
|
||||
.userInfoUri(userInfoUri)
|
||||
.userNameAttributeName("login");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +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.client.servlet;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2ClientRegistrationRepositoryConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class OAuth2ClientRegistrationRepositoryConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
|
||||
|
||||
private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration";
|
||||
|
||||
@Test
|
||||
void clientRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() {
|
||||
this.contextRunner.withUserConfiguration(OAuth2ClientRegistrationRepositoryConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(ClientRegistrationRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void clientRegistrationRepositoryBeanShouldBeCreatedWhenPropertiesPresent() {
|
||||
this.contextRunner.withUserConfiguration(OAuth2ClientRegistrationRepositoryConfiguration.class)
|
||||
.withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd",
|
||||
REGISTRATION_PREFIX + ".foo.client-secret=secret", REGISTRATION_PREFIX + ".foo.provider=github")
|
||||
.run((context) -> {
|
||||
ClientRegistrationRepository repository = context.getBean(ClientRegistrationRepository.class);
|
||||
ClientRegistration registration = repository.findByRegistrationId("foo");
|
||||
assertThat(registration).isNotNull();
|
||||
assertThat(registration.getClientSecret()).isEqualTo("secret");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -53,77 +53,74 @@ import org.springframework.web.filter.CompositeFilter;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2WebSecurityConfiguration}.
|
||||
* Tests for {@link OAuth2ClientWebSecurityAutoConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class OAuth2WebSecurityConfigurationTests {
|
||||
class OAuth2ClientWebSecurityAutoConfigurationTests {
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner();
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(OAuth2ClientWebSecurityAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void securityConfigurerConfiguresOAuth2Login() {
|
||||
void autoConfigurationIsConditionalOnAuthorizedClientService() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(ClientRegistrationRepositoryConfiguration.class,
|
||||
OAuth2WebSecurityConfiguration.class)
|
||||
.run((context) -> {
|
||||
ClientRegistrationRepository expected = context.getBean(ClientRegistrationRepository.class);
|
||||
ClientRegistrationRepository actual = (ClientRegistrationRepository) ReflectionTestUtils.getField(
|
||||
getSecurityFilters(context, OAuth2LoginAuthenticationFilter.class).get(0),
|
||||
"clientRegistrationRepository");
|
||||
assertThat(isEqual(expected.findByRegistrationId("first"), actual.findByRegistrationId("first")))
|
||||
.isTrue();
|
||||
assertThat(isEqual(expected.findByRegistrationId("second"), actual.findByRegistrationId("second")))
|
||||
.isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityConfigurerConfiguresAuthorizationCode() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(ClientRegistrationRepositoryConfiguration.class,
|
||||
OAuth2WebSecurityConfiguration.class)
|
||||
.run((context) -> {
|
||||
ClientRegistrationRepository expected = context.getBean(ClientRegistrationRepository.class);
|
||||
ClientRegistrationRepository actual = (ClientRegistrationRepository) ReflectionTestUtils.getField(
|
||||
getSecurityFilters(context, OAuth2AuthorizationCodeGrantFilter.class).get(0),
|
||||
"clientRegistrationRepository");
|
||||
assertThat(isEqual(expected.findByRegistrationId("first"), actual.findByRegistrationId("first")))
|
||||
.isTrue();
|
||||
assertThat(isEqual(expected.findByRegistrationId("second"), actual.findByRegistrationId("second")))
|
||||
.isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityConfigurerBacksOffWhenClientRegistrationBeanAbsent() {
|
||||
this.contextRunner.withUserConfiguration(TestConfig.class, OAuth2WebSecurityConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(getSecurityFilters(context, OAuth2LoginAuthenticationFilter.class)).isEmpty();
|
||||
assertThat(getSecurityFilters(context, OAuth2AuthorizationCodeGrantFilter.class)).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configurationRegistersAuthorizedClientServiceBean() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(ClientRegistrationRepositoryConfiguration.class,
|
||||
OAuth2WebSecurityConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(OAuth2AuthorizedClientService.class));
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(OAuth2ClientWebSecurityAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configurationRegistersAuthorizedClientRepositoryBean() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(ClientRegistrationRepositoryConfiguration.class,
|
||||
OAuth2WebSecurityConfiguration.class)
|
||||
this.contextRunner.withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(OAuth2AuthorizedClientRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void authorizedClientRepositoryBeanIsConditionalOnMissingBean() {
|
||||
this.contextRunner.withUserConfiguration(OAuth2AuthorizedClientRepositoryConfiguration.class).run((context) -> {
|
||||
assertThat(context).hasSingleBean(OAuth2AuthorizedClientRepository.class);
|
||||
assertThat(context).hasBean("testAuthorizedClientRepository");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityConfigurerConfiguresOAuth2Login() {
|
||||
this.contextRunner.withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class).run((context) -> {
|
||||
ClientRegistrationRepository expected = context.getBean(ClientRegistrationRepository.class);
|
||||
ClientRegistrationRepository actual = (ClientRegistrationRepository) ReflectionTestUtils.getField(
|
||||
getSecurityFilters(context, OAuth2LoginAuthenticationFilter.class).get(0),
|
||||
"clientRegistrationRepository");
|
||||
assertThat(isEqual(expected.findByRegistrationId("first"), actual.findByRegistrationId("first"))).isTrue();
|
||||
assertThat(isEqual(expected.findByRegistrationId("second"), actual.findByRegistrationId("second")))
|
||||
.isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityConfigurerConfiguresAuthorizationCode() {
|
||||
this.contextRunner.withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class).run((context) -> {
|
||||
ClientRegistrationRepository expected = context.getBean(ClientRegistrationRepository.class);
|
||||
ClientRegistrationRepository actual = (ClientRegistrationRepository) ReflectionTestUtils.getField(
|
||||
getSecurityFilters(context, OAuth2AuthorizationCodeGrantFilter.class).get(0),
|
||||
"clientRegistrationRepository");
|
||||
assertThat(isEqual(expected.findByRegistrationId("first"), actual.findByRegistrationId("first"))).isTrue();
|
||||
assertThat(isEqual(expected.findByRegistrationId("second"), actual.findByRegistrationId("second")))
|
||||
.isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityConfigurerBacksOffWhenClientRegistrationBeanAbsent() {
|
||||
this.contextRunner.withUserConfiguration(TestConfig.class).run((context) -> {
|
||||
assertThat(getSecurityFilters(context, OAuth2LoginAuthenticationFilter.class)).isEmpty();
|
||||
assertThat(getSecurityFilters(context, OAuth2AuthorizationCodeGrantFilter.class)).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityFilterChainConfigBacksOffWhenOtherSecurityFilterChainBeanPresent() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(WebMvcAutoConfiguration.class))
|
||||
.withUserConfiguration(TestSecurityFilterChainConfiguration.class, OAuth2WebSecurityConfiguration.class)
|
||||
.withUserConfiguration(TestSecurityFilterChainConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(getSecurityFilters(context, OAuth2LoginAuthenticationFilter.class)).isEmpty();
|
||||
assertThat(getSecurityFilters(context, OAuth2AuthorizationCodeGrantFilter.class)).isEmpty();
|
||||
@@ -133,9 +130,7 @@ class OAuth2WebSecurityConfigurationTests {
|
||||
|
||||
@Test
|
||||
void securityFilterChainConfigConditionalOnSecurityFilterChainClass() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(ClientRegistrationRepositoryConfiguration.class,
|
||||
OAuth2WebSecurityConfiguration.class)
|
||||
this.contextRunner.withUserConfiguration(ClientRegistrationRepositoryConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class))
|
||||
.run((context) -> {
|
||||
assertThat(getSecurityFilters(context, OAuth2LoginAuthenticationFilter.class)).isEmpty();
|
||||
@@ -143,28 +138,6 @@ class OAuth2WebSecurityConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void authorizedClientServiceBeanIsConditionalOnMissingBean() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class,
|
||||
OAuth2WebSecurityConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(OAuth2AuthorizedClientService.class);
|
||||
assertThat(context).hasBean("testAuthorizedClientService");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void authorizedClientRepositoryBeanIsConditionalOnMissingBean() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(OAuth2AuthorizedClientRepositoryConfiguration.class,
|
||||
OAuth2WebSecurityConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(OAuth2AuthorizedClientRepository.class);
|
||||
assertThat(context).hasBean("testAuthorizedClientRepository");
|
||||
});
|
||||
}
|
||||
|
||||
private List<Filter> getSecurityFilters(AssertableWebApplicationContext context, Class<? extends Filter> filter) {
|
||||
return getSecurityFilterChain(context).getFilters().stream().filter(filter::isInstance).toList();
|
||||
}
|
||||
@@ -219,6 +192,30 @@ class OAuth2WebSecurityConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ClientRegistrationRepositoryConfiguration.class)
|
||||
static class OAuth2AuthorizedClientServiceConfiguration {
|
||||
|
||||
@Bean
|
||||
InMemoryOAuth2AuthorizedClientService authorizedClientService(
|
||||
ClientRegistrationRepository clientRegistrationRepository) {
|
||||
return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(OAuth2AuthorizedClientServiceConfiguration.class)
|
||||
static class OAuth2AuthorizedClientRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
OAuth2AuthorizedClientRepository testAuthorizedClientRepository(
|
||||
OAuth2AuthorizedClientService authorizedClientService) {
|
||||
return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(TestConfig.class)
|
||||
static class ClientRegistrationRepositoryConfiguration {
|
||||
@@ -251,7 +248,7 @@ class OAuth2WebSecurityConfigurationTests {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ClientRegistrationRepositoryConfiguration.class)
|
||||
@Import(OAuth2AuthorizedClientServiceConfiguration.class)
|
||||
static class TestSecurityFilterChainConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -264,28 +261,4 @@ class OAuth2WebSecurityConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ClientRegistrationRepositoryConfiguration.class)
|
||||
static class OAuth2AuthorizedClientServiceConfiguration {
|
||||
|
||||
@Bean
|
||||
OAuth2AuthorizedClientService testAuthorizedClientService(
|
||||
ClientRegistrationRepository clientRegistrationRepository) {
|
||||
return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ClientRegistrationRepositoryConfiguration.class)
|
||||
static class OAuth2AuthorizedClientRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
OAuth2AuthorizedClientRepository testAuthorizedClientRepository(
|
||||
OAuth2AuthorizedClientService authorizedClientService) {
|
||||
return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
# AutoConfigureWebClient auto-configuration imports
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientWebSecurityAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcAutoConfiguration
|
||||
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebClientAutoConfiguration
|
||||
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebDriverAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientWebSecurityAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -22,7 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration;
|
||||
|
||||
Reference in New Issue
Block a user