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 accessSecurityContext
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 intoSecurityContextHolder
:@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.