From 2638555e530176698be484f5a7fbdad1cd8a0248 Mon Sep 17 00:00:00 2001 From: Mark Chesney Date: Mon, 4 Sep 2023 21:15:12 -0700 Subject: [PATCH] Allow redirect strategy to be customized Closes gh-12795 --- ...stedUrlRedirectInvalidSessionStrategy.java | 16 +++++++- .../session/SessionManagementFilterTests.java | 38 ++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/session/RequestedUrlRedirectInvalidSessionStrategy.java b/web/src/main/java/org/springframework/security/web/session/RequestedUrlRedirectInvalidSessionStrategy.java index 2720e72937..da2d8cf297 100644 --- a/web/src/main/java/org/springframework/security/web/session/RequestedUrlRedirectInvalidSessionStrategy.java +++ b/web/src/main/java/org/springframework/security/web/session/RequestedUrlRedirectInvalidSessionStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2023 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. @@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; +import org.springframework.util.Assert; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; /** @@ -32,12 +33,13 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder; * detected by the {@code SessionManagementFilter}. * * @author Craig Andrews + * @author Mark Chesney */ public final class RequestedUrlRedirectInvalidSessionStrategy implements InvalidSessionStrategy { private final Log logger = LogFactory.getLog(getClass()); - private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); + private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); private boolean createNewSession = true; @@ -68,4 +70,14 @@ public final class RequestedUrlRedirectInvalidSessionStrategy implements Invalid this.createNewSession = createNewSession; } + /** + * Sets the redirect strategy to use. The default is {@link DefaultRedirectStrategy}. + * @param redirectStrategy the redirect strategy to use. + * @since 6.2 + */ + public void setRedirectStrategy(RedirectStrategy redirectStrategy) { + Assert.notNull(redirectStrategy, "redirectStrategy cannot be null"); + this.redirectStrategy = redirectStrategy; + } + } diff --git a/web/src/test/java/org/springframework/security/web/session/SessionManagementFilterTests.java b/web/src/test/java/org/springframework/security/web/session/SessionManagementFilterTests.java index 043bfa1e07..1570bf734c 100644 --- a/web/src/test/java/org/springframework/security/web/session/SessionManagementFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/session/SessionManagementFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2023 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. @@ -20,6 +20,7 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.mock.web.MockFilterChain; @@ -29,6 +30,7 @@ import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.session.SessionAuthenticationException; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; @@ -46,9 +48,11 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; /** * @author Luke Taylor * @author Rob Winch + * @author Mark Chesney */ public class SessionManagementFilterTests { + @BeforeEach @AfterEach public void clearContext() { SecurityContextHolder.clearContext(); @@ -174,6 +178,38 @@ public class SessionManagementFilterTests { assertThat(response.getRedirectedUrl()).isEqualTo("/requested"); } + @Test + public void responseIsRedirectedToRequestedUrlIfContextPathIsSetAndSessionIsInvalid() throws Exception { + // given + DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); + redirectStrategy.setContextRelative(true); + RequestedUrlRedirectInvalidSessionStrategy invalidSessionStrategy = new RequestedUrlRedirectInvalidSessionStrategy(); + invalidSessionStrategy.setCreateNewSession(true); + invalidSessionStrategy.setRedirectStrategy(redirectStrategy); + SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class); + SessionAuthenticationStrategy sessionAuthenticationStrategy = mock(SessionAuthenticationStrategy.class); + SessionManagementFilter filter = new SessionManagementFilter(securityContextRepository, + sessionAuthenticationStrategy); + filter.setInvalidSessionStrategy(invalidSessionStrategy); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setContextPath("/context"); + request.setRequestedSessionId("xxx"); + request.setRequestedSessionIdValid(false); + request.setRequestURI("/context/requested"); + MockHttpServletResponse response = new MockHttpServletResponse(); + FilterChain chain = mock(FilterChain.class); + + // when + filter.doFilter(request, response, chain); + + // then + verify(securityContextRepository).containsContext(request); + verifyNoMoreInteractions(securityContextRepository, sessionAuthenticationStrategy, chain); + assertThat(response.isCommitted()).isTrue(); + assertThat(response.getRedirectedUrl()).isEqualTo("/context/requested"); + assertThat(response.getStatus()).isEqualTo(302); + } + @Test public void customAuthenticationTrustResolver() throws Exception { AuthenticationTrustResolver trustResolver = mock(AuthenticationTrustResolver.class);