Search code examples
javaspringspring-securityspring-test-mvc

Null Authentication during Spring Security test


I wanted to integration test a Spring security authentication. Just if logging in works. But during the test the following error appeared:

java.lang.AssertionError: Authentication should not be null

My custom UserDetailsService is just fetching User from databse and mapping it to my custom UserDetails. What am I doing wrong here? This is what else I have:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {Application.class})
@WebAppConfiguration
public class SecurityConfigTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders
            .webAppContextSetup(context)
            .apply(springSecurity())
            .build();
    }
    @Test
    public void shouldAuthenticate() throws Exception {
        mockMvc
            .perform(formLogin())
            .andExpect(authenticated());
    }
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsService userDetailsService;

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(new BCryptPasswordEncoder());
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http
            .httpBasic()
            .and()
            .authorizeRequests()
                .antMatchers("/", "/login").permitAll()
            .and()
            .csrf().disable();
    }
}
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application extends SpringBootServletInitializer{
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Solution

  • As explained in the Spring Security Reference Manual, mockMvc.perform(formLogin()):

    will submit a POST to "/login" with the username "user", the password "password", and a valid CSRF token.

    So if your login URL isn't /login, the username isn't user, or the password isn't password, you shouldn't expect it to work.

    To supply a username/password combination for a user that actually exists in your database, you should be able to use mockMvc.perform(formLogin("/auth").user("admin").password("pass")) (assuming the login URL is /auth, the user is named admin, and the password is pass).

    Check out the reference manual for further details and examples.