瀏覽代碼

Merge branch '6.3.x'

Closes gh-16063
Rob Winch 9 月之前
父節點
當前提交
5a95952c95

+ 4 - 1
config/src/main/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.java

@@ -34,6 +34,7 @@ import org.springframework.security.web.server.SecurityWebFilterChain;
 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;
@@ -81,11 +82,13 @@ class WebFluxSecurityConfiguration {
 
 	@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;
 	}
 

+ 28 - 0
config/src/test/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfigurationTests.java

@@ -32,6 +32,8 @@ import org.springframework.security.config.test.SpringTestContext;
 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;
 
@@ -70,6 +72,20 @@ public class WebFluxSecurityConfigurationTests {
 		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
@@ -107,6 +123,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
 	static class SubclassConfig extends WebFluxSecurityConfiguration {
 

+ 32 - 0
docs/modules/ROOT/pages/reactive/exploits/firewall.adoc

@@ -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.