Re-generate tokens in CookieCsrfTokenRepository
Fixes support for re-generating tokens within a request such as when CsrfAuthenticationStrategy removes a null token and saves an empty cookie value on the response. Closes gh-12141
This commit is contained in:
parent
33ce3b59b8
commit
6b0ed0205b
|
@ -43,6 +43,9 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository {
|
||||||
|
|
||||||
static final String DEFAULT_CSRF_HEADER_NAME = "X-XSRF-TOKEN";
|
static final String DEFAULT_CSRF_HEADER_NAME = "X-XSRF-TOKEN";
|
||||||
|
|
||||||
|
private static final String CSRF_TOKEN_REMOVED_ATTRIBUTE_NAME = CookieCsrfTokenRepository.class.getName()
|
||||||
|
.concat(".REMOVED");
|
||||||
|
|
||||||
private String parameterName = DEFAULT_CSRF_PARAMETER_NAME;
|
private String parameterName = DEFAULT_CSRF_PARAMETER_NAME;
|
||||||
|
|
||||||
private String headerName = DEFAULT_CSRF_HEADER_NAME;
|
private String headerName = DEFAULT_CSRF_HEADER_NAME;
|
||||||
|
@ -79,10 +82,24 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository {
|
||||||
cookie.setDomain(this.cookieDomain);
|
cookie.setDomain(this.cookieDomain);
|
||||||
}
|
}
|
||||||
response.addCookie(cookie);
|
response.addCookie(cookie);
|
||||||
|
|
||||||
|
// Set request attribute to signal that response has blank cookie value,
|
||||||
|
// which allows loadToken to return null when token has been removed
|
||||||
|
if (!StringUtils.hasLength(tokenValue)) {
|
||||||
|
request.setAttribute(CSRF_TOKEN_REMOVED_ATTRIBUTE_NAME, Boolean.TRUE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
request.removeAttribute(CSRF_TOKEN_REMOVED_ATTRIBUTE_NAME);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CsrfToken loadToken(HttpServletRequest request) {
|
public CsrfToken loadToken(HttpServletRequest request) {
|
||||||
|
// Return null when token has been removed during the current request
|
||||||
|
// which allows loadDeferredToken to re-generate the token
|
||||||
|
if (Boolean.TRUE.equals(request.getAttribute(CSRF_TOKEN_REMOVED_ATTRIBUTE_NAME))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Cookie cookie = WebUtils.getCookie(request, this.cookieName);
|
Cookie cookie = WebUtils.getCookie(request, this.cookieName);
|
||||||
if (cookie == null) {
|
if (cookie == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -263,6 +263,32 @@ public class CookieCsrfTokenRepositoryTests {
|
||||||
assertThat(tokenCookie.isHttpOnly()).isEqualTo(true);
|
assertThat(tokenCookie.isHttpOnly()).isEqualTo(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadDeferredTokenWhenExistsAndNullSavedThenGeneratedAndSaved() {
|
||||||
|
CsrfToken generatedToken = this.repository.generateToken(this.request);
|
||||||
|
this.request
|
||||||
|
.setCookies(new Cookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME, generatedToken.getToken()));
|
||||||
|
this.repository.saveToken(null, this.request, this.response);
|
||||||
|
DeferredCsrfToken deferredCsrfToken = this.repository.loadDeferredToken(this.request, this.response);
|
||||||
|
CsrfToken csrfToken = deferredCsrfToken.get();
|
||||||
|
assertThat(csrfToken).isNotNull();
|
||||||
|
assertThat(generatedToken).isNotEqualTo(csrfToken);
|
||||||
|
assertThat(deferredCsrfToken.isGenerated()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadDeferredTokenWhenExistsAndNullSavedAndNonNullSavedThenLoaded() {
|
||||||
|
CsrfToken generatedToken = this.repository.generateToken(this.request);
|
||||||
|
this.request
|
||||||
|
.setCookies(new Cookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME, generatedToken.getToken()));
|
||||||
|
this.repository.saveToken(null, this.request, this.response);
|
||||||
|
this.repository.saveToken(generatedToken, this.request, this.response);
|
||||||
|
DeferredCsrfToken deferredCsrfToken = this.repository.loadDeferredToken(this.request, this.response);
|
||||||
|
CsrfToken csrfToken = deferredCsrfToken.get();
|
||||||
|
assertThatCsrfToken(csrfToken).isEqualTo(generatedToken);
|
||||||
|
assertThat(deferredCsrfToken.isGenerated()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loadDeferredTokenWhenExistsThenLoaded() {
|
public void loadDeferredTokenWhenExistsThenLoaded() {
|
||||||
CsrfToken generatedToken = this.repository.generateToken(this.request);
|
CsrfToken generatedToken = this.repository.generateToken(this.request);
|
||||||
|
|
Loading…
Reference in New Issue