diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java index 021dacda14..8b83500121 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java @@ -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()); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java deleted file mode 100644 index 707d866952..0000000000 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java +++ /dev/null @@ -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()); - } - -} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java index a4f17ba352..8a4b922800 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java @@ -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(); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java index 41eda3bd4c..c17444265e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java @@ -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 diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java index 9f7a052cb2..b2949da65e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java @@ -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 diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerOpaqueTokenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerOpaqueTokenConfiguration.java index ab1c206c61..b7762639b9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerOpaqueTokenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerOpaqueTokenConfiguration.java @@ -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 diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2LoginConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2LoginConfiguration.java index b270cfbed7..e18cb99a02 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2LoginConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2LoginConfiguration.java @@ -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 diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java index 1432bac73a..d4ec2146ea 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java @@ -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) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/WebSecurityEnablerConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/WebSecurityEnablerConfiguration.java index ae826ca9f1..ee9e662bdb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/WebSecurityEnablerConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/WebSecurityEnablerConfiguration.java @@ -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 { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java index 72279e127c..8ae77dcfd0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java @@ -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 { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java index 23b2372080..b99ec14341 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java @@ -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 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(); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java index 91fbc0f35f..7557912d48 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java @@ -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(); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfigurationTests.java index 42ecc0906f..792b2301d2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfigurationTests.java @@ -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(); + + } + + } + } diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevtoolsSecurityConfiguration.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevtoolsSecurityConfiguration.java index 5f9e3f1905..c7b1630a1c 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevtoolsSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevtoolsSecurityConfiguration.java @@ -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 { diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc index 75d60cbe11..39830d8333 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc @@ -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]] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc index fd1f7e5976..8f363f469e 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc @@ -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. diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java index 508ca409ae..1938745348 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java @@ -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> DEFAULT_INCLUDES; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilterTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilterTests.java index 79b430b93f..9ca2e188c5 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilterTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilterTests.java @@ -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(); }