瀏覽代碼

Add Annotated Support for WebTestClient

Fixes gh-4457
Rob Winch 8 年之前
父節點
當前提交
544f39f826

+ 11 - 2
test/src/main/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurers.java

@@ -25,6 +25,7 @@ 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.security.test.context.TestSecurityContextHolder;
 import org.springframework.test.web.reactive.server.MockServerConfigurer;
 import org.springframework.test.web.reactive.server.WebTestClient;
 import org.springframework.test.web.reactive.server.WebTestClientConfigurer;
@@ -39,6 +40,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.Supplier;
 
 /**
  * Test utilities for working with Spring Security and
@@ -56,7 +58,10 @@ public class SecurityMockServerConfigurers {
 	public static MockServerConfigurer springSecurity() {
 		return new MockServerConfigurer() {
 			public void beforeServerCreated(WebHttpHandlerBuilder builder) {
-				builder.filters( filters -> filters.add(0, new MutatorFilter()));
+				builder.filters( filters -> {
+					filters.add(0, new MutatorFilter());
+					filters.add(0, new SetupMutatorFilter(createMutator( () -> TestSecurityContextHolder.getContext().getAuthentication())));
+				});
 			}
 		};
 	}
@@ -68,7 +73,7 @@ public class SecurityMockServerConfigurers {
 	 * @return the {@link WebTestClientConfigurer} to use
 	 */
 	public static <T extends WebTestClientConfigurer & MockServerConfigurer> T mockPrincipal(Principal principal) {
-		return (T) new MutatorWebTestClientConfigurer(m -> m.mutate().principal(Mono.just(principal)).build());
+		return (T) new MutatorWebTestClientConfigurer(createMutator(() -> principal));
 	}
 
 	/**
@@ -115,6 +120,10 @@ public class SecurityMockServerConfigurers {
 		return new UserExchangeMutator(username);
 	}
 
+	private static Function<ServerWebExchange, ServerWebExchange> createMutator(Supplier<Principal> principal) {
+		return m -> principal.get() == null ? m : m.mutate().principal(Mono.just(principal.get())).build();
+	}
+
 	/**
 	 * Updates the WebServerExchange using {@code {@link SecurityMockServerConfigurers#mockUser(UserDetails)}. Defaults to use a
 	 * password of "password" and granted authorities of "ROLE_USER".

+ 80 - 0
test/src/test/java/org/springframework/security/test/web/reactive/server/AbstractMockServerConfigurersTests.java

@@ -0,0 +1,80 @@
+/*
+ *
+ *  * 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.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+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.springSecurity;
+
+/**
+ * @author Rob Winch
+ * @since 5.0
+ */
+abstract class AbstractMockServerConfigurersTests {
+	protected PrincipalController controller = new PrincipalController();
+
+	protected User.UserBuilder userBuilder = User
+		.withUsername("user")
+		.password("password")
+		.roles("USER");
+
+	protected 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
+	protected 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;
+		}
+	}
+}

+ 118 - 0
test/src/test/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurersAnnotatedTests.java

@@ -0,0 +1,118 @@
+/*
+ *
+ *  * 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.junit.runner.RunWith;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.test.context.TestSecurityContextHolder;
+import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+import java.security.Principal;
+
+import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockPrincipal;
+import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity;
+
+/**
+ * @author Rob Winch
+ * @since 5.0
+ */
+@RunWith(SpringRunner.class)
+@SecurityTestExecutionListeners
+public class SecurityMockServerConfigurersAnnotatedTests extends AbstractMockServerConfigurersTests {
+
+	WebTestClient client = WebTestClient
+		.bindToController(controller)
+		.apply(springSecurity())
+		.configureClient()
+		.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
+		.build();
+
+	@Test
+	@WithMockUser
+	public void withMockUserWhenOnMethodThenSuccess() {
+		client
+			.get()
+			.exchange()
+			.expectStatus().isOk();
+
+		Authentication authentication = TestSecurityContextHolder.getContext().getAuthentication();
+		controller.assertPrincipalIsEqualTo(authentication);
+	}
+
+	@Test
+	@WithMockUser
+	public void withMockUserWhenGlobalMockPrincipalThenOverridesAnnotation() {
+		Principal principal = () -> "principal";
+		client = WebTestClient
+			.bindToController(controller)
+			.apply(springSecurity())
+			.apply(mockPrincipal(principal))
+			.configureClient()
+			.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
+			.build();
+
+		client
+			.get()
+			.exchange()
+			.expectStatus().isOk();
+
+		controller.assertPrincipalIsEqualTo(principal);
+	}
+
+	@Test
+	@WithMockUser
+	public void withMockUserWhenMutateWithMockPrincipalThenOverridesAnnotation() {
+		Principal principal = () -> "principal";
+		client
+			.mutateWith(mockPrincipal(principal))
+			.get()
+			.exchange()
+			.expectStatus().isOk();
+
+		controller.assertPrincipalIsEqualTo(principal);
+	}
+
+	@Test
+	@WithMockUser
+	public void withMockUserWhenMutateWithMockPrincipalAndNoMutateThenOverridesAnnotationAndUsesAnnotation() {
+		Principal principal = () -> "principal";
+		client
+			.mutateWith(mockPrincipal(principal))
+			.get()
+			.exchange()
+			.expectStatus().isOk();
+
+		controller.assertPrincipalIsEqualTo(principal);
+
+
+		client
+			.get()
+			.exchange()
+			.expectStatus().isOk();
+
+		principal = controller.removePrincipal();
+		assertPrincipalCreatedFromUserDetails(principal, userBuilder.build());
+	}
+}

+ 90 - 0
test/src/test/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurersClassAnnotatedTests.java

@@ -0,0 +1,90 @@
+/*
+ *
+ *  * 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.junit.runner.RunWith;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.test.context.TestSecurityContextHolder;
+import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+import java.security.Principal;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockUser;
+import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity;
+
+/**
+ * @author Rob Winch
+ * @since 5.0
+ */
+@WithMockUser
+@RunWith(SpringRunner.class)
+@SecurityTestExecutionListeners
+public class SecurityMockServerConfigurersClassAnnotatedTests extends AbstractMockServerConfigurersTests {
+	WebTestClient client = WebTestClient
+		.bindToController(controller)
+		.apply(springSecurity())
+		.configureClient()
+		.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
+		.build();
+
+	@Test
+	public void wheMockUserWhenClassAnnotatedThenSuccess() {
+		client
+			.get()
+			.exchange()
+			.expectStatus().isOk()
+			.expectBody(String.class).consumeWith( response -> assertThat(response.getResponseBody()).contains("\"username\":\"user\""));
+
+		Authentication authentication = TestSecurityContextHolder.getContext().getAuthentication();
+		controller.assertPrincipalIsEqualTo(authentication);
+	}
+
+	@Test
+	@WithMockUser("method-user")
+	public void withMockUserWhenClassAndMethodAnnotationThenMethodOverrides() {
+		client
+			.get()
+			.exchange()
+			.expectStatus().isOk()
+			.expectBody(String.class).consumeWith( response -> assertThat(response.getResponseBody()).contains("\"username\":\"method-user\""));
+
+		Authentication authentication = TestSecurityContextHolder.getContext().getAuthentication();
+		controller.assertPrincipalIsEqualTo(authentication);
+	}
+
+	@Test
+	public void withMockUserWhenMutateWithThenMustateWithOverrides() {
+		client
+			.mutateWith(mockUser("mutateWith-mockUser"))
+			.get()
+			.exchange()
+			.expectStatus().isOk()
+			.expectBody(String.class).consumeWith( response -> assertThat(response.getResponseBody()).contains("\"username\":\"mutateWith-mockUser\""));
+
+		Principal principal = controller.removePrincipal();
+		assertPrincipalCreatedFromUserDetails(principal, userBuilder.username("mutateWith-mockUser").build());
+	}
+}

+ 1 - 46
test/src/test/java/org/springframework/security/test/web/reactive/server/SecurityMockServerConfigurersTests.java

@@ -22,25 +22,19 @@ 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();
-
+public class SecurityMockServerConfigurersTests extends AbstractMockServerConfigurersTests {
 	WebTestClient client = WebTestClient
 		.bindToController(controller)
 		.apply(springSecurity())
@@ -48,11 +42,6 @@ public class SecurityMockServerConfigurersTests {
 		.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";
@@ -197,38 +186,4 @@ public class SecurityMockServerConfigurersTests {
 
 		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;
-		}
-	}
 }