2 changed files with 471 additions and 229 deletions
@ -1,229 +0,0 @@
@@ -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 |
||||
} |
||||
} |
||||
@ -0,0 +1,471 @@
@@ -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); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue