Merge branch '5.8.x'
Closes gh-dry-run
This commit is contained in:
+9
-8
@@ -38,17 +38,17 @@ public final class CsrfAuthenticationStrategy implements SessionAuthenticationSt
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final CsrfTokenRepository csrfTokenRepository;
|
||||
private final CsrfTokenRepository tokenRepository;
|
||||
|
||||
private CsrfTokenRequestHandler requestHandler;
|
||||
private CsrfTokenRequestHandler requestHandler = new CsrfTokenRequestAttributeHandler();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param csrfTokenRepository the {@link CsrfTokenRepository} to use
|
||||
* @param tokenRepository the {@link CsrfTokenRepository} to use
|
||||
*/
|
||||
public CsrfAuthenticationStrategy(CsrfTokenRepository csrfTokenRepository) {
|
||||
this.requestHandler = new CsrfTokenRepositoryRequestHandler(csrfTokenRepository);
|
||||
this.csrfTokenRepository = csrfTokenRepository;
|
||||
public CsrfAuthenticationStrategy(CsrfTokenRepository tokenRepository) {
|
||||
Assert.notNull(tokenRepository, "tokenRepository cannot be null");
|
||||
this.tokenRepository = tokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,8 +64,9 @@ public final class CsrfAuthenticationStrategy implements SessionAuthenticationSt
|
||||
@Override
|
||||
public void onAuthentication(Authentication authentication, HttpServletRequest request,
|
||||
HttpServletResponse response) throws SessionAuthenticationException {
|
||||
this.csrfTokenRepository.saveToken(null, request, response);
|
||||
this.requestHandler.handle(request, response);
|
||||
this.tokenRepository.saveToken(null, request, response);
|
||||
DeferredCsrfToken deferredCsrfToken = this.tokenRepository.loadDeferredToken(request, response);
|
||||
this.requestHandler.handle(request, response, deferredCsrfToken::get);
|
||||
this.logger.debug("Replaced CSRF Token");
|
||||
}
|
||||
|
||||
|
||||
@@ -81,30 +81,21 @@ public final class CsrfFilter extends OncePerRequestFilter {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final CsrfTokenRequestHandler requestHandler;
|
||||
private final CsrfTokenRepository tokenRepository;
|
||||
|
||||
private RequestMatcher requireCsrfProtectionMatcher = DEFAULT_CSRF_MATCHER;
|
||||
|
||||
private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl();
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param csrfTokenRepository the {@link CsrfTokenRepository} to use
|
||||
* @deprecated Use {@link CsrfFilter#CsrfFilter(CsrfTokenRequestHandler)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public CsrfFilter(CsrfTokenRepository csrfTokenRepository) {
|
||||
this(new CsrfTokenRepositoryRequestHandler(csrfTokenRepository));
|
||||
}
|
||||
private CsrfTokenRequestHandler requestHandler = new CsrfTokenRequestAttributeHandler();
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param requestHandler the {@link CsrfTokenRequestHandler} to use. Default is
|
||||
* {@link CsrfTokenRepositoryRequestHandler}.
|
||||
* @param tokenRepository the {@link CsrfTokenRepository} to use
|
||||
*/
|
||||
public CsrfFilter(CsrfTokenRequestHandler requestHandler) {
|
||||
Assert.notNull(requestHandler, "requestHandler cannot be null");
|
||||
this.requestHandler = requestHandler;
|
||||
public CsrfFilter(CsrfTokenRepository tokenRepository) {
|
||||
Assert.notNull(tokenRepository, "tokenRepository cannot be null");
|
||||
this.tokenRepository = tokenRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -115,7 +106,8 @@ public final class CsrfFilter extends OncePerRequestFilter {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
DeferredCsrfToken deferredCsrfToken = this.requestHandler.handle(request, response);
|
||||
DeferredCsrfToken deferredCsrfToken = this.tokenRepository.loadDeferredToken(request, response);
|
||||
this.requestHandler.handle(request, response, deferredCsrfToken::get);
|
||||
if (!this.requireCsrfProtectionMatcher.matches(request)) {
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
this.logger.trace("Did not protect against CSRF since request did not match "
|
||||
@@ -173,6 +165,21 @@ public final class CsrfFilter extends OncePerRequestFilter {
|
||||
this.accessDeniedHandler = accessDeniedHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a {@link CsrfTokenRequestHandler} that is used to make the
|
||||
* {@link CsrfToken} available as a request attribute.
|
||||
*
|
||||
* <p>
|
||||
* The default is {@link CsrfTokenRequestAttributeHandler}.
|
||||
* </p>
|
||||
* @param requestHandler the {@link CsrfTokenRequestHandler} to use
|
||||
* @since 5.8
|
||||
*/
|
||||
public void setRequestHandler(CsrfTokenRequestHandler requestHandler) {
|
||||
Assert.notNull(requestHandler, "requestHandler cannot be null");
|
||||
this.requestHandler = requestHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constant time comparison to prevent against timing attacks.
|
||||
* @param expected
|
||||
|
||||
@@ -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.
|
||||
@@ -26,6 +26,7 @@ import jakarta.servlet.http.HttpSession;
|
||||
* {@link HttpSession}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Steve Riesenberg
|
||||
* @since 3.2
|
||||
* @see HttpSessionCsrfTokenRepository
|
||||
*/
|
||||
@@ -55,4 +56,20 @@ public interface CsrfTokenRepository {
|
||||
*/
|
||||
CsrfToken loadToken(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Defers loading the {@link CsrfToken} using the {@link HttpServletRequest} and
|
||||
* {@link HttpServletResponse} until it is needed by the application.
|
||||
* <p>
|
||||
* The returned {@link DeferredCsrfToken} is cached to allow subsequent calls to
|
||||
* {@link DeferredCsrfToken#get()} to return the same {@link CsrfToken} without the
|
||||
* cost of loading or generating the token again.
|
||||
* @param request the {@link HttpServletRequest} to use
|
||||
* @param response the {@link HttpServletResponse} to use
|
||||
* @return a {@link DeferredCsrfToken} that will load the {@link CsrfToken}
|
||||
* @since 5.8
|
||||
*/
|
||||
default DeferredCsrfToken loadDeferredToken(HttpServletRequest request, HttpServletResponse response) {
|
||||
return new RepositoryDeferredCsrfToken(this, request, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-66
@@ -31,29 +31,10 @@ import org.springframework.util.Assert;
|
||||
* @author Steve Riesenberg
|
||||
* @since 5.8
|
||||
*/
|
||||
public class CsrfTokenRepositoryRequestHandler implements CsrfTokenRequestHandler {
|
||||
|
||||
private final CsrfTokenRepository csrfTokenRepository;
|
||||
public class CsrfTokenRequestAttributeHandler implements CsrfTokenRequestHandler {
|
||||
|
||||
private String csrfRequestAttributeName = "_csrf";
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public CsrfTokenRepositoryRequestHandler() {
|
||||
this(new HttpSessionCsrfTokenRepository());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param csrfTokenRepository the {@link CsrfTokenRepository} to use. Default
|
||||
* {@link HttpSessionCsrfTokenRepository}
|
||||
*/
|
||||
public CsrfTokenRepositoryRequestHandler(CsrfTokenRepository csrfTokenRepository) {
|
||||
Assert.notNull(csrfTokenRepository, "csrfTokenRepository cannot be null");
|
||||
this.csrfTokenRepository = csrfTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link CsrfToken} is available as a request attribute named
|
||||
* {@code CsrfToken.class.getName()}. By default, an additional request attribute that
|
||||
@@ -67,18 +48,18 @@ public class CsrfTokenRepositoryRequestHandler implements CsrfTokenRequestHandle
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeferredCsrfToken handle(HttpServletRequest request, HttpServletResponse response) {
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response,
|
||||
Supplier<CsrfToken> deferredCsrfToken) {
|
||||
Assert.notNull(request, "request cannot be null");
|
||||
Assert.notNull(response, "response cannot be null");
|
||||
Assert.notNull(deferredCsrfToken, "deferredCsrfToken cannot be null");
|
||||
|
||||
request.setAttribute(HttpServletResponse.class.getName(), response);
|
||||
DeferredCsrfToken deferredCsrfToken = new RepositoryDeferredCsrfToken(request, response);
|
||||
CsrfToken csrfToken = new SupplierCsrfToken(deferredCsrfToken::get);
|
||||
CsrfToken csrfToken = new SupplierCsrfToken(deferredCsrfToken);
|
||||
request.setAttribute(CsrfToken.class.getName(), csrfToken);
|
||||
String csrfAttrName = (this.csrfRequestAttributeName != null) ? this.csrfRequestAttributeName
|
||||
: csrfToken.getParameterName();
|
||||
request.setAttribute(csrfAttrName, csrfToken);
|
||||
return deferredCsrfToken;
|
||||
}
|
||||
|
||||
private static final class SupplierCsrfToken implements CsrfToken {
|
||||
@@ -114,46 +95,4 @@ public class CsrfTokenRepositoryRequestHandler implements CsrfTokenRequestHandle
|
||||
|
||||
}
|
||||
|
||||
private final class RepositoryDeferredCsrfToken implements DeferredCsrfToken {
|
||||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
private final HttpServletResponse response;
|
||||
|
||||
private CsrfToken csrfToken;
|
||||
|
||||
private Boolean missingToken;
|
||||
|
||||
RepositoryDeferredCsrfToken(HttpServletRequest request, HttpServletResponse response) {
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CsrfToken get() {
|
||||
init();
|
||||
return this.csrfToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGenerated() {
|
||||
init();
|
||||
return this.missingToken;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (this.csrfToken != null) {
|
||||
return;
|
||||
}
|
||||
this.csrfToken = CsrfTokenRepositoryRequestHandler.this.csrfTokenRepository.loadToken(this.request);
|
||||
this.missingToken = (this.csrfToken == null);
|
||||
if (this.missingToken) {
|
||||
this.csrfToken = CsrfTokenRepositoryRequestHandler.this.csrfTokenRepository.generateToken(this.request);
|
||||
CsrfTokenRepositoryRequestHandler.this.csrfTokenRepository.saveToken(this.csrfToken, this.request,
|
||||
this.response);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+9
-6
@@ -16,20 +16,22 @@
|
||||
|
||||
package org.springframework.security.web.csrf;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An interface that is used to determine the {@link CsrfToken} to use and make the
|
||||
* {@link CsrfToken} available as a request attribute. Implementations of this interface
|
||||
* may choose to perform additional tasks or customize how the token is made available to
|
||||
* the application through request attributes.
|
||||
* A callback interface that is used to make the {@link CsrfToken} created by the
|
||||
* {@link CsrfTokenRepository} available as a request attribute. Implementations of this
|
||||
* interface may choose to perform additional tasks or customize how the token is made
|
||||
* available to the application through request attributes.
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
* @since 5.8
|
||||
* @see CsrfTokenRepositoryRequestHandler
|
||||
* @see CsrfTokenRequestAttributeHandler
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CsrfTokenRequestHandler extends CsrfTokenRequestResolver {
|
||||
@@ -38,8 +40,9 @@ public interface CsrfTokenRequestHandler extends CsrfTokenRequestResolver {
|
||||
* Handles a request using a {@link CsrfToken}.
|
||||
* @param request the {@code HttpServletRequest} being handled
|
||||
* @param response the {@code HttpServletResponse} being handled
|
||||
* @param csrfToken the {@link CsrfToken} created by the {@link CsrfTokenRepository}
|
||||
*/
|
||||
DeferredCsrfToken handle(HttpServletRequest request, HttpServletResponse response);
|
||||
void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken);
|
||||
|
||||
@Override
|
||||
default String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
*
|
||||
* @author Steve Riesenberg
|
||||
* @since 5.8
|
||||
* @see CsrfTokenRepositoryRequestHandler
|
||||
* @see CsrfTokenRequestAttributeHandler
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CsrfTokenRequestResolver {
|
||||
|
||||
@@ -20,11 +20,12 @@ package org.springframework.security.web.csrf;
|
||||
* An interface that allows delayed access to a {@link CsrfToken} that may be generated.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Steve Riesenberg
|
||||
* @since 5.8
|
||||
*/
|
||||
public interface DeferredCsrfToken {
|
||||
|
||||
/***
|
||||
/**
|
||||
* Gets the {@link CsrfToken}
|
||||
* @return a non-null {@link CsrfToken}
|
||||
*/
|
||||
|
||||
+3
-2
@@ -27,8 +27,9 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 4.1
|
||||
* @deprecated Use org.springframework.security.web.csrf.CsrfTokenRequestHandler which
|
||||
* returns a {@link DeferredCsrfToken}
|
||||
* @deprecated Use
|
||||
* {@link CsrfTokenRepository#loadDeferredToken(HttpServletRequest, HttpServletResponse)}
|
||||
* which returns a {@link DeferredCsrfToken}
|
||||
*/
|
||||
@Deprecated
|
||||
public final class LazyCsrfTokenRepository implements CsrfTokenRepository {
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @author Steve Riesenberg
|
||||
* @since 5.8
|
||||
*/
|
||||
final class RepositoryDeferredCsrfToken implements DeferredCsrfToken {
|
||||
|
||||
private final CsrfTokenRepository csrfTokenRepository;
|
||||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
private final HttpServletResponse response;
|
||||
|
||||
private CsrfToken csrfToken;
|
||||
|
||||
private boolean missingToken;
|
||||
|
||||
RepositoryDeferredCsrfToken(CsrfTokenRepository csrfTokenRepository, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
this.csrfTokenRepository = csrfTokenRepository;
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CsrfToken get() {
|
||||
init();
|
||||
return this.csrfToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGenerated() {
|
||||
init();
|
||||
return this.missingToken;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (this.csrfToken != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.csrfToken = this.csrfTokenRepository.loadToken(this.request);
|
||||
this.missingToken = (this.csrfToken == null);
|
||||
if (this.missingToken) {
|
||||
this.csrfToken = this.csrfTokenRepository.generateToken(this.request);
|
||||
this.csrfTokenRepository.saveToken(this.csrfToken, this.request, this.response);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+29
-1
@@ -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.
|
||||
@@ -25,6 +25,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
|
||||
@@ -245,6 +246,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));
|
||||
|
||||
+12
-19
@@ -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.
|
||||
@@ -32,7 +32,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
@@ -82,31 +81,31 @@ 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).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());
|
||||
assertThat(tokenInRequest.getHeaderName()).isSameAs(this.generatedToken.getHeaderName());
|
||||
assertThat(tokenInRequest.getParameterName()).isSameAs(this.generatedToken.getParameterName());
|
||||
assertThat(this.request.getAttribute(this.generatedToken.getParameterName())).isSameAs(tokenInRequest);
|
||||
// verify after the test accesses the CsrfToken which causes the lazy save to
|
||||
// occur
|
||||
verify(this.csrfTokenRepository).saveToken(null, this.request, this.response);
|
||||
verify(this.csrfTokenRepository).saveToken(eq(this.generatedToken), any(HttpServletRequest.class),
|
||||
any(HttpServletResponse.class));
|
||||
}
|
||||
|
||||
// SEC-2872
|
||||
@@ -121,16 +120,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() {
|
||||
this.strategy.onAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"), this.request,
|
||||
this.response);
|
||||
verify(this.csrfTokenRepository).saveToken(isNull(), any(HttpServletRequest.class),
|
||||
any(HttpServletResponse.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,7 +43,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;
|
||||
@@ -87,11 +86,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;
|
||||
@@ -104,7 +99,7 @@ public class CsrfFilterTests {
|
||||
|
||||
@Test
|
||||
public void constructorNullRepository() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CsrfFilter((CsrfTokenRequestHandler) null));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CsrfFilter(null));
|
||||
}
|
||||
|
||||
// SEC-2276
|
||||
@@ -129,7 +124,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.csrfAttrName)).isEqualTo(this.token);
|
||||
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||
@@ -140,7 +136,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.csrfAttrName)).isEqualTo(this.token);
|
||||
@@ -152,7 +149,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.csrfAttrName)).isEqualTo(this.token);
|
||||
@@ -165,7 +163,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);
|
||||
@@ -178,7 +177,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.csrfAttrName)).isEqualTo(this.token);
|
||||
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||
@@ -189,7 +189,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.csrfAttrName)).isEqualTo(this.token);
|
||||
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||
@@ -200,7 +201,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.csrfAttrName)).isEqualTo(this.token);
|
||||
@@ -213,7 +215,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);
|
||||
@@ -226,7 +229,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.csrfAttrName)).isEqualTo(this.token);
|
||||
@@ -240,7 +244,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.csrfAttrName)).isEqualTo(this.token);
|
||||
@@ -248,16 +253,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.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 +279,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 +295,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 +311,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.csrfAttrName)).isEqualTo(this.token);
|
||||
assertThatCsrfToken(this.request.getAttribute(CsrfToken.class.getName())).isEqualTo(this.token);
|
||||
@@ -317,7 +326,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 +342,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 +351,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 +377,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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+27
-37
@@ -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("_csrf")).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
|
||||
+22
-1
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user