Add deferred CsrfTokenRepository.loadDeferredToken

* Move DeferredCsrfToken to top-level and implement Supplier<CsrfToken>
* Move RepositoryDeferredCsrfToken to top-level and make package-private
* Add CsrfTokenRepository.loadToken(HttpServletRequest, HttpServletResponse)
* Update CsrfFilter
* Rename CsrfTokenRepositoryRequestHandler to CsrfTokenRequestAttributeHandler

Issue gh-11892
Closes gh-11918
This commit is contained in:
Steve Riesenberg
2022-09-27 14:53:54 -05:00
parent 0e215a21ad
commit 475b3bb6bb
31 changed files with 536 additions and 353 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* 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.
@@ -26,6 +26,7 @@ import org.springframework.mock.web.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.springframework.security.web.csrf.CsrfTokenAssert.assertThatCsrfToken;
/**
* @author Rob Winch
@@ -246,6 +247,33 @@ public class CookieCsrfTokenRepositoryTests {
assertThat(loadToken.getToken()).isEqualTo(value);
}
@Test
public void loadDeferredTokenWhenDoesNotExistThenGeneratedAndSaved() {
DeferredCsrfToken deferredCsrfToken = this.repository.loadDeferredToken(this.request, this.response);
CsrfToken csrfToken = deferredCsrfToken.get();
assertThat(csrfToken).isNotNull();
assertThat(deferredCsrfToken.isGenerated()).isTrue();
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
assertThat(tokenCookie).isNotNull();
assertThat(tokenCookie.getMaxAge()).isEqualTo(-1);
assertThat(tokenCookie.getName()).isEqualTo(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
assertThat(tokenCookie.getPath()).isEqualTo(this.request.getContextPath());
assertThat(tokenCookie.getSecure()).isEqualTo(this.request.isSecure());
assertThat(tokenCookie.getValue()).isEqualTo(csrfToken.getToken());
assertThat(tokenCookie.isHttpOnly()).isEqualTo(true);
}
@Test
public void loadDeferredTokenWhenExistsThenLoaded() {
CsrfToken generatedToken = this.repository.generateToken(this.request);
this.request
.setCookies(new Cookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME, generatedToken.getToken()));
DeferredCsrfToken deferredCsrfToken = this.repository.loadDeferredToken(this.request, this.response);
CsrfToken csrfToken = deferredCsrfToken.get();
assertThatCsrfToken(csrfToken).isEqualTo(generatedToken);
assertThat(deferredCsrfToken.isGenerated()).isFalse();
}
@Test
public void setCookieNameNullIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setCookieName(null));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* 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.
@@ -82,23 +82,25 @@ public class CsrfAuthenticationStrategyTests {
@Test
public void onAuthenticationWhenCustomRequestHandlerThenUsed() {
given(this.csrfTokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.existingToken, false));
CsrfTokenRequestHandler requestHandler = mock(CsrfTokenRequestHandler.class);
this.strategy.setRequestHandler(requestHandler);
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
this.response);
verify(requestHandler).handle(eq(this.request), eq(this.response));
verify(requestHandler).handle(eq(this.request), eq(this.response), any());
verifyNoMoreInteractions(requestHandler);
}
@Test
public void logoutRemovesCsrfTokenAndSavesNew() {
given(this.csrfTokenRepository.loadToken(this.request)).willReturn(null, this.existingToken);
given(this.csrfTokenRepository.generateToken(this.request)).willReturn(this.generatedToken);
public void logoutRemovesCsrfTokenAndLoadsNewDeferredCsrfToken() {
given(this.csrfTokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.generatedToken, false));
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
this.response);
verify(this.csrfTokenRepository).saveToken(null, this.request, this.response);
verify(this.csrfTokenRepository).saveToken(eq(this.generatedToken), any(HttpServletRequest.class),
any(HttpServletResponse.class));
verify(this.csrfTokenRepository).loadDeferredToken(this.request, this.response);
// SEC-2404, SEC-2832
CsrfToken tokenInRequest = (CsrfToken) this.request.getAttribute(CsrfToken.class.getName());
assertThat(tokenInRequest.getToken()).isSameAs(this.generatedToken.getToken());
@@ -119,17 +121,10 @@ public class CsrfAuthenticationStrategyTests {
any(HttpServletResponse.class));
CsrfToken tokenInRequest = (CsrfToken) this.request.getAttribute(CsrfToken.class.getName());
tokenInRequest.getToken();
verify(this.csrfTokenRepository).loadToken(this.request);
verify(this.csrfTokenRepository).generateToken(this.request);
verify(this.csrfTokenRepository).saveToken(eq(this.generatedToken), any(HttpServletRequest.class),
any(HttpServletResponse.class));
}
@Test
public void logoutWhenNoCsrfToken() {
given(this.csrfTokenRepository.generateToken(this.request)).willReturn(this.generatedToken);
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
this.response);
verify(this.csrfTokenRepository).saveToken(any(CsrfToken.class), any(HttpServletRequest.class),
any(HttpServletResponse.class));
}
}

View File

@@ -44,7 +44,6 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
@@ -86,11 +85,7 @@ public class CsrfFilterTests {
}
private CsrfFilter createCsrfFilter(CsrfTokenRepository repository) {
return createCsrfFilter(new CsrfTokenRepositoryRequestHandler(repository));
}
private CsrfFilter createCsrfFilter(CsrfTokenRequestHandler requestHandler) {
CsrfFilter filter = new CsrfFilter(requestHandler);
CsrfFilter filter = new CsrfFilter(repository);
filter.setRequireCsrfProtectionMatcher(this.requestMatcher);
filter.setAccessDeniedHandler(this.deniedHandler);
return filter;
@@ -103,7 +98,7 @@ public class CsrfFilterTests {
@Test
public void constructorNullRepository() {
assertThatIllegalArgumentException().isThrownBy(() -> new CsrfFilter((CsrfTokenRequestHandler) null));
assertThatIllegalArgumentException().isThrownBy(() -> new CsrfFilter(null));
}
// SEC-2276
@@ -128,7 +123,8 @@ public class CsrfFilterTests {
@Test
public void doFilterAccessDeniedNoTokenPresent() throws ServletException, IOException {
given(this.requestMatcher.matches(this.request)).willReturn(true);
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.filter.doFilter(this.request, this.response, this.filterChain);
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
@@ -139,7 +135,8 @@ public class CsrfFilterTests {
@Test
public void doFilterAccessDeniedIncorrectTokenPresent() throws ServletException, IOException {
given(this.requestMatcher.matches(this.request)).willReturn(true);
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.request.setParameter(this.token.getParameterName(), this.token.getToken() + " INVALID");
this.filter.doFilter(this.request, this.response, this.filterChain);
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
@@ -151,7 +148,8 @@ public class CsrfFilterTests {
@Test
public void doFilterAccessDeniedIncorrectTokenPresentHeader() throws ServletException, IOException {
given(this.requestMatcher.matches(this.request)).willReturn(true);
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.request.addHeader(this.token.getHeaderName(), this.token.getToken() + " INVALID");
this.filter.doFilter(this.request, this.response, this.filterChain);
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
@@ -164,7 +162,8 @@ public class CsrfFilterTests {
public void doFilterAccessDeniedIncorrectTokenPresentHeaderPreferredOverParameter()
throws ServletException, IOException {
given(this.requestMatcher.matches(this.request)).willReturn(true);
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
this.request.addHeader(this.token.getHeaderName(), this.token.getToken() + " INVALID");
this.filter.doFilter(this.request, this.response, this.filterChain);
@@ -177,7 +176,8 @@ public class CsrfFilterTests {
@Test
public void doFilterNotCsrfRequestExistingToken() throws ServletException, IOException {
given(this.requestMatcher.matches(this.request)).willReturn(false);
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.filter.doFilter(this.request, this.response, this.filterChain);
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
@@ -188,7 +188,8 @@ public class CsrfFilterTests {
@Test
public void doFilterNotCsrfRequestGenerateToken() throws ServletException, IOException {
given(this.requestMatcher.matches(this.request)).willReturn(false);
given(this.tokenRepository.generateToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, true));
this.filter.doFilter(this.request, this.response, this.filterChain);
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
@@ -199,7 +200,8 @@ public class CsrfFilterTests {
@Test
public void doFilterIsCsrfRequestExistingTokenHeader() throws ServletException, IOException {
given(this.requestMatcher.matches(this.request)).willReturn(true);
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.request.addHeader(this.token.getHeaderName(), this.token.getToken());
this.filter.doFilter(this.request, this.response, this.filterChain);
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
@@ -212,7 +214,8 @@ public class CsrfFilterTests {
public void doFilterIsCsrfRequestExistingTokenHeaderPreferredOverInvalidParam()
throws ServletException, IOException {
given(this.requestMatcher.matches(this.request)).willReturn(true);
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.request.setParameter(this.token.getParameterName(), this.token.getToken() + " INVALID");
this.request.addHeader(this.token.getHeaderName(), this.token.getToken());
this.filter.doFilter(this.request, this.response, this.filterChain);
@@ -225,7 +228,8 @@ public class CsrfFilterTests {
@Test
public void doFilterIsCsrfRequestExistingToken() throws ServletException, IOException {
given(this.requestMatcher.matches(this.request)).willReturn(true);
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
this.filter.doFilter(this.request, this.response, this.filterChain);
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
@@ -239,7 +243,8 @@ public class CsrfFilterTests {
@Test
public void doFilterIsCsrfRequestGenerateToken() throws ServletException, IOException {
given(this.requestMatcher.matches(this.request)).willReturn(true);
given(this.tokenRepository.generateToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, true));
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
this.filter.doFilter(this.request, this.response, this.filterChain);
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
@@ -247,17 +252,17 @@ public class CsrfFilterTests {
// LazyCsrfTokenRepository requires the response as an attribute
assertThat(this.request.getAttribute(HttpServletResponse.class.getName())).isEqualTo(this.response);
verify(this.filterChain).doFilter(this.request, this.response);
verify(this.tokenRepository).saveToken(this.token, this.request, this.response);
verifyNoMoreInteractions(this.deniedHandler);
}
@Test
public void doFilterDefaultRequireCsrfProtectionMatcherAllowedMethods() throws ServletException, IOException {
this.filter = createCsrfFilter(this.tokenRepository);
this.filter = new CsrfFilter(this.tokenRepository);
this.filter.setAccessDeniedHandler(this.deniedHandler);
for (String method : Arrays.asList("GET", "TRACE", "OPTIONS", "HEAD")) {
resetRequestResponse();
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.request.setMethod(method);
this.filter.doFilter(this.request, this.response, this.filterChain);
verify(this.filterChain).doFilter(this.request, this.response);
@@ -273,11 +278,12 @@ public class CsrfFilterTests {
*/
@Test
public void doFilterDefaultRequireCsrfProtectionMatcherAllowedMethodsCaseSensitive() throws Exception {
this.filter = new CsrfFilter(new CsrfTokenRepositoryRequestHandler(this.tokenRepository));
this.filter = new CsrfFilter(this.tokenRepository);
this.filter.setAccessDeniedHandler(this.deniedHandler);
for (String method : Arrays.asList("get", "TrAcE", "oPTIOnS", "hEaD")) {
resetRequestResponse();
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.request.setMethod(method);
this.filter.doFilter(this.request, this.response, this.filterChain);
verify(this.deniedHandler).handle(eq(this.request), eq(this.response),
@@ -288,11 +294,12 @@ public class CsrfFilterTests {
@Test
public void doFilterDefaultRequireCsrfProtectionMatcherDeniedMethods() throws ServletException, IOException {
this.filter = new CsrfFilter(new CsrfTokenRepositoryRequestHandler(this.tokenRepository));
this.filter = new CsrfFilter(this.tokenRepository);
this.filter.setAccessDeniedHandler(this.deniedHandler);
for (String method : Arrays.asList("POST", "PUT", "PATCH", "DELETE", "INVALID")) {
resetRequestResponse();
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.request.setMethod(method);
this.filter.doFilter(this.request, this.response, this.filterChain);
verify(this.deniedHandler).handle(eq(this.request), eq(this.response),
@@ -303,10 +310,11 @@ public class CsrfFilterTests {
@Test
public void doFilterDefaultAccessDenied() throws ServletException, IOException {
this.filter = new CsrfFilter(new CsrfTokenRepositoryRequestHandler(this.tokenRepository));
this.filter = new CsrfFilter(this.tokenRepository);
this.filter.setRequireCsrfProtectionMatcher(this.requestMatcher);
given(this.requestMatcher.matches(this.request)).willReturn(true);
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.filter.doFilter(this.request, this.response, this.filterChain);
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
@@ -317,7 +325,7 @@ public class CsrfFilterTests {
@Test
public void doFilterWhenSkipRequestInvokedThenSkips() throws Exception {
CsrfTokenRepository repository = mock(CsrfTokenRepository.class);
CsrfFilter filter = createCsrfFilter(repository);
CsrfFilter filter = new CsrfFilter(repository);
lenient().when(repository.loadToken(any(HttpServletRequest.class))).thenReturn(this.token);
MockHttpServletRequest request = new MockHttpServletRequest();
CsrfFilter.skipRequest(request);
@@ -333,7 +341,8 @@ public class CsrfFilterTests {
given(token.getToken()).willReturn(null);
given(token.getHeaderName()).willReturn(this.token.getHeaderName());
given(token.getParameterName()).willReturn(this.token.getParameterName());
given(this.tokenRepository.loadToken(this.request)).willReturn(token);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(token, false));
given(this.requestMatcher.matches(this.request)).willReturn(true);
filter.doFilterInternal(this.request, this.response, this.filterChain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
@@ -341,13 +350,15 @@ public class CsrfFilterTests {
@Test
public void doFilterWhenRequestHandlerThenUsed() throws Exception {
CsrfTokenRequestHandler requestHandler = mock(CsrfTokenRequestHandler.class);
given(requestHandler.handle(this.request, this.response))
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(this.token, false));
this.filter = createCsrfFilter(requestHandler);
CsrfTokenRequestHandler requestHandler = mock(CsrfTokenRequestHandler.class);
this.filter = createCsrfFilter(this.tokenRepository);
this.filter.setRequestHandler(requestHandler);
this.request.setParameter(this.token.getParameterName(), this.token.getToken());
this.filter.doFilter(this.request, this.response, this.filterChain);
verify(requestHandler).handle(eq(this.request), eq(this.response));
verify(this.tokenRepository).loadDeferredToken(this.request, this.response);
verify(requestHandler).handle(eq(this.request), eq(this.response), any());
verify(this.filterChain).doFilter(this.request, this.response);
}
@@ -365,41 +376,20 @@ public class CsrfFilterTests {
@Test
public void doFilterWhenCsrfRequestAttributeNameThenNoCsrfTokenMethodInvokedOnGet()
throws ServletException, IOException {
CsrfFilter filter = createCsrfFilter(this.tokenRepository);
String csrfAttrName = "_csrf";
CsrfTokenRepositoryRequestHandler requestHandler = new CsrfTokenRepositoryRequestHandler(this.tokenRepository);
CsrfTokenRequestAttributeHandler requestHandler = new CsrfTokenRequestAttributeHandler();
requestHandler.setCsrfRequestAttributeName(csrfAttrName);
this.filter = createCsrfFilter(requestHandler);
CsrfToken expectedCsrfToken = spy(this.token);
given(this.tokenRepository.loadToken(this.request)).willReturn(expectedCsrfToken);
filter.setRequestHandler(requestHandler);
CsrfToken expectedCsrfToken = mock(CsrfToken.class);
given(this.tokenRepository.loadDeferredToken(this.request, this.response))
.willReturn(new TestDeferredCsrfToken(expectedCsrfToken, true));
this.filter.doFilter(this.request, this.response, this.filterChain);
filter.doFilter(this.request, this.response, this.filterChain);
verifyNoInteractions(expectedCsrfToken);
CsrfToken tokenFromRequest = (CsrfToken) this.request.getAttribute(csrfAttrName);
assertThatCsrfToken(tokenFromRequest).isEqualTo(expectedCsrfToken);
}
private static final class TestDeferredCsrfToken implements DeferredCsrfToken {
private final CsrfToken csrfToken;
private final boolean isGenerated;
private TestDeferredCsrfToken(CsrfToken csrfToken, boolean isGenerated) {
this.csrfToken = csrfToken;
this.isGenerated = isGenerated;
}
@Override
public CsrfToken get() {
return this.csrfToken;
}
@Override
public boolean isGenerated() {
return this.isGenerated;
}
}
}

View File

@@ -18,29 +18,22 @@ package org.springframework.security.web.csrf;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.springframework.security.web.csrf.CsrfTokenAssert.assertThatCsrfToken;
/**
* Tests for {@link CsrfTokenRepositoryRequestHandler}.
* Tests for {@link CsrfTokenRequestAttributeHandler}.
*
* @author Steve Riesenberg
* @since 5.8
*/
@ExtendWith(MockitoExtension.class)
public class CsrfTokenRepositoryRequestHandlerTests {
@Mock
CsrfTokenRepository tokenRepository;
public class CsrfTokenRequestAttributeHandlerTests {
private MockHttpServletRequest request;
@@ -48,76 +41,73 @@ public class CsrfTokenRepositoryRequestHandlerTests {
private CsrfToken token;
private CsrfTokenRepositoryRequestHandler handler;
private CsrfTokenRequestAttributeHandler handler;
@BeforeEach
public void setup() {
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
this.token = new DefaultCsrfToken("headerName", "paramName", "csrfTokenValue");
this.handler = new CsrfTokenRepositoryRequestHandler(this.tokenRepository);
}
@Test
public void constructorWhenCsrfTokenRepositoryIsNullThenThrowsIllegalArgumentException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> new CsrfTokenRepositoryRequestHandler(null))
.withMessage("csrfTokenRepository cannot be null");
// @formatter:on
this.handler = new CsrfTokenRequestAttributeHandler();
}
@Test
public void handleWhenRequestIsNullThenThrowsIllegalArgumentException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.handler.handle(null, this.response))
.isThrownBy(() -> this.handler.handle(null, this.response, () -> this.token))
.withMessage("request cannot be null");
// @formatter:on
}
@Test
public void handleWhenResponseIsNullThenThrowsIllegalArgumentException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.handler.handle(this.request, null))
.isThrownBy(() -> this.handler.handle(this.request, null, () -> this.token))
.withMessage("response cannot be null");
// @formatter:on
}
@Test
public void handleWhenCsrfTokenSupplierIsNullThenThrowsIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.handler.handle(this.request, this.response, null))
.withMessage("deferredCsrfToken cannot be null");
}
@Test
public void handleWhenCsrfTokenIsNullThenThrowsIllegalArgumentException() {
// @formatter:off
this.handler.setCsrfRequestAttributeName(null);
assertThatIllegalStateException()
.isThrownBy(() -> this.handler.handle(this.request, this.response, () -> null))
.withMessage("csrfTokenSupplier returned null delegate");
// @formatter:on
}
@Test
public void handleWhenCsrfRequestAttributeSetThenUsed() {
given(this.tokenRepository.generateToken(this.request)).willReturn(this.token);
this.handler.setCsrfRequestAttributeName("_csrf");
this.handler.handle(this.request, this.response);
this.handler.handle(this.request, this.response, () -> this.token);
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
assertThatCsrfToken(this.request.getAttribute("_csrf")).isEqualTo(this.token);
}
@Test
public void handleWhenValidParametersThenRequestAttributesSet() {
given(this.tokenRepository.loadToken(this.request)).willReturn(this.token);
this.handler.handle(this.request, this.response);
this.handler.handle(this.request, this.response, () -> this.token);
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
assertThatCsrfToken(this.request.getAttribute(this.token.getParameterName())).isEqualTo(this.token);
}
@Test
public void resolveCsrfTokenValueWhenRequestIsNullThenThrowsIllegalArgumentException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.handler.resolveCsrfTokenValue(null, this.token))
assertThatIllegalArgumentException().isThrownBy(() -> this.handler.resolveCsrfTokenValue(null, this.token))
.withMessage("request cannot be null");
// @formatter:on
}
@Test
public void resolveCsrfTokenValueWhenCsrfTokenIsNullThenThrowsIllegalArgumentException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.handler.resolveCsrfTokenValue(this.request, null))
assertThatIllegalArgumentException().isThrownBy(() -> this.handler.resolveCsrfTokenValue(this.request, null))
.withMessage("csrfToken cannot be null");
// @formatter:on
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* 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.
@@ -24,6 +24,7 @@ import org.springframework.mock.web.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.springframework.security.web.csrf.CsrfTokenAssert.assertThatCsrfToken;
/**
* @author Rob Winch
@@ -85,6 +86,26 @@ public class HttpSessionCsrfTokenRepositoryTests {
assertThat(this.repo.loadToken(this.request)).isNull();
}
@Test
public void loadDeferredTokenWhenDoesNotExistThenGeneratedAndSaved() {
DeferredCsrfToken deferredCsrfToken = this.repo.loadDeferredToken(this.request, this.response);
CsrfToken csrfToken = deferredCsrfToken.get();
assertThat(csrfToken).isNotNull();
assertThat(deferredCsrfToken.isGenerated()).isTrue();
String attrName = this.request.getSession().getAttributeNames().nextElement();
assertThatCsrfToken(this.request.getSession().getAttribute(attrName)).isEqualTo(csrfToken);
}
@Test
public void loadDeferredTokenWhenExistsThenLoaded() {
CsrfToken tokenToSave = new DefaultCsrfToken("123", "abc", "def");
this.repo.saveToken(tokenToSave, this.request, this.response);
DeferredCsrfToken deferredCsrfToken = this.repo.loadDeferredToken(this.request, this.response);
CsrfToken csrfToken = deferredCsrfToken.get();
assertThatCsrfToken(csrfToken).isEqualTo(tokenToSave);
assertThat(deferredCsrfToken.isGenerated()).isFalse();
}
@Test
public void saveToken() {
CsrfToken tokenToSave = new DefaultCsrfToken("123", "abc", "def");

View File

@@ -0,0 +1,40 @@
/*
* 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.web.csrf;
final class TestDeferredCsrfToken implements DeferredCsrfToken {
private final CsrfToken csrfToken;
private final boolean isGenerated;
TestDeferredCsrfToken(CsrfToken csrfToken, boolean isGenerated) {
this.csrfToken = csrfToken;
this.isGenerated = isGenerated;
}
@Override
public CsrfToken get() {
return this.csrfToken;
}
@Override
public boolean isGenerated() {
return this.isGenerated;
}
}