Browse Source

NamespaceSessionManagementTests groovy->java

Issue: gh-4939
Josh Cummings 6 years ago
parent
commit
ee8182dceb

+ 0 - 229
config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.groovy

@@ -1,229 +0,0 @@
-/*
- * 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
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.security.config.annotation.web.configurers
-
-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.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.AbstractSessionFixationProtectionStrategy;
-import org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy;
-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.session.ConcurrentSessionFilter
-import org.springframework.security.web.session.SessionManagementFilter
-import org.springframework.security.web.session.InvalidSessionStrategy
-
-/**
- *
- * @author Rob Winch
- */
-class NamespaceSessionManagementTests extends BaseSpringSpec {
-
-	def "http/session-management"() {
-		when:
-			loadConfig(SessionManagementConfig)
-		then:
-			findSessionAuthenticationStrategy(AbstractSessionFixationProtectionStrategy)
-	}
-
-	@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).sessionInformationExpiredStrategy.destinationUrl == "/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
-		}
-	}
-
-	// gh-3371
-	def "http/session-management custom invalidationstrategy"() {
-		setup:
-			InvalidSessionStrategyConfig.ISS = Mock(InvalidSessionStrategy)
-		when:
-			loadConfig(InvalidSessionStrategyConfig)
-		then:
-			findFilter(SessionManagementFilter).invalidSessionStrategy == InvalidSessionStrategyConfig.ISS
-	}
-
-	@EnableWebSecurity
-	static class InvalidSessionStrategyConfig extends WebSecurityConfigurerAdapter {
-		static InvalidSessionStrategy ISS
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			http
-				.sessionManagement()
-					.invalidSessionStrategy(ISS)
-		}
-	}
-
-	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:
-			if(isChangeSession()) {
-				findSessionAuthenticationStrategy(ChangeSessionIdAuthenticationStrategy)
-			} else {
-				findSessionAuthenticationStrategy(SessionFixationProtectionStrategy).migrateSessionAttributes
-			}
-	}
-
-	@EnableWebSecurity
-	static class SFPMigrateSessionManagementConfig extends WebSecurityConfigurerAdapter {
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			http
-				.sessionManagement()
-		}
-	}
-
-	def "SEC-2913: Default JavaConfig session fixation AuthenticationStrategy has NullEventPublisher"() {
-		setup:
-			loadConfig(SFPPostProcessedConfig)
-		when:
-			findSessionAuthenticationStrategy(AbstractSessionFixationProtectionStrategy).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 { c.isAssignableFrom(it.class) }
-	}
-
-	@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)
-		}
-
-	}
-
-	boolean isChangeSession() {
-		try {
-			new ChangeSessionIdAuthenticationStrategy()
-			return true
-		} catch(Exception e) {}
-		return false
-	}
-}

+ 471 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.java

@@ -0,0 +1,471 @@
+/*
+ * Copyright 2002-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.config.annotation.web.configurers;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpSession;
+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.test.SpringTestRule;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.session.SessionInformation;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.core.session.SessionRegistryImpl;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
+import org.springframework.security.web.authentication.session.SessionAuthenticationException;
+import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
+import org.springframework.security.web.authentication.session.SessionFixationProtectionEvent;
+import org.springframework.security.web.session.InvalidSessionStrategy;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.ResultMatcher;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ *
+ * @author Rob Winch
+ * @author Josh Cummings
+ */
+public class NamespaceSessionManagementTests {
+
+	@Rule
+	public final SpringTestRule spring = new SpringTestRule();
+
+	@Autowired
+	MockMvc mvc;
+
+	@Test
+	public void authenticateWhenDefaultSessionManagementThenMatchesNamespace() throws Exception {
+		this.spring.register
+				(SessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class).autowire();
+
+		MockHttpSession session = new MockHttpSession();
+		String sessionId = session.getId();
+
+		MvcResult result =
+				this.mvc.perform(get("/auth")
+						.session(session)
+						.with(httpBasic("user", "password")))
+						.andExpect(session())
+						.andReturn();
+
+		assertThat(result.getRequest().getSession(false).getId()).isNotEqualTo(sessionId);
+	}
+
+	@EnableWebSecurity
+	static class SessionManagementConfig extends WebSecurityConfigurerAdapter {
+	}
+
+	@Test
+	public void authenticateWhenUsingInvalidSessionUrlThenMatchesNamespace() throws Exception {
+		this.spring.register(CustomSessionManagementConfig.class).autowire();
+
+		this.mvc.perform(get("/auth")
+				.with(request -> {
+					request.setRequestedSessionIdValid(false);
+					request.setRequestedSessionId("id");
+					return request;
+				}))
+				.andExpect(redirectedUrl("/invalid-session"));
+	}
+
+
+	@Test
+	public void authenticateWhenUsingExpiredUrlThenMatchesNamespace() throws Exception {
+		this.spring.register(CustomSessionManagementConfig.class).autowire();
+
+		MockHttpSession session = new MockHttpSession();
+		SessionInformation sessionInformation = new SessionInformation(new Object(), session.getId(), new Date(0));
+		sessionInformation.expireNow();
+		SessionRegistry sessionRegistry = this.spring.getContext().getBean(SessionRegistry.class);
+		when(sessionRegistry.getSessionInformation(session.getId())).thenReturn(sessionInformation);
+
+		this.mvc.perform(get("/auth").session(session))
+				.andExpect(redirectedUrl("/expired-session"));
+	}
+
+	@Test
+	public void authenticateWhenUsingMaxSessionsThenMatchesNamespace() throws Exception {
+		this.spring.register(CustomSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class).autowire();
+
+		this.mvc.perform(get("/auth")
+				.with(httpBasic("user", "password")))
+				.andExpect(status().isOk());
+
+		this.mvc.perform(get("/auth")
+				.with(httpBasic("user", "password")))
+				.andExpect(redirectedUrl("/session-auth-error"));
+	}
+
+	@Test
+	public void authenticateWhenUsingFailureUrlThenMatchesNamespace() throws Exception {
+		this.spring.register(CustomSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class).autowire();
+
+		MockHttpServletRequest mock = spy(MockHttpServletRequest.class);
+		mock.setSession(new MockHttpSession());
+		when(mock.changeSessionId()).thenThrow(SessionAuthenticationException.class);
+		mock.setMethod("GET");
+
+		this.mvc.perform(get("/auth")
+				.with(request -> mock)
+				.with(httpBasic("user", "password")))
+				.andExpect(redirectedUrl("/session-auth-error"));
+	}
+
+	@Test
+	public void authenticateWhenUsingSessionRegistryThenMatchesNamespace() throws Exception {
+		this.spring.register(CustomSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class).autowire();
+
+		SessionRegistry sessionRegistry = this.spring.getContext().getBean(SessionRegistry.class);
+
+		this.mvc.perform(get("/auth")
+				.with(httpBasic("user", "password")))
+				.andExpect(status().isOk());
+
+		verify(sessionRegistry).registerNewSession(any(String.class), any(Object.class));
+	}
+
+	@EnableWebSecurity
+	static class CustomSessionManagementConfig extends WebSecurityConfigurerAdapter {
+		SessionRegistry sessionRegistry = spy(SessionRegistryImpl.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.authorizeRequests()
+					.anyRequest().authenticated()
+					.and()
+				.httpBasic()
+					.and()
+				.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(sessionRegistry()); // session-management/concurrency-control@session-registry-ref
+		}
+
+		@Bean
+		SessionRegistry sessionRegistry() {
+			return this.sessionRegistry;
+		}
+	}
+
+
+	// gh-3371
+	@Test
+	public void authenticateWhenUsingCustomInvalidSessionStrategyThenMatchesNamespace() throws Exception {
+		this.spring.register(InvalidSessionStrategyConfig.class).autowire();
+
+		this.mvc.perform(get("/auth")
+				.with(request -> {
+					request.setRequestedSessionIdValid(false);
+					request.setRequestedSessionId("id");
+					return request;
+				}))
+				.andExpect(status().isOk());
+
+		verifyBean(InvalidSessionStrategy.class)
+				.onInvalidSessionDetected(any(HttpServletRequest.class), any(HttpServletResponse.class));
+	}
+
+	@EnableWebSecurity
+	static class InvalidSessionStrategyConfig extends WebSecurityConfigurerAdapter {
+		InvalidSessionStrategy invalidSessionStrategy = mock(InvalidSessionStrategy.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+					.invalidSessionStrategy(invalidSessionStrategy());
+		}
+
+		@Bean
+		InvalidSessionStrategy invalidSessionStrategy() {
+			return this.invalidSessionStrategy;
+		}
+	}
+
+	@Test
+	public void authenticateWhenUsingCustomSessionAuthenticationStrategyThenMatchesNamespace() throws Exception {
+		this.spring.register(RefsSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class).autowire();
+
+		this.mvc.perform(get("/auth")
+				.with(httpBasic("user", "password")))
+				.andExpect(status().isOk());
+
+		verifyBean(SessionAuthenticationStrategy.class)
+				.onAuthentication(any(Authentication.class),
+						any(HttpServletRequest.class), any(HttpServletResponse.class));
+	}
+
+	@EnableWebSecurity
+	static class RefsSessionManagementConfig extends WebSecurityConfigurerAdapter {
+		SessionAuthenticationStrategy sessionAuthenticationStrategy =
+				mock(SessionAuthenticationStrategy.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+					.sessionAuthenticationStrategy(sessionAuthenticationStrategy()) // session-management@session-authentication-strategy-ref
+					.and()
+				.httpBasic();
+		}
+
+		@Bean
+		SessionAuthenticationStrategy sessionAuthenticationStrategy() {
+			return this.sessionAuthenticationStrategy;
+		}
+	}
+
+	@Test
+	public void authenticateWhenNoSessionFixationProtectionThenMatchesNamespace() throws Exception {
+		this.spring.register(SFPNoneSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class).autowire();
+
+		MockHttpSession givenSession = new MockHttpSession();
+		String givenSessionId = givenSession.getId();
+		MockHttpSession resultingSession = (MockHttpSession)
+				this.mvc.perform(get("/auth")
+						.session(givenSession)
+						.with(httpBasic("user", "password")))
+						.andExpect(status().isOk())
+						.andReturn().getRequest().getSession(false);
+
+		assertThat(givenSessionId).isEqualTo(resultingSession.getId());
+	}
+
+	@EnableWebSecurity
+	static class SFPNoneSessionManagementConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+					.sessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy())
+					.and()
+				.httpBasic();
+		}
+	}
+
+	@Test
+	public void authenticateWhenMigrateSessionFixationProtectionThenMatchesNamespace() throws Exception {
+		this.spring.register(SFPMigrateSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class).autowire();
+
+		MockHttpSession givenSession = new MockHttpSession();
+		String givenSessionId = givenSession.getId();
+		givenSession.setAttribute("name", "value");
+
+		MockHttpSession resultingSession = (MockHttpSession)
+				this.mvc.perform(get("/auth")
+						.session(givenSession)
+						.with(httpBasic("user", "password")))
+						.andExpect(status().isOk())
+						.andReturn().getRequest().getSession(false);
+
+		assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
+		assertThat(resultingSession.getAttribute("name")).isEqualTo("value");
+	}
+
+	@EnableWebSecurity
+	static class SFPMigrateSessionManagementConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+					.and()
+				.httpBasic();
+		}
+	}
+
+	// SEC-2913
+	@Test
+	public void authenticateWhenUsingSessionFixationProtectionThenUsesNonNullEventPublisher() throws Exception {
+		this.spring.register(SFPPostProcessedConfig.class, UserDetailsServiceConfig.class).autowire();
+
+		this.mvc.perform(get("/auth")
+				.session(new MockHttpSession())
+				.with(httpBasic("user", "password")))
+				.andExpect(status().isNotFound());
+
+		verifyBean(MockEventListener.class).onApplicationEvent(any(SessionFixationProtectionEvent.class));
+	}
+
+	@EnableWebSecurity
+	static class SFPPostProcessedConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+					.and()
+				.httpBasic();
+		}
+
+		@Bean
+		public MockEventListener eventListener() {
+			return spy(new MockEventListener());
+		}
+	}
+
+	@Test
+	public void authenticateWhenNewSessionFixationProtectionThenMatchesNamespace() throws Exception {
+		this.spring.register(SFPNewSessionSessionManagementConfig.class, UserDetailsServiceConfig.class).autowire();
+
+		MockHttpSession givenSession = new MockHttpSession();
+		String givenSessionId = givenSession.getId();
+		givenSession.setAttribute("name", "value");
+
+		MockHttpSession resultingSession = (MockHttpSession)
+				this.mvc.perform(get("/auth")
+						.session(givenSession)
+						.with(httpBasic("user", "password")))
+						.andExpect(status().isNotFound())
+						.andReturn().getRequest().getSession(false);
+
+		assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
+		assertThat(resultingSession.getAttribute("name")).isNull();
+	}
+
+	@EnableWebSecurity
+	static class SFPNewSessionSessionManagementConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.sessionManagement()
+					.sessionFixation().newSession()
+					.and()
+				.httpBasic();
+		}
+	}
+
+
+	private <T> T verifyBean(Class<T> clazz) {
+		return verify(this.spring.getContext().getBean(clazz));
+	}
+
+	static class MockEventListener implements ApplicationListener<SessionFixationProtectionEvent> {
+		List<SessionFixationProtectionEvent> events = new ArrayList<>();
+
+		public void onApplicationEvent(SessionFixationProtectionEvent event) {
+			this.events.add(event);
+		}
+	}
+
+	@Configuration
+	static class UserDetailsServiceConfig {
+		@Bean
+		UserDetailsService userDetailsService() {
+			return new InMemoryUserDetailsManager(
+					User.withDefaultPasswordEncoder()
+							.username("user")
+							.password("password")
+							.roles("USER")
+							.build());
+		}
+	}
+
+	@RestController
+	static class BasicController {
+		@GetMapping("/")
+		public String ok() {
+			return "ok";
+		}
+
+		@GetMapping("/auth")
+		public String auth(Principal principal) {
+			return principal.getName();
+		}
+	}
+
+	private static SessionResultMatcher session() {
+		return new SessionResultMatcher();
+	}
+
+	private static class SessionResultMatcher implements ResultMatcher {
+		private String id;
+		private Boolean valid;
+		private Boolean exists = true;
+
+		public ResultMatcher exists(boolean exists) {
+			this.exists = exists;
+			return this;
+		}
+
+		public ResultMatcher valid(boolean valid) {
+			this.valid = valid;
+			return this.exists(true);
+		}
+
+		public ResultMatcher id(String id) {
+			this.id = id;
+			return this.exists(true);
+		}
+
+		@Override
+		public void match(MvcResult result) {
+			if (!this.exists) {
+				assertThat(result.getRequest().getSession(false)).isNull();
+				return;
+			}
+
+			assertThat(result.getRequest().getSession(false)).isNotNull();
+
+			MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false);
+
+			if (this.valid != null) {
+				if (this.valid) {
+					assertThat(session.isInvalid()).isFalse();
+				} else {
+					assertThat(session.isInvalid()).isTrue();
+				}
+			}
+
+			if (this.id != null) {
+				assertThat(session.getId()).isEqualTo(this.id);
+			}
+		}
+	}
+}