mocking authentication spring security

a) This is not a unit test, it's an integration test. A unit test would be no problem.

b) I'd try to keep your test setups separated. Why not just deactive spring security in tests where you are not testing security-related features?

c) If all else fails: inject a JdbcTemplate object and create the user data manulally in SQL during test setup. See Support classes for integration testing


I'd consider using an annotation such as @WithMockUser to populate test security context with "personas" (test user with specific authorities like 'admin', 'salesman', etc.).

If @Secured is on the repo, it must be because specs were stating something like "user must have this grant to query that", and so security should be unit tested too.

If UsernameAuthenticationToken (what @WithMockUser creates) doesn't meet your needs, then you might choose an other annotation, like this one I wrote, or even write one of your own creating the exact Authentication implementation you want.

Libs here, sample result extracted from there

@RunWith(SpringRunner.class)
@Import(JwtAuthenticationTokenMessageServiceTests.TestConfig.class)
public class JwtAuthenticationTokenMessageServiceTests {

    @Autowired
    private MessageService<JwtAuthenticationToken> messageService;

    @Test
    @WithMockAuthentication(authType = JwtAuthenticationToken.class, authorities = "ROLE_AUTHORIZED_PERSONNEL")
    public void secretWithScopeAuthorizedPersonnelAuthority() {
        assertThat(messageService.getSecret()).isEqualTo("Secret message");
    }

    @TestConfiguration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    @Import({ JwtTestConf.class, JwtAuthenticationTokenServletApp.JwtAuthenticationTokenMessageService.class })
    public static class TestConfig {
    }

It depends on what you want to test.

  • If you want to test business logic of your application without any security stuff, you can disable security altogether. Assuming that you use SpringJunit4Runner, you can put security configuration into separate file and don't include it into @ContextConfiguration.

  • If you want to test authorization (e.g. correct work of @Secured annotations), you can access SecurityContext directly, bypassing all authentication-related stuff (in this case you can put authentication configuration into separate file and don't load it as well):

    All you need is to put an appropriate Authentication object into SecurityContextHolder:

    @Test
    public void myTest() {
        login(...);
        ...
        logout();
    }
    
    private void login(...) {
        SecurityContextHolder.getContext().setAuthentication(
            new UsernamePasswordAuthenticationToken(...)
        )
    }
    
    private void logout() {
        SecurityContextHolder.clearContext();
    }
    
  • Finally, if you want to test authentication, you can run the test with the database containing test data.