Skip to content

Commit

Permalink
Merge branch '6.3.x'
Browse files Browse the repository at this point in the history
Closes gh-16063
  • Loading branch information
rwinch committed Nov 11, 2024
2 parents c61ccd9 + e1ad989 commit 5a95952
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.springframework.security.web.server.WebFilterChainProxy;
import org.springframework.security.web.server.WebFilterChainProxy.DefaultWebFilterChainDecorator;
import org.springframework.security.web.server.WebFilterChainProxy.WebFilterChainDecorator;
import org.springframework.security.web.server.firewall.ServerExchangeRejectedHandler;
import org.springframework.security.web.server.firewall.ServerWebExchangeFirewall;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
Expand Down Expand Up @@ -81,11 +82,13 @@ void setFilterChainPostProcessor(ObjectPostProcessor<WebFilterChainDecorator> po

@Bean(SPRING_SECURITY_WEBFILTERCHAINFILTER_BEAN_NAME)
@Order(WEB_FILTER_CHAIN_FILTER_ORDER)
WebFilterChainProxy springSecurityWebFilterChainFilter(ObjectProvider<ServerWebExchangeFirewall> firewall) {
WebFilterChainProxy springSecurityWebFilterChainFilter(ObjectProvider<ServerWebExchangeFirewall> firewall,
ObjectProvider<ServerExchangeRejectedHandler> rejectedHandler) {
WebFilterChainProxy proxy = new WebFilterChainProxy(getSecurityWebFilterChains());
WebFilterChainDecorator decorator = this.postProcessor.postProcess(new DefaultWebFilterChainDecorator());
proxy.setFilterChainDecorator(decorator);
firewall.ifUnique(proxy::setFirewall);
rejectedHandler.ifUnique(proxy::setExchangeRejectedHandler);
return proxy;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.users.ReactiveAuthenticationTestConfiguration;
import org.springframework.security.web.server.WebFilterChainProxy;
import org.springframework.security.web.server.firewall.HttpStatusExchangeRejectedHandler;
import org.springframework.security.web.server.firewall.ServerExchangeRejectedHandler;
import org.springframework.security.web.server.firewall.ServerWebExchangeFirewall;
import org.springframework.web.server.handler.DefaultWebFilterChain;

Expand Down Expand Up @@ -70,6 +72,20 @@ void loadConfigWhenDefaultThenFirewalled() throws Exception {
assertThat(exchange.getResponse().getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
}

@Test
void loadConfigWhenCustomRejectedHandler() throws Exception {
this.spring
.register(ServerHttpSecurityConfiguration.class, ReactiveAuthenticationTestConfiguration.class,
WebFluxSecurityConfiguration.class, CustomServerExchangeRejectedHandlerConfig.class)
.autowire();
WebFilterChainProxy webFilterChainProxy = this.spring.getContext().getBean(WebFilterChainProxy.class);
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/;/").build());
DefaultWebFilterChain chain = emptyChain();
webFilterChainProxy.filter(exchange, chain).block();
assertThat(exchange.getResponse().getStatusCode())
.isEqualTo(CustomServerExchangeRejectedHandlerConfig.EXPECTED_STATUS);
}

@Test
void loadConfigWhenFirewallBeanThenCustomized() throws Exception {
this.spring
Expand Down Expand Up @@ -107,6 +123,18 @@ ServerWebExchangeFirewall noOpFirewall() {

}

@Configuration
static class CustomServerExchangeRejectedHandlerConfig {

static HttpStatus EXPECTED_STATUS = HttpStatus.I_AM_A_TEAPOT;

@Bean
ServerExchangeRejectedHandler rejectedHandler() {
return new HttpStatusExchangeRejectedHandler(EXPECTED_STATUS);
}

}

@Configuration
static class SubclassConfig extends WebFluxSecurityConfiguration {

Expand Down
32 changes: 32 additions & 0 deletions docs/modules/ROOT/pages/reactive/exploits/firewall.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,35 @@ firewall.setAllowedHeaderValues {
}
----
======

The `ServerExchangeRejectedHandler` interface is used to handle `ServerExchangeRejectedException` throw by Spring Security's `ServerWebExchangeFirewall`.
By default `HttpStatusExchangeRejectedHandler` is used to send an HTTP 400 response to clients when a request is rejected.
To customize the behavior, users can expose a `ServerExchangeRejectedHandler` Bean.
For example, the following will send an HTTP 404 when the request is rejected:


.Send 404 on Request Rejected
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
ServerExchangeRejectedHandler rejectedHandler() {
return new HttpStatusExchangeRejectedHandler(HttpStatus.NOT_FOUND);
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun rejectedHandler(): ServerExchangeRejectedHandler {
return HttpStatusExchangeRejectedHandler(HttpStatus.NOT_FOUND)
}
----
======

Handling can be completely customized by creating a custom `ServerExchangeRejectedHandler` implementation.

0 comments on commit 5a95952

Please sign in to comment.