Default HttpSessionRequestCache.matchingRequestParameterName=continue

Closes gh-11757
This commit is contained in:
Rob Winch
2022-08-25 12:09:15 -05:00
parent b28efbc4b8
commit f84f08c4b9
12 changed files with 117 additions and 36 deletions

View File

@@ -34,7 +34,6 @@ import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.security.web.csrf.LazyCsrfTokenRepository;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.never;
@@ -81,13 +80,8 @@ public class DeferHttpSessionJavaConfigTests {
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
LazyCsrfTokenRepository csrfRepository = new LazyCsrfTokenRepository(new HttpSessionCsrfTokenRepository());
csrfRepository.setDeferLoadToken(true);
HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
requestCache.setMatchingRequestParameterName("continue");
// @formatter:off
http
.requestCache((cache) -> cache
.requestCache(requestCache)
)
.securityContext((securityContext) -> securityContext
.requireExplicitSave(true)
)

View File

@@ -23,6 +23,7 @@ import java.util.concurrent.Callable;
import com.google.common.net.HttpHeaders;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
@@ -54,6 +55,7 @@ import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.test.web.servlet.RequestCacheResultMatcher;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
import org.springframework.test.web.servlet.MockMvc;
@@ -192,8 +194,11 @@ public class HttpSecurityConfigurationTests {
public void authenticateWhenDefaultFilterChainBeanThenRedirectsToSavedRequest() throws Exception {
this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class).autowire();
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mockMvc.perform(get("/messages"))
.andReturn()
MvcResult mvcResult = this.mockMvc.perform(get("/messages"))
.andReturn();
HttpServletRequest request = mvcResult.getRequest();
HttpServletResponse response = mvcResult.getResponse();
MockHttpSession session = (MockHttpSession) mvcResult
.getRequest()
.getSession();
// @formatter:on
@@ -203,10 +208,8 @@ public class HttpSecurityConfigurationTests {
.param("password", "password")
.session(session)
.with(csrf());
// @formatter:on
// @formatter:off
this.mockMvc.perform(loginRequest)
.andExpect(redirectedUrl("http://localhost/messages"));
.andExpect(RequestCacheResultMatcher.redirectToCachedRequest());
// @formatter:on
}

View File

@@ -42,6 +42,8 @@ import org.springframework.security.web.authentication.session.SessionAuthentica
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
@@ -187,9 +189,11 @@ public class CsrfConfigurerTests {
public void loginWhenCsrfDisabledThenRedirectsToPreviousPostRequest() throws Exception {
this.spring.register(DisableCsrfEnablesRequestCacheConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(post("/to-save")).andReturn();
RequestCache requestCache = new HttpSessionRequestCache();
String redirectUrl = requestCache.getRequest(mvcResult.getRequest(), mvcResult.getResponse()).getRedirectUrl();
this.mvc.perform(post("/login").param("username", "user").param("password", "password")
.session((MockHttpSession) mvcResult.getRequest().getSession())).andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/to-save"));
.andExpect(redirectedUrl(redirectUrl));
}
@Test
@@ -215,9 +219,11 @@ public class CsrfConfigurerTests {
given(CsrfDisablesPostRequestFromRequestCacheConfig.REPO.generateToken(any())).willReturn(csrfToken);
this.spring.register(CsrfDisablesPostRequestFromRequestCacheConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/some-url")).andReturn();
RequestCache requestCache = new HttpSessionRequestCache();
String redirectUrl = requestCache.getRequest(mvcResult.getRequest(), mvcResult.getResponse()).getRedirectUrl();
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf())
.session((MockHttpSession) mvcResult.getRequest().getSession())).andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/some-url"));
.andExpect(redirectedUrl(redirectUrl));
verify(CsrfDisablesPostRequestFromRequestCacheConfig.REPO, atLeastOnce())
.loadToken(any(HttpServletRequest.class));
}

View File

@@ -36,6 +36,7 @@ import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.test.web.servlet.RequestCacheResultMatcher;
import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
@@ -177,7 +178,7 @@ public class RequestCacheConfigurerTests {
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/messages"));
this.mvc.perform(formLogin(session)).andExpect(RequestCacheResultMatcher.redirectToCachedRequest());
}
@Test
@@ -191,7 +192,7 @@ public class RequestCacheConfigurerTests {
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/messages"));
this.mvc.perform(formLogin(session)).andExpect(RequestCacheResultMatcher.redirectToCachedRequest());
}
@Test
@@ -206,7 +207,7 @@ public class RequestCacheConfigurerTests {
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/messages"));
this.mvc.perform(formLogin(session)).andExpect(RequestCacheResultMatcher.redirectToCachedRequest());
}
@Test
@@ -221,7 +222,7 @@ public class RequestCacheConfigurerTests {
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/messages"));
this.mvc.perform(formLogin(session)).andExpect(RequestCacheResultMatcher.redirectToCachedRequest());
}
// gh-6102
@@ -275,7 +276,7 @@ public class RequestCacheConfigurerTests {
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/bob"));
this.mvc.perform(formLogin(session)).andExpect(RequestCacheResultMatcher.redirectToCachedRequest());
}
@Test

View File

@@ -35,6 +35,7 @@ import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.test.web.servlet.RequestCacheResultMatcher;
import org.springframework.security.test.web.support.WebTestUtils;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.access.AccessDeniedHandler;
@@ -337,7 +338,7 @@ public class CsrfConfigTests {
.session(session)
.with(csrf());
this.mvc.perform(login)
.andExpect(redirectedUrl("http://localhost/authenticated"));
.andExpect(RequestCacheResultMatcher.redirectToCachedRequest());
// @formatter:on
}

View File

@@ -79,6 +79,7 @@ import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.test.web.servlet.RequestCacheResultMatcher;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.access.ExceptionTranslationFilter;
@@ -807,7 +808,7 @@ public class MiscHttpConfigTests {
.session(session)
.with(csrf());
session = (MockHttpSession) this.mvc.perform(loginRequest)
.andExpect(redirectedUrl("https://localhost:9443/protected"))
.andExpect(RequestCacheResultMatcher.redirectToCachedRequest())
.andReturn()
.getRequest()
.getSession(false);

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2022 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.test.web.servlet;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.test.web.servlet.ResultMatcher;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Ensures that the MockMvcResult redirects to the saved ReqeuestCache.getRedirectUrl().
*/
public final class RequestCacheResultMatcher {
/**
* Verifies that the MockMvcResult redirects to the saved
* ReqeustCache.getRedirectUrl().
* @return a ResultMatcher that performs the verification.
*/
public static ResultMatcher redirectToCachedRequest() {
return (mvcResult) -> {
RequestCache requestCache = new HttpSessionRequestCache();
MockHttpServletResponse response = mvcResult.getResponse();
SavedRequest savedRequest = requestCache.getRequest(mvcResult.getRequest(), response);
assertThat(savedRequest).describedAs("savedReqeust cannot be null").isNotNull();
String cachedRedirectUrl = savedRequest.getRedirectUrl();
assertThat(response.getRedirectedUrl()).isEqualTo(cachedRedirectUrl);
};
}
private RequestCacheResultMatcher() {
}
}