mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-15 01:07:30 +08:00
Make security auto-configs back off when SecurityFilterChain present
Closes gh-22739
This commit is contained in:
parent
c9b8a05321
commit
bbbbe8e4d2
@ -19,6 +19,8 @@ package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.info.InfoEndpoint;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
@ -29,28 +31,46 @@ import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAu
|
||||
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;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.WebSecurityEnablerConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Spring Security when actuator is
|
||||
* on the classpath. Specifically, it permits access to the health and info endpoints
|
||||
* while securing everything else.
|
||||
* on the classpath. It allows unauthenticated access to the {@link HealthEndpoint} and
|
||||
* {@link InfoEndpoint}. If the user specifies their own
|
||||
* {@link WebSecurityConfigurerAdapter} or {@link SecurityFilterChain} bean, this will
|
||||
* back-off completely and the user should specify all the bits that they want to
|
||||
* configure as part of the custom security configuration.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.1.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
|
||||
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@AutoConfigureBefore(SecurityAutoConfiguration.class)
|
||||
@AutoConfigureAfter({ HealthEndpointAutoConfiguration.class, InfoEndpointAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, OAuth2ClientAutoConfiguration.class,
|
||||
OAuth2ResourceServerAutoConfiguration.class, Saml2RelyingPartyAutoConfiguration.class })
|
||||
@Import({ ManagementWebSecurityConfigurerAdapter.class, WebSecurityEnablerConfiguration.class })
|
||||
public class ManagementWebSecurityAutoConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class ManagementWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests((requests) -> {
|
||||
requests.requestMatchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)).permitAll();
|
||||
requests.anyRequest().authenticated();
|
||||
});
|
||||
http.formLogin(Customizer.withDefaults());
|
||||
http.httpBasic(Customizer.withDefaults());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.actuate.autoconfigure.security.servlet;
|
||||
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.info.InfoEndpoint;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* The default configuration for web security when the actuator dependency is on the
|
||||
* classpath. It is different from
|
||||
* {@link org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration}
|
||||
* in that it allows unauthenticated access to the {@link HealthEndpoint} and
|
||||
* {@link InfoEndpoint}. If the user specifies their own
|
||||
* {@link WebSecurityConfigurerAdapter}, this will back-off completely and the user should
|
||||
* specify all the bits that they want to configure as part of the custom security
|
||||
* configuration.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class ManagementWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests((requests) -> {
|
||||
requests.requestMatchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)).permitAll();
|
||||
requests.anyRequest().authenticated();
|
||||
});
|
||||
http.formLogin(Customizer.withDefaults());
|
||||
http.httpBasic(Customizer.withDefaults());
|
||||
}
|
||||
|
||||
}
|
@ -30,8 +30,10 @@ import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
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;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
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.http.HttpStatus;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
@ -42,6 +44,7 @@ import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -85,6 +88,15 @@ class ManagementWebSecurityAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigIsConditionalOnSecurityFilterChainClass() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class)).run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(ManagementWebSecurityAutoConfiguration.class);
|
||||
HttpStatus status = getResponseStatus(context, "/actuator/health");
|
||||
assertThat(status).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void usesMatchersBasedOffConfiguredActuatorBasePath() {
|
||||
this.contextRunner.withPropertyValues("management.endpoints.web.base-path=/").run((context) -> {
|
||||
@ -103,11 +115,20 @@ class ManagementWebSecurityAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void backsOffIfSecurityFilterChainBeanIsPresent() {
|
||||
this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class).run((context) -> {
|
||||
assertThat(context.getBeansOfType(SecurityFilterChain.class).size()).isEqualTo(1);
|
||||
assertThat(context.containsBean("testSecurityFilterChain")).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void backOffIfOAuth2ResourceServerAutoConfigurationPresent() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(OAuth2ResourceServerAutoConfiguration.class))
|
||||
.withPropertyValues("spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://authserver")
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(ManagementWebSecurityConfigurerAdapter.class));
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(
|
||||
ManagementWebSecurityAutoConfiguration.ManagementWebSecurityConfigurerAdapter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -118,7 +139,8 @@ class ManagementWebSecurityAutoConfigurationTests {
|
||||
"spring.security.saml2.relyingparty.registration.simplesamlphp.identity-provider.single-sign-on.sign-request=false",
|
||||
"spring.security.saml2.relyingparty.registration.simplesamlphp.identityprovider.entity-id=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php",
|
||||
"spring.security.saml2.relyingparty.registration.simplesamlphp.identityprovider.verification.credentials[0].certificate-location=classpath:saml/certificate-location")
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(ManagementWebSecurityConfigurerAdapter.class));
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(
|
||||
ManagementWebSecurityAutoConfiguration.ManagementWebSecurityConfigurerAdapter.class));
|
||||
}
|
||||
|
||||
private HttpStatus getResponseStatus(AssertableWebApplicationContext context, String path)
|
||||
@ -149,4 +171,15 @@ class ManagementWebSecurityAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TestSecurityFilterChainConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain testSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http.antMatcher("/**").authorizeRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client.servlet;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
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;
|
||||
@ -28,6 +29,7 @@ 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;
|
||||
|
||||
/**
|
||||
* {@link WebSecurityConfigurerAdapter} to add OAuth client support.
|
||||
@ -52,7 +54,8 @@ class OAuth2WebSecurityConfiguration {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
|
||||
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
|
||||
static class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,7 @@ import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
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.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition;
|
||||
@ -37,6 +38,7 @@ import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoders;
|
||||
import org.springframework.security.oauth2.jwt.JwtValidators;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
/**
|
||||
* Configures a {@link JwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI or Public
|
||||
@ -96,7 +98,8 @@ class OAuth2ResourceServerJwtConfiguration {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
|
||||
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
|
||||
static class OAuth2WebSecurityConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
|
@ -16,6 +16,7 @@
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
|
||||
|
||||
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.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
|
||||
@ -26,6 +27,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
||||
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
/**
|
||||
* Configures a {@link OpaqueTokenIntrospector} when a token introspection endpoint is
|
||||
@ -52,7 +54,8 @@ class OAuth2ResourceServerOpaqueTokenConfiguration {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
|
||||
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
|
||||
static class OAuth2WebSecurityConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
|
@ -17,11 +17,13 @@
|
||||
package org.springframework.boot.autoconfigure.security.saml2;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
/**
|
||||
* {@link WebSecurityConfigurerAdapter} configuration for Spring Security's relying party
|
||||
@ -30,11 +32,12 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
|
||||
@ConditionalOnBean(RelyingPartyRegistrationRepository.class)
|
||||
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
|
||||
class Saml2LoginConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
|
||||
static class Saml2LoginConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
|
@ -24,22 +24,23 @@ import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
/**
|
||||
* The default configuration for web security. It relies on Spring Security's
|
||||
* content-negotiation strategy to determine what sort of authentication to use. If the
|
||||
* user specifies their own {@link WebSecurityConfigurerAdapter}, this will back-off
|
||||
* completely and the users should specify all the bits that they want to configure as
|
||||
* part of the custom security configuration.
|
||||
* user specifies their own {@link WebSecurityConfigurerAdapter} or
|
||||
* {@link SecurityFilterChain} bean, this will back-off completely and the users should
|
||||
* specify all the bits that they want to configure as part of the custom security
|
||||
* configuration.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
|
||||
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
public class SpringBootWebSecurityConfiguration {
|
||||
class SpringBootWebSecurityConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Order(SecurityProperties.BASIC_AUTH_ORDER)
|
||||
|
@ -16,31 +16,28 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.servlet;
|
||||
|
||||
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.context.annotation.Configuration;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* If there is a bean of type WebSecurityConfigurerAdapter, this adds the
|
||||
* {@link EnableWebSecurity @EnableWebSecurity} annotation. This will make sure that the
|
||||
* annotation is present with default security auto-configuration and also if the user
|
||||
* adds custom security and forgets to add the annotation. If
|
||||
* {@link EnableWebSecurity @EnableWebSecurity} has already been added or if a bean with
|
||||
* name {@value BeanIds#SPRING_SECURITY_FILTER_CHAIN} has been configured by the user,
|
||||
* this will back-off.
|
||||
* Adds the{@link EnableWebSecurity @EnableWebSecurity} annotation if Spring Security is
|
||||
* on the classpath. This will make sure that the annotation is present with default
|
||||
* security auto-configuration and also if the user adds custom security and forgets to
|
||||
* add the annotation. If {@link EnableWebSecurity @EnableWebSecurity} has already been
|
||||
* added or if a bean with name {@value BeanIds#SPRING_SECURITY_FILTER_CHAIN} has been
|
||||
* configured by the user, this will back-off.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
|
||||
@ConditionalOnClass(EnableWebSecurity.class)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityEnablerConfiguration {
|
||||
class WebSecurityEnablerConfiguration {
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import javax.servlet.Filter;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
@ -31,6 +32,7 @@ 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.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;
|
||||
@ -115,7 +117,7 @@ class OAuth2WebSecurityConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityConfigurerBacksOffWhenOtherWebSecurityAdapterPresent() {
|
||||
void securityConfigurerBacksOffBacksOffWhenOtherWebSecurityAdapterPresent() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(TestWebSecurityConfigurerConfig.class, OAuth2WebSecurityConfiguration.class)
|
||||
.run((context) -> {
|
||||
@ -125,6 +127,28 @@ class OAuth2WebSecurityConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityConfigurerBacksOffBacksOffWhenOtherSecurityFilterChainBeanPresent() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(TestSecurityFilterChainConfig.class, OAuth2WebSecurityConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(getFilters(context, OAuth2LoginAuthenticationFilter.class)).isEmpty();
|
||||
assertThat(getFilters(context, OAuth2AuthorizationCodeGrantFilter.class)).isEmpty();
|
||||
assertThat(context).getBean(OAuth2AuthorizedClientService.class).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityConfigurerBacksOffConditionalOnSecurityFilterChainClass() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(ClientRegistrationRepositoryConfiguration.class,
|
||||
OAuth2WebSecurityConfiguration.class)
|
||||
.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class)).run((context) -> {
|
||||
assertThat(getFilters(context, OAuth2LoginAuthenticationFilter.class)).isEmpty();
|
||||
assertThat(getFilters(context, OAuth2AuthorizationCodeGrantFilter.class)).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void authorizedClientServiceBeanIsConditionalOnMissingBean() {
|
||||
this.contextRunner.withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class,
|
||||
@ -211,6 +235,19 @@ class OAuth2WebSecurityConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ClientRegistrationRepositoryConfiguration.class)
|
||||
static class TestSecurityFilterChainConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain testSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http.antMatcher("/**").authorizeRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ClientRegistrationRepositoryConfiguration.class)
|
||||
static class OAuth2AuthorizedClientServiceConfiguration {
|
||||
|
@ -41,6 +41,7 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
||||
@ -279,6 +280,30 @@ class OAuth2ResourceServerAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void jwtSecurityFilterShouldBeConditionalOnSecurityFilterChainClass() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com")
|
||||
.withUserConfiguration(JwtDecoderConfig.class)
|
||||
.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class)).run((context) -> {
|
||||
assertThat(context).hasSingleBean(OAuth2ResourceServerAutoConfiguration.class);
|
||||
assertThat(getBearerTokenFilter(context)).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void opaqueTokenSecurityFilterShouldBeConditionalOnSecurityFilterChainClass() {
|
||||
this.contextRunner
|
||||
.withPropertyValues(
|
||||
"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com",
|
||||
"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id",
|
||||
"spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret")
|
||||
.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class)).run((context) -> {
|
||||
assertThat(context).hasSingleBean(OAuth2ResourceServerAutoConfiguration.class);
|
||||
assertThat(getBearerTokenFilter(context)).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigurationWhenJwkSetUriAndIntrospectionUriAvailable() {
|
||||
this.contextRunner
|
||||
@ -351,6 +376,24 @@ class OAuth2ResourceServerAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void jwtSecurityConfigurerBacksOffWhenSecurityFilterChainBeanIsPresent() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com")
|
||||
.withUserConfiguration(JwtDecoderConfig.class, TestSecurityFilterChainConfig.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(SecurityFilterChain.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void opaqueTokenSecurityConfigurerBacksOffWhenSecurityFilterChainBeanIsPresent() {
|
||||
this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class)
|
||||
.withPropertyValues(
|
||||
"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com",
|
||||
"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id",
|
||||
"spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret")
|
||||
.run((context) -> assertThat(context).hasSingleBean(SecurityFilterChain.class));
|
||||
}
|
||||
|
||||
private Filter getBearerTokenFilter(AssertableWebApplicationContext context) {
|
||||
FilterChainProxy filterChain = (FilterChainProxy) context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
List<SecurityFilterChain> filterChains = filterChain.getFilterChains();
|
||||
@ -427,4 +470,16 @@ class OAuth2ResourceServerAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableWebSecurity
|
||||
static class TestSecurityFilterChainConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain testSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http.antMatcher("/**").authorizeRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
@ -47,7 +48,7 @@ import static org.mockito.Mockito.mock;
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class Saml2RelyingPartyAutoConfigurationTests {
|
||||
class Saml2RelyingPartyAutoConfigurationTests {
|
||||
|
||||
private static final String PREFIX = "spring.security.saml2.relyingparty.registration";
|
||||
|
||||
@ -133,6 +134,20 @@ public class Saml2RelyingPartyAutoConfigurationTests {
|
||||
.run((context) -> assertThat(hasFilter(context, Saml2WebSsoAuthenticationFilter.class)).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void samlLoginShouldBackOffWhenASecurityFilterChainBeanIsPresent() {
|
||||
this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class)
|
||||
.withPropertyValues(getPropertyValues())
|
||||
.run((context) -> assertThat(hasFilter(context, Saml2WebSsoAuthenticationFilter.class)).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void samlLoginShouldShouldBeConditionalOnSecurityWebFilterClass() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class))
|
||||
.withPropertyValues(getPropertyValues())
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(SecurityFilterChain.class));
|
||||
}
|
||||
|
||||
private String[] getPropertyValuesWithoutSigningCredentials(boolean signRequests) {
|
||||
return new String[] { PREFIX
|
||||
+ ".foo.identityprovider.singlesignon.url=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php",
|
||||
@ -183,4 +198,15 @@ public class Saml2RelyingPartyAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TestSecurityFilterChainConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain testSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http.antMatcher("/**").authorizeRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoCon
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.test.City;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.filter.OrderedFilter;
|
||||
@ -37,12 +38,14 @@ import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@ -67,6 +70,28 @@ class SecurityAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void enableWebSecurityIsConditionalOnClass() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.security.config"))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean("springSecurityFilterChain"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityConfigurerBacksOffWhenOtherSecurityFilterChainBeanPresent() {
|
||||
this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class).run((context) -> {
|
||||
assertThat(context.getBeansOfType(SecurityFilterChain.class).size()).isEqualTo(1);
|
||||
assertThat(context.containsBean("testSecurityFilterChain")).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityConfigurerBacksOffWhenOtherWebSecurityAdapterBeanPresent() {
|
||||
this.contextRunner.withUserConfiguration(WebSecurity.class).run((context) -> {
|
||||
assertThat(context.getBeansOfType(WebSecurityConfigurerAdapter.class).size()).isEqualTo(1);
|
||||
assertThat(context.containsBean("securityAutoConfigurationTests.WebSecurity")).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultFilterOrderWithSecurityAdapter() {
|
||||
this.contextRunner
|
||||
@ -207,4 +232,16 @@ class SecurityAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TestSecurityFilterChainConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain testSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http.antMatcher("/**").authorizeRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
/**
|
||||
@ -31,7 +32,7 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class RemoteDevtoolsSecurityConfiguration {
|
||||
|
||||
|
@ -2265,7 +2265,7 @@ For more about Spring Security, see the {spring-security}[Spring Security projec
|
||||
|
||||
[[howto-switch-off-spring-boot-security-configuration]]
|
||||
=== Switch off the Spring Boot Security Configuration
|
||||
If you define a `@Configuration` with a `WebSecurityConfigurerAdapter` in your application, it switches off the default webapp security settings in Spring Boot.
|
||||
If you define a `@Configuration` with a `WebSecurityConfigurerAdapter` or a `SecurityFilterChain` bean in your application, it switches off the default webapp security settings in Spring Boot.
|
||||
|
||||
|
||||
[[howto-change-the-user-details-service-and-add-user-accounts]]
|
||||
|
@ -3656,8 +3656,8 @@ You can register multiple relying parties under the `spring.security.saml2.relyi
|
||||
For security purposes, all actuators other than `/health` and `/info` are disabled by default.
|
||||
The configprop:management.endpoints.web.exposure.include[] property can be used to enable the actuators.
|
||||
|
||||
If Spring Security is on the classpath and no other WebSecurityConfigurerAdapter is present, all actuators other than `/health` and `/info` are secured by Spring Boot auto-configuration.
|
||||
If you define a custom `WebSecurityConfigurerAdapter`, Spring Boot auto-configuration will back off and you will be in full control of actuator access rules.
|
||||
If Spring Security is on the classpath and no other `WebSecurityConfigurerAdapter` or `SecurityFilterChain` bean is present, all actuators other than `/health` and `/info` are secured by Spring Boot auto-configuration.
|
||||
If you define a custom `WebSecurityConfigurerAdapter` or `SecurityFilterChain` bean, Spring Boot auto-configuration will back off and you will be in full control of actuator access rules.
|
||||
|
||||
NOTE: Before setting the `management.endpoints.web.exposure.include`, ensure that the exposed actuators do not contain sensitive information and/or are secured by placing them behind a firewall or by something like Spring Security.
|
||||
|
||||
|
@ -52,7 +52,8 @@ public final class WebMvcTypeExcludeFilter extends StandardAnnotationCustomizabl
|
||||
private static final Class<?>[] NO_CONTROLLERS = {};
|
||||
|
||||
private static final String[] OPTIONAL_INCLUDES = {
|
||||
"org.springframework.security.config.annotation.web.WebSecurityConfigurer" };
|
||||
"org.springframework.security.config.annotation.web.WebSecurityConfigurer",
|
||||
"org.springframework.security.web.SecurityFilterChain" };
|
||||
|
||||
private static final Set<Class<?>> DEFAULT_INCLUDES;
|
||||
|
||||
|
@ -28,6 +28,7 @@ import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -57,6 +58,7 @@ class WebMvcTypeExcludeFilterTests {
|
||||
assertThat(excludes(filter, ExampleService.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isFalse();
|
||||
assertThat(excludes(filter, SecurityFilterChain.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleHandlerInterceptor.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleModule.class)).isFalse();
|
||||
}
|
||||
@ -72,6 +74,7 @@ class WebMvcTypeExcludeFilterTests {
|
||||
assertThat(excludes(filter, ExampleService.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isFalse();
|
||||
assertThat(excludes(filter, SecurityFilterChain.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleHandlerInterceptor.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleModule.class)).isFalse();
|
||||
}
|
||||
@ -87,6 +90,7 @@ class WebMvcTypeExcludeFilterTests {
|
||||
assertThat(excludes(filter, ExampleService.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isTrue();
|
||||
assertThat(excludes(filter, SecurityFilterChain.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleHandlerInterceptor.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleModule.class)).isTrue();
|
||||
}
|
||||
@ -116,6 +120,7 @@ class WebMvcTypeExcludeFilterTests {
|
||||
assertThat(excludes(filter, ExampleService.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isFalse();
|
||||
assertThat(excludes(filter, SecurityFilterChain.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleHandlerInterceptor.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleModule.class)).isFalse();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user