Skip to content

Commit bbbbe8e

Browse files
committed
Make security auto-configs back off when SecurityFilterChain present
Closes gh-22739
1 parent c9b8a05 commit bbbbe8e

File tree

18 files changed

+264
-90
lines changed

18 files changed

+264
-90
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
2020
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
2121
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
22+
import org.springframework.boot.actuate.health.HealthEndpoint;
23+
import org.springframework.boot.actuate.info.InfoEndpoint;
2224
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2325
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
2426
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -29,28 +31,46 @@
2931
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
3032
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration;
3133
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
32-
import org.springframework.boot.autoconfigure.security.servlet.WebSecurityEnablerConfiguration;
3334
import org.springframework.context.annotation.Configuration;
34-
import org.springframework.context.annotation.Import;
35+
import org.springframework.security.config.Customizer;
36+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
3537
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
38+
import org.springframework.security.web.SecurityFilterChain;
3639

3740
/**
3841
* {@link EnableAutoConfiguration Auto-configuration} for Spring Security when actuator is
39-
* on the classpath. Specifically, it permits access to the health and info endpoints
40-
* while securing everything else.
42+
* on the classpath. It allows unauthenticated access to the {@link HealthEndpoint} and
43+
* {@link InfoEndpoint}. If the user specifies their own
44+
* {@link WebSecurityConfigurerAdapter} or {@link SecurityFilterChain} bean, this will
45+
* back-off completely and the user should specify all the bits that they want to
46+
* configure as part of the custom security configuration.
4147
*
4248
* @author Madhura Bhave
4349
* @since 2.1.0
4450
*/
4551
@Configuration(proxyBeanMethods = false)
46-
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
47-
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
52+
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
53+
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
4854
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
4955
@AutoConfigureBefore(SecurityAutoConfiguration.class)
5056
@AutoConfigureAfter({ HealthEndpointAutoConfiguration.class, InfoEndpointAutoConfiguration.class,
5157
WebEndpointAutoConfiguration.class, OAuth2ClientAutoConfiguration.class,
5258
OAuth2ResourceServerAutoConfiguration.class, Saml2RelyingPartyAutoConfiguration.class })
53-
@Import({ ManagementWebSecurityConfigurerAdapter.class, WebSecurityEnablerConfiguration.class })
5459
public class ManagementWebSecurityAutoConfiguration {
5560

61+
@Configuration(proxyBeanMethods = false)
62+
static class ManagementWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
63+
64+
@Override
65+
protected void configure(HttpSecurity http) throws Exception {
66+
http.authorizeRequests((requests) -> {
67+
requests.requestMatchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)).permitAll();
68+
requests.anyRequest().authenticated();
69+
});
70+
http.formLogin(Customizer.withDefaults());
71+
http.httpBasic(Customizer.withDefaults());
72+
}
73+
74+
}
75+
5676
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java

Lines changed: 0 additions & 51 deletions
This file was deleted.

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
3131
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration;
3232
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
33+
import org.springframework.boot.test.context.FilteredClassLoader;
3334
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
3435
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
36+
import org.springframework.context.annotation.Bean;
3537
import org.springframework.context.annotation.Configuration;
3638
import org.springframework.http.HttpStatus;
3739
import org.springframework.mock.web.MockFilterChain;
@@ -42,6 +44,7 @@
4244
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
4345
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
4446
import org.springframework.security.web.FilterChainProxy;
47+
import org.springframework.security.web.SecurityFilterChain;
4548
import org.springframework.web.context.WebApplicationContext;
4649

4750
import static org.assertj.core.api.Assertions.assertThat;
@@ -85,6 +88,15 @@ void securesEverythingElse() {
8588
});
8689
}
8790

91+
@Test
92+
void autoConfigIsConditionalOnSecurityFilterChainClass() {
93+
this.contextRunner.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class)).run((context) -> {
94+
assertThat(context).doesNotHaveBean(ManagementWebSecurityAutoConfiguration.class);
95+
HttpStatus status = getResponseStatus(context, "/actuator/health");
96+
assertThat(status).isEqualTo(HttpStatus.UNAUTHORIZED);
97+
});
98+
}
99+
88100
@Test
89101
void usesMatchersBasedOffConfiguredActuatorBasePath() {
90102
this.contextRunner.withPropertyValues("management.endpoints.web.base-path=/").run((context) -> {
@@ -103,11 +115,20 @@ void backOffIfCustomSecurityIsAdded() {
103115
});
104116
}
105117

118+
@Test
119+
void backsOffIfSecurityFilterChainBeanIsPresent() {
120+
this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class).run((context) -> {
121+
assertThat(context.getBeansOfType(SecurityFilterChain.class).size()).isEqualTo(1);
122+
assertThat(context.containsBean("testSecurityFilterChain")).isTrue();
123+
});
124+
}
125+
106126
@Test
107127
void backOffIfOAuth2ResourceServerAutoConfigurationPresent() {
108128
this.contextRunner.withConfiguration(AutoConfigurations.of(OAuth2ResourceServerAutoConfiguration.class))
109129
.withPropertyValues("spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://authserver")
110-
.run((context) -> assertThat(context).doesNotHaveBean(ManagementWebSecurityConfigurerAdapter.class));
130+
.run((context) -> assertThat(context).doesNotHaveBean(
131+
ManagementWebSecurityAutoConfiguration.ManagementWebSecurityConfigurerAdapter.class));
111132
}
112133

113134
@Test
@@ -118,7 +139,8 @@ void backOffIfSaml2RelyingPartyAutoConfigurationPresent() {
118139
"spring.security.saml2.relyingparty.registration.simplesamlphp.identity-provider.single-sign-on.sign-request=false",
119140
"spring.security.saml2.relyingparty.registration.simplesamlphp.identityprovider.entity-id=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php",
120141
"spring.security.saml2.relyingparty.registration.simplesamlphp.identityprovider.verification.credentials[0].certificate-location=classpath:saml/certificate-location")
121-
.run((context) -> assertThat(context).doesNotHaveBean(ManagementWebSecurityConfigurerAdapter.class));
142+
.run((context) -> assertThat(context).doesNotHaveBean(
143+
ManagementWebSecurityAutoConfiguration.ManagementWebSecurityConfigurerAdapter.class));
122144
}
123145

124146
private HttpStatus getResponseStatus(AssertableWebApplicationContext context, String path)
@@ -149,4 +171,15 @@ protected void configure(HttpSecurity http) throws Exception {
149171

150172
}
151173

174+
@Configuration(proxyBeanMethods = false)
175+
static class TestSecurityFilterChainConfig {
176+
177+
@Bean
178+
SecurityFilterChain testSecurityFilterChain(HttpSecurity http) throws Exception {
179+
return http.antMatcher("/**").authorizeRequests((authorize) -> authorize.anyRequest().authenticated())
180+
.build();
181+
}
182+
183+
}
184+
152185
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.autoconfigure.security.oauth2.client.servlet;
1818

1919
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
20+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2021
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2122
import org.springframework.context.annotation.Bean;
2223
import org.springframework.context.annotation.Configuration;
@@ -28,6 +29,7 @@
2829
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
2930
import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository;
3031
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
32+
import org.springframework.security.web.SecurityFilterChain;
3133

3234
/**
3335
* {@link WebSecurityConfigurerAdapter} to add OAuth client support.
@@ -52,7 +54,8 @@ OAuth2AuthorizedClientRepository authorizedClientRepository(OAuth2AuthorizedClie
5254
}
5355

5456
@Configuration(proxyBeanMethods = false)
55-
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
57+
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
58+
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
5659
static class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
5760

5861
@Override

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Base64;
2222

2323
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2425
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2526
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2627
import org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition;
@@ -37,6 +38,7 @@
3738
import org.springframework.security.oauth2.jwt.JwtDecoders;
3839
import org.springframework.security.oauth2.jwt.JwtValidators;
3940
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
41+
import org.springframework.security.web.SecurityFilterChain;
4042

4143
/**
4244
* Configures a {@link JwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI or Public
@@ -96,7 +98,8 @@ JwtDecoder jwtDecoderByIssuerUri() {
9698
}
9799

98100
@Configuration(proxyBeanMethods = false)
99-
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
101+
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
102+
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
100103
static class OAuth2WebSecurityConfigurerAdapter {
101104

102105
@Bean

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerOpaqueTokenConfiguration.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
1717

1818
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
19+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
1920
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2021
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2122
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
@@ -26,6 +27,7 @@
2627
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
2728
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
2829
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
30+
import org.springframework.security.web.SecurityFilterChain;
2931

3032
/**
3133
* Configures a {@link OpaqueTokenIntrospector} when a token introspection endpoint is
@@ -52,7 +54,8 @@ NimbusOpaqueTokenIntrospector opaqueTokenIntrospector(OAuth2ResourceServerProper
5254
}
5355

5456
@Configuration(proxyBeanMethods = false)
55-
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
57+
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
58+
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
5659
static class OAuth2WebSecurityConfigurerAdapter {
5760

5861
@Bean

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2LoginConfiguration.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
package org.springframework.boot.autoconfigure.security.saml2;
1818

1919
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
20+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2021
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2122
import org.springframework.context.annotation.Configuration;
2223
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
2324
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
2425
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
26+
import org.springframework.security.web.SecurityFilterChain;
2527

2628
/**
2729
* {@link WebSecurityConfigurerAdapter} configuration for Spring Security's relying party
@@ -30,11 +32,12 @@
3032
* @author Madhura Bhave
3133
*/
3234
@Configuration(proxyBeanMethods = false)
35+
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
3336
@ConditionalOnBean(RelyingPartyRegistrationRepository.class)
37+
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
3438
class Saml2LoginConfiguration {
3539

3640
@Configuration(proxyBeanMethods = false)
37-
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
3841
static class Saml2LoginConfigurerAdapter extends WebSecurityConfigurerAdapter {
3942

4043
@Override

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,23 @@
2424
import org.springframework.context.annotation.Configuration;
2525
import org.springframework.core.annotation.Order;
2626
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
27+
import org.springframework.security.web.SecurityFilterChain;
2728

2829
/**
2930
* The default configuration for web security. It relies on Spring Security's
3031
* content-negotiation strategy to determine what sort of authentication to use. If the
31-
* user specifies their own {@link WebSecurityConfigurerAdapter}, this will back-off
32-
* completely and the users should specify all the bits that they want to configure as
33-
* part of the custom security configuration.
32+
* user specifies their own {@link WebSecurityConfigurerAdapter} or
33+
* {@link SecurityFilterChain} bean, this will back-off completely and the users should
34+
* specify all the bits that they want to configure as part of the custom security
35+
* configuration.
3436
*
3537
* @author Madhura Bhave
36-
* @since 2.0.0
3738
*/
3839
@Configuration(proxyBeanMethods = false)
39-
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
40-
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
40+
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
41+
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
4142
@ConditionalOnWebApplication(type = Type.SERVLET)
42-
public class SpringBootWebSecurityConfiguration {
43+
class SpringBootWebSecurityConfiguration {
4344

4445
@Configuration(proxyBeanMethods = false)
4546
@Order(SecurityProperties.BASIC_AUTH_ORDER)

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/WebSecurityEnablerConfiguration.java

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,28 @@
1616

1717
package org.springframework.boot.autoconfigure.security.servlet;
1818

19-
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
19+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2020
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2121
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
2222
import org.springframework.context.annotation.Configuration;
2323
import org.springframework.security.config.BeanIds;
2424
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
25-
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
2625

2726
/**
28-
* If there is a bean of type WebSecurityConfigurerAdapter, this adds the
29-
* {@link EnableWebSecurity @EnableWebSecurity} annotation. This will make sure that the
30-
* annotation is present with default security auto-configuration and also if the user
31-
* adds custom security and forgets to add the annotation. If
32-
* {@link EnableWebSecurity @EnableWebSecurity} has already been added or if a bean with
33-
* name {@value BeanIds#SPRING_SECURITY_FILTER_CHAIN} has been configured by the user,
34-
* this will back-off.
27+
* Adds the{@link EnableWebSecurity @EnableWebSecurity} annotation if Spring Security is
28+
* on the classpath. This will make sure that the annotation is present with default
29+
* security auto-configuration and also if the user adds custom security and forgets to
30+
* add the annotation. If {@link EnableWebSecurity @EnableWebSecurity} has already been
31+
* added or if a bean with name {@value BeanIds#SPRING_SECURITY_FILTER_CHAIN} has been
32+
* configured by the user, this will back-off.
3533
*
3634
* @author Madhura Bhave
37-
* @since 2.0.0
3835
*/
3936
@Configuration(proxyBeanMethods = false)
40-
@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
4137
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
38+
@ConditionalOnClass(EnableWebSecurity.class)
4239
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
4340
@EnableWebSecurity
44-
public class WebSecurityEnablerConfiguration {
41+
class WebSecurityEnablerConfiguration {
4542

4643
}

0 commit comments

Comments
 (0)