Superseded by https://github.com/spring-projects/spring-framework/issues/33789
Related https://github.com/spring-cloud/spring-cloud-gateway/issues/3568 https://github.com/spring-projects/spring-security/issues/15995 https://github.com/spring-projects/spring-security/issues/16002 #16013
Workaround https://github.com/spring-projects/spring-security/issues/15989#issuecomment-2442660753
Updated Description
When using WebFlux + Spring Cloud + Spring Security'sStrictServerWebExchangeFirewall
the following exception occurs
java.lang.UnsupportedOperationException at org.springframework.http.ReadOnlyHttpHeaders.set(ReadOnlyHttpHeaders.java:110)
Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below:
Error has been observed at the following site(s):
*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ AuthorizationWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ ExceptionTranslationWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ LogoutWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ ServerRequestCacheWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ LogoutPageGeneratingWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ LoginPageGeneratingWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ OAuth2AuthorizationCodeGrantWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ AuthenticationWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ OAuth2LoginAuthenticationWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ OAuth2AuthorizationRequestRedirectWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ OAuth2AuthorizationRequestRedirectWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ ReactorContextWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ CsrfWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ HttpsRedirectWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ HttpHeaderWriterWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
*__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
*__checkpoint ⇢ HTTP GET \"/api/foo\" [ExceptionHandlingWebHandler]\nOriginal Stack Trace:
at org.springframework.http.ReadOnlyHttpHeaders.set(ReadOnlyHttpHeaders.java:110)
at org.springframework.http.ReadOnlyHttpHeaders.set(ReadOnlyHttpHeaders.java:39)
at org.springframework.http.HttpHeaders.set(HttpHeaders.java:1735)
at org.springframework.http.HttpHeaders.set(HttpHeaders.java:76)
at org.springframework.http.HttpHeaders.set(HttpHeaders.java:1735)
at org.springframework.http.HttpHeaders.setBearerAuth(HttpHeaders.java:830)
at org.springframework.cloud.gateway.filter.factory.TokenRelayGatewayFilterFactory.lambda$withBearerAuth$5(TokenRelayGatewayFilterFactory.java:92)
at org.springframework.http.server.reactive.DefaultServerHttpRequestBuilder.headers(DefaultServerHttpRequestBuilder.java:117)
at org.springframework.cloud.gateway.filter.factory.TokenRelayGatewayFilterFactory.lambda$withBearerAuth$6(TokenRelayGatewayFilterFactory.java:92)
at org.springframework.web.server.DefaultServerWebExchangeBuilder.request(DefaultServerWebExchangeBuilder.java:58)
at org.springframework.cloud.gateway.filter.factory.TokenRelayGatewayFilterFactory.withBearerAuth(TokenRelayGatewayFilterFactory.java:92)
at org.springframework.cloud.gateway.filter.factory.TokenRelayGatewayFilterFactory.lambda$apply$2(TokenRelayGatewayFilterFactory.java:65)
Original Description
Rob and I chatted about it
https://github.com/spring-projects/spring-framework/blob/c27a5687dcc8708584edd0141630af66ce6cbe90/spring-web/src/main/java/org/springframework/http/HttpHeaders.java#L1890
headers is read only, AND headers.headers is read only, so calling HttpHeaders.writableHttpHeaders() does not, in fact, result in writable headers.
The question is, is it a security or framework bug.
/cc @rwinch @rstoyanchev
Comment From: rwinch
I'm going to close this issue in favor of https://github.com/spring-projects/spring-framework/issues/33789
Comment From: rwinch
For those experiencing this issue, DO NOT disable Spring Security's firewall as a workaround to the underlying Spring Framework issue. Instead, you can use the following as a workaround:
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
WebFilter writeableHeaders() {
return (exchange, chain) -> {
HttpHeaders writeableHeaders = HttpHeaders.writableHttpHeaders(
exchange.getRequest().getHeaders());
ServerHttpRequestDecorator writeableRequest = new ServerHttpRequestDecorator(
exchange.getRequest()) {
@Override
public HttpHeaders getHeaders() {
return writeableHeaders;
}
};
ServerWebExchange writeableExchange = exchange.mutate()
.request(writeableRequest)
.build();
return chain.filter(writeableExchange);
};
}
You can find a complete demo of the workaround at https://github.com/rwinch/spring-sample/tree/spring-framework-33789-readonly-headers
Comment From: dongKos
@rwinch your solution works like magic thanks!
Comment From: TimofejOv
For those experiencing this issue, DO NOT disable Spring Security's firewall as a workaround to the underlying Spring Framework issue. Instead, you can use the following as a workaround:
@Bean @Order(Ordered.HIGHEST_PRECEDENCE) WebFilter writeableHeaders() { return (exchange, chain) -> { HttpHeaders writeableHeaders = HttpHeaders.writableHttpHeaders( exchange.getRequest().getHeaders()); ServerHttpRequestDecorator writeableRequest = new ServerHttpRequestDecorator( exchange.getRequest()) { @Override public HttpHeaders getHeaders() { return writeableHeaders; } }; ServerWebExchange writeableExchange = exchange.mutate() .request(writeableRequest) .build(); return chain.filter(writeableExchange); }; }
You can find a complete demo of the workaround at https://github.com/rwinch/spring-sample/tree/spring-framework-33789-readonly-headers
Hello.
What could be the solution for WebMvc case? I get UnsupportedOperationException in app with spring-cloud-gateway-mvc (4.3.1)+ spring-security (6.5.5) + spring-webmvc (6.2.11).
Thank you.
Comment From: rodrigorodrigues
For those experiencing this issue, DO NOT disable Spring Security's firewall as a workaround to the underlying Spring Framework issue. Instead, you can use the following as a workaround:
@Bean @Order(Ordered.HIGHEST_PRECEDENCE) WebFilter writeableHeaders() { return (exchange, chain) -> { HttpHeaders writeableHeaders = HttpHeaders.writableHttpHeaders( exchange.getRequest().getHeaders()); ServerHttpRequestDecorator writeableRequest = new ServerHttpRequestDecorator( exchange.getRequest()) { @Override public HttpHeaders getHeaders() { return writeableHeaders; } }; ServerWebExchange writeableExchange = exchange.mutate() .request(writeableRequest) .build(); return chain.filter(writeableExchange); }; } You can find a complete demo of the workaround at https://github.com/rwinch/spring-sample/tree/spring-framework-33789-readonly-headers
Hi @rwinch, can you please suggest a solution that works for Spring Boot 4? It seems this method HttpHeaders.writableHttpHeaders
is being removed.