Search code examples
javaspringspring-securityspring-bootspring-security-test

Testing Spring Boot Security configuration


I've done a very simple demo app to try testing of Spring Boot security.

This is my App configuration

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@SpringBootApplication
public class DemoApplication extends WebSecurityConfigurerAdapter {

  @Autowired
  private SecurityService securityService;

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.userDetailsService(securityService);
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests().anyRequest().fullyAuthenticated();
      http.httpBasic();
      http.csrf().disable();
  }

  public static void main(String[] args) {
      SpringApplication.run(DemoApplication.class, args);
  }
}

My UserDetailsService implementation accepts all users with password 'password' granted admin role to the 'admin' user.

@Service
public class SecurityService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Collection<GrantedAuthority> authorities;
        if (username.equals("admin")) {
            authorities = Arrays.asList(() -> "ROLE_ADMIN", () -> "ROLE_BASIC");
        } else {
            authorities = Arrays.asList(() -> "ROLE_BASIC");
        }
        return new User(username, "password", authorities);
    }
}

And I finally created a simple test to check it:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = DemoApplication.class)
@WebAppConfiguration
public class DemoApplicationTests {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Test
    public void thatAuthManagerUsesMyService() {
        Authentication auth = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken("admin", "password")
        );

        assertTrue(auth.isAuthenticated());     
    }
}

I expected the test to pass, but I got a BadCredentialsException instead. After debugging I realized that the AuthenticationManager injected by Spring in the test is not the one I configured. While digging the object in the eclipse debugger I saw that the UserDetailsServer was an InMemoryUserDetailsManager.

I also checked that the configure() methods in DemoApplication are called. What am I doing wrong?


Solution

  • Per WebSecurityConfigurerAdapter api reference for authenticationManagerBean()

    Override this method to expose the AuthenticationManager from configure(AuthenticationManagerBuilder) to be exposed as a Bean.

    So just override authenticationManagerBean() in your WebSecurityConfigurerAdapter and expose it as a bean with @Bean.

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }