CsrfWebFilter not generating the CSRF token with Webflux
See original GitHub issueSummary
I have a Spring Webflux application secured by Spring Security with CSRF protection enabled by default. In this application, I can’t get the CSRF token to be saved in the Websession nor added in the model.
Actual Behavior
After some investigations, I noticed that the problem comes from Spring Security’s CsrfWebFilter.class
, in which there is the following method:
private Mono<Void> continueFilterChain(ServerWebExchange exchange, WebFilterChain chain) {
return Mono.defer(() -> {
Mono<CsrfToken> csrfToken = this.csrfToken(exchange);
exchange.getAttributes().put(CsrfToken.class.getName(), csrfToken);
return chain.filter(exchange);
});
}
In this method, the CsrfToken
Mono is never subscribed, which prevents the token to be generated and added in the Websession.
Moreover, when my page is rendered, the _csrf
parameter is null in the view model.
Expected Behavior
The CsrfToken
Mono should be subscribed so that the WebSessionServerCsrfTokenRepository
could generate and save the token in the Websession. The _csrf
parameter should be accessible from the view model (maybe this one is an issue with Thymeleaf).
Workaround
As a workaround, I rewrite the CsrfWebFilter
in my application and just override the above method this way:
private Mono<Void> continueFilterChain(ServerWebExchange exchange, WebFilterChain chain) {
return Mono.defer(() -> {
return this.csrfToken(exchange)
.doOnNext(csrfToken -> exchange.getAttributes().put(CsrfToken.class.getName(), csrfToken))
.then(chain.filter(exchange));
});
}
Then, to be able to retrieve the _csrf
parameter in the model, I add this method in an abstract controller:
@ModelAttribute("_csrf")
public CsrfToken csrfToken(final ServerWebExchange exchange) {
return exchange.getAttribute(CsrfToken.class.getName());
}
Is it a valid workaround?
Configuration
Here is my Security configuration class:
@EnableWebFluxSecurity
public class SecurityConfiguration {
@Bean
public SecurityWebFilterChain springWebFilterChain(final ServerHttpSecurity http) {
http.authorizeExchange()
.pathMatchers("/**").permitAll()
.and()
.oauth2Login()
.and()
.oauth2Client();
return http.build();
}
@Bean
public ServerOAuth2AuthorizedClientRepository authorizedClientRepository(
final ReactiveOAuth2AuthorizedClientService authorizedClientService) {
return new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
}
}
Version
My application runs on Netty
with Spring Boot 2.1.0.RELEASE
, Spring Security 5.1.1.RELEASE
, and Thymeleaf 3.0.10.RELEASE
.
Issue Analytics
- State:
- Created 5 years ago
- Comments:18 (3 by maintainers)
Is there a way to solve this problem if you are using functional framework in Spring 5? The ControllerAdvice doesn’t seem to have any effect if you aren’t actually defining Controllers.
In case one does not have a controller, the simplest workaround is to implement a custom WebFilter which places the
Mono<CsrfToken>
inside of the filter chain like so: