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";
|
||||
|
||||
private static final String CSRF_TOKEN_REMOVED_ATTRIBUTE_NAME = CookieCsrfTokenRepository.class.getName()
|
||||
.concat(".REMOVED");
|
||||
|
||||
private String parameterName = DEFAULT_CSRF_PARAMETER_NAME;
|
||||
|
||||
private String headerName = DEFAULT_CSRF_HEADER_NAME;
|
||||
|
@ -79,10 +82,24 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository {
|
|||
cookie.setDomain(this.cookieDomain);
|
||||
}
|
||||
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
|
||||
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);
|
||||
if (cookie == null) {
|
||||
return null;
|
||||
|
|
|
@ -263,6 +263,32 @@ public class CookieCsrfTokenRepositoryTests {
|
|||
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
|
||||
public void loadDeferredTokenWhenExistsThenLoaded() {
|
||||
CsrfToken generatedToken = this.repository.generateToken(this.request);
|
||||
|
|
Loading…
Reference in New Issue