Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
Recently I have added
Spring Security
to my Spring Boot project using the following class:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MySecurityConfig {
as result, by default all my URLs are now protected with authentication and a self-generated password.
The problem is that all tests in a @WebMvcTest class that I used for unit-testing a controller:
@RunWith(SpringRunner.class)
@WebMvcTest(SomeController.class)
public class SomeControllerTest {...}
are now failing everywhere because of lack of authorization.
Question: can I tell @Test methods to ignore authorization so they keep succeeding as before?
How can I prevent the @EnableWebSecurity config class from being picked on a specific @WebMvcTest unit testing class?
I would like the tests already in place to be able to still go through and to test the authentication features separately later on.
So far I have tried to use a nested config class in the testing class in order to exclude security configs:
@RunWith(SpringRunner.class)
@WebMvcTest(SomeController.class)
public class SomeControllerTest {
@Configuration
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class})
static class ContextConfiguration { }
....}
but it seems not to work.
NOTE : I am using Spring Boot 1.5.8
–
For me in Spring Boot 2.2.4 (JUnit5) the below seems to have worked and bypass the security filter.
@ExtendWith(SpringExtension.class)
@WebMvcTest(SomeController.class)
@AutoConfigureMockMvc(addFilters = false)
public class SomeControllerTest {
Note: this simply disables any filters in the SpringSecurity configuration. It won't disable the security completely. In other words it will still bootstrap security without loading any filters.
–
In Spring Boot 2.2.6, @WebMvcTest is meta annotated with @AutoConfigureWebMvc which auto-configure org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration as you can see in spring.factories of spring-boot-test-autoconfigure.jar
So you just have to exclude SecurityAutoConfiguration in your test to disable Spring Security :
@WebMvcTest(excludeAutoConfiguration = SecurityAutoConfiguration.class)
–
–
You can set secure=false in the @WebMvcTest annoation.
It will skip the spring security MockMvc auto configuration in your Test
@WebMvcTest(controllers = SomeController.class, secure = false)
public class SomeControllerTest {
Note by the author:
As of 2021, this answer has been obsolete for a few years and it probably won't work for you.
–
In Spring Boot 2.4 both secure
flags were removed and none of the answers here actually work.
I ended up excluding all the security myself and wrapping it around in a custom annotation.
import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@WebMvcTest(excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = WebSecurityConfigurer.class)},
excludeAutoConfiguration = {SecurityAutoConfiguration.class,
SecurityFilterAutoConfiguration.class,
OAuth2ClientAutoConfiguration.class,
OAuth2ResourceServerAutoConfiguration.class})
public @interface UnsecuredWebMvcTest {
@AliasFor(annotation = WebMvcTest.class, attribute = "controllers")
Class<?>[] value() default {};
@AliasFor(annotation = WebMvcTest.class, attribute = "controllers")
Class<?>[] controllers() default {};
–
–
With Spring Security 4+, I find @WithMockUser
annotation to be very handy. It provides a mock user and password to test spring security methods annotated with @PreAuthorize or @PostAuthorize. All you need to do is annotate the test method with @WithMockUser
. The default role for the user is USER
. You can override the default username and role too.
//default
@Test
@WithMockUser
public void getProfile() {
//your test here
//with username and roles
@Test
@WithMockUser(username = "john", roles={"ADMIN"})
public void getProfile() {
//your test here
NOTE: This annotation can be used for classes.
@WithMockUser(username = "john", roles={"ADMIN"})
public class UsersAdminSecurityTest {
This worked for me, using spring boot 2.3.1.
@ExtendWith(SpringExtension.class)
@WebMvcTest(SomeController.class)
@AutoConfigureMockMvc(addFilters = false)
public class SomeControllerTest {
–
–
I understand this is a specific question for Spring Boot 1.5 but seems a bit old. In order to have a successful OAuth2 secured controller unit test running I applied the following steps, kindly notice I used Spring Boot 2.2.6, Gradle 5.x, and JUnit 5. This mechanism should work the same way deprecated ones based on @AutoConfigureMockMvc(secure = false)
or @WebMvcTest(controllers = SomeController.class, secure = false)
This is for a REST API project that is secured (OAuth2) using Microsoft's Azure Active Directory, but essentially this testing strategy should work for any OIDC, OAuth2 configuration.
The trick is to have a Controller test file and annotate it with @WebMvcTest annotation, however, the following parameters are required:
@WebMvcTest(
value = YourController.class
// this disables loading up the WebSecurityConfig.java file, otherwise it fails on start up
, useDefaultFilters = false
// this one indicates the specific filter to be used, in this case
// related to the GreetController we want to test
, includeFilters = {
@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
value = YourController.class
Here the configurations that make the test run successfully.
build.gradle
plugins {
id 'org.springframework.boot' version '2.2.6.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
group = 'com.grailscoder'
version = '0.0.1-SNAPSHOT'
configurations {
compileOnly {
extendsFrom annotationProcessor
repositories {
mavenCentral()
ext {
set('azureVersion', "2.2.4")
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.microsoft.azure:azure-active-directory-spring-boot-starter'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.5.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.2'
dependencyManagement {
imports {
mavenBom "com.microsoft.azure:azure-spring-boot-bom:${azureVersion}"
test {
useJUnitPlatform()
GreetController.java
package com.grailscoder.controller;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
public class GreetController {
@GetMapping("/greets")
@PreAuthorize("hasRole('ROLE_USER')") // This is validating against Active Directory's User role granted to the
// current user.
@ResponseStatus(HttpStatus.OK)
public String getGreetMessage() {
return "Greets from secret controller";
WebSecurityConfig.java
package com.grailscoder.config;
import com.microsoft.azure.spring.autoconfigure.aad.AADAppRoleStatelessAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@RequiredArgsConstructor
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final AADAppRoleStatelessAuthenticationFilter aadAuthFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
http.authorizeRequests()
.antMatchers("/", "/index.html", "/public").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(aadAuthFilter, UsernamePasswordAuthenticationFilter.class);
application.properties
azure.activedirectory.client-id=xxxxx-AD-client-id-goes-here
azure.activedirectory.session-stateless=true
GreetControllerTest.java
package com.grailscoder.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(
value = GreetController.class
// this disables loading up the WebSecurityConfig.java file, otherwise it fails on start up
, useDefaultFilters = false
// this one indicates the specific filter to be used, in this case
// related to the GreetController we want to test
, includeFilters = {
@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
value = GreetController.class
class GreetControllerTest {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@BeforeEach
void setUp() {
// add setup stuff here
@Test
@WithMockUser
void testGreet() throws Exception {
ResultActions result = mockMvc.perform(get("/greets"))
.andExpect(status().isOk());
System.out.println(result.andReturn().getResponse().getContentAsString());
I understand in order to have a similar test JUnit 4 based with a completely different approach, the following test could be used as a reference (but I haven't tried): https://github.com/spring-projects/spring-security/blob/master/samples/boot/oauth2resourceserver/src/test/java/sample/OAuth2ResourceServerControllerTests.java
In my case, for Spring Boot version 2.5.4
, I'm able to bypass Jwt security by setting useDefaultFilters = false
in @WebMvcTest
@WebMvcTest(controllers = YourController.class, useDefaultFilters = false)
public class YourControllerTest {
// Test cases
–
I solved the problem by using following annotations and properties:
@WebMvcTest(controllers =
SomeController.class,
excludeAutoConfiguration = {
MySecurityConfig.class,
ManagementWebSecurityAutoConfiguration.class,
SecurityAutoConfiguration.class
@ContextConfiguration(classes = SomeController.class)
public class SomeControllerTest {
NOTE: I' using spring boot 2.6.6, so secure=false
didn't work for me!
@AutoConfigureMockMvc(secure = false)
does not work because secure
is deprecated
what works:
@AutoConfigureMockMvc(addFilters = false)
does not completely disable spring security just bypass its filter chain.
@WebMvcTest(excludeAutoConfiguration = {SecurityAutoConfiguration.class})
(and if you are using Spring Boot actuator:
@WebMvcTest(excludeAutoConfiguration = {SecurityAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class})
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.