Skip to content

Commit 5a95952

Browse files
committed
Merge branch '6.3.x'
Closes gh-16063
2 parents c61ccd9 + e1ad989 commit 5a95952

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.security.web.server.WebFilterChainProxy;
3535
import org.springframework.security.web.server.WebFilterChainProxy.DefaultWebFilterChainDecorator;
3636
import org.springframework.security.web.server.WebFilterChainProxy.WebFilterChainDecorator;
37+
import org.springframework.security.web.server.firewall.ServerExchangeRejectedHandler;
3738
import org.springframework.security.web.server.firewall.ServerWebExchangeFirewall;
3839
import org.springframework.util.ClassUtils;
3940
import org.springframework.util.ObjectUtils;
@@ -81,11 +82,13 @@ void setFilterChainPostProcessor(ObjectPostProcessor<WebFilterChainDecorator> po
8182

8283
@Bean(SPRING_SECURITY_WEBFILTERCHAINFILTER_BEAN_NAME)
8384
@Order(WEB_FILTER_CHAIN_FILTER_ORDER)
84-
WebFilterChainProxy springSecurityWebFilterChainFilter(ObjectProvider<ServerWebExchangeFirewall> firewall) {
85+
WebFilterChainProxy springSecurityWebFilterChainFilter(ObjectProvider<ServerWebExchangeFirewall> firewall,
86+
ObjectProvider<ServerExchangeRejectedHandler> rejectedHandler) {
8587
WebFilterChainProxy proxy = new WebFilterChainProxy(getSecurityWebFilterChains());
8688
WebFilterChainDecorator decorator = this.postProcessor.postProcess(new DefaultWebFilterChainDecorator());
8789
proxy.setFilterChainDecorator(decorator);
8890
firewall.ifUnique(proxy::setFirewall);
91+
rejectedHandler.ifUnique(proxy::setExchangeRejectedHandler);
8992
return proxy;
9093
}
9194

config/src/test/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfigurationTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import org.springframework.security.config.test.SpringTestContextExtension;
3333
import org.springframework.security.config.users.ReactiveAuthenticationTestConfiguration;
3434
import org.springframework.security.web.server.WebFilterChainProxy;
35+
import org.springframework.security.web.server.firewall.HttpStatusExchangeRejectedHandler;
36+
import org.springframework.security.web.server.firewall.ServerExchangeRejectedHandler;
3537
import org.springframework.security.web.server.firewall.ServerWebExchangeFirewall;
3638
import org.springframework.web.server.handler.DefaultWebFilterChain;
3739

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

75+
@Test
76+
void loadConfigWhenCustomRejectedHandler() throws Exception {
77+
this.spring
78+
.register(ServerHttpSecurityConfiguration.class, ReactiveAuthenticationTestConfiguration.class,
79+
WebFluxSecurityConfiguration.class, CustomServerExchangeRejectedHandlerConfig.class)
80+
.autowire();
81+
WebFilterChainProxy webFilterChainProxy = this.spring.getContext().getBean(WebFilterChainProxy.class);
82+
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/;/").build());
83+
DefaultWebFilterChain chain = emptyChain();
84+
webFilterChainProxy.filter(exchange, chain).block();
85+
assertThat(exchange.getResponse().getStatusCode())
86+
.isEqualTo(CustomServerExchangeRejectedHandlerConfig.EXPECTED_STATUS);
87+
}
88+
7389
@Test
7490
void loadConfigWhenFirewallBeanThenCustomized() throws Exception {
7591
this.spring
@@ -107,6 +123,18 @@ ServerWebExchangeFirewall noOpFirewall() {
107123

108124
}
109125

126+
@Configuration
127+
static class CustomServerExchangeRejectedHandlerConfig {
128+
129+
static HttpStatus EXPECTED_STATUS = HttpStatus.I_AM_A_TEAPOT;
130+
131+
@Bean
132+
ServerExchangeRejectedHandler rejectedHandler() {
133+
return new HttpStatusExchangeRejectedHandler(EXPECTED_STATUS);
134+
}
135+
136+
}
137+
110138
@Configuration
111139
static class SubclassConfig extends WebFluxSecurityConfiguration {
112140

docs/modules/ROOT/pages/reactive/exploits/firewall.adoc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,35 @@ firewall.setAllowedHeaderValues {
200200
}
201201
----
202202
======
203+
204+
The `ServerExchangeRejectedHandler` interface is used to handle `ServerExchangeRejectedException` throw by Spring Security's `ServerWebExchangeFirewall`.
205+
By default `HttpStatusExchangeRejectedHandler` is used to send an HTTP 400 response to clients when a request is rejected.
206+
To customize the behavior, users can expose a `ServerExchangeRejectedHandler` Bean.
207+
For example, the following will send an HTTP 404 when the request is rejected:
208+
209+
210+
.Send 404 on Request Rejected
211+
[tabs]
212+
======
213+
Java::
214+
+
215+
[source,java,role="primary"]
216+
----
217+
@Bean
218+
ServerExchangeRejectedHandler rejectedHandler() {
219+
return new HttpStatusExchangeRejectedHandler(HttpStatus.NOT_FOUND);
220+
}
221+
----
222+
223+
Kotlin::
224+
+
225+
[source,kotlin,role="secondary"]
226+
----
227+
@Bean
228+
fun rejectedHandler(): ServerExchangeRejectedHandler {
229+
return HttpStatusExchangeRejectedHandler(HttpStatus.NOT_FOUND)
230+
}
231+
----
232+
======
233+
234+
Handling can be completely customized by creating a custom `ServerExchangeRejectedHandler` implementation.

0 commit comments

Comments
 (0)