diff --git a/web/src/main/java/org/springframework/security/web/server/context/ReactorContextWebFilter.java b/web/src/main/java/org/springframework/security/web/server/context/ReactorContextWebFilter.java index 1a5f7fe3ff..7db3bdf4b2 100644 --- a/web/src/main/java/org/springframework/security/web/server/context/ReactorContextWebFilter.java +++ b/web/src/main/java/org/springframework/security/web/server/context/ReactorContextWebFilter.java @@ -22,6 +22,7 @@ import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; +import reactor.util.context.Context; /** * @author Rob Winch @@ -39,8 +40,12 @@ public class ReactorContextWebFilter implements WebFilter { public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { return chain.filter(exchange) .subscriberContext(c -> c.hasKey(SecurityContext.class) ? c : - Mono.defer(() -> this.repository.load(exchange)) - .as(ReactiveSecurityContextHolder::withSecurityContext) + withSecurityContext(c, exchange) ); } + + private Context withSecurityContext(Context mainContext, ServerWebExchange exchange) { + return mainContext.putAll(Mono.defer(() -> this.repository.load(exchange)) + .as(ReactiveSecurityContextHolder::withSecurityContext)); + } } diff --git a/web/src/test/java/org/springframework/security/web/server/context/ReactorContextWebFilterTests.java b/web/src/test/java/org/springframework/security/web/server/context/ReactorContextWebFilterTests.java index f42499b9a8..1e46b10057 100644 --- a/web/src/test/java/org/springframework/security/web/server/context/ReactorContextWebFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/context/ReactorContextWebFilterTests.java @@ -22,12 +22,19 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.security.test.web.reactive.server.WebTestHandler; +import org.springframework.test.context.TestPropertySource; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import org.springframework.web.server.handler.DefaultWebFilterChain; import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; +import reactor.util.context.Context; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -98,4 +105,21 @@ public class ReactorContextWebFilterTests { verify(this.repository).load(any()); } + + @Test + // gh-4962 + public void filterWhenMainContextThenDoesNotOverride() { + String contextKey = "main"; + WebFilter mainContextWebFilter = (e, c) -> c + .filter(e) + .subscriberContext(Context.of(contextKey, true)); + + WebFilterChain chain = new DefaultWebFilterChain(e -> Mono.empty(), mainContextWebFilter, this.filter); + Mono filter = chain.filter(MockServerWebExchange.from(this.exchange.build())); + StepVerifier.create(filter) + .expectAccessibleContext() + .hasKey(contextKey) + .then() + .verifyComplete(); + } }