Support ServerExchangeRejectedHandler @Bean
Closes gh-15975
This commit is contained in:
parent
e48d6b039b
commit
e86d88d0cf
|
@ -31,6 +31,7 @@ import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||||
import org.springframework.security.web.reactive.result.view.CsrfRequestDataValueProcessor;
|
import org.springframework.security.web.reactive.result.view.CsrfRequestDataValueProcessor;
|
||||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||||
import org.springframework.security.web.server.WebFilterChainProxy;
|
import org.springframework.security.web.server.WebFilterChainProxy;
|
||||||
|
import org.springframework.security.web.server.firewall.ServerExchangeRejectedHandler;
|
||||||
import org.springframework.security.web.server.firewall.ServerWebExchangeFirewall;
|
import org.springframework.security.web.server.firewall.ServerWebExchangeFirewall;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
@ -67,9 +68,11 @@ class WebFluxSecurityConfiguration {
|
||||||
|
|
||||||
@Bean(SPRING_SECURITY_WEBFILTERCHAINFILTER_BEAN_NAME)
|
@Bean(SPRING_SECURITY_WEBFILTERCHAINFILTER_BEAN_NAME)
|
||||||
@Order(WEB_FILTER_CHAIN_FILTER_ORDER)
|
@Order(WEB_FILTER_CHAIN_FILTER_ORDER)
|
||||||
WebFilterChainProxy springSecurityWebFilterChainFilter(ObjectProvider<ServerWebExchangeFirewall> firewall) {
|
WebFilterChainProxy springSecurityWebFilterChainFilter(ObjectProvider<ServerWebExchangeFirewall> firewall,
|
||||||
|
ObjectProvider<ServerExchangeRejectedHandler> rejectedHandler) {
|
||||||
WebFilterChainProxy webFilterChainProxy = new WebFilterChainProxy(getSecurityWebFilterChains());
|
WebFilterChainProxy webFilterChainProxy = new WebFilterChainProxy(getSecurityWebFilterChains());
|
||||||
firewall.ifUnique(webFilterChainProxy::setFirewall);
|
firewall.ifUnique(webFilterChainProxy::setFirewall);
|
||||||
|
rejectedHandler.ifUnique(webFilterChainProxy::setExchangeRejectedHandler);
|
||||||
return webFilterChainProxy;
|
return webFilterChainProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ import org.springframework.security.config.test.SpringTestContext;
|
||||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||||
import org.springframework.security.config.users.ReactiveAuthenticationTestConfiguration;
|
import org.springframework.security.config.users.ReactiveAuthenticationTestConfiguration;
|
||||||
import org.springframework.security.web.server.WebFilterChainProxy;
|
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.security.web.server.firewall.ServerWebExchangeFirewall;
|
||||||
import org.springframework.web.server.handler.DefaultWebFilterChain;
|
import org.springframework.web.server.handler.DefaultWebFilterChain;
|
||||||
|
|
||||||
|
@ -66,6 +68,18 @@ public class WebFluxSecurityConfigurationTests {
|
||||||
assertThat(exchange.getResponse().getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
|
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
|
@Test
|
||||||
void loadConfigWhenFirewallBeanThenCustomized() throws Exception {
|
void loadConfigWhenFirewallBeanThenCustomized() throws Exception {
|
||||||
this.spring.register(ServerHttpSecurityConfiguration.class, ReactiveAuthenticationTestConfiguration.class,
|
this.spring.register(ServerHttpSecurityConfiguration.class, ReactiveAuthenticationTestConfiguration.class,
|
||||||
|
@ -99,6 +113,18 @@ public class WebFluxSecurityConfigurationTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class CustomServerExchangeRejectedHandlerConfig {
|
||||||
|
|
||||||
|
static HttpStatus EXPECTED_STATUS = HttpStatus.I_AM_A_TEAPOT;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ServerExchangeRejectedHandler rejectedHandler() {
|
||||||
|
return new HttpStatusExchangeRejectedHandler(EXPECTED_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class SubclassConfig extends WebFluxSecurityConfiguration {
|
static class SubclassConfig extends WebFluxSecurityConfiguration {
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue