Parcourir la source

ServerWebExchangeReactorContextWebFilter

Fixes: gh-5779
Rob Winch il y a 7 ans
Parent
commit
07b6699fd9

+ 13 - 0
config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java

@@ -133,6 +133,7 @@ import org.springframework.web.cors.reactive.DefaultCorsProcessor;
 import org.springframework.web.server.ServerWebExchange;
 import org.springframework.web.server.WebFilter;
 import org.springframework.web.server.WebFilterChain;
+import reactor.util.context.Context;
 
 import static org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry;
 import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.match;
@@ -1098,6 +1099,7 @@ public class ServerHttpSecurity {
 			}
 			sortedWebFilters.add(f);
 		});
+		sortedWebFilters.add(0, new ServerWebExchangeReactorContextWebFilter());
 		return new MatcherSecurityWebFilterChain(getSecurityMatcher(), sortedWebFilters);
 	}
 
@@ -2191,4 +2193,15 @@ public class ServerHttpSecurity {
 				+ '}';
 		}
 	}
+
+	/**
+	 * Workaround https://jira.spring.io/projects/SPR/issues/SPR-17213
+	 */
+	static class ServerWebExchangeReactorContextWebFilter implements WebFilter {
+		@Override
+		public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
+			return chain.filter(exchange)
+					.subscriberContext(Context.of(ServerWebExchange.class, exchange));
+		}
+	}
 }

+ 28 - 0
config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java

@@ -27,12 +27,16 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.config.annotation.web.reactive.ServerHttpSecurityConfigurationBuilder;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
+import org.springframework.security.web.server.SecurityWebFilterChain;
 import org.springframework.security.web.server.WebFilterChainProxy;
 import org.springframework.security.web.server.context.ServerSecurityContextRepository;
 import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository;
 import org.springframework.test.web.reactive.server.EntityExchangeResult;
 import org.springframework.test.web.reactive.server.FluxExchangeResult;
 import org.springframework.test.web.reactive.server.WebTestClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
 import reactor.test.publisher.TestPublisher;
 
@@ -117,9 +121,33 @@ public class ServerHttpSecurityTests {
 			.expectBody().isEmpty();
 	}
 
+	@Test
+	public void buildWhenServerWebExchangeFromContextThenFound() {
+		SecurityWebFilterChain filter = this.http.build();
+
+		WebTestClient client = WebTestClient.bindToController(new SubscriberContextController())
+				.webFilter(new WebFilterChainProxy(filter))
+				.build();
+
+		client.get().uri("/foo/bar")
+				.exchange()
+				.expectBody(String.class).isEqualTo("/foo/bar");
+	}
+
 	private WebTestClient buildClient() {
 		WebFilterChainProxy springSecurityFilterChain = new WebFilterChainProxy(
 			this.http.build());
 		return WebTestClientBuilder.bindToWebFilters(springSecurityFilterChain).build();
 	}
+
+	@RestController
+	private static class SubscriberContextController {
+		@GetMapping("/**")
+		Mono<String> pathWithinApplicationFromContext() {
+			return Mono.subscriberContext()
+				.filter(c -> c.hasKey(ServerWebExchange.class))
+				.map(c -> c.get(ServerWebExchange.class))
+				.map(e -> e.getRequest().getPath().pathWithinApplication().value());
+		}
+	}
 }