A mocked Spring security configuration for testing

Thomas Uhrig · January 17, 2016

Spring security is great! It gives you the possibility to secure your app and to create a login with a few simple lines of code. However, it could also become annoying during development, when you have to log yourself in again and again. So why not create a mocked Spring authentication for development and testing?

Create a new profile to active the mock

Before we implement the actual mock, we first create a new profile to active or deactivate it. Spring profiles give you the opportunity to decide which bean Spring should use when starting your app. This means you can say “Hey Spring! Use my mock!” or “Hey Spring! Use my production implementation!”. Let’s call our profile SECURITY_MOCK. First, we add the profile to our production security configuration, so that we can switch it off and use the mock instead. Note that this is the only change we need to do to our already existing code!

@Profile("!SECURITY_MOCK") // If we don't use the SECURITY_MOCK profile, we use this bean!
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // Your production security configuration
}

Now we create our mock configuration:

@Profile("SECURITY_MOCK") // If we use the SECURITY_MOCK profile, we use this bean!
@Configuration
@EnableWebSecurity
public class SecurityMockConfig extends WebSecurityConfigurerAdapter {
    // Your mocked security configuration
}

Using a profile like shown above, we can decide which implementation Spring will use. We just need to pass the profile to our application.properties:

spring.profiles.active=SECURITY_MOCK

A mocked authentication provider

Now that we have defined a profile to switch our mock on and off, we need to do the actual implementation. The first thing we do, is to write a mocked authentication provider. Spring will use this authentication provider to check the user, validate its password and to return the user details. The authentication provider depends on our own implementation, but it might look like that:

@Profile("SECURITY_MOCK")
@Primary
@Service
public class AuthenticationProviderMock implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        MyOwnUser myUser = getUser(authentication.getPrincipal().toString());
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken
                = new UsernamePasswordAuthenticationToken(myUser, "", mockGrantedAuthorities());
        usernamePasswordAuthenticationToken.setDetails(myUser);
        return usernamePasswordAuthenticationToken;
    }

    private MyOwnUser getUser(String principal) {
        return ... // Return our own user class here!
    }

    @Override
    public boolean supports(final Class authentication) {
        return true;
    }

    private List mockGrantedAuthorities() {
        return ... // Create our own authorities here!
    }
} 

A couple of things are important right here:

  • Use the SECURITY_MOCK profile again and annotate the class with @Primary so it will replace any other bean when using the mock profile!
  • As I’m pretty sure you want to use a custom user class, set it to the details!

The mocked security config

After you implemented the mocked authentication provider, the actual security config will be very easy. The only thing you need to do is to use your authentication provider:

@Autowired
private AuthenticationProviderMock authenticationProviderMock;

@Override
protected void configure(final HttpSecurity http) throws Exception {

    // Note that this might depend on your concrete app!
    http
           .authenticationProvider(authenticationProviderMock)
           .formLogin()
           .and()
           .authorizeRequests()
           .anyRequest()
           .hasAnyAuthority( /* your roles! */ )
           .and()
           .sessionManagement()
           .invalidSessionUrl(HOME_PAGE_URI)
           .sessionFixation()
           .newSession();
}

@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProviderMock);
}

Usage

After you implemented both, the mocked security config and the authentication provider mock, the usage is straight forward. You just activate the profile (in your application.properties) and then you can use the authenticated user in our code:

@Override
public MyOwnUser getCurrentUser() {
    return (MyOwnUser) SecurityContextHolder
            .getContext()
            .getAuthentication()
            .getDetails();
}

Best regards, Thomas.