Skip to content

Commit

Permalink
LazyCsrfTokenRepository#loadToken Supports Deferring Delegation
Browse files Browse the repository at this point in the history
Previously LazyCsrfTokenRepository supported lazily saving the CsrfToken
which allowed for lazily saving the CsrfToken. However, it did not
support lazily reading the CsrfToken. This meant every request required
reading the CsrfToken (often the HttpSession).

This commit allows for lazily reading the CsrfToken and thus prevents
unnecessary reads to the HttpSession.

Closes gh-11700
  • Loading branch information
rwinch committed Aug 16, 2022
1 parent a73e32e commit 2aedf58
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public final class LazyCsrfTokenRepository implements CsrfTokenRepository {

private final CsrfTokenRepository delegate;

private boolean deferLoadToken;

/**
* Creates a new instance
* @param delegate the {@link CsrfTokenRepository} to use. Cannot be null
Expand All @@ -48,6 +50,15 @@ public LazyCsrfTokenRepository(CsrfTokenRepository delegate) {
this.delegate = delegate;
}

/**
* Determines if {@link #loadToken(HttpServletRequest)} should be lazily loaded.
* @param deferLoadToken true if should lazily load
* {@link #loadToken(HttpServletRequest)}. Default false.
*/
public void setDeferLoadToken(boolean deferLoadToken) {
this.deferLoadToken = deferLoadToken;
}

/**
* Generates a new token
* @param request the {@link HttpServletRequest} to use. The
Expand Down Expand Up @@ -77,6 +88,9 @@ public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletRe
*/
@Override
public CsrfToken loadToken(HttpServletRequest request) {
if (this.deferLoadToken) {
return new LazyLoadCsrfToken(request, this.delegate);
}
return this.delegate.loadToken(request);
}

Expand All @@ -92,6 +106,55 @@ private HttpServletResponse getResponse(HttpServletRequest request) {
return response;
}

private final class LazyLoadCsrfToken implements CsrfToken {

private final HttpServletRequest request;

private final CsrfTokenRepository tokenRepository;

private CsrfToken token;

private LazyLoadCsrfToken(HttpServletRequest request, CsrfTokenRepository tokenRepository) {
this.request = request;
this.tokenRepository = tokenRepository;
}

private CsrfToken getDelegate() {
if (this.token != null) {
return this.token;
}
// load from the delegate repository
this.token = LazyCsrfTokenRepository.this.delegate.loadToken(this.request);
if (this.token == null) {
// return a generated token that is lazily saved since
// LazyCsrfTokenRepository#loadToken always returns a value
this.token = generateToken(this.request);
}
return this.token;
}

@Override
public String getHeaderName() {
return getDelegate().getHeaderName();
}

@Override
public String getParameterName() {
return getDelegate().getParameterName();
}

@Override
public String getToken() {
return getDelegate().getToken();
}

@Override
public String toString() {
return "LazyLoadCsrfToken{" + "token=" + this.token + '}';
}

}

private static final class SaveOnAccessCsrfToken implements CsrfToken {

private transient CsrfTokenRepository tokenRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;

/**
Expand Down Expand Up @@ -97,4 +98,15 @@ public void loadTokenDelegates() {
verify(this.delegate).loadToken(this.request);
}

@Test
public void loadTokenWhenDeferLoadToken() {
given(this.delegate.loadToken(this.request)).willReturn(this.token);
this.repository.setDeferLoadToken(true);
CsrfToken loadToken = this.repository.loadToken(this.request);
verifyNoInteractions(this.delegate);
assertThat(loadToken.getToken()).isEqualTo(this.token.getToken());
assertThat(loadToken.getHeaderName()).isEqualTo(this.token.getHeaderName());
assertThat(loadToken.getParameterName()).isEqualTo(this.token.getParameterName());
}

}

0 comments on commit 2aedf58

Please sign in to comment.