diff --git a/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java b/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java index 473dbaf56c6..80f036e7d85 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java +++ b/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java @@ -57,6 +57,8 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository { private Boolean secure; + private int cookieMaxAge = -1; + public CookieCsrfTokenRepository() { } @@ -71,7 +73,7 @@ public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletRe Cookie cookie = new Cookie(this.cookieName, tokenValue); cookie.setSecure((this.secure != null) ? this.secure : request.isSecure()); cookie.setPath(StringUtils.hasLength(this.cookiePath) ? this.cookiePath : this.getRequestContext(request)); - cookie.setMaxAge((token != null) ? -1 : 0); + cookie.setMaxAge((token != null) ? this.cookieMaxAge : 0); cookie.setHttpOnly(this.cookieHttpOnly); if (StringUtils.hasLength(this.cookieDomain)) { cookie.setDomain(this.cookieDomain); @@ -98,7 +100,7 @@ public CsrfToken loadToken(HttpServletRequest request) { * provide a token */ public void setParameterName(String parameterName) { - Assert.notNull(parameterName, "parameterName is not null"); + Assert.notNull(parameterName, "parameterName cannot be null"); this.parameterName = parameterName; } @@ -108,7 +110,7 @@ public void setParameterName(String parameterName) { * token */ public void setHeaderName(String headerName) { - Assert.notNull(headerName, "headerName is not null"); + Assert.notNull(headerName, "headerName cannot be null"); this.headerName = headerName; } @@ -118,7 +120,7 @@ public void setHeaderName(String headerName) { * and read from */ public void setCookieName(String cookieName) { - Assert.notNull(cookieName, "cookieName is not null"); + Assert.notNull(cookieName, "cookieName cannot be null"); this.cookieName = cookieName; } @@ -192,4 +194,30 @@ public void setSecure(Boolean secure) { this.secure = secure; } + /** + * Sets maximum age in seconds for the cookie that the expected CSRF token is saved to + * and read from. By default maximum age value is -1. + * + *

+ * A positive value indicates that the cookie will expire after that many seconds have + * passed. Note that the value is the maximum age when the cookie will expire, + * not the cookie's current age. + * + *

+ * A negative value means that the cookie is not stored persistently and will be + * deleted when the Web browser exits. + * + *

+ * A zero value causes the cookie to be deleted immediately therefore it is not a + * valid value and in that case an {@link IllegalArgumentException} will be thrown. + * @param cookieMaxAge an integer specifying the maximum age of the cookie in seconds; + * if negative, means the cookie is not stored; if zero, the method throws an + * {@link IllegalArgumentException} + * @since 5.5 + */ + public void setCookieMaxAge(int cookieMaxAge) { + Assert.isTrue(cookieMaxAge != 0, "cookieMaxAge cannot be zero"); + this.cookieMaxAge = cookieMaxAge; + } + } diff --git a/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java b/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java index e204be126b1..722bc01a698 100644 --- a/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java +++ b/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java @@ -190,6 +190,16 @@ public void saveTokenWithCookieDomain() { assertThat(tokenCookie.getDomain()).isEqualTo(domainName); } + @Test + public void saveTokenWithCookieMaxAge() { + int maxAge = 1200; + this.repository.setCookieMaxAge(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 public void loadTokenNoCookiesNull() { assertThat(this.repository.loadToken(this.request)).isNull(); @@ -251,4 +261,9 @@ public void setHeaderNameNullIllegalArgumentException() { assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setHeaderName(null)); } + @Test + public void setCookieMaxAgeZeroIllegalArgumentException() { + assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setCookieMaxAge(0)); + } + }