Last active
February 18, 2025 12:20
-
-
Save mpalourdio/6a6afabcc4824b08e8f580d32e11caef to your computer and use it in GitHub Desktop.
Spring Security : MockMvc tests with XorCsrfTokenRequestAttributeHandler - Custom RequestPostProcessor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package xx.xx.xxxxxxx.xxxxxxx.requestpostprocessor; | |
import jakarta.servlet.http.Cookie; | |
import jakarta.servlet.http.HttpServletResponse; | |
import org.springframework.mock.web.MockHttpServletRequest; | |
import org.springframework.mock.web.MockHttpServletResponse; | |
import org.springframework.security.test.web.support.WebTestUtils; | |
import org.springframework.test.web.servlet.request.RequestPostProcessor; | |
public final class XorCsrfRequestPostProcessor implements RequestPostProcessor { | |
static final String XSRF_TOKEN_COOKIE_NAME = "XSRF-TOKEN"; | |
static final String X_XSRF_TOKEN_HEADER_NAME = "X-XSRF-TOKEN"; | |
private XorCsrfRequestPostProcessor() { | |
} | |
@Override | |
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { | |
HttpServletResponse response = new MockHttpServletResponse(); | |
var csrfTokenRepository = WebTestUtils.getCsrfTokenRepository(request); | |
var csrfTokenRequestHandler = WebTestUtils.getCsrfTokenRequestHandler(request); | |
var deferredCsrfToken = csrfTokenRepository.loadDeferredToken(request, response); | |
csrfTokenRequestHandler.handle(request, response, deferredCsrfToken::get); | |
var cookie = new Cookie(XSRF_TOKEN_COOKIE_NAME, deferredCsrfToken.get().getToken()); | |
request.setCookies(cookie); | |
request.addHeader(X_XSRF_TOKEN_HEADER_NAME, deferredCsrfToken.get().getToken()); | |
return request; | |
} | |
/** | |
* Provides ability to use XorCsrfTokenRequestAttributeHandler as RequestPostProcessor for mockMvc tests | |
* <p> | |
* <ul> | |
* <li>Fixes: | |
* <ul> | |
* <li><a href="https://stackoverflow.com/questions/74729765/csrf-in-tests-stopped-working-with-spring-boot-3-and-spring-security-6">StackOverFlow</a> | |
* <li><a href="https://github.com/spring-projects/spring-security/issues/12774">GitHub Issue</a> | |
* </ul> | |
* </ul> | |
* </ul> | |
* <pre> | |
* <p>Example:</p> | |
* @Test | |
* void postRequestTest() throws Exception { | |
* mockMvc.perform(post("/api/post") | |
* .with(xorCsrf())) | |
* .andReturn(); | |
* </<pre> | |
*/ | |
public static XorCsrfRequestPostProcessor xorCsrf() { | |
return new XorCsrfRequestPostProcessor(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package xx.xx.xxxxxxx.xxxxxxx.requestpostprocessor; | |
import jakarta.servlet.http.HttpServletRequest; | |
import jakarta.servlet.http.HttpServletResponse; | |
import org.junit.jupiter.api.Test; | |
import org.springframework.mock.web.MockHttpServletRequest; | |
import org.springframework.mock.web.MockHttpServletResponse; | |
import org.springframework.security.test.web.support.WebTestUtils; | |
import java.util.Objects; | |
import static xx.xx.xxxxxxx.xxxxxxx.XorCsrfRequestPostProcessor.*; | |
import static java.util.Arrays.asList; | |
import static org.assertj.core.api.Assertions.assertThat; | |
class XorCsrfRequestPostProcessorTest { | |
@Test | |
void testHasXsrfTokenCookie() { | |
var xorCsrf = xorCsrf(); | |
var mockHttpServletRequest = xorCsrf.postProcessRequest(new MockHttpServletRequest()); | |
var cookies = asList(Objects.requireNonNull(mockHttpServletRequest.getCookies())); | |
var deferredCsrfToken = getDeferredCsrfToken(mockHttpServletRequest); | |
assertThat(cookies.getFirst().getName()).isEqualTo(XSRF_TOKEN_COOKIE_NAME); | |
assertThat(cookies.getFirst().getValue()).isEqualTo(deferredCsrfToken); | |
} | |
@Test | |
void testHasXsrfTokenHeader() { | |
var xorCsrf = xorCsrf(); | |
var mockHttpServletRequest = xorCsrf.postProcessRequest(new MockHttpServletRequest()); | |
var header = mockHttpServletRequest.getHeader(X_XSRF_TOKEN_HEADER_NAME); | |
var deferredCsrfToken = getDeferredCsrfToken(mockHttpServletRequest); | |
assertThat(header).isEqualTo(deferredCsrfToken); | |
} | |
private static String getDeferredCsrfToken(HttpServletRequest mockHttpServletRequest) { | |
var csrfTokenRepository = WebTestUtils.getCsrfTokenRepository(mockHttpServletRequest); | |
HttpServletResponse response = new MockHttpServletResponse(); | |
var deferredCsrfToken = csrfTokenRepository.loadDeferredToken(mockHttpServletRequest, response); | |
return deferredCsrfToken.get().getToken(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See those topics
* https://stackoverflow.com/questions/74729765/csrf-in-tests-stopped-working-with-spring-boot-3-and-spring-security-6
* spring-projects/spring-security#12774