Add setCookieCustomizer to csrf token repository
- Mark setCookieHttpOnly, setCookieDomain, setCookieMaxAge and setSecure as deprecated. - Add the method setCookieCustomizer which allows to set properties to the ResponseCookieBuilder without having to add new setter methods. Closes gh-12086
This commit is contained in:
committed by
Josh Cummings
parent
cd0f02de49
commit
b79ba89eeb
@@ -20,6 +20,7 @@ import jakarta.servlet.http.Cookie;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.mock.web.MockCookie;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
@@ -29,6 +30,7 @@ import static org.springframework.security.web.csrf.CsrfTokenAssert.assertThatCs
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @author Alex Montoya
|
||||
* @since 4.1
|
||||
*/
|
||||
public class CookieCsrfTokenRepositoryTests {
|
||||
@@ -102,7 +104,17 @@ public class CookieCsrfTokenRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveTokenSecureFlagFalse() {
|
||||
void saveTokenSecureFlagTrueUsingCustomizer() {
|
||||
this.request.setSecure(false);
|
||||
this.repository.setCookieCustomizer(customizer -> customizer.secure(Boolean.TRUE));
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
|
||||
assertThat(tokenCookie.getSecure()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenSecureFlagFalse() {
|
||||
this.request.setSecure(true);
|
||||
this.repository.setSecure(Boolean.FALSE);
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
@@ -112,7 +124,17 @@ public class CookieCsrfTokenRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveTokenNull() {
|
||||
void saveTokenSecureFlagFalseUsingCustomizer() {
|
||||
this.request.setSecure(true);
|
||||
this.repository.setCookieCustomizer(customizer -> customizer.secure(Boolean.FALSE));
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
|
||||
assertThat(tokenCookie.getSecure()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenNull() {
|
||||
this.request.setSecure(true);
|
||||
this.repository.saveToken(null, this.request, this.response);
|
||||
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
|
||||
@@ -133,7 +155,16 @@ public class CookieCsrfTokenRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveTokenHttpOnlyFalse() {
|
||||
void saveTokenHttpOnlyTrueUsingCustomizer() {
|
||||
this.repository.setCookieCustomizer(customizer -> customizer.httpOnly(true));
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
|
||||
assertThat(tokenCookie.isHttpOnly()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenHttpOnlyFalse() {
|
||||
this.repository.setCookieHttpOnly(false);
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
@@ -142,7 +173,16 @@ public class CookieCsrfTokenRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveTokenWithHttpOnlyFalse() {
|
||||
void saveTokenHttpOnlyFalseUsingCustomizer() {
|
||||
this.repository.setCookieCustomizer(customizer -> customizer.httpOnly(false));
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
|
||||
assertThat(tokenCookie.isHttpOnly()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenWithHttpOnlyFalse() {
|
||||
this.repository = CookieCsrfTokenRepository.withHttpOnlyFalse();
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
@@ -190,6 +230,16 @@ public class CookieCsrfTokenRepositoryTests {
|
||||
assertThat(tokenCookie.getDomain()).isEqualTo(domainName);
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenWithCookieDomainUsingCustomizer() {
|
||||
String domainName = "example.com";
|
||||
this.repository.setCookieCustomizer(customizer -> customizer.domain(domainName));
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
|
||||
assertThat(tokenCookie.getDomain()).isEqualTo(domainName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveTokenWithCookieMaxAge() {
|
||||
int maxAge = 1200;
|
||||
@@ -200,6 +250,46 @@ public class CookieCsrfTokenRepositoryTests {
|
||||
assertThat(tokenCookie.getMaxAge()).isEqualTo(maxAge);
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenWithCookieMaxAgeUsingCustomizer() {
|
||||
int maxAge = 1200;
|
||||
this.repository.setCookieCustomizer(customizer -> customizer.maxAge(maxAge));
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
|
||||
assertThat(tokenCookie.getMaxAge()).isEqualTo(maxAge);
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenWithSameSiteNull() {
|
||||
String sameSitePolicy = null;
|
||||
this.repository.setCookieCustomizer(customizer -> customizer.sameSite(sameSitePolicy));
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
|
||||
assertThat(((MockCookie)tokenCookie).getSameSite()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenWithSameSiteStrict() {
|
||||
String sameSitePolicy = "Strict";
|
||||
this.repository.setCookieCustomizer(customizer -> customizer.sameSite(sameSitePolicy));
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
|
||||
assertThat(((MockCookie)tokenCookie).getSameSite()).isEqualTo(sameSitePolicy);
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenWithSameSiteLax() {
|
||||
String sameSitePolicy = "Lax";
|
||||
this.repository.setCookieCustomizer(customizer -> customizer.sameSite(sameSitePolicy));
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
|
||||
assertThat(((MockCookie)tokenCookie).getSameSite()).isEqualTo(sameSitePolicy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadTokenNoCookiesNull() {
|
||||
assertThat(this.repository.loadToken(this.request)).isNull();
|
||||
@@ -299,6 +389,28 @@ public class CookieCsrfTokenRepositoryTests {
|
||||
assertThat(deferredCsrfToken.isGenerated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void cookieCustomizer() {
|
||||
String domainName = "example.com";
|
||||
String customPath = "/custompath";
|
||||
String sameSitePolicy = "Strict";
|
||||
this.repository.setCookieCustomizer(customizer -> {
|
||||
customizer.domain(domainName);
|
||||
customizer.secure(false);
|
||||
customizer.path(customPath);
|
||||
customizer.sameSite(sameSitePolicy);
|
||||
});
|
||||
CsrfToken token = this.repository.generateToken(this.request);
|
||||
this.repository.saveToken(token, this.request, this.response);
|
||||
Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME);
|
||||
assertThat(tokenCookie).isNotNull();
|
||||
assertThat(tokenCookie.getMaxAge()).isEqualTo(-1);
|
||||
assertThat(tokenCookie.getDomain()).isEqualTo(domainName);
|
||||
assertThat(tokenCookie.getPath()).isEqualTo(customPath);
|
||||
assertThat(tokenCookie.isHttpOnly()).isEqualTo(Boolean.TRUE);
|
||||
assertThat(((MockCookie)tokenCookie).getSameSite()).isEqualTo(sameSitePolicy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCookieNameNullIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setCookieName(null));
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.security.web.server.csrf;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -35,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Eric Deandrea
|
||||
* @author Thomas Vitale
|
||||
* @author Alonso Araya
|
||||
* @author Alex Montoya
|
||||
* @since 5.1
|
||||
*/
|
||||
public class CookieServerCsrfTokenRepositoryTests {
|
||||
@@ -61,6 +63,8 @@ public class CookieServerCsrfTokenRepositoryTests {
|
||||
|
||||
private String expectedCookieValue = "csrfToken";
|
||||
|
||||
private String expectedSameSitePolicy = null;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
this.csrfTokenRepository = new CookieServerCsrfTokenRepository();
|
||||
@@ -120,6 +124,12 @@ public class CookieServerCsrfTokenRepositoryTests {
|
||||
saveAndAssertExpectedValues(createToken());
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenWhenSameSiteThenCookieSameSite() {
|
||||
setExpectedSameSitePolicy("Lax");
|
||||
saveAndAssertExpectedValues(createToken());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveTokenWhenCustomPropertiesThenCustomProperties() {
|
||||
setExpectedDomain("spring.io");
|
||||
@@ -127,12 +137,48 @@ public class CookieServerCsrfTokenRepositoryTests {
|
||||
setExpectedPath("/some/path");
|
||||
setExpectedHeaderName("headerName");
|
||||
setExpectedParameterName("paramName");
|
||||
setExpectedSameSitePolicy("Strict");
|
||||
setExpectedCookieMaxAge(3600);
|
||||
saveAndAssertExpectedValues(createToken());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveTokenWhenSslInfoPresentThenSecure() {
|
||||
void saveTokenWhenCustomPropertiesThenCustomPropertiesUsingCustomizer() {
|
||||
String expectedDomain = "spring.io";
|
||||
int expectedMaxAge = 3600;
|
||||
String expectedPath = "/some/path";
|
||||
String expectedSameSite = "Strict";
|
||||
|
||||
setExpectedCookieName("csrfCookie");
|
||||
|
||||
setExpectedHeaderName("headerName");
|
||||
setExpectedParameterName("paramName");
|
||||
|
||||
CsrfToken token = createToken();
|
||||
|
||||
this.csrfTokenRepository.setCookieCustomizer(customizer -> {
|
||||
customizer.domain(expectedDomain);
|
||||
customizer.maxAge(expectedMaxAge);
|
||||
customizer.path(expectedPath);
|
||||
customizer.sameSite(expectedSameSite);
|
||||
});
|
||||
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(this.request);
|
||||
this.csrfTokenRepository.saveToken(exchange, token).block();
|
||||
ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName);
|
||||
assertThat(cookie).isNotNull();
|
||||
assertThat(cookie.getMaxAge()).isEqualTo(Duration.of(expectedMaxAge, ChronoUnit.SECONDS));
|
||||
assertThat(cookie.getDomain()).isEqualTo(expectedDomain);
|
||||
assertThat(cookie.getPath()).isEqualTo(expectedPath);
|
||||
assertThat(cookie.getSameSite()).isEqualTo(expectedSameSite);
|
||||
assertThat(cookie.isSecure()).isEqualTo(this.expectedSecure);
|
||||
assertThat(cookie.isHttpOnly()).isEqualTo(this.expectedHttpOnly);
|
||||
assertThat(cookie.getName()).isEqualTo(this.expectedCookieName);
|
||||
assertThat(cookie.getValue()).isEqualTo(this.expectedCookieValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenWhenSslInfoPresentThenSecure() {
|
||||
this.request.sslInfo(new MockSslInfo());
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(this.request);
|
||||
this.csrfTokenRepository.saveToken(exchange, createToken()).block();
|
||||
@@ -160,6 +206,16 @@ public class CookieServerCsrfTokenRepositoryTests {
|
||||
assertThat(cookie.isSecure()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenWhenSecureFlagTrueThenSecureUsingCustomizer() {
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(this.request);
|
||||
this.csrfTokenRepository.setCookieCustomizer(customizer -> customizer.secure(true));
|
||||
this.csrfTokenRepository.saveToken(exchange, createToken()).block();
|
||||
ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName);
|
||||
assertThat(cookie).isNotNull();
|
||||
assertThat(cookie.isSecure()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveTokenWhenSecureFlagFalseThenNotSecure() {
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(this.request);
|
||||
@@ -170,6 +226,16 @@ public class CookieServerCsrfTokenRepositoryTests {
|
||||
assertThat(cookie.isSecure()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenWhenSecureFlagFalseThenNotSecureUsingCustomizer() {
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(this.request);
|
||||
this.csrfTokenRepository.setCookieCustomizer(customizer -> customizer.secure(false));
|
||||
this.csrfTokenRepository.saveToken(exchange, createToken()).block();
|
||||
ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName);
|
||||
assertThat(cookie).isNotNull();
|
||||
assertThat(cookie.isSecure()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveTokenWhenSecureFlagFalseAndSslInfoThenNotSecure() {
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(this.request);
|
||||
@@ -181,6 +247,17 @@ public class CookieServerCsrfTokenRepositoryTests {
|
||||
assertThat(cookie.isSecure()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveTokenWhenSecureFlagFalseAndSslInfoThenNotSecureUsingCustomizer() {
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(this.request);
|
||||
this.request.sslInfo(new MockSslInfo());
|
||||
this.csrfTokenRepository.setCookieCustomizer(customizer -> customizer.secure(false));
|
||||
this.csrfTokenRepository.saveToken(exchange, createToken()).block();
|
||||
ResponseCookie cookie = exchange.getResponse().getCookies().getFirst(this.expectedCookieName);
|
||||
assertThat(cookie).isNotNull();
|
||||
assertThat(cookie.isSecure()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadTokenWhenCookieExistThenTokenFound() {
|
||||
loadAndAssertExpectedValues();
|
||||
@@ -248,6 +325,11 @@ public class CookieServerCsrfTokenRepositoryTests {
|
||||
this.expectedMaxAge = Duration.ofSeconds(expectedCookieMaxAge);
|
||||
}
|
||||
|
||||
private void setExpectedSameSitePolicy(String sameSitePolicy){
|
||||
this.csrfTokenRepository.setCookieCustomizer(customizer -> customizer.sameSite(sameSitePolicy));
|
||||
this.expectedSameSitePolicy = sameSitePolicy;
|
||||
}
|
||||
|
||||
private void setExpectedCookieValue(String expectedCookieValue) {
|
||||
this.expectedCookieValue = expectedCookieValue;
|
||||
}
|
||||
@@ -284,6 +366,7 @@ public class CookieServerCsrfTokenRepositoryTests {
|
||||
assertThat(cookie.isHttpOnly()).isEqualTo(this.expectedHttpOnly);
|
||||
assertThat(cookie.getName()).isEqualTo(this.expectedCookieName);
|
||||
assertThat(cookie.getValue()).isEqualTo(this.expectedCookieValue);
|
||||
assertThat(cookie.getSameSite()).isEqualTo(this.expectedSameSitePolicy);
|
||||
}
|
||||
|
||||
private void generateTokenAndAssertExpectedValues() {
|
||||
|
||||
Reference in New Issue
Block a user