|
@@ -18,46 +18,67 @@
|
|
|
|
|
|
package org.springframework.security.test.web.reactive.server;
|
|
|
|
|
|
+import org.springframework.http.client.reactive.ClientHttpConnector;
|
|
|
+import org.springframework.lang.Nullable;
|
|
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
|
import org.springframework.security.core.Authentication;
|
|
|
import org.springframework.security.core.GrantedAuthority;
|
|
|
import org.springframework.security.core.userdetails.User;
|
|
|
import org.springframework.security.core.userdetails.UserDetails;
|
|
|
+import org.springframework.test.web.reactive.server.MockServerConfigurer;
|
|
|
+import org.springframework.test.web.reactive.server.WebTestClient;
|
|
|
+import org.springframework.test.web.reactive.server.WebTestClientConfigurer;
|
|
|
import org.springframework.web.server.ServerWebExchange;
|
|
|
+import org.springframework.web.server.WebFilter;
|
|
|
+import org.springframework.web.server.WebFilterChain;
|
|
|
+import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
|
|
import reactor.core.publisher.Mono;
|
|
|
|
|
|
import java.security.Principal;
|
|
|
import java.util.Collection;
|
|
|
+import java.util.List;
|
|
|
+import java.util.function.Consumer;
|
|
|
import java.util.function.Function;
|
|
|
-import java.util.function.UnaryOperator;
|
|
|
|
|
|
/**
|
|
|
* Test utilities for working with Spring Security and
|
|
|
- * {{@link org.springframework.test.web.reactive.server.WebTestClient}} using
|
|
|
- * {{{@link org.springframework.test.web.reactive.server.ExchangeMutatorWebFilter}}}.
|
|
|
+ * {{@link org.springframework.test.web.reactive.server.WebTestClient.Builder#apply(WebTestClientConfigurer)}}.
|
|
|
*
|
|
|
* @author Rob Winch
|
|
|
* @since 5.0
|
|
|
*/
|
|
|
-public class SecurityExchangeMutators {
|
|
|
+public class SecurityMockServerConfigurers {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sets up Spring Security's {@link WebTestClient} test support
|
|
|
+ * @return the MockServerConfigurer to use
|
|
|
+ */
|
|
|
+ public static MockServerConfigurer springSecurity() {
|
|
|
+ return new MockServerConfigurer() {
|
|
|
+ public void beforeServerCreated(WebHttpHandlerBuilder builder) {
|
|
|
+ builder.filters( filters -> filters.add(0, new MutatorFilter()));
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Updates the ServerWebExchange to use the provided Principal
|
|
|
*
|
|
|
* @param principal the principal to use.
|
|
|
- * @return the {@link Function<ServerWebExchange, ServerWebExchange>}} to use
|
|
|
+ * @return the {@link WebTestClientConfigurer} to use
|
|
|
*/
|
|
|
- public static Function<ServerWebExchange, ServerWebExchange> withPrincipal(Principal principal) {
|
|
|
- return m -> m.mutate().principal(Mono.just(principal)).build();
|
|
|
+ public static <T extends WebTestClientConfigurer & MockServerConfigurer> T mockPrincipal(Principal principal) {
|
|
|
+ return (T) new MutatorWebTestClientConfigurer(m -> m.mutate().principal(Mono.just(principal)).build());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Updates the ServerWebExchange to use the provided Authentication as the Principal
|
|
|
*
|
|
|
* @param authentication the Authentication to use.
|
|
|
- * @return the {@link Function<ServerWebExchange, ServerWebExchange>}} to use
|
|
|
+ * @return the {@link WebTestClientConfigurer}} to use
|
|
|
*/
|
|
|
- public static Function<ServerWebExchange, ServerWebExchange> withAuthentication(Authentication authentication) {
|
|
|
- return withPrincipal(authentication);
|
|
|
+ public static <T extends WebTestClientConfigurer & MockServerConfigurer> T mockAuthentication(Authentication authentication) {
|
|
|
+ return mockPrincipal(authentication);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -65,10 +86,10 @@ public class SecurityExchangeMutators {
|
|
|
* the Principal
|
|
|
*
|
|
|
* @param userDetails the UserDetails to use.
|
|
|
- * @return the {@link Function<ServerWebExchange, ServerWebExchange>}} to use
|
|
|
+ * @return the {@link WebTestClientConfigurer} to use
|
|
|
*/
|
|
|
- public static Function<ServerWebExchange, ServerWebExchange> withUser(UserDetails userDetails) {
|
|
|
- return withAuthentication(new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities()));
|
|
|
+ public static <T extends WebTestClientConfigurer & MockServerConfigurer> T mockUser(UserDetails userDetails) {
|
|
|
+ return mockAuthentication(new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities()));
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -76,10 +97,10 @@ public class SecurityExchangeMutators {
|
|
|
* the Principal. This uses a default username of "user", password of "password", and granted authorities of
|
|
|
* "ROLE_USER".
|
|
|
*
|
|
|
- * @return the {@link Function<ServerWebExchange, ServerWebExchange>}} to use
|
|
|
+ * @return the {@link UserExchangeMutator} to use
|
|
|
*/
|
|
|
- public static UserExchangeMutator withUser() {
|
|
|
- return withUser("user");
|
|
|
+ public static UserExchangeMutator mockUser() {
|
|
|
+ return mockUser("user");
|
|
|
}
|
|
|
|
|
|
|
|
@@ -88,17 +109,17 @@ public class SecurityExchangeMutators {
|
|
|
* the Principal. This uses a default password of "password" and granted authorities of
|
|
|
* "ROLE_USER".
|
|
|
*
|
|
|
- * @return the {@link Function<ServerWebExchange, ServerWebExchange>}} to use
|
|
|
+ * @return the {@link WebTestClientConfigurer} to use
|
|
|
*/
|
|
|
- public static UserExchangeMutator withUser(String username) {
|
|
|
+ public static UserExchangeMutator mockUser(String username) {
|
|
|
return new UserExchangeMutator(username);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Updates the WebServerExchange using {@code SecurityExchangeMutators#withUser(UserDetails)}. Defaults to use a
|
|
|
+ * Updates the WebServerExchange using {@code {@link SecurityMockServerConfigurers#mockUser(UserDetails)}. Defaults to use a
|
|
|
* password of "password" and granted authorities of "ROLE_USER".
|
|
|
*/
|
|
|
- public static class UserExchangeMutator implements Function<ServerWebExchange, ServerWebExchange> {
|
|
|
+ public static class UserExchangeMutator implements WebTestClientConfigurer, MockServerConfigurer {
|
|
|
private final User.UserBuilder userBuilder;
|
|
|
|
|
|
private UserExchangeMutator(String username) {
|
|
@@ -182,8 +203,73 @@ public class SecurityExchangeMutators {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public ServerWebExchange apply(ServerWebExchange serverWebExchange) {
|
|
|
- return withUser(userBuilder.build()).apply(serverWebExchange);
|
|
|
+ public void beforeServerCreated(WebHttpHandlerBuilder builder) {
|
|
|
+ configurer().beforeServerCreated(builder);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void afterConfigureAdded(WebTestClient.MockServerSpec<?> serverSpec) {
|
|
|
+ configurer().afterConfigureAdded(serverSpec);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void afterConfigurerAdded(WebTestClient.Builder builder, @Nullable WebHttpHandlerBuilder webHttpHandlerBuilder, @Nullable ClientHttpConnector clientHttpConnector) {
|
|
|
+ configurer().afterConfigurerAdded(builder, webHttpHandlerBuilder, clientHttpConnector);
|
|
|
+ }
|
|
|
+
|
|
|
+ private <T extends WebTestClientConfigurer & MockServerConfigurer> T configurer() {
|
|
|
+ return mockUser(userBuilder.build());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class MutatorWebTestClientConfigurer implements WebTestClientConfigurer, MockServerConfigurer {
|
|
|
+ private final Function<ServerWebExchange, ServerWebExchange> mutator;
|
|
|
+
|
|
|
+ private MutatorWebTestClientConfigurer(Function<ServerWebExchange, ServerWebExchange> mutator) {
|
|
|
+ this.mutator = mutator;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void beforeServerCreated(WebHttpHandlerBuilder builder) {
|
|
|
+ builder.filters(addSetupMutatorFilter());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void afterConfigurerAdded(WebTestClient.Builder builder, @Nullable WebHttpHandlerBuilder webHttpHandlerBuilder, @Nullable ClientHttpConnector clientHttpConnector) {
|
|
|
+ webHttpHandlerBuilder.filters(addSetupMutatorFilter());
|
|
|
+ }
|
|
|
+
|
|
|
+ private Consumer<List<WebFilter>> addSetupMutatorFilter() {
|
|
|
+ return filters -> filters.add(0, new SetupMutatorFilter(mutator));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class SetupMutatorFilter implements WebFilter {
|
|
|
+ private final Function<ServerWebExchange, ServerWebExchange> mutator;
|
|
|
+
|
|
|
+ private SetupMutatorFilter(Function<ServerWebExchange, ServerWebExchange> mutator) {
|
|
|
+ this.mutator = mutator;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain webFilterChain) {
|
|
|
+ exchange.getAttributes().computeIfAbsent(MutatorFilter.ATTRIBUTE_NAME, key -> mutator);
|
|
|
+ return webFilterChain.filter(exchange);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class MutatorFilter implements WebFilter {
|
|
|
+
|
|
|
+ public static final String ATTRIBUTE_NAME = "mutator";
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain webFilterChain) {
|
|
|
+ Function<ServerWebExchange, ServerWebExchange> mutator = exchange.getAttribute(ATTRIBUTE_NAME);
|
|
|
+ if(mutator != null) {
|
|
|
+ exchange.getAttributes().remove(ATTRIBUTE_NAME);
|
|
|
+ exchange = mutator.apply(exchange);
|
|
|
+ }
|
|
|
+ return webFilterChain.filter(exchange);
|
|
|
}
|
|
|
}
|
|
|
}
|