'Disable Spring Security config class for @WebMvcTest in Spring Boot

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



Solution 1:[1]

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.

Solution 2:[2]

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) 

Solution 3:[3]

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 {};
}

Solution 4:[4]

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 {
} 

Solution 5:[5]

This worked for me, using spring boot 2.3.1.

@ExtendWith(SpringExtension.class)
@WebMvcTest(SomeController.class)
@AutoConfigureMockMvc(addFilters = false)
public class SomeControllerTest {
}

Solution 6:[6]

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

Solution 7:[7]

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
}

Solution 8:[8]

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!

Solution 9:[9]

@AutoConfigureMockMvc(addFilters = false)

Just adding addFilters = false resolved this.

Solution 10:[10]

The cause of this error is that the daemonize package is required, but it cannot be found in the repositories available on the system

sudo dnf install daemonize

It can be give you error. Before above pls run below command first

sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Fabien
Solution 3
Solution 4 alltej
Solution 5 Edor Linus
Solution 6
Solution 7 nguyentaijs
Solution 8 Tyler2P
Solution 9 Suraj Rao
Solution 10 Sajidur Rahman