Configure WebSecurity using WebSecurityCustomizer

Replace `WebSecurityConfigurer` and `WebSecurityConfigurerAdapter`
configurations with `WebSecurityCustomizer` or `SecurityFilterChain`
beans.

Closes gh-23421
This commit is contained in:
Madhura Bhave 2020-08-14 11:09:37 -07:00 committed by Phillip Webb
parent 79b98c9edd
commit 0818f27f44
20 changed files with 136 additions and 118 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -64,6 +64,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer; import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.DispatcherServlet;
@ -158,18 +159,23 @@ public class CloudFoundryActuatorAutoConfiguration {
* specific paths. The Cloud foundry endpoints are protected by their own security * specific paths. The Cloud foundry endpoints are protected by their own security
* interceptor. * interceptor.
*/ */
@ConditionalOnClass(WebSecurity.class) @ConditionalOnClass({ WebSecurityCustomizer.class, WebSecurity.class })
@Order(SecurityProperties.IGNORED_ORDER)
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public static class IgnoredPathsWebSecurityConfigurer implements WebSecurityConfigurer<WebSecurity> { public static class IgnoredCloudFoundryPathsWebSecurityConfiguration {
@Override @Bean
public void init(WebSecurity builder) throws Exception { IgnoredCloudFoundryPathsWebSecurityCustomizer ignoreCloudFoundryPathsWebSecurityCustomizer() {
builder.ignoring().requestMatchers(new AntPathRequestMatcher("/cloudfoundryapplication/**")); return new IgnoredCloudFoundryPathsWebSecurityCustomizer();
} }
}
@Order(SecurityProperties.IGNORED_ORDER)
static class IgnoredCloudFoundryPathsWebSecurityCustomizer implements WebSecurityCustomizer {
@Override @Override
public void configure(WebSecurity builder) throws Exception { public void customize(WebSecurity web) {
web.ignoring().requestMatchers(new AntPathRequestMatcher("/cloudfoundryapplication/**"));
} }
} }

View File

@ -31,6 +31,7 @@ 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.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration; import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer; import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@ -49,7 +50,7 @@ import org.springframework.security.web.SecurityFilterChain;
* @since 2.1.0 * @since 2.1.0
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class }) @ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class }) @ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@AutoConfigureBefore(SecurityAutoConfiguration.class) @AutoConfigureBefore(SecurityAutoConfiguration.class)
@ -58,19 +59,15 @@ import org.springframework.security.web.SecurityFilterChain;
OAuth2ResourceServerAutoConfiguration.class, Saml2RelyingPartyAutoConfiguration.class }) OAuth2ResourceServerAutoConfiguration.class, Saml2RelyingPartyAutoConfiguration.class })
public class ManagementWebSecurityAutoConfiguration { public class ManagementWebSecurityAutoConfiguration {
@Configuration(proxyBeanMethods = false) @Bean
static class ManagementWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { SecurityFilterChain managementSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> {
@Override requests.requestMatchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)).permitAll();
protected void configure(HttpSecurity http) throws Exception { requests.anyRequest().authenticated();
http.authorizeRequests((requests) -> { });
requests.requestMatchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)).permitAll(); http.formLogin(Customizer.withDefaults());
requests.anyRequest().authenticated(); http.httpBasic(Customizer.withDefaults());
}); return http.build();
http.formLogin(Customizer.withDefaults());
http.httpBasic(Customizer.withDefaults());
}
} }
} }

View File

@ -56,6 +56,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
class ManagementWebSecurityAutoConfigurationTests { class ManagementWebSecurityAutoConfigurationTests {
private static final String MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN = "managementSecurityFilterChain";
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner().withConfiguration( private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner().withConfiguration(
AutoConfigurations.of(HealthContributorAutoConfiguration.class, HealthEndpointAutoConfiguration.class, AutoConfigurations.of(HealthContributorAutoConfiguration.class, HealthEndpointAutoConfiguration.class,
InfoEndpointAutoConfiguration.class, EnvironmentEndpointAutoConfiguration.class, InfoEndpointAutoConfiguration.class, EnvironmentEndpointAutoConfiguration.class,
@ -65,6 +67,7 @@ class ManagementWebSecurityAutoConfigurationTests {
@Test @Test
void permitAllForHealth() { void permitAllForHealth() {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
assertThat(context).hasBean(MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN);
HttpStatus status = getResponseStatus(context, "/actuator/health"); HttpStatus status = getResponseStatus(context, "/actuator/health");
assertThat(status).isEqualTo(HttpStatus.OK); assertThat(status).isEqualTo(HttpStatus.OK);
}); });
@ -127,8 +130,8 @@ class ManagementWebSecurityAutoConfigurationTests {
void backOffIfOAuth2ResourceServerAutoConfigurationPresent() { void backOffIfOAuth2ResourceServerAutoConfigurationPresent() {
this.contextRunner.withConfiguration(AutoConfigurations.of(OAuth2ResourceServerAutoConfiguration.class)) this.contextRunner.withConfiguration(AutoConfigurations.of(OAuth2ResourceServerAutoConfiguration.class))
.withPropertyValues("spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://authserver") .withPropertyValues("spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://authserver")
.run((context) -> assertThat(context).doesNotHaveBean( .run((context) -> assertThat(context).doesNotHaveBean(ManagementWebSecurityAutoConfiguration.class)
ManagementWebSecurityAutoConfiguration.ManagementWebSecurityConfigurerAdapter.class)); .doesNotHaveBean(MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN));
} }
@Test @Test
@ -139,8 +142,8 @@ class ManagementWebSecurityAutoConfigurationTests {
"spring.security.saml2.relyingparty.registration.simplesamlphp.identity-provider.single-sign-on.sign-request=false", "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.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") "spring.security.saml2.relyingparty.registration.simplesamlphp.identityprovider.verification.credentials[0].certificate-location=classpath:saml/certificate-location")
.run((context) -> assertThat(context).doesNotHaveBean( .run((context) -> assertThat(context).doesNotHaveBean(ManagementWebSecurityAutoConfiguration.class)
ManagementWebSecurityAutoConfiguration.ManagementWebSecurityConfigurerAdapter.class)); .doesNotHaveBean(MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN));
} }
private HttpStatus getResponseStatus(AssertableWebApplicationContext context, String path) private HttpStatus getResponseStatus(AssertableWebApplicationContext context, String path)

View File

@ -54,15 +54,16 @@ class OAuth2WebSecurityConfiguration {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class }) @ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class }) @ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
static class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { static class OAuth2SecurityFilterChainConfiguration {
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> requests.anyRequest().authenticated()); http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
http.oauth2Login(Customizer.withDefaults()); http.oauth2Login(Customizer.withDefaults());
http.oauth2Client(); http.oauth2Client();
return http.build();
} }
} }

View File

@ -50,7 +50,6 @@ import org.springframework.security.web.SecurityFilterChain;
* @author HaiTao Zhang * @author HaiTao Zhang
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
class OAuth2ResourceServerJwtConfiguration { class OAuth2ResourceServerJwtConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ -98,22 +97,16 @@ class OAuth2ResourceServerJwtConfiguration {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class }) @ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class }) @ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
static class OAuth2WebSecurityConfigurerAdapter { static class OAuth2SecurityFilterChainConfiguration {
@Bean @Bean
@ConditionalOnBean(JwtDecoder.class) @ConditionalOnBean(JwtDecoder.class)
WebSecurityConfigurerAdapter jwtDecoderWebSecurityConfigurerAdapter() { SecurityFilterChain jwtSecurityFilterChain(HttpSecurity http) throws Exception {
return new WebSecurityConfigurerAdapter() { http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
@Override return http.build();
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
}
};
} }
} }

View File

@ -56,20 +56,14 @@ class OAuth2ResourceServerOpaqueTokenConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class }) @ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class }) @ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
static class OAuth2WebSecurityConfigurerAdapter { static class OAuth2SecurityFilterChainConfiguration {
@Bean @Bean
@ConditionalOnBean(OpaqueTokenIntrospector.class) @ConditionalOnBean(OpaqueTokenIntrospector.class)
WebSecurityConfigurerAdapter opaqueTokenWebSecurityConfigurerAdapter() { SecurityFilterChain opaqueTokenSecurityFilterChain(HttpSecurity http) throws Exception {
return new WebSecurityConfigurerAdapter() { http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken);
@Override return http.build();
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken);
}
};
} }
} }

View File

@ -32,14 +32,14 @@ class Oauth2ResourceServerConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(JwtDecoder.class) @ConditionalOnClass(JwtDecoder.class)
@Import({ OAuth2ResourceServerJwtConfiguration.JwtDecoderConfiguration.class, @Import({ OAuth2ResourceServerJwtConfiguration.JwtDecoderConfiguration.class,
OAuth2ResourceServerJwtConfiguration.OAuth2WebSecurityConfigurerAdapter.class }) OAuth2ResourceServerJwtConfiguration.OAuth2SecurityFilterChainConfiguration.class })
static class JwtConfiguration { static class JwtConfiguration {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@Import({ OAuth2ResourceServerOpaqueTokenConfiguration.OpaqueTokenIntrospectionClientConfiguration.class, @Import({ OAuth2ResourceServerOpaqueTokenConfiguration.OpaqueTokenIntrospectionClientConfiguration.class,
OAuth2ResourceServerOpaqueTokenConfiguration.OAuth2WebSecurityConfigurerAdapter.class }) OAuth2ResourceServerOpaqueTokenConfiguration.OAuth2SecurityFilterChainConfiguration.class })
static class OpaqueTokenConfiguration { static class OpaqueTokenConfiguration {
} }

View File

@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.security.saml2;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@ -32,19 +33,15 @@ import org.springframework.security.web.SecurityFilterChain;
* @author Madhura Bhave * @author Madhura Bhave
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class }) @ConditionalOnMissingBean({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
@ConditionalOnBean(RelyingPartyRegistrationRepository.class) @ConditionalOnBean(RelyingPartyRegistrationRepository.class)
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class }) @ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })
class Saml2LoginConfiguration { class Saml2LoginConfiguration {
@Configuration(proxyBeanMethods = false) @Bean
static class Saml2LoginConfigurerAdapter extends WebSecurityConfigurerAdapter { SecurityFilterChain samlSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> requests.anyRequest().authenticated()).saml2Login();
@Override return http.build();
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> requests.anyRequest().authenticated()).saml2Login();
}
} }
} }

View File

@ -21,8 +21,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order; 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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
@ -37,15 +39,16 @@ import org.springframework.security.web.SecurityFilterChain;
* @author Madhura Bhave * @author Madhura Bhave
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class }) @ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class }) @ConditionalOnMissingBean({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class })
@ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration { class SpringBootWebSecurityConfiguration {
@Configuration(proxyBeanMethods = false) @Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER) @Order(SecurityProperties.BASIC_AUTH_ORDER)
static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter { SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
return http.build();
} }
} }

View File

@ -117,7 +117,7 @@ class OAuth2WebSecurityConfigurationTests {
} }
@Test @Test
void securityConfigurerBacksOffBacksOffWhenOtherWebSecurityAdapterPresent() { void securityFilterChainConfigBacksOffWhenOtherWebSecurityAdapterPresent() {
this.contextRunner this.contextRunner
.withUserConfiguration(TestWebSecurityConfigurerConfig.class, OAuth2WebSecurityConfiguration.class) .withUserConfiguration(TestWebSecurityConfigurerConfig.class, OAuth2WebSecurityConfiguration.class)
.run((context) -> { .run((context) -> {
@ -128,7 +128,7 @@ class OAuth2WebSecurityConfigurationTests {
} }
@Test @Test
void securityConfigurerBacksOffBacksOffWhenOtherSecurityFilterChainBeanPresent() { void securityFilterChainConfigBacksOffWhenOtherSecurityFilterChainBeanPresent() {
this.contextRunner this.contextRunner
.withUserConfiguration(TestSecurityFilterChainConfig.class, OAuth2WebSecurityConfiguration.class) .withUserConfiguration(TestSecurityFilterChainConfig.class, OAuth2WebSecurityConfiguration.class)
.run((context) -> { .run((context) -> {
@ -139,7 +139,7 @@ class OAuth2WebSecurityConfigurationTests {
} }
@Test @Test
void securityConfigurerBacksOffConditionalOnSecurityFilterChainClass() { void securityFilterChainConfigConditionalOnSecurityFilterChainClass() {
this.contextRunner this.contextRunner
.withUserConfiguration(ClientRegistrationRepositoryConfiguration.class, .withUserConfiguration(ClientRegistrationRepositoryConfiguration.class,
OAuth2WebSecurityConfiguration.class) OAuth2WebSecurityConfiguration.class)

View File

@ -38,6 +38,7 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.security.config.BeanIds; import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
@ -220,6 +221,11 @@ class Saml2RelyingPartyAutoConfigurationTests {
} }
@EnableWebSecurity
static class WebSecurityEnablerConfiguration {
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class WebSecurityConfigurerAdapterConfiguration { static class WebSecurityConfigurerAdapterConfiguration {

View File

@ -76,6 +76,12 @@ class SecurityAutoConfigurationTests {
.run((context) -> assertThat(context).doesNotHaveBean("springSecurityFilterChain")); .run((context) -> assertThat(context).doesNotHaveBean("springSecurityFilterChain"));
} }
@Test
void filterChainBeanIsConditionalOnClassSecurityFilterChain() {
this.contextRunner.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class))
.run((context) -> assertThat(context).doesNotHaveBean(SecurityFilterChain.class));
}
@Test @Test
void securityConfigurerBacksOffWhenOtherSecurityFilterChainBeanPresent() { void securityConfigurerBacksOffWhenOtherSecurityFilterChainBeanPresent() {
this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class).run((context) -> { this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class).run((context) -> {

View File

@ -19,10 +19,10 @@ package org.springframework.boot.devtools.autoconfigure;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 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.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@ -32,13 +32,12 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
* *
* @author Madhura Bhave * @author Madhura Bhave
*/ */
@ConditionalOnClass({ SecurityFilterChain.class, WebSecurityConfigurerAdapter.class }) @ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
class RemoteDevtoolsSecurityConfiguration { class RemoteDevtoolsSecurityConfiguration {
@Order(SecurityProperties.BASIC_AUTH_ORDER - 1)
@Configuration @Configuration
static class SecurityConfiguration extends WebSecurityConfigurerAdapter { static class SecurityConfiguration {
private final String url; private final String url;
@ -48,10 +47,12 @@ class RemoteDevtoolsSecurityConfiguration {
this.url = servletContextPath + devToolsProperties.getRemote().getContextPath() + "/restart"; this.url = servletContextPath + devToolsProperties.getRemote().getContextPath() + "/restart";
} }
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { @Order(SecurityProperties.BASIC_AUTH_ORDER - 1)
SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.requestMatcher(new AntPathRequestMatcher(this.url)).authorizeRequests().anyRequest().anonymous().and() http.requestMatcher(new AntPathRequestMatcher(this.url)).authorizeRequests().anyRequest().anonymous().and()
.csrf().disable(); .csrf().disable();
return http.build();
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,14 +26,14 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer; import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.User.UserBuilder; import org.springframework.security.core.userdetails.User.UserBuilder;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { public class SecurityConfiguration {
@Bean @Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() { public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
@ -53,8 +53,8 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
return builder.build(); return builder.build();
} }
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> { http.authorizeRequests((requests) -> {
requests.mvcMatchers("/actuator/beans").hasRole("BEANS"); requests.mvcMatchers("/actuator/beans").hasRole("BEANS");
requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll(); requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll();
@ -66,6 +66,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
}); });
http.cors(Customizer.withDefaults()); http.cors(Customizer.withDefaults());
http.httpBasic(); http.httpBasic();
return http.build();
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,11 +24,12 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 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.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -69,11 +70,12 @@ class ShutdownSampleActuatorApplicationTests {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class SecurityConfiguration extends WebSecurityConfigurerAdapter { static class SecurityConfiguration {
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.csrf().disable(); http.csrf().disable();
return http.build();
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,12 +21,12 @@ import org.springframework.boot.actuate.web.mappings.MappingsEndpoint;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration @Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { public class SecurityConfiguration {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@Bean @Bean
@ -38,8 +38,8 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.authorities("ROLE_ACTUATOR", "ROLE_USER").build()); .authorities("ROLE_ACTUATOR", "ROLE_USER").build());
} }
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { SecurityFilterChain configure(HttpSecurity http) throws Exception {
// @formatter:off // @formatter:off
http.authorizeRequests() http.authorizeRequests()
.requestMatchers(EndpointRequest.to("health", "info")).permitAll() .requestMatchers(EndpointRequest.to("health", "info")).permitAll()
@ -47,6 +47,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.antMatchers("/**").hasRole("USER") .antMatchers("/**").hasRole("USER")
.and() .and()
.httpBasic(); .httpBasic();
return http.build();
// @formatter:on // @formatter:on
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -29,9 +29,9 @@ import org.springframework.core.annotation.Order;
import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.annotation.Secured;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -68,10 +68,10 @@ public class SampleMethodSecurityApplication implements WebMvcConfigurer {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter { protected static class ApplicationSecurity {
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> { http.authorizeRequests((requests) -> {
requests.antMatchers("/login").permitAll(); requests.antMatchers("/login").permitAll();
requests.anyRequest().fullyAuthenticated(); requests.anyRequest().fullyAuthenticated();
@ -82,19 +82,21 @@ public class SampleMethodSecurityApplication implements WebMvcConfigurer {
}); });
http.logout((logout) -> logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))); http.logout((logout) -> logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout")));
http.exceptionHandling((exceptions) -> exceptions.accessDeniedPage("/access?error")); http.exceptionHandling((exceptions) -> exceptions.accessDeniedPage("/access?error"));
return http.build();
} }
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@Order(1) @Order(1)
protected static class ActuatorSecurity extends WebSecurityConfigurerAdapter { protected static class ActuatorSecurity {
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { SecurityFilterChain actuatorSecurity(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint()); http.requestMatcher(EndpointRequest.toAnyEndpoint());
http.authorizeRequests((requests) -> requests.anyRequest().authenticated()); http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
http.httpBasic(); http.httpBasic();
return http.build();
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,10 +21,11 @@ import java.util.Map;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer; import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -58,10 +59,10 @@ public class SampleWebSecureCustomApplication implements WebMvcConfigurer {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter { protected static class ApplicationSecurity {
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> { http.authorizeRequests((requests) -> {
requests.antMatchers("/css/**").permitAll(); requests.antMatchers("/css/**").permitAll();
requests.anyRequest().fullyAuthenticated(); requests.anyRequest().fullyAuthenticated();
@ -71,6 +72,7 @@ public class SampleWebSecureCustomApplication implements WebMvcConfigurer {
form.failureUrl("/login?error").permitAll(); form.failureUrl("/login?error").permitAll();
}); });
http.logout(LogoutConfigurer::permitAll); http.logout(LogoutConfigurer::permitAll);
return http.build();
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,9 +26,9 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer; import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.provisioning.JdbcUserDetailsManager; import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -62,10 +62,10 @@ public class SampleWebSecureJdbcApplication implements WebMvcConfigurer {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter { protected static class ApplicationSecurity {
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> { http.authorizeRequests((requests) -> {
requests.antMatchers("/css/**").permitAll(); requests.antMatchers("/css/**").permitAll();
requests.anyRequest().fullyAuthenticated(); requests.anyRequest().fullyAuthenticated();
@ -75,6 +75,7 @@ public class SampleWebSecureJdbcApplication implements WebMvcConfigurer {
form.failureUrl("/login?error").permitAll(); form.failureUrl("/login?error").permitAll();
}); });
http.logout(LogoutConfigurer::permitAll); http.logout(LogoutConfigurer::permitAll);
return http.build();
} }
@Bean @Bean

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,10 +22,11 @@ import java.util.Map;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest; import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer; import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -59,10 +60,10 @@ public class SampleWebSecureApplication implements WebMvcConfigurer {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter { protected static class ApplicationSecurity {
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> { http.authorizeRequests((requests) -> {
requests.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll(); requests.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();
requests.anyRequest().fullyAuthenticated(); requests.anyRequest().fullyAuthenticated();
@ -72,6 +73,7 @@ public class SampleWebSecureApplication implements WebMvcConfigurer {
form.failureUrl("/login?error").permitAll(); form.failureUrl("/login?error").permitAll();
}); });
http.logout(LogoutConfigurer::permitAll); http.logout(LogoutConfigurer::permitAll);
return http.build();
} }
} }