i'm trying to write some end-to-end tests using Spring WebTestClient, and i'm facing and issue regarding the CSRF Token set by Spring Security.
if i try to execute the REST API with Postman everything is working fine, i do a GET and get my CSRF Token back, then i do POST setting X-XSRF-TOKEN header
from the POST i got back a new XSRF-TOKEN, which is first unset and the set again
XSRF-TOKEN=; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/,XSRF-TOKEN=b09c4e89-8954-4314-927f-787cafdabab4; Path=/
(as discussed also here: https://security.stackexchange.com/questions/241178/why-does-spring-security-unset-and-set-the-same-cookie-in-one-request
Postman again i working fine, unsetting and then setting the cookie to the new value.
if i try to replicate the same flow with a WebTestClient the problem is that when i go to retrieve the new XSRF-TOKEN cookie value from the POST the value is empty, seems like WebTestClient only retrieve the "unset" part of the header Set-Cookie, but not the second part.
i've also replicated the issue with just WebClient (which is used inside of WebTestClient if i'm not wrong) and Mockoon, setting a header like this in the Mockoon response of /test
XSRF-TOKEN=AAAA; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/,XSRF-TOKEN=BBB; Path=/
and
Mono<String> string = this.webClient.get().uri("/test").exchangeToMono(response -> {
response.cookies();
if (response.statusCode().equals(HttpStatus.OK)) {
return response.bodyToMono(String.class);
} else if (response.statusCode().is4xxClientError()) {
return Mono.just("Error response");
} else {
return response.createException()
.flatMap(Mono::error);
}
});
only the first value is read ('AAAA') but since the method of ClientRespose is
MultiValueMap<String, ResponseCookie> cookies();
i was expecting to get both values in the MultiValueMap
UPDATE:
managed to debug down to https://github.com/netty/netty/blob/4.1/codec-http/src/main/java/io/netty/handler/codec/http/cookie/ClientCookieDecoder.java
char c = header.charAt(i);
if (c == ',') {
// Having multiple cookies in a single Set-Cookie header is
// deprecated, modern browsers only parse the first one
break loop;
so it seems this is by design, but then i don't understand why a MultiValueMap is needed