|
|
|
@ -1,5 +1,5 @@ |
|
|
|
/* |
|
|
|
/* |
|
|
|
* Copyright 2002-2022 the original author or authors. |
|
|
|
* Copyright 2002-2024 the original author or authors. |
|
|
|
* |
|
|
|
* |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
@ -46,6 +46,9 @@ import static org.mockito.Mockito.verify; |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class XorServerCsrfTokenRequestAttributeHandlerTests { |
|
|
|
public class XorServerCsrfTokenRequestAttributeHandlerTests { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* Token format: 3 random pad bytes + 3 padded bytes. |
|
|
|
|
|
|
|
*/ |
|
|
|
private static final byte[] XOR_CSRF_TOKEN_BYTES = new byte[] { 1, 1, 1, 96, 99, 98 }; |
|
|
|
private static final byte[] XOR_CSRF_TOKEN_BYTES = new byte[] { 1, 1, 1, 96, 99, 98 }; |
|
|
|
|
|
|
|
|
|
|
|
private static final String XOR_CSRF_TOKEN_VALUE = Base64.getEncoder().encodeToString(XOR_CSRF_TOKEN_BYTES); |
|
|
|
private static final String XOR_CSRF_TOKEN_VALUE = Base64.getEncoder().encodeToString(XOR_CSRF_TOKEN_BYTES); |
|
|
|
@ -188,6 +191,78 @@ public class XorServerCsrfTokenRequestAttributeHandlerTests { |
|
|
|
StepVerifier.create(csrfToken).expectNext(this.token.getToken()).verifyComplete(); |
|
|
|
StepVerifier.create(csrfToken).expectNext(this.token.getToken()).verifyComplete(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// gh-13310, gh-15184
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void resolveCsrfTokenValueWhenCsrfBytesIsShorterThanRandomBytesThenReturnsNull() { |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* Token format: 3 random pad bytes + 2 padded bytes. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
byte[] actualBytes = { 1, 1, 1, 96, 99 }; |
|
|
|
|
|
|
|
String actualToken = Base64.getEncoder().encodeToString(actualBytes); |
|
|
|
|
|
|
|
this.exchange = MockServerWebExchange |
|
|
|
|
|
|
|
.builder(MockServerHttpRequest.post("/") |
|
|
|
|
|
|
|
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) |
|
|
|
|
|
|
|
.header(this.token.getHeaderName(), actualToken)) |
|
|
|
|
|
|
|
.build(); |
|
|
|
|
|
|
|
String tokenValue = this.handler.resolveCsrfTokenValue(this.exchange, this.token).block(); |
|
|
|
|
|
|
|
assertThat(tokenValue).isNull(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// gh-13310, gh-15184
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void resolveCsrfTokenValueWhenCsrfBytesIsLongerThanRandomBytesThenReturnsNull() { |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* Token format: 3 random pad bytes + 4 padded bytes. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
byte[] actualBytes = { 1, 1, 1, 96, 99, 98, 97 }; |
|
|
|
|
|
|
|
String actualToken = Base64.getEncoder().encodeToString(actualBytes); |
|
|
|
|
|
|
|
this.exchange = MockServerWebExchange |
|
|
|
|
|
|
|
.builder(MockServerHttpRequest.post("/") |
|
|
|
|
|
|
|
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) |
|
|
|
|
|
|
|
.header(this.token.getHeaderName(), actualToken)) |
|
|
|
|
|
|
|
.build(); |
|
|
|
|
|
|
|
String tokenValue = this.handler.resolveCsrfTokenValue(this.exchange, this.token).block(); |
|
|
|
|
|
|
|
assertThat(tokenValue).isNull(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// gh-13310, gh-15184
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void resolveCsrfTokenValueWhenTokenBytesIsShorterThanActualBytesThenReturnsNull() { |
|
|
|
|
|
|
|
this.exchange = MockServerWebExchange |
|
|
|
|
|
|
|
.builder(MockServerHttpRequest.post("/") |
|
|
|
|
|
|
|
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) |
|
|
|
|
|
|
|
.header(this.token.getHeaderName(), XOR_CSRF_TOKEN_VALUE)) |
|
|
|
|
|
|
|
.build(); |
|
|
|
|
|
|
|
CsrfToken csrfToken = new DefaultCsrfToken("headerName", "paramName", "a"); |
|
|
|
|
|
|
|
String tokenValue = this.handler.resolveCsrfTokenValue(this.exchange, csrfToken).block(); |
|
|
|
|
|
|
|
assertThat(tokenValue).isNull(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// gh-13310, gh-15184
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void resolveCsrfTokenValueWhenTokenBytesIsLongerThanActualBytesThenReturnsNull() { |
|
|
|
|
|
|
|
this.exchange = MockServerWebExchange |
|
|
|
|
|
|
|
.builder(MockServerHttpRequest.post("/") |
|
|
|
|
|
|
|
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) |
|
|
|
|
|
|
|
.header(this.token.getHeaderName(), XOR_CSRF_TOKEN_VALUE)) |
|
|
|
|
|
|
|
.build(); |
|
|
|
|
|
|
|
CsrfToken csrfToken = new DefaultCsrfToken("headerName", "paramName", "abcde"); |
|
|
|
|
|
|
|
String tokenValue = this.handler.resolveCsrfTokenValue(this.exchange, csrfToken).block(); |
|
|
|
|
|
|
|
assertThat(tokenValue).isNull(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// gh-13310, gh-15184
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void resolveCsrfTokenValueWhenActualBytesIsEmptyThenReturnsNull() { |
|
|
|
|
|
|
|
this.exchange = MockServerWebExchange |
|
|
|
|
|
|
|
.builder(MockServerHttpRequest.post("/") |
|
|
|
|
|
|
|
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) |
|
|
|
|
|
|
|
.header(this.token.getHeaderName(), "")) |
|
|
|
|
|
|
|
.build(); |
|
|
|
|
|
|
|
String tokenValue = this.handler.resolveCsrfTokenValue(this.exchange, this.token).block(); |
|
|
|
|
|
|
|
assertThat(tokenValue).isNull(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static Answer<Void> fillByteArray() { |
|
|
|
private static Answer<Void> fillByteArray() { |
|
|
|
return (invocation) -> { |
|
|
|
return (invocation) -> { |
|
|
|
byte[] bytes = invocation.getArgument(0); |
|
|
|
byte[] bytes = invocation.getArgument(0); |
|
|
|
|