parent
67f80dfadc
commit
03f2d654ad
|
@ -25,6 +25,7 @@ import org.springframework.context.ApplicationContext;
|
|||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers;
|
||||
import org.springframework.security.web.server.header.ContentTypeOptionsHttpHeadersWriter;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
@ -36,7 +37,7 @@ import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
|
|||
import java.nio.charset.Charset;
|
||||
import java.util.Base64;
|
||||
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityExchangeMutators.withUser;
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity;
|
||||
import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;
|
||||
|
||||
/**
|
||||
|
@ -172,26 +173,29 @@ public class HelloWebfluxApplicationTests {
|
|||
.expectStatus().isOk();
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void mockSupport() throws Exception {
|
||||
// ExchangeMutatorWebFilter exchangeMutator = new ExchangeMutatorWebFilter();
|
||||
// WebTestClient mockRest = WebTestClient.bindToApplicationContext(this.context).webFilter(exchangeMutator).build();
|
||||
//
|
||||
// mockRest
|
||||
// .mutate()
|
||||
// .filter(exchangeMutator.perClient(withUser()))
|
||||
// .build()
|
||||
// .get()
|
||||
// .uri("/principal")
|
||||
// .exchange()
|
||||
// .expectStatus().isOk();
|
||||
//
|
||||
// mockRest
|
||||
// .get()
|
||||
// .uri("/principal")
|
||||
// .exchange()
|
||||
// .expectStatus().isUnauthorized();
|
||||
// }
|
||||
@Test
|
||||
public void mockSupport() throws Exception {
|
||||
WebTestClient mockRest = WebTestClient
|
||||
.bindToApplicationContext(this.context)
|
||||
.apply(springSecurity())
|
||||
.build();
|
||||
|
||||
mockRest
|
||||
.mutate()
|
||||
.apply(SecurityMockServerConfigurers.mockUser())
|
||||
.build()
|
||||
.get()
|
||||
.uri("/principal")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).isEqualTo("{\"username\":\"user\"}");
|
||||
|
||||
mockRest
|
||||
.get()
|
||||
.uri("/principal")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void me() throws Exception {
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.junit.runner.RunWith;
|
|||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.security.web.server.header.ContentTypeOptionsHttpHeadersWriter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
@ -34,7 +33,6 @@ import java.nio.charset.Charset;
|
|||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityExchangeMutators.withUser;
|
||||
import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers;
|
||||
import org.springframework.security.web.server.WebFilterChainFilter;
|
||||
import org.springframework.security.web.server.header.ContentTypeOptionsHttpHeadersWriter;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
@ -37,7 +38,7 @@ import org.springframework.web.reactive.function.server.RouterFunction;
|
|||
import java.nio.charset.Charset;
|
||||
import java.util.Base64;
|
||||
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityExchangeMutators.withUser;
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity;
|
||||
import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;
|
||||
|
||||
/**
|
||||
|
@ -178,26 +179,28 @@ public class HelloWebfluxFnApplicationTests {
|
|||
.expectStatus().isOk();
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void mockSupport() throws Exception {
|
||||
// ExchangeMutatorWebFilter exchangeMutator = new ExchangeMutatorWebFilter();
|
||||
// WebTestClient mockRest = WebTestClient.bindToRouterFunction(this.routerFunction).webFilter(exchangeMutator, springSecurityFilterChain).build();
|
||||
//
|
||||
// mockRest
|
||||
// .mutate()
|
||||
// .filter(exchangeMutator.perClient(withUser()))
|
||||
// .build()
|
||||
// .get()
|
||||
// .uri("/principal")
|
||||
// .exchange()
|
||||
// .expectStatus().isOk();
|
||||
//
|
||||
// mockRest
|
||||
// .get()
|
||||
// .uri("/principal")
|
||||
// .exchange()
|
||||
// .expectStatus().isUnauthorized();
|
||||
// }
|
||||
@Test
|
||||
public void mockSupport() throws Exception {
|
||||
WebTestClient mockRest = WebTestClient.bindToRouterFunction(this.routerFunction)
|
||||
.webFilter(springSecurityFilterChain)
|
||||
.apply(springSecurity())
|
||||
.build();
|
||||
|
||||
mockRest
|
||||
.mutate()
|
||||
.apply(SecurityMockServerConfigurers.mockUser())
|
||||
.build()
|
||||
.get()
|
||||
.uri("/principal")
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
mockRest
|
||||
.get()
|
||||
.uri("/principal")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void principal() throws Exception {
|
||||
|
|
|
@ -8,9 +8,12 @@ dependencies {
|
|||
|
||||
optional project(':spring-security-config')
|
||||
optional 'io.projectreactor:reactor-core'
|
||||
optional 'org.springframework:spring-webflux'
|
||||
|
||||
provided 'javax.servlet:javax.servlet-api'
|
||||
|
||||
testCompile 'com.fasterxml.jackson.core:jackson-databind'
|
||||
testCompile 'org.skyscreamer:jsonassert'
|
||||
testCompile 'org.springframework:spring-webmvc'
|
||||
testCompile 'org.springframework:spring-tx'
|
||||
testCompile powerMockDependencies
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.test.web.reactive.server;
|
||||
|
||||
import org.assertj.core.api.AssertionsForInterfaceTypes;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
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.web.server.ServerWebExchange;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityExchangeMutators.withAuthentication;
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityExchangeMutators.withPrincipal;
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityExchangeMutators.withUser;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SecurityExchangeMutatorsTests {
|
||||
@Mock
|
||||
Principal principal;
|
||||
@Mock
|
||||
Authentication authentication;
|
||||
|
||||
ServerWebExchange exchange = MockServerHttpRequest.get("/").toExchange();
|
||||
|
||||
User.UserBuilder userBuilder = User.withUsername("user").password("password").roles("USER");
|
||||
|
||||
@Test
|
||||
public void withPrincipalWhenHappyPathThenSuccess() {
|
||||
assertThat(withPrincipal(principal).apply(exchange).getPrincipal().block()).isEqualTo(principal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withAuthenticationWhenHappyPathThenSuccess() {
|
||||
assertThat(withAuthentication(authentication).apply(exchange).getPrincipal().block()).isEqualTo(authentication);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withUserWhenDefaultsThenSuccess() {
|
||||
Principal principal = withUser().apply(exchange).getPrincipal().block();
|
||||
|
||||
assertPrincipalCreatedFromUserDetails(principal, userBuilder.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withUserStringWhenHappyPathThenSuccess() {
|
||||
Principal principal = withUser(userBuilder.build().getUsername() ).apply(exchange).getPrincipal().block();
|
||||
|
||||
assertPrincipalCreatedFromUserDetails(principal, userBuilder.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withUserStringWhenCustomThenSuccess() {
|
||||
SecurityExchangeMutators.UserExchangeMutator withUser = withUser("admin").password("secret").roles("USER", "ADMIN");
|
||||
userBuilder = User.withUsername("admin").password("secret").roles("USER", "ADMIN");
|
||||
|
||||
Principal principal = withUser.apply(exchange).getPrincipal().block();
|
||||
|
||||
assertPrincipalCreatedFromUserDetails(principal, userBuilder.build() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withUserUserDetailsWhenHappyPathThenSuccess() {
|
||||
Principal principal = withUser(userBuilder.build()).apply(exchange).getPrincipal().block();
|
||||
|
||||
assertPrincipalCreatedFromUserDetails(principal, userBuilder.build());
|
||||
}
|
||||
|
||||
private void assertPrincipalCreatedFromUserDetails(Principal principal, UserDetails originalUserDetails) {
|
||||
assertThat(principal).isInstanceOf(UsernamePasswordAuthenticationToken.class);
|
||||
|
||||
UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) principal;
|
||||
assertThat(authentication.getCredentials()).isEqualTo(originalUserDetails.getPassword());
|
||||
assertThat(authentication.getAuthorities()).containsOnlyElementsOf(originalUserDetails.getAuthorities());
|
||||
|
||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||
assertThat(userDetails.getPassword()).isEqualTo(authentication.getCredentials());
|
||||
assertThat(authentication.getAuthorities()).containsOnlyElementsOf(userDetails.getAuthorities());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.test.web.reactive.server;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.*;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class SecurityMockServerConfigurersTests {
|
||||
PrincipalController controller = new PrincipalController();
|
||||
|
||||
WebTestClient client = WebTestClient
|
||||
.bindToController(controller)
|
||||
.apply(springSecurity())
|
||||
.configureClient()
|
||||
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.build();
|
||||
|
||||
User.UserBuilder userBuilder = User
|
||||
.withUsername("user")
|
||||
.password("password")
|
||||
.roles("USER");
|
||||
|
||||
@Test
|
||||
public void mockPrincipalWhenLocalThenSuccess() {
|
||||
Principal principal = () -> "principal";
|
||||
client
|
||||
.mutate()
|
||||
.apply(mockPrincipal(principal))
|
||||
.build()
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
controller.assertPrincipalIsEqualTo(principal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockPrincipalWhenGlobalTheWorks() {
|
||||
Principal principal = () -> "principal";
|
||||
client = WebTestClient
|
||||
.bindToController(controller)
|
||||
.apply(springSecurity())
|
||||
.apply(mockPrincipal(principal))
|
||||
.configureClient()
|
||||
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.build();
|
||||
|
||||
client
|
||||
.mutate()
|
||||
.build()
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
controller.assertPrincipalIsEqualTo(principal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockPrincipalWhenMultipleInvocationsThenLastInvocationWins() {
|
||||
Principal principal = () -> "principal";
|
||||
client
|
||||
.mutate()
|
||||
.apply(mockPrincipal(() -> "will be overridden"))
|
||||
.apply(mockPrincipal(principal))
|
||||
.build()
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
controller.assertPrincipalIsEqualTo(principal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockAuthenticationWhenLocalThenSuccess() {
|
||||
TestingAuthenticationToken authentication = new TestingAuthenticationToken("authentication", "secret", "ROLE_USER");
|
||||
client
|
||||
.mutate()
|
||||
.apply(mockAuthentication(authentication))
|
||||
.build()
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
controller.assertPrincipalIsEqualTo(authentication);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockAuthenticationWhenGlobalThenSuccess() {
|
||||
TestingAuthenticationToken authentication = new TestingAuthenticationToken("authentication", "secret", "ROLE_USER");
|
||||
client = WebTestClient
|
||||
.bindToController(controller)
|
||||
.apply(springSecurity())
|
||||
.apply(mockAuthentication(authentication))
|
||||
.configureClient()
|
||||
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.build();
|
||||
client
|
||||
.mutate()
|
||||
.build()
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
controller.assertPrincipalIsEqualTo(authentication);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockUserWhenDefaultsThenSuccess() {
|
||||
client
|
||||
.mutate()
|
||||
.apply(mockUser())
|
||||
.build()
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
Principal actual = controller.removePrincipal();
|
||||
|
||||
assertPrincipalCreatedFromUserDetails(actual, userBuilder.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockUserWhenGlobalThenSuccess() {
|
||||
client = WebTestClient
|
||||
.bindToController(controller)
|
||||
.apply(springSecurity())
|
||||
.apply(mockUser())
|
||||
.configureClient()
|
||||
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.build();
|
||||
client
|
||||
.mutate()
|
||||
.build()
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
Principal actual = controller.removePrincipal();
|
||||
|
||||
assertPrincipalCreatedFromUserDetails(actual, userBuilder.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockUserStringWhenLocalThenSuccess() {
|
||||
client
|
||||
.mutate()
|
||||
.apply(mockUser(userBuilder.build().getUsername()))
|
||||
.build()
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
Principal actual = controller.removePrincipal();
|
||||
|
||||
assertPrincipalCreatedFromUserDetails(actual, userBuilder.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockUserStringWhenCustomThenSuccess() {
|
||||
this.userBuilder = User.withUsername("admin").password("secret").roles("USER", "ADMIN");
|
||||
client
|
||||
.mutate()
|
||||
.apply(mockUser("admin").password("secret").roles("USER", "ADMIN"))
|
||||
.build()
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
Principal actual = controller.removePrincipal();
|
||||
|
||||
assertPrincipalCreatedFromUserDetails(actual, userBuilder.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockUserUserDetailsLocalThenSuccess() {
|
||||
UserDetails userDetails = this.userBuilder.build();
|
||||
client
|
||||
.mutate()
|
||||
.apply(mockUser(userDetails))
|
||||
.build()
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
Principal actual = controller.removePrincipal();
|
||||
|
||||
assertPrincipalCreatedFromUserDetails(actual, userBuilder.build());
|
||||
}
|
||||
|
||||
private void assertPrincipalCreatedFromUserDetails(Principal principal, UserDetails originalUserDetails) {
|
||||
assertThat(principal).isInstanceOf(UsernamePasswordAuthenticationToken.class);
|
||||
|
||||
UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) principal;
|
||||
assertThat(authentication.getCredentials()).isEqualTo(originalUserDetails.getPassword());
|
||||
assertThat(authentication.getAuthorities()).containsOnlyElementsOf(originalUserDetails.getAuthorities());
|
||||
|
||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||
assertThat(userDetails.getPassword()).isEqualTo(authentication.getCredentials());
|
||||
assertThat(authentication.getAuthorities()).containsOnlyElementsOf(userDetails.getAuthorities());
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class PrincipalController {
|
||||
Principal principal;
|
||||
|
||||
@RequestMapping("/**")
|
||||
public Principal get(Principal principal) {
|
||||
this.principal = principal;
|
||||
return principal;
|
||||
}
|
||||
|
||||
public Principal removePrincipal() {
|
||||
Principal result = this.principal;
|
||||
this.principal = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void assertPrincipalIsEqualTo(Principal expected) {
|
||||
assertThat(this.principal).isEqualTo(expected);
|
||||
this.principal = null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue