SEC-2197: Allow multiple invocations on HttpSecurity

Previously invoking methods like HttpSecurity#authorizeUrls() multiple
times would override one another. This has now changed to be more
intuitive. Initially this was required for the way that defaults were
provided so that they could be overriden, but this is no longer the case.
This commit is contained in:
Rob Winch 2013-07-21 22:56:23 -05:00
parent 686a7a8d62
commit e1d8db4e95
17 changed files with 516 additions and 44 deletions

View File

@ -29,6 +29,7 @@ import org.springframework.security.config.annotation.AbstractConfiguredSecurity
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherConfigurer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
@ -111,6 +112,7 @@ import org.springframework.util.Assert;
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity> implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
private AuthenticationManager authenticationManager;
private final RequestMatcherConfigurer requestMatcherConfigurer = new RequestMatcherConfigurer();
private List<Filter> filters = new ArrayList<Filter>();
private RequestMatcher requestMatcher = new AnyRequestMatcher();
private FilterComparator comparitor = new FilterComparator();
@ -132,8 +134,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
}
/**
* Allows configuring OpenID based authentication. Multiple invocations of
* {@link #openidLogin()} will override previous invocations.
* Allows configuring OpenID based authentication.
*
* <h2>Example Configurations</h2>
*
@ -235,12 +236,11 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @see OpenIDLoginConfigurer
*/
public OpenIDLoginConfigurer<HttpSecurity> openidLogin() throws Exception {
return apply(new OpenIDLoginConfigurer<HttpSecurity>());
return getOrApply(new OpenIDLoginConfigurer<HttpSecurity>());
}
/**
* Allows configuring of Session Management. Multiple invocations of
* {@link #sessionManagement()} will override previous invocations.
* Allows configuring of Session Management.
*
* <h2>Example Configuration</h2>
*
@ -303,7 +303,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public SessionManagementConfigurer<HttpSecurity> sessionManagement() throws Exception {
return apply(new SessionManagementConfigurer<HttpSecurity>());
return getOrApply(new SessionManagementConfigurer<HttpSecurity>());
}
/**
@ -358,7 +358,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @see {@link #requiresChannel()}
*/
public PortMapperConfigurer<HttpSecurity> portMapper() throws Exception {
return apply(new PortMapperConfigurer<HttpSecurity>());
return getOrApply(new PortMapperConfigurer<HttpSecurity>());
}
/**
@ -434,7 +434,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public JeeConfigurer<HttpSecurity> jee() throws Exception {
return apply(new JeeConfigurer<HttpSecurity>());
return getOrApply(new JeeConfigurer<HttpSecurity>());
}
/**
@ -467,12 +467,11 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public X509Configurer<HttpSecurity> x509() throws Exception {
return apply(new X509Configurer<HttpSecurity>());
return getOrApply(new X509Configurer<HttpSecurity>());
}
/**
* Allows configuring of Remember Me authentication. Multiple invocations of
* {@link #rememberMe()} will override previous invocations.
* Allows configuring of Remember Me authentication.
*
* <h2>Example Configuration</h2>
*
@ -514,15 +513,12 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public RememberMeConfigurer<HttpSecurity> rememberMe() throws Exception {
return apply(new RememberMeConfigurer<HttpSecurity>());
return getOrApply(new RememberMeConfigurer<HttpSecurity>());
}
/**
* Allows restricting access based upon the {@link HttpServletRequest} using
* {@link RequestMatcher} implementations (i.e. via URL patterns). Invoking
* {@link #authorizeUrls()} twice will override previous invocations of
* {@link #authorizeUrls()}.
*
* <h2>Example Configurations</h2>
*
@ -611,7 +607,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public ExpressionUrlAuthorizationConfigurer<HttpSecurity> authorizeUrls() throws Exception {
return apply(new ExpressionUrlAuthorizationConfigurer<HttpSecurity>());
return getOrApply(new ExpressionUrlAuthorizationConfigurer<HttpSecurity>());
}
/**
@ -624,7 +620,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public RequestCacheConfigurer<HttpSecurity> requestCache() throws Exception {
return apply(new RequestCacheConfigurer<HttpSecurity>());
return getOrApply(new RequestCacheConfigurer<HttpSecurity>());
}
/**
@ -635,7 +631,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling() throws Exception {
return apply(new ExceptionHandlingConfigurer<HttpSecurity>());
return getOrApply(new ExceptionHandlingConfigurer<HttpSecurity>());
}
/**
@ -647,7 +643,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public SecurityContextConfigurer<HttpSecurity> securityContext() throws Exception {
return apply(new SecurityContextConfigurer<HttpSecurity>());
return getOrApply(new SecurityContextConfigurer<HttpSecurity>());
}
/**
@ -659,7 +655,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public ServletApiConfigurer<HttpSecurity> servletApi() throws Exception {
return apply(new ServletApiConfigurer<HttpSecurity>());
return getOrApply(new ServletApiConfigurer<HttpSecurity>());
}
/**
@ -715,7 +711,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public LogoutConfigurer<HttpSecurity> logout() throws Exception {
return apply(new LogoutConfigurer<HttpSecurity>());
return getOrApply(new LogoutConfigurer<HttpSecurity>());
}
/**
@ -796,7 +792,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public AnonymousConfigurer<HttpSecurity> anonymous() throws Exception {
return apply(new AnonymousConfigurer<HttpSecurity>());
return getOrApply(new AnonymousConfigurer<HttpSecurity>());
}
/**
@ -876,13 +872,12 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
return apply(new FormLoginConfigurer<HttpSecurity>());
return getOrApply(new FormLoginConfigurer<HttpSecurity>());
}
/**
* Configures channel security. In order for this configuration to be useful at least
* one mapping to a required channel must be provided. Invoking this method multiple times
* will reset previous invocations of the method.
* one mapping to a required channel must be provided.
*
* <h2>Example Configuration</h2>
*
@ -925,12 +920,11 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public ChannelSecurityConfigurer<HttpSecurity> requiresChannel() throws Exception {
return apply(new ChannelSecurityConfigurer<HttpSecurity>());
return getOrApply(new ChannelSecurityConfigurer<HttpSecurity>());
}
/**
* Configures HTTP Basic authentication. Multiple infocations of
* {@link #httpBasic()} will override previous invocations.
* Configures HTTP Basic authentication.
*
* <h2>Example Configuration</h2>
*
@ -968,7 +962,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @throws Exception
*/
public HttpBasicConfigurer<HttpSecurity> httpBasic() throws Exception {
return apply(new HttpBasicConfigurer<HttpSecurity>());
return getOrApply(new HttpBasicConfigurer<HttpSecurity>());
}
@Override
@ -1115,9 +1109,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
* </pre>
*
* The configuration differs from the previous configurations because it invokes
* {@link #requestMatchers()} twice which resets the {@link RequestMatcherConfigurer}.
* Therefore the configuration below only matches on URLs that start with "/oauth/**".
* The configuration below is also the same as the above configuration.
*
* <pre>
* &#064;Configuration
@ -1153,7 +1145,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @return the {@link RequestMatcherConfigurer} for further customizations
*/
public RequestMatcherConfigurer requestMatchers() {
return new RequestMatcherConfigurer();
return requestMatcherConfigurer;
}
/**
@ -1252,6 +1244,23 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
private RequestMatcherConfigurer(){}
}
/**
* If the {@link SecurityConfigurer} has already been specified get the original, otherwise apply the new {@link SecurityConfigurerAdapter}.
*
* @param configurer the {@link SecurityConfigurer} to apply if one is not found for this {@link SecurityConfigurer} class.
* @return the current {@link SecurityConfigurer} for the configurer passed in
* @throws Exception
*/
@SuppressWarnings("unchecked")
private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(C configurer)
throws Exception {
C existingConfig = (C) getConfigurer(configurer.getClass());
if(existingConfig != null) {
return existingConfig;
}
return apply(configurer);
}
/**
* Internal {@link RequestMatcher} instance used by {@link RequestMatcher}
* that will match if any of the passed in {@link RequestMatcher} instances

View File

@ -0,0 +1,54 @@
/*
* Copyright 2002-2013 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
*
* http://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.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
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.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter
/**
*
* @author Rob Winch
*/
class AnonymousConfigurerTests extends BaseSpringSpec {
def "invoke logout twice does not override"() {
when:
loadConfig(InvokeTwiceDoesNotOverride)
then:
findFilter(AnonymousAuthenticationFilter).key == "custom"
}
@Configuration
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.anonymous()
.key("custom")
.and()
.anonymous()
}
}
}

View File

@ -15,10 +15,13 @@
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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.web.access.channel.ChannelDecisionManagerImpl
import org.springframework.security.web.access.channel.ChannelProcessingFilter
import org.springframework.security.web.access.channel.InsecureChannelProcessor
@ -50,4 +53,27 @@ class ChannelSecurityConfigurerTests extends BaseSpringSpec {
and: "ChannelProcessingFilter is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as ChannelProcessingFilter) >> {ChannelProcessingFilter o -> o}
}
def "invoke requiresChannel twice does not override"() {
setup:
loadConfig(DuplicateInvocationsDoesNotOverrideConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "https://localhost"
}
@EnableWebSecurity
@Configuration
static class DuplicateInvocationsDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requiresChannel()
.anyRequest().requiresSecure()
.and()
.requiresChannel()
}
}
}

View File

@ -29,6 +29,7 @@ import org.springframework.security.config.annotation.authentication.builders.Au
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.configurers.JeeConfigurerTests.InvokeTwiceDoesNotOverride;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint
@ -178,4 +179,27 @@ class ExceptionHandlingConfigurerTests extends BaseSpringSpec {
.formLogin()
}
}
def "invoke exceptionHandling twice does not override"() {
setup:
InvokeTwiceDoesNotOverrideConfig.AEP = Mock(AuthenticationEntryPoint)
when:
loadConfig(InvokeTwiceDoesNotOverrideConfig)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == InvokeTwiceDoesNotOverrideConfig.AEP
}
@EnableWebSecurity
@Configuration
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint AEP
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(AEP)
.and()
.exceptionHandling()
}
}
}

View File

@ -411,4 +411,36 @@ public class ExpressionUrlAuthorizationConfigurerTests extends BaseSpringSpec {
.withUser("user").password("password").roles("USER")
}
}
def "invoke authorizeUrls twice does not reset"() {
setup:
loadConfig(InvokeTwiceDoesNotResetConfig)
when:
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "Access is denied"
response.status == HttpServletResponse.SC_UNAUTHORIZED
}
@EnableWebSecurity
@Configuration
static class InvokeTwiceDoesNotResetConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeUrls()
.anyRequest().authenticated()
.and()
.authorizeUrls()
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
}
}
}

View File

@ -196,6 +196,30 @@ class FormLoginConfigurerTests extends BaseSpringSpec {
}
}
def "duplicate formLogin does not override"() {
setup:
DuplicateInvocationsDoesNotOverrideConfig.FAILURE_HANDLER = Mock(AuthenticationFailureHandler)
when:
loadConfig(DuplicateInvocationsDoesNotOverrideConfig)
then:
findFilter(UsernamePasswordAuthenticationFilter).usernameParameter == "custom-username"
}
@EnableWebSecurity
@Configuration
static class DuplicateInvocationsDoesNotOverrideConfig extends BaseWebConfig {
static AuthenticationFailureHandler FAILURE_HANDLER
@Override
protected void configure(HttpSecurity http) {
http
.formLogin()
.usernameParameter("custom-username")
.and()
.formLogin()
}
}
def "formLogin ObjectPostProcessor"() {
setup: "initialize the AUTH_FILTER as a mock"
AnyObjectPostProcessor opp = Mock()

View File

@ -99,4 +99,35 @@ class HttpBasicConfigurerTests extends BaseSpringSpec {
.inMemoryAuthentication()
}
}
}
def "duplicate httpBasic invocations does not override"() {
setup:
DuplicateDoesNotOverrideConfig.ENTRY_POINT = Mock(AuthenticationEntryPoint)
when:
loadConfig(DuplicateDoesNotOverrideConfig)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == DuplicateDoesNotOverrideConfig.ENTRY_POINT
}
@EnableWebSecurity
@Configuration
static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint ENTRY_POINT
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.authenticationEntryPoint(ENTRY_POINT)
.and()
.httpBasic()
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
}
}
}

View File

@ -15,10 +15,13 @@
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
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.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter
@ -43,4 +46,24 @@ class JeeConfigurerTests extends BaseSpringSpec {
and: "J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource is registered with LifecycleManager"
1 * opp.postProcess(_ as J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource) >> {J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource o -> o}
}
def "invoke jee twice does not override"() {
when:
loadConfig(InvokeTwiceDoesNotOverride)
then:
findFilter(J2eePreAuthenticatedProcessingFilter).authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER"] as Set
}
@Configuration
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.jee()
.mappableRoles("USER")
.and()
.jee()
}
}
}

View File

@ -15,10 +15,13 @@
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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.web.authentication.logout.LogoutFilter
/**
@ -40,4 +43,25 @@ class LogoutConfigurerTests extends BaseSpringSpec {
then: "LogoutFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as LogoutFilter) >> {LogoutFilter o -> o}
}
def "invoke logout twice does not override"() {
when:
loadConfig(InvokeTwiceDoesNotOverride)
then:
findFilter(LogoutFilter).filterProcessesUrl == "/custom/logout"
}
@Configuration
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.logout()
.logoutUrl("/custom/logout")
.and()
.logout()
}
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 2002-2013 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
*
* http://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.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
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.config.annotation.web.configurers.SessionCreationPolicy;
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.context.SecurityContextRepository
import org.springframework.security.web.savedrequest.RequestCache
import org.springframework.security.web.session.ConcurrentSessionFilter
import org.springframework.security.web.session.SessionManagementFilter
/**
*
* @author Rob Winch
*/
class PortMapperConfigurerTests extends BaseSpringSpec {
def "invoke portMapper twice does not override"() {
setup:
loadConfig(InvokeTwiceDoesNotOverride)
request.setServerPort(543)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "https://localhost:123"
}
@Configuration
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requiresChannel()
.anyRequest().requiresSecure()
.and()
.portMapper()
.http(543).mapsTo(123)
.and()
.portMapper()
}
}
}

View File

@ -69,4 +69,19 @@ public class RememberMeConfigurerTests extends BaseSpringSpec {
then: "RememberMeAuthenticationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as RememberMeAuthenticationFilter) >> {RememberMeAuthenticationFilter o -> o}
}
def "invoke rememberMe twice does not reset"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
UserDetailsService uds = authenticationBldr.getDefaultUserDetailsService()
when:
http
.rememberMe()
.userDetailsService(authenticationBldr.getDefaultUserDetailsService())
.and()
.rememberMe()
then: "RememberMeAuthenticationFilter is registered with LifecycleManager"
http.getConfigurer(RememberMeConfigurer).userDetailsService != null
}
}

View File

@ -17,8 +17,9 @@ package org.springframework.security.config.annotation.web.configurers
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.savedrequest.RequestCache
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter
/**
@ -40,4 +41,20 @@ class RequestCacheConfigurerTests extends BaseSpringSpec {
then: "RequestCacheAwareFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as RequestCacheAwareFilter) >> {RequestCacheAwareFilter o -> o}
}
def "invoke requestCache twice does not reset"() {
setup:
RequestCache RC = Mock()
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.requestCache()
.requestCache(RC)
.and()
.requestCache()
then:
http.getSharedObject(RequestCache) == RC
}
}

View File

@ -15,11 +15,15 @@
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.context.SecurityContextRepository
/**
*
@ -40,4 +44,28 @@ class SecurityContextConfigurerTests extends BaseSpringSpec {
then: "SecurityContextPersistenceFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as SecurityContextPersistenceFilter) >> {SecurityContextPersistenceFilter o -> o}
}
def "invoke securityContext twice does not override"() {
setup:
InvokeTwiceDoesNotOverrideConfig.SCR = Mock(SecurityContextRepository)
when:
loadConfig(InvokeTwiceDoesNotOverrideConfig)
then:
findFilter(SecurityContextPersistenceFilter).repo == InvokeTwiceDoesNotOverrideConfig.SCR
}
@Configuration
@EnableWebSecurity
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
static SecurityContextRepository SCR
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.securityContext()
.securityContextRepository(SCR)
.and()
.securityContext()
}
}
}

View File

@ -107,4 +107,28 @@ class ServletApiConfigurerTests extends BaseSpringSpec {
.withUser("user").password("password").roles("USER")
}
}
def "invoke servletApi twice does not override"() {
setup:
InvokeTwiceDoesNotOverrideConfig.ENTRYPOINT = Mock(AuthenticationEntryPoint)
when:
loadConfig(InvokeTwiceDoesNotOverrideConfig)
then:
findFilter(SecurityContextHolderAwareRequestFilter).authenticationEntryPoint == InvokeTwiceDoesNotOverrideConfig.ENTRYPOINT
}
@Configuration
@EnableWebSecurity
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint ENTRYPOINT
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(ENTRYPOINT)
.and()
.exceptionHandling()
}
}
}

View File

@ -24,6 +24,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.SessionCreationPolicy;
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.context.SecurityContextRepository
import org.springframework.security.web.savedrequest.RequestCache
@ -88,6 +89,27 @@ class SessionManagementConfigurerTests extends BaseSpringSpec {
}
def "invoke sessionManagement twice does not override"() {
when:
loadConfig(InvokeTwiceDoesNotOverride)
then:
findFilter(SecurityContextPersistenceFilter).repo.class == NullSecurityContextRepository
}
@Configuration
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.stateless)
.and()
.sessionManagement()
}
}
def "sessionManagement ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()

View File

@ -15,10 +15,13 @@
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
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.web.authentication.preauth.x509.X509AuthenticationFilter
/**
@ -40,4 +43,18 @@ class X509ConfigurerTests extends BaseSpringSpec {
then: "X509AuthenticationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as X509AuthenticationFilter) >> {X509AuthenticationFilter o -> o}
}
def "invoke x509 twice does not override"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.x509()
.subjectPrincipalRegex(".*")
.and()
.x509()
then:
http.getConfigurer(X509Configurer).subjectPrincipalRegex == ".*"
}
}

View File

@ -15,10 +15,13 @@
*/
package org.springframework.security.config.annotation.web.configurers.openid
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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.userdetails.UserDetailsByNameServiceWrapper
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.openid.OpenIDAuthenticationFilter
@ -48,4 +51,38 @@ class OpenIDLoginConfigurerTests extends BaseSpringSpec {
and: "OpenIDAuthenticationProvider is registered with LifecycleManager"
1 * opp.postProcess(_ as OpenIDAuthenticationProvider) >> {OpenIDAuthenticationProvider o -> o}
}
def "invoke openidLogin twice does not override"() {
setup:
loadConfig(InvokeTwiceDoesNotOverrideConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl.endsWith("/login/custom")
}
@Configuration
@EnableWebSecurity
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().authenticated()
.and()
.openidLogin()
.loginPage("/login/custom")
.and()
.openidLogin()
}
}
}