Commit ab6bdc7a authored by Madhura Bhave's avatar Madhura Bhave

Apply springSecurity configurer to WebTestClient

Also, @WebFluxTest now adds any ServerHttpSecurity beans
to the context.

Closes gh-13632
parent 424dfc39
......@@ -29,6 +29,7 @@ import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.stereotype.Controller;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.reactive.config.WebFluxConfigurer;
......@@ -43,6 +44,9 @@ class WebFluxTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
private static final Set<Class<?>> DEFAULT_INCLUDES;
private static final String[] OPTIONAL_INCLUDES = {
"org.springframework.security.config.web.server.ServerHttpSecurity" };
static {
Set<Class<?>> includes = new LinkedHashSet<>();
includes.add(ControllerAdvice.class);
......@@ -51,6 +55,13 @@ class WebFluxTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
includes.add(Converter.class);
includes.add(GenericConverter.class);
includes.add(WebExceptionHandler.class);
for (String optionalInclude : OPTIONAL_INCLUDES) {
try {
includes.add(ClassUtils.forName(optionalInclude, null));
}
catch (Exception ex) {
}
}
DEFAULT_INCLUDES = Collections.unmodifiableSet(includes);
}
......
......@@ -33,6 +33,8 @@ import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.web.reactive.server.MockServerConfigurer;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.WebHandler;
......@@ -47,6 +49,7 @@ import org.springframework.web.server.WebHandler;
@Configuration
@ConditionalOnClass({ WebClient.class, WebTestClient.class })
@AutoConfigureAfter({ CodecsAutoConfiguration.class, WebFluxAutoConfiguration.class })
@Import(WebTestClientSecurityConfiguration.class)
@EnableConfigurationProperties
public class WebTestClientAutoConfiguration {
......@@ -54,9 +57,14 @@ public class WebTestClientAutoConfiguration {
@ConditionalOnMissingBean
@ConditionalOnBean(WebHandler.class)
public WebTestClient webTestClient(ApplicationContext applicationContext,
List<WebTestClientBuilderCustomizer> customizers) {
WebTestClient.Builder builder = WebTestClient
.bindToApplicationContext(applicationContext).configureClient();
List<WebTestClientBuilderCustomizer> customizers,
List<MockServerConfigurer> configurers) {
WebTestClient.MockServerSpec<?> mockServerSpec = WebTestClient
.bindToApplicationContext(applicationContext);
for (MockServerConfigurer configurer : configurers) {
mockServerSpec.apply(configurer);
}
WebTestClient.Builder builder = mockServerSpec.configureClient();
for (WebTestClientBuilderCustomizer customizer : customizers) {
customizer.customize(builder);
}
......
/*
* Copyright 2012-2018 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.boot.test.autoconfigure.web.reactive;
/** Configuration for Spring Security's {@link org.springframework.test.web.reactive.server.WebTestClient} integration.
*
* @author Madhura Bhave
*/
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers;
import org.springframework.test.web.reactive.server.MockServerConfigurer;
@Configuration
@ConditionalOnClass(SecurityMockServerConfigurers.class)
class WebTestClientSecurityConfiguration {
@Bean
public MockServerConfigurer get() {
return SecurityMockServerConfigurers.springSecurity();
}
}
......@@ -78,6 +78,8 @@ org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration
# AutoConfigureWebClient auto-configuration imports
org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient=\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientAutoConfiguration
# AutoConfigureWebFlux auto-configuration imports
......
......@@ -30,6 +30,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
import org.springframework.restdocs.templates.TemplateFormats;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.FileSystemUtils;
......@@ -46,6 +47,7 @@ import static org.springframework.restdocs.webtestclient.WebTestClientRestDocume
*/
@RunWith(SpringRunner.class)
@WebFluxTest
@WithMockUser
@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.example.com", uriPort = 443)
public class WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests {
......@@ -59,8 +61,8 @@ public class WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrat
@Test
public void defaultSnippetsAreWritten() throws Exception {
this.webTestClient.get().uri("/").exchange().expectBody()
.consumeWith(document("default-snippets"));
this.webTestClient.get().uri("/").exchange().expectStatus().is2xxSuccessful()
.expectBody().consumeWith(document("default-snippets"));
File defaultSnippetsDir = new File("target/generated-snippets/default-snippets");
assertThat(defaultSnippetsDir).exists();
assertThat(new File(defaultSnippetsDir, "curl-request.md"))
......
......@@ -25,6 +25,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.FileSystemUtils;
......@@ -39,6 +40,7 @@ import static org.springframework.restdocs.webtestclient.WebTestClientRestDocume
*/
@RunWith(SpringRunner.class)
@WebFluxTest
@WithMockUser
@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.example.com", uriPort = 443)
public class WebTestClientRestDocsAutoConfigurationIntegrationTests {
......
......@@ -25,6 +25,7 @@ import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
......@@ -53,6 +54,7 @@ public class WebFluxTypeExcludeFilterTests {
assertThat(excludes(filter, ExampleWeb.class)).isFalse();
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
assertThat(excludes(filter, ExampleServerHttpSecurity.class)).isFalse();
}
@Test
......@@ -65,6 +67,7 @@ public class WebFluxTypeExcludeFilterTests {
assertThat(excludes(filter, ExampleWeb.class)).isFalse();
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
assertThat(excludes(filter, ExampleServerHttpSecurity.class)).isFalse();
}
@Test
......@@ -77,6 +80,7 @@ public class WebFluxTypeExcludeFilterTests {
assertThat(excludes(filter, ExampleWeb.class)).isTrue();
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
assertThat(excludes(filter, ExampleServerHttpSecurity.class)).isTrue();
}
@Test
......@@ -89,6 +93,7 @@ public class WebFluxTypeExcludeFilterTests {
assertThat(excludes(filter, ExampleWeb.class)).isFalse();
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isFalse();
assertThat(excludes(filter, ExampleServerHttpSecurity.class)).isFalse();
}
@Test
......@@ -101,6 +106,7 @@ public class WebFluxTypeExcludeFilterTests {
assertThat(excludes(filter, ExampleWeb.class)).isFalse();
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
assertThat(excludes(filter, ExampleServerHttpSecurity.class)).isFalse();
}
private boolean excludes(WebFluxTypeExcludeFilter filter, Class<?> type)
......@@ -164,4 +170,8 @@ public class WebFluxTypeExcludeFilterTests {
}
static class ExampleServerHttpSecurity extends ServerHttpSecurity {
}
}
......@@ -18,19 +18,24 @@ package org.springframework.boot.test.autoconfigure.web.reactive;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.List;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.codec.CodecConfigurer;
import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
......@@ -80,6 +85,41 @@ public class WebTestClientAutoConfigurationTests {
});
}
@Test
@SuppressWarnings("unchecked")
public void shouldApplySpringSecurityConfigurer() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.run((context) -> {
WebTestClient webTestClient = context.getBean(WebTestClient.class);
WebTestClient.Builder builder = (WebTestClient.Builder) ReflectionTestUtils
.getField(webTestClient, "builder");
WebHttpHandlerBuilder httpHandlerBuilder = (WebHttpHandlerBuilder) ReflectionTestUtils
.getField(builder, "httpHandlerBuilder");
List<WebFilter> filters = (List<WebFilter>) ReflectionTestUtils
.getField(httpHandlerBuilder, "filters");
assertThat(filters.get(0).getClass().getName()).isEqualTo(
"org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers$MutatorFilter");
});
}
@Test
@SuppressWarnings("unchecked")
public void shouldNotApplySpringSecurityConfigurerWhenSpringSecurityNotOnClassPath() {
FilteredClassLoader classLoader = new FilteredClassLoader(
SecurityMockServerConfigurers.class);
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.withClassLoader(classLoader).run((context) -> {
WebTestClient webTestClient = context.getBean(WebTestClient.class);
WebTestClient.Builder builder = (WebTestClient.Builder) ReflectionTestUtils
.getField(webTestClient, "builder");
WebHttpHandlerBuilder httpHandlerBuilder = (WebHttpHandlerBuilder) ReflectionTestUtils
.getField(builder, "httpHandlerBuilder");
List<WebFilter> filters = (List<WebFilter>) ReflectionTestUtils
.getField(httpHandlerBuilder, "filters");
assertThat(filters.size()).isEqualTo(0);
});
}
@Configuration
static class BaseConfiguration {
......
......@@ -21,6 +21,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
......@@ -30,6 +31,7 @@ import org.springframework.test.web.reactive.server.WebTestClient;
* @author Stephane Nicoll
*/
@RunWith(SpringRunner.class)
@WithMockUser
@WebFluxTest
public class WebFluxTestAllControllersIntegrationTests {
......
......@@ -23,6 +23,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
......@@ -32,6 +33,7 @@ import org.springframework.test.web.reactive.server.WebTestClient;
* @author Stephane Nicoll
*/
@RunWith(SpringRunner.class)
@WithMockUser
@WebFluxTest(controllers = ExampleController2.class)
public class WebFluxTestConverterIntegrationTests {
......
......@@ -21,6 +21,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
......@@ -30,6 +31,7 @@ import org.springframework.test.web.reactive.server.WebTestClient;
* @author Stephane Nicoll
*/
@RunWith(SpringRunner.class)
@WithMockUser
@WebFluxTest(controllers = ExampleController1.class)
public class WebFluxTestOneControllerIntegrationTests {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment