The context: I created a test annotation @WithMockAuthentication
to populate test security context with an Authentication
instance, much like @WithMockUser
does.
The main difference being, in my case, the instance is a Mockito mock.
What I experience: As soon as I replace an actual instance with a mock, the Authentication
instance provided as controller method parameter is null in annotated tests: in the WithSecurityContextFactory
, if I replace:
public Authentication workingAuthentication(WithMockAuthentication annotation) {
return new TestAuthentication(annotation.name(), Stream.of(annotation.authorities()).map(SimpleGrantedAuthority::new).collect(Collectors.toSet()));
}
with
public Authentication bogousAuthentication(WithMockAuthentication annotation) {
var auth = mock(Authentication.class);
when(auth.getName()).thenReturn(annotation.name());
when(auth.getAuthorities()).thenReturn((Collection) Stream.of(annotation.authorities()).map(SimpleGrantedAuthority::new).collect(Collectors.toSet()));
when(auth.isAuthenticated()).thenReturn(true);
return auth;
}
Then I get NPE in the controller tests at
@RequestMapping("/method")
@PreAuthorize("hasRole('ROLE_AUTHORIZED')")
public ResponseEntity<String> securedMethod(Authentication auth) {
// Here, auth is null if Authentication is a mock
return ResponseEntity.ok(String.format("Hey %s, how are you?", auth.getName()));
}
I've created a minimal sample to reproduce. Run the test to see the failure.
I'm pretty sure I face a bug. Enough to create an issue in spring-security project, but it seems that Spring team team has no time to investigate...
[EDIT] This last statement is uselessly offensive and completely wrong as the answer is provided by Rob Winch, who is a major member of spring-security :/ My Bad