Auto-configure MockMvc with Spring Security
When Spring Security and its spring-security-test module are on the classpath, `@WebMvcTest` will now auto-configure Spring Security and configure its MockMvc-based test support. This behaviour can be disabled using the new secure attribute on `@WebMvcTest` and `@AutoConfigureMockMvc`. Closes gh-5476
This commit is contained in:
parent
41ddda4a15
commit
9153ca9526
|
@ -101,6 +101,16 @@
|
|||
<artifactId>spring-restdocs-mockmvc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
|
|
|
@ -43,8 +43,8 @@ import org.springframework.test.web.servlet.MvcResult;
|
|||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@ImportAutoConfiguration({ MockMvcAutoConfiguration.class,
|
||||
MockMvcWebClientAutoConfiguration.class,
|
||||
MockMvcWebDriverAutoConfiguration.class })
|
||||
MockMvcWebClientAutoConfiguration.class, MockMvcWebDriverAutoConfiguration.class,
|
||||
MockMvcSecurityAutoConfiguration.class })
|
||||
@PropertyMapping("spring.test.mockmvc")
|
||||
public @interface AutoConfigureMockMvc {
|
||||
|
||||
|
@ -78,4 +78,11 @@ public @interface AutoConfigureMockMvc {
|
|||
@PropertyMapping("webdriver.enabled")
|
||||
boolean webDriverEnabled() default true;
|
||||
|
||||
/**
|
||||
* If Spring Security's {@link MockMvc} support should be auto-configured when it is
|
||||
* on the classpath. Defaults to {@code true}.
|
||||
* @return if Spring Security's MockMvc support is auto-configured
|
||||
*/
|
||||
boolean secure() default true;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.servlet;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Auto-configuration for Spring Security's testing support.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = "spring.test.mockmvc", name = "secure", havingValue = "true", matchIfMissing = true)
|
||||
@Import({ SecurityAutoConfiguration.class, ServerPropertiesAutoConfiguration.class,
|
||||
MockMvcSecurityConfiguration.class })
|
||||
public class MockMvcSecurityAutoConfiguration {
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.servlet;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.test.context.TestSecurityContextHolder;
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
|
||||
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
|
||||
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcConfigurerAdapter;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Configuration for Spring Security's MockMvc integration.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(SecurityMockMvcRequestPostProcessors.class)
|
||||
class MockMvcSecurityConfiguration {
|
||||
|
||||
private static final String DEFAULT_SECURITY_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(name = DEFAULT_SECURITY_FILTER_NAME)
|
||||
public SecurityMockMvcBuilderCustomizer securityMockMvcBuilderCustomizer() {
|
||||
return new SecurityMockMvcBuilderCustomizer();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link MockMvcBuilderCustomizer} that ensures that requests run with the user in
|
||||
* the {@link TestSecurityContextHolder}.
|
||||
*
|
||||
* @see SecurityMockMvcRequestPostProcessors#testSecurityContext
|
||||
*/
|
||||
class SecurityMockMvcBuilderCustomizer implements MockMvcBuilderCustomizer {
|
||||
|
||||
@Override
|
||||
public void customize(ConfigurableMockMvcBuilder<?> builder) {
|
||||
builder.apply(new MockMvcConfigurerAdapter() {
|
||||
|
||||
@Override
|
||||
public RequestPostProcessor beforeMockMvcCreated(
|
||||
ConfigurableMockMvcBuilder<?> builder,
|
||||
WebApplicationContext context) {
|
||||
return SecurityMockMvcRequestPostProcessors.testSecurityContext();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -45,9 +45,9 @@ import org.springframework.test.web.servlet.MockMvc;
|
|||
* {@code WebMvcConfigurer} and {@code HandlerMethodArgumentResolver} beans but not
|
||||
* {@code @Component}, {@code @Service} or {@code @Repository} beans).
|
||||
* <p>
|
||||
* By default, tests annotated with {@code @WebMvcTest} will also auto-configure
|
||||
* {@link MockMvc} (include support for HtmlUnit WebClient and Selenium WebDriver). For
|
||||
* more fine-grained control of MockMVC that
|
||||
* By default, tests annotated with {@code @WebMvcTest} will also auto-configure Spring
|
||||
* Security and {@link MockMvc} (include support for HtmlUnit WebClient and Selenium
|
||||
* WebDriver). For more fine-grained control of MockMVC the
|
||||
* {@link AutoConfigureMockMvc @AutoConfigureMockMvc} annotation can be used.
|
||||
* <p>
|
||||
* Typically {@code @WebMvcTest} is used in combination with {@link MockBean @MockBean} or
|
||||
|
@ -118,4 +118,12 @@ public @interface WebMvcTest {
|
|||
*/
|
||||
Filter[] excludeFilters() default {};
|
||||
|
||||
/**
|
||||
* If Spring Security's {@link MockMvc} support should be auto-configured when it is
|
||||
* on the classpath. Defaults to {@code true}.
|
||||
* @return if Spring Security's MockMvc support is auto-configured
|
||||
*/
|
||||
@AliasFor(annotation = AutoConfigureMockMvc.class, attribute = "secure")
|
||||
boolean secure() default true;
|
||||
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
|||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(RestDocsTestController.class)
|
||||
@WebMvcTest(controllers = RestDocsTestController.class, secure = false)
|
||||
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
|
||||
public class RestDocsAutoConfigurationAdvancedConfigurationIntegrationTests {
|
||||
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.security;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MockMvcSecurityAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@WebMvcTest
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(properties = { "security.user.password=secret", "debug=true" })
|
||||
public class MockMvcSecurityAutoConfigurationIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
ConditionEvaluationReport conditionEvaluationReport;
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "test", password = "test", roles = "USER")
|
||||
public void okResponseWithMockUser() throws Exception {
|
||||
this.mockMvc.perform(get("/")).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unauthorizedResponseWithNoUser() throws Exception {
|
||||
this.mockMvc.perform(get("/")).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void okResponseWithBasicAuthCredentialsForKnownUser() throws Exception {
|
||||
this.mockMvc
|
||||
.perform(get("/").header(HttpHeaders.AUTHORIZATION,
|
||||
"Basic " + Base64Utils.encodeToString("user:secret".getBytes())))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.security;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Tests application for {@link MockMvcSecurityAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SecurityTestApplication {
|
||||
|
||||
@RestController
|
||||
static class MyController {
|
||||
|
||||
@RequestMapping("/")
|
||||
@Secured("ROLE_USER")
|
||||
public String index() {
|
||||
return "Hello";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
|
@ -40,6 +41,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc(alwaysPrint = false)
|
||||
@WithMockUser(username = "user", password = "secret")
|
||||
public class MockMvcSpringBootTestIntegrationTests {
|
||||
|
||||
@MockBean
|
||||
|
|
|
@ -33,7 +33,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
* @author Phillip Webb
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest
|
||||
@WebMvcTest(secure = false)
|
||||
public class WebMvcTestAllControllersIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
|
|
|
@ -33,7 +33,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
* @author Phillip Webb
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(ExampleController2.class)
|
||||
@WebMvcTest(controllers = ExampleController2.class, secure = false)
|
||||
public class WebMvcTestOneControllerIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
|
|
|
@ -32,7 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* @author Phillip Webb
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest
|
||||
@WebMvcTest(secure = false)
|
||||
public class WebMvcTestWebClientIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
|
|
|
@ -33,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* @author Phillip Webb
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest
|
||||
@WebMvcTest(secure = false)
|
||||
public class WebMvcTestWebDriverIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
|
|
Loading…
Reference in New Issue