Cache Xor CsrfToken

Closes gh-11988
This commit is contained in:
Steve Riesenberg 2022-10-12 10:27:09 -05:00
parent ffbcaca24a
commit 05e4a1dd20
No known key found for this signature in database
GPG Key ID: 5F311AB48A55D521
4 changed files with 44 additions and 3 deletions

View File

@ -59,12 +59,12 @@ public final class XorCsrfTokenRequestAttributeHandler extends CsrfTokenRequestA
}
private Supplier<CsrfToken> deferCsrfTokenUpdate(Supplier<CsrfToken> csrfTokenSupplier) {
return () -> {
return new CachedCsrfTokenSupplier(() -> {
CsrfToken csrfToken = csrfTokenSupplier.get();
Assert.state(csrfToken != null, "csrfToken supplier returned null");
String updatedToken = createXoredCsrfToken(this.secureRandom, csrfToken.getToken());
return new DefaultCsrfToken(csrfToken.getHeaderName(), csrfToken.getParameterName(), updatedToken);
};
});
}
@Override
@ -123,4 +123,24 @@ public final class XorCsrfTokenRequestAttributeHandler extends CsrfTokenRequestA
return xoredCsrf;
}
private static final class CachedCsrfTokenSupplier implements Supplier<CsrfToken> {
private final Supplier<CsrfToken> delegate;
private CsrfToken csrfToken;
private CachedCsrfTokenSupplier(Supplier<CsrfToken> delegate) {
this.delegate = delegate;
}
@Override
public CsrfToken get() {
if (this.csrfToken == null) {
this.csrfToken = this.delegate.get();
}
return this.csrfToken;
}
}
}

View File

@ -53,7 +53,8 @@ public final class XorServerCsrfTokenRequestAttributeHandler extends ServerCsrfT
Assert.notNull(exchange, "exchange cannot be null");
Assert.notNull(csrfToken, "csrfToken cannot be null");
Mono<CsrfToken> updatedCsrfToken = csrfToken.map((token) -> new DefaultCsrfToken(token.getHeaderName(),
token.getParameterName(), createXoredCsrfToken(this.secureRandom, token.getToken())));
token.getParameterName(), createXoredCsrfToken(this.secureRandom, token.getToken())))
.cast(CsrfToken.class).cache();
super.handle(exchange, updatedCsrfToken);
}

View File

@ -148,6 +148,15 @@ public class XorCsrfTokenRequestAttributeHandlerTests {
assertThat(csrfTokenAttribute.getToken()).isEqualTo(XOR_CSRF_TOKEN_VALUE);
}
@Test
public void handleWhenCsrfTokenRequestedTwiceThenCached() {
this.handler.handle(this.request, this.response, () -> this.token);
CsrfToken csrfTokenAttribute = (CsrfToken) this.request.getAttribute(CsrfToken.class.getName());
assertThat(csrfTokenAttribute.getToken()).isNotEqualTo(this.token.getToken());
assertThat(csrfTokenAttribute.getToken()).isEqualTo(csrfTokenAttribute.getToken());
}
@Test
public void resolveCsrfTokenValueWhenRequestIsNullThenThrowsIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.handler.resolveCsrfTokenValue(null, this.token))

View File

@ -110,6 +110,17 @@ public class XorServerCsrfTokenRequestAttributeHandlerTests {
verify(this.secureRandom).nextBytes(anyByteArray());
}
@Test
public void handleWhenCsrfTokenRequestedTwiceThenCached() {
this.handler.handle(this.exchange, Mono.just(this.token));
Mono<CsrfToken> csrfTokenAttribute = this.exchange.getAttribute(CsrfToken.class.getName());
assertThat(csrfTokenAttribute).isNotNull();
CsrfToken csrfToken1 = csrfTokenAttribute.block();
CsrfToken csrfToken2 = csrfTokenAttribute.block();
assertThat(csrfToken1.getToken()).isNotEqualTo(this.token.getToken());
assertThat(csrfToken1.getToken()).isEqualTo(csrfToken2.getToken());
}
@Test
public void resolveCsrfTokenValueWhenExchangeIsNullThenThrowsIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.handler.resolveCsrfTokenValue(null, this.token))