Browse Source

SEC-2913: Post Process default session fixation AuthenticationStrategy

Before the default session fixation AuthenticationStrategy used a
NullEventPublisher when using the Java Configuration. This was due to the
fact that it is not exposed as a Bean and is not post processed.

We now post process the default session fixation AuthenticationStrategy
which initializes the EventPublisher properly.
Rob Winch 10 năm trước cách đây
mục cha
commit
6c541468f6

+ 5 - 1
config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java

@@ -91,7 +91,8 @@ import org.springframework.util.Assert;
  */
 public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>> extends
 		AbstractHttpConfigurer<SessionManagementConfigurer<H>, H> {
-	private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = createDefaultSessionFixationProtectionStrategy();
+	private final SessionAuthenticationStrategy DEFAULT_SESSION_FIXATION_STRATEGY = createDefaultSessionFixationProtectionStrategy();
+	private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = DEFAULT_SESSION_FIXATION_STRATEGY;
 	private SessionAuthenticationStrategy sessionAuthenticationStrategy;
 	private InvalidSessionStrategy invalidSessionStrategy;
 	private List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<SessionAuthenticationStrategy>();
@@ -475,6 +476,9 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
 			return sessionAuthenticationStrategy;
 		}
 		List<SessionAuthenticationStrategy> delegateStrategies = sessionAuthenticationStrategies;
+		if(DEFAULT_SESSION_FIXATION_STRATEGY == sessionFixationAuthenticationStrategy) {
+			sessionFixationAuthenticationStrategy = postProcess(sessionFixationAuthenticationStrategy);
+		}
 		if (isConcurrentSessionControlEnabled()) {
 			SessionRegistry sessionRegistry = getSessionRegistry(http);
 			ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlStrategy = new ConcurrentSessionControlAuthenticationStrategy(

+ 162 - 130
config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.groovy

@@ -15,19 +15,19 @@
  */
 package org.springframework.security.config.annotation.web.configurers
 
-import org.springframework.context.annotation.Configuration
+import org.springframework.context.ApplicationListener
+import org.springframework.context.annotation.Bean
+import org.springframework.mock.web.MockHttpSession
+import org.springframework.security.authentication.TestingAuthenticationToken
 import org.springframework.security.config.annotation.BaseSpringSpec
-import org.springframework.security.config.annotation.ObjectPostProcessor
-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.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.session.SessionRegistry
-import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
-import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
+import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy
+import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy
+import org.springframework.security.web.authentication.session.SessionFixationProtectionEvent
 import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy
-import org.springframework.security.web.context.SecurityContextPersistenceFilter
-import org.springframework.security.web.context.SecurityContextRepository
 import org.springframework.security.web.session.ConcurrentSessionFilter
 import org.springframework.security.web.session.SessionManagementFilter
 
@@ -37,124 +37,156 @@ import org.springframework.security.web.session.SessionManagementFilter
  */
 class NamespaceSessionManagementTests extends BaseSpringSpec {
 
-    def "http/session-management"() {
-        when:
-            loadConfig(SessionManagementConfig)
-        then:
-            findSessionAuthenticationStrategy(SessionFixationProtectionStrategy)
-    }
-
-    @EnableWebSecurity
-    static class SessionManagementConfig extends WebSecurityConfigurerAdapter {
-        @Override
-        protected void configure(HttpSecurity http) throws Exception {
-            // enabled by default
-        }
-    }
-
-    def "http/session-management custom"() {
-        setup:
-            CustomSessionManagementConfig.SR = Mock(SessionRegistry)
-        when:
-            loadConfig(CustomSessionManagementConfig)
-            def concurrentStrategy = findFilter(SessionManagementFilter).sessionAuthenticationStrategy.delegateStrategies[0]
-        then:
-            findFilter(SessionManagementFilter).invalidSessionStrategy.destinationUrl == "/invalid-session"
-            findFilter(SessionManagementFilter).failureHandler.defaultFailureUrl == "/session-auth-error"
-            concurrentStrategy.maximumSessions == 1
-            concurrentStrategy.exceptionIfMaximumExceeded
-            concurrentStrategy.sessionRegistry == CustomSessionManagementConfig.SR
-            findFilter(ConcurrentSessionFilter).expiredUrl == "/expired-session"
-    }
-
-    @EnableWebSecurity
-    static class CustomSessionManagementConfig extends WebSecurityConfigurerAdapter {
-        static SessionRegistry SR
-        @Override
-        protected void configure(HttpSecurity http) throws Exception {
-            http
-                .sessionManagement()
-                    .invalidSessionUrl("/invalid-session") // session-management@invalid-session-url
-                    .sessionAuthenticationErrorUrl("/session-auth-error") // session-management@session-authentication-error-url
-                    .maximumSessions(1) // session-management/concurrency-control@max-sessions
-                        .maxSessionsPreventsLogin(true) // session-management/concurrency-control@error-if-maximum-exceeded
-                        .expiredUrl("/expired-session") // session-management/concurrency-control@expired-url
-                        .sessionRegistry(SR) // session-management/concurrency-control@session-registry-ref
-        }
-    }
-
-    def "http/session-management refs"() {
-        setup:
-            RefsSessionManagementConfig.SAS = Mock(SessionAuthenticationStrategy)
-        when:
-            loadConfig(RefsSessionManagementConfig)
-        then:
-            findFilter(SessionManagementFilter).sessionAuthenticationStrategy.delegateStrategies.find { it ==  RefsSessionManagementConfig.SAS }
-    }
-
-    @EnableWebSecurity
-    static class RefsSessionManagementConfig extends WebSecurityConfigurerAdapter {
-        static SessionAuthenticationStrategy SAS
-        @Override
-        protected void configure(HttpSecurity http) throws Exception {
-            http
-                .sessionManagement()
-                    .sessionAuthenticationStrategy(SAS) // session-management@session-authentication-strategy-ref
-        }
-    }
-
-    def "http/session-management@session-fixation-protection=none"() {
-        when:
-            loadConfig(SFPNoneSessionManagementConfig)
-        then:
-            findFilter(SessionManagementFilter).sessionAuthenticationStrategy.delegateStrategies.find { it instanceof  NullAuthenticatedSessionStrategy }
-    }
-
-    @EnableWebSecurity
-    static class SFPNoneSessionManagementConfig extends WebSecurityConfigurerAdapter {
-        @Override
-        protected void configure(HttpSecurity http) throws Exception {
-            http
-                .sessionManagement()
-                    .sessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy())
-        }
-    }
-
-    def "http/session-management@session-fixation-protection=migrateSession (default)"() {
-        when:
-            loadConfig(SFPMigrateSessionManagementConfig)
-        then:
-            findSessionAuthenticationStrategy(SessionFixationProtectionStrategy).migrateSessionAttributes
-    }
-
-    @EnableWebSecurity
-    static class SFPMigrateSessionManagementConfig extends WebSecurityConfigurerAdapter {
-        @Override
-        protected void configure(HttpSecurity http) throws Exception {
-            http
-                .sessionManagement()
-        }
-    }
-
-    def "http/session-management@session-fixation-protection=newSession"() {
-        when:
-            loadConfig(SFPNewSessionSessionManagementConfig)
-        then:
-            !findSessionAuthenticationStrategy(SessionFixationProtectionStrategy).migrateSessionAttributes
-    }
-
-    def findSessionAuthenticationStrategy(def c) {
-        findFilter(SessionManagementFilter).sessionAuthenticationStrategy.delegateStrategies.find { it.class.isAssignableFrom(c) }
-    }
-
-    @EnableWebSecurity
-    static class SFPNewSessionSessionManagementConfig extends WebSecurityConfigurerAdapter {
-        @Override
-        protected void configure(HttpSecurity http) throws Exception {
-            http
-                .sessionManagement()
-                    .sessionFixation()
-                        .newSession()
-        }
-    }
+	def "http/session-management"() {
+		when:
+			loadConfig(SessionManagementConfig)
+		then:
+			findSessionAuthenticationStrategy(SessionFixationProtectionStrategy)
+	}
+
+	@EnableWebSecurity
+	static class SessionManagementConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// enabled by default
+		}
+	}
+
+	def "http/session-management custom"() {
+		setup:
+			CustomSessionManagementConfig.SR = Mock(SessionRegistry)
+		when:
+			loadConfig(CustomSessionManagementConfig)
+			def concurrentStrategy = findFilter(SessionManagementFilter).sessionAuthenticationStrategy.delegateStrategies[0]
+		then:
+			findFilter(SessionManagementFilter).invalidSessionStrategy.destinationUrl == "/invalid-session"
+			findFilter(SessionManagementFilter).failureHandler.defaultFailureUrl == "/session-auth-error"
+			concurrentStrategy.maximumSessions == 1
+			concurrentStrategy.exceptionIfMaximumExceeded
+			concurrentStrategy.sessionRegistry == CustomSessionManagementConfig.SR
+			findFilter(ConcurrentSessionFilter).expiredUrl == "/expired-session"
+	}
+
+	@EnableWebSecurity
+	static class CustomSessionManagementConfig extends WebSecurityConfigurerAdapter {
+		static SessionRegistry SR
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+					.invalidSessionUrl("/invalid-session") // session-management@invalid-session-url
+					.sessionAuthenticationErrorUrl("/session-auth-error") // session-management@session-authentication-error-url
+					.maximumSessions(1) // session-management/concurrency-control@max-sessions
+						.maxSessionsPreventsLogin(true) // session-management/concurrency-control@error-if-maximum-exceeded
+						.expiredUrl("/expired-session") // session-management/concurrency-control@expired-url
+						.sessionRegistry(SR) // session-management/concurrency-control@session-registry-ref
+		}
+	}
+
+	def "http/session-management refs"() {
+		setup:
+			RefsSessionManagementConfig.SAS = Mock(SessionAuthenticationStrategy)
+		when:
+			loadConfig(RefsSessionManagementConfig)
+		then:
+			findFilter(SessionManagementFilter).sessionAuthenticationStrategy.delegateStrategies.find { it ==  RefsSessionManagementConfig.SAS }
+	}
+
+	@EnableWebSecurity
+	static class RefsSessionManagementConfig extends WebSecurityConfigurerAdapter {
+		static SessionAuthenticationStrategy SAS
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+					.sessionAuthenticationStrategy(SAS) // session-management@session-authentication-strategy-ref
+		}
+	}
+
+	def "http/session-management@session-fixation-protection=none"() {
+		when:
+			loadConfig(SFPNoneSessionManagementConfig)
+		then:
+			findFilter(SessionManagementFilter).sessionAuthenticationStrategy.delegateStrategies.find { it instanceof  NullAuthenticatedSessionStrategy }
+	}
+
+	@EnableWebSecurity
+	static class SFPNoneSessionManagementConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+					.sessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy())
+		}
+	}
+
+	def "http/session-management@session-fixation-protection=migrateSession (default)"() {
+		when:
+			loadConfig(SFPMigrateSessionManagementConfig)
+		then:
+			findSessionAuthenticationStrategy(SessionFixationProtectionStrategy).migrateSessionAttributes
+	}
+
+	@EnableWebSecurity
+	static class SFPMigrateSessionManagementConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+		}
+	}
+
+	def "http/session-management@session-fixation-protection=changeSessionId"() {
+		setup:
+			loadConfig(SFPPostProcessedConfig)
+		when:
+			findSessionAuthenticationStrategy(SessionFixationProtectionStrategy).onSessionChange("id", new MockHttpSession(), new TestingAuthenticationToken("u","p","ROLE_USER"))
+		then:
+			context.getBean(MockEventListener).events
+	}
+
+	@EnableWebSecurity
+	static class SFPPostProcessedConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+		}
+
+		@Bean
+		public MockEventListener eventListener() {
+			new MockEventListener()
+		}
+	}
+
+	def "http/session-management@session-fixation-protection=newSession"() {
+		when:
+			loadConfig(SFPNewSessionSessionManagementConfig)
+		then:
+			!findSessionAuthenticationStrategy(SessionFixationProtectionStrategy).migrateSessionAttributes
+	}
+
+	def findSessionAuthenticationStrategy(def c) {
+		findFilter(SessionManagementFilter).sessionAuthenticationStrategy.delegateStrategies.find { it.class.isAssignableFrom(c) }
+	}
+
+	@EnableWebSecurity
+	static class SFPNewSessionSessionManagementConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+					.sessionFixation()
+						.newSession()
+		}
+	}
+
+	static class MockEventListener implements ApplicationListener<SessionFixationProtectionEvent> {
+		List<SessionFixationProtectionEvent> events = []
+
+		public void onApplicationEvent(SessionFixationProtectionEvent event) {
+			events.add(event)
+		}
+
+	}
 }

+ 204 - 201
config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.groovy

@@ -34,6 +34,7 @@ import org.springframework.security.web.access.ExceptionTranslationFilter
 import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy
 import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy
 import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy
+import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
 import org.springframework.security.web.context.NullSecurityContextRepository
 import org.springframework.security.web.context.SecurityContextPersistenceFilter
 import org.springframework.security.web.context.SecurityContextRepository
@@ -48,205 +49,207 @@ import org.springframework.security.web.session.SessionManagementFilter
  */
 class SessionManagementConfigurerTests extends BaseSpringSpec {
 
-    def "sessionManagement does not override explicit RequestCache"() {
-        setup:
-            SessionManagementDoesNotOverrideExplicitRequestCacheConfig.REQUEST_CACHE = Mock(RequestCache)
-        when:
-            loadConfig(SessionManagementDoesNotOverrideExplicitRequestCacheConfig)
-        then:
-            findFilter(ExceptionTranslationFilter).requestCache == SessionManagementDoesNotOverrideExplicitRequestCacheConfig.REQUEST_CACHE
-    }
-
-    @EnableWebSecurity
-    static class SessionManagementDoesNotOverrideExplicitRequestCacheConfig extends WebSecurityConfigurerAdapter {
-        static RequestCache REQUEST_CACHE
-
-        @Override
-        protected void configure(HttpSecurity http) throws Exception {
-            http
-                .requestCache()
-                    .requestCache(REQUEST_CACHE)
-                    .and()
-                .sessionManagement()
-                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
-        }
-
-    }
-
-    def "sessionManagement does not override explict SecurityContextRepository"() {
-        setup:
-            SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig.SECURITY_CONTEXT_REPO = Mock(SecurityContextRepository)
-        when:
-            loadConfig(SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig)
-        then:
-            findFilter(SecurityContextPersistenceFilter).repo == SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig.SECURITY_CONTEXT_REPO
-    }
-
-    @EnableWebSecurity
-    static class SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig extends WebSecurityConfigurerAdapter {
-        static SecurityContextRepository SECURITY_CONTEXT_REPO
-
-        @Override
-        protected void configure(HttpSecurity http) throws Exception {
-            http
-                .securityContext()
-                    .securityContextRepository(SECURITY_CONTEXT_REPO)
-                    .and()
-                .sessionManagement()
-                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
-        }
-
-    }
-
-    def "invoke sessionManagement twice does not override"() {
-        when:
-            loadConfig(InvokeTwiceDoesNotOverride)
-        then:
-            findFilter(SecurityContextPersistenceFilter).repo.class == NullSecurityContextRepository
-    }
-
-    @EnableWebSecurity
-    static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
-        @Override
-        protected void configure(HttpSecurity http) throws Exception {
-            http
-                .sessionManagement()
-                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
-                    .and()
-                .sessionManagement()
-        }
-
-    }
-
-    def 'SEC-2137: disable session fixation and enable concurrency control'() {
-        setup: "context where session fixation is disabled and concurrency control is enabled"
-            loadConfig(DisableSessionFixationEnableConcurrencyControlConfig)
-            String originalSessionId = request.session.id
-            String credentials = "user:password"
-            request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
-        when: "authenticate"
-            springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
-        then: "session invalidate is not called"
-            request.session.id == originalSessionId
-    }
-
-    @EnableWebSecurity
-    static class DisableSessionFixationEnableConcurrencyControlConfig extends WebSecurityConfigurerAdapter {
-        @Override
-        public void configure(HttpSecurity http) {
-            http
-                .httpBasic()
-                    .and()
-                .sessionManagement()
-                    .sessionFixation().none()
-                    .maximumSessions(1)
-        }
-        @Override
-        protected void configure(AuthenticationManagerBuilder auth) {
-            auth
-                .inMemoryAuthentication()
-                    .withUser("user").password("password").roles("USER")
-        }
-    }
-
-    def 'session fixation and enable concurrency control'() {
-        setup: "context where session fixation is disabled and concurrency control is enabled"
-            loadConfig(ConcurrencyControlConfig)
-            def authenticatedSession
-        when: "authenticate successfully"
-            request.servletPath = "/login"
-            request.method = "POST"
-            request.setParameter("username", "user");
-            request.setParameter("password","password")
-            springSecurityFilterChain.doFilter(request, response, chain)
-            authenticatedSession = request.session
-        then: "authentication is sucessful"
-            response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
-            response.redirectedUrl == "/"
-        when: "authenticate with the same user"
-            super.setup()
-            request.servletPath = "/login"
-            request.method = "POST"
-            request.setParameter("username", "user");
-            request.setParameter("password","password")
-            springSecurityFilterChain.doFilter(request, response, chain)
-        then:
-            response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
-            response.redirectedUrl == '/login?error'
-        when: 'SEC-2574: When Session Expires and authentication attempted'
-            context.publishEvent(new HttpSessionDestroyedEvent(authenticatedSession))
-            super.setup()
-            request.servletPath = "/login"
-            request.method = "POST"
-            request.setParameter("username", "user");
-            request.setParameter("password","password")
-            springSecurityFilterChain.doFilter(request, response, chain)
-        then: "authentication is successful"
-            response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
-            response.redirectedUrl == "/"
-    }
-
-    @EnableWebSecurity
-    static class ConcurrencyControlConfig extends WebSecurityConfigurerAdapter {
-        @Override
-        public void configure(HttpSecurity http) {
-            http
-                .formLogin()
-                    .and()
-                .sessionManagement()
-                    .maximumSessions(1)
-                        .maxSessionsPreventsLogin(true)
-        }
-        @Override
-        protected void configure(AuthenticationManagerBuilder auth) {
-            auth
-                .inMemoryAuthentication()
-                    .withUser("user").password("password").roles("USER")
-        }
-    }
-
-    def "sessionManagement ObjectPostProcessor"() {
-        setup:
-            AnyObjectPostProcessor opp = Mock()
-            HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
-        when:
-            http
-                .sessionManagement()
-                    .maximumSessions(1)
-                        .and()
-                    .and()
-                .build()
-
-        then: "SessionManagementFilter is registered with ObjectPostProcessor"
-            1 * opp.postProcess(_ as SessionManagementFilter) >> {SessionManagementFilter o -> o}
-        and: "ConcurrentSessionFilter is registered with ObjectPostProcessor"
-            1 * opp.postProcess(_ as ConcurrentSessionFilter) >> {ConcurrentSessionFilter o -> o}
-        and: "ConcurrentSessionControlAuthenticationStrategy is registered with ObjectPostProcessor"
-            1 * opp.postProcess(_ as ConcurrentSessionControlAuthenticationStrategy) >> {ConcurrentSessionControlAuthenticationStrategy o -> o}
-        and: "CompositeSessionAuthenticationStrategy is registered with ObjectPostProcessor"
-            1 * opp.postProcess(_ as CompositeSessionAuthenticationStrategy) >> {CompositeSessionAuthenticationStrategy o -> o}
-        and: "RegisterSessionAuthenticationStrategy is registered with ObjectPostProcessor"
-            1 * opp.postProcess(_ as RegisterSessionAuthenticationStrategy) >> {RegisterSessionAuthenticationStrategy o -> o}
-    }
-
-    def "use sharedObject trustResolver"() {
-        setup:
-            SharedTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
-        when:
-            loadConfig(SharedTrustResolverConfig)
-        then:
-            findFilter(SecurityContextPersistenceFilter).repo.trustResolver == SharedTrustResolverConfig.TR
-            findFilter(SessionManagementFilter).trustResolver == SharedTrustResolverConfig.TR
-    }
-
-    @EnableWebSecurity
-    static class SharedTrustResolverConfig extends WebSecurityConfigurerAdapter {
-        static AuthenticationTrustResolver TR
-
-        @Override
-        protected void configure(HttpSecurity http) throws Exception {
-            http
-                .setSharedObject(AuthenticationTrustResolver, TR)
-        }
-    }
+	def "sessionManagement does not override explicit RequestCache"() {
+		setup:
+			SessionManagementDoesNotOverrideExplicitRequestCacheConfig.REQUEST_CACHE = Mock(RequestCache)
+		when:
+			loadConfig(SessionManagementDoesNotOverrideExplicitRequestCacheConfig)
+		then:
+			findFilter(ExceptionTranslationFilter).requestCache == SessionManagementDoesNotOverrideExplicitRequestCacheConfig.REQUEST_CACHE
+	}
+
+	@EnableWebSecurity
+	static class SessionManagementDoesNotOverrideExplicitRequestCacheConfig extends WebSecurityConfigurerAdapter {
+		static RequestCache REQUEST_CACHE
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.requestCache()
+					.requestCache(REQUEST_CACHE)
+					.and()
+				.sessionManagement()
+					.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+		}
+
+	}
+
+	def "sessionManagement does not override explict SecurityContextRepository"() {
+		setup:
+			SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig.SECURITY_CONTEXT_REPO = Mock(SecurityContextRepository)
+		when:
+			loadConfig(SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig)
+		then:
+			findFilter(SecurityContextPersistenceFilter).repo == SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig.SECURITY_CONTEXT_REPO
+	}
+
+	@EnableWebSecurity
+	static class SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig extends WebSecurityConfigurerAdapter {
+		static SecurityContextRepository SECURITY_CONTEXT_REPO
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.securityContext()
+					.securityContextRepository(SECURITY_CONTEXT_REPO)
+					.and()
+				.sessionManagement()
+					.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+		}
+
+	}
+
+	def "invoke sessionManagement twice does not override"() {
+		when:
+			loadConfig(InvokeTwiceDoesNotOverride)
+		then:
+			findFilter(SecurityContextPersistenceFilter).repo.class == NullSecurityContextRepository
+	}
+
+	@EnableWebSecurity
+	static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+					.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+					.and()
+				.sessionManagement()
+		}
+
+	}
+
+	def 'SEC-2137: disable session fixation and enable concurrency control'() {
+		setup: "context where session fixation is disabled and concurrency control is enabled"
+			loadConfig(DisableSessionFixationEnableConcurrencyControlConfig)
+			String originalSessionId = request.session.id
+			String credentials = "user:password"
+			request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
+		when: "authenticate"
+			springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
+		then: "session invalidate is not called"
+			request.session.id == originalSessionId
+	}
+
+	@EnableWebSecurity
+	static class DisableSessionFixationEnableConcurrencyControlConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		public void configure(HttpSecurity http) {
+			http
+				.httpBasic()
+					.and()
+				.sessionManagement()
+					.sessionFixation().none()
+					.maximumSessions(1)
+		}
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) {
+			auth
+				.inMemoryAuthentication()
+					.withUser("user").password("password").roles("USER")
+		}
+	}
+
+	def 'session fixation and enable concurrency control'() {
+		setup: "context where session fixation is disabled and concurrency control is enabled"
+			loadConfig(ConcurrencyControlConfig)
+			def authenticatedSession
+		when: "authenticate successfully"
+			request.servletPath = "/login"
+			request.method = "POST"
+			request.setParameter("username", "user");
+			request.setParameter("password","password")
+			springSecurityFilterChain.doFilter(request, response, chain)
+			authenticatedSession = request.session
+		then: "authentication is sucessful"
+			response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
+			response.redirectedUrl == "/"
+		when: "authenticate with the same user"
+			super.setup()
+			request.servletPath = "/login"
+			request.method = "POST"
+			request.setParameter("username", "user");
+			request.setParameter("password","password")
+			springSecurityFilterChain.doFilter(request, response, chain)
+		then:
+			response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
+			response.redirectedUrl == '/login?error'
+		when: 'SEC-2574: When Session Expires and authentication attempted'
+			context.publishEvent(new HttpSessionDestroyedEvent(authenticatedSession))
+			super.setup()
+			request.servletPath = "/login"
+			request.method = "POST"
+			request.setParameter("username", "user");
+			request.setParameter("password","password")
+			springSecurityFilterChain.doFilter(request, response, chain)
+		then: "authentication is successful"
+			response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
+			response.redirectedUrl == "/"
+	}
+
+	@EnableWebSecurity
+	static class ConcurrencyControlConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		public void configure(HttpSecurity http) {
+			http
+				.formLogin()
+					.and()
+				.sessionManagement()
+					.maximumSessions(1)
+						.maxSessionsPreventsLogin(true)
+		}
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) {
+			auth
+				.inMemoryAuthentication()
+					.withUser("user").password("password").roles("USER")
+		}
+	}
+
+	def "sessionManagement ObjectPostProcessor"() {
+		setup:
+			AnyObjectPostProcessor opp = Mock()
+			HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
+		when:
+			http
+				.sessionManagement()
+					.maximumSessions(1)
+						.and()
+					.and()
+				.build()
+
+		then: "SessionManagementFilter is registered with ObjectPostProcessor"
+			1 * opp.postProcess(_ as SessionManagementFilter) >> {SessionManagementFilter o -> o}
+		and: "ConcurrentSessionFilter is registered with ObjectPostProcessor"
+			1 * opp.postProcess(_ as ConcurrentSessionFilter) >> {ConcurrentSessionFilter o -> o}
+		and: "ConcurrentSessionControlAuthenticationStrategy is registered with ObjectPostProcessor"
+			1 * opp.postProcess(_ as ConcurrentSessionControlAuthenticationStrategy) >> {ConcurrentSessionControlAuthenticationStrategy o -> o}
+		and: "CompositeSessionAuthenticationStrategy is registered with ObjectPostProcessor"
+			1 * opp.postProcess(_ as CompositeSessionAuthenticationStrategy) >> {CompositeSessionAuthenticationStrategy o -> o}
+		and: "RegisterSessionAuthenticationStrategy is registered with ObjectPostProcessor"
+			1 * opp.postProcess(_ as RegisterSessionAuthenticationStrategy) >> {RegisterSessionAuthenticationStrategy o -> o}
+		and: "SessionFixationProtectionStrategy is registered with ObjectPostProcessor"
+			1 * opp.postProcess(_ as SessionFixationProtectionStrategy) >> {SessionFixationProtectionStrategy o -> o}
+	}
+
+	def "use sharedObject trustResolver"() {
+		setup:
+			SharedTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
+		when:
+			loadConfig(SharedTrustResolverConfig)
+		then:
+			findFilter(SecurityContextPersistenceFilter).repo.trustResolver == SharedTrustResolverConfig.TR
+			findFilter(SessionManagementFilter).trustResolver == SharedTrustResolverConfig.TR
+	}
+
+	@EnableWebSecurity
+	static class SharedTrustResolverConfig extends WebSecurityConfigurerAdapter {
+		static AuthenticationTrustResolver TR
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.setSharedObject(AuthenticationTrustResolver, TR)
+		}
+	}
 }