I have a Spring OncePerRequestFilter filter with an implementation of doFilterInternal that looks like this:
@Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException {
final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && containsRole(auth, "SpecificRole")) {
doThingsWithTheRequest(request);
}
filterChain.doFilter(request, response);
}
And containsRole looks like this:
protected boolean containsRole(final Authentication auth, final String role) {
for (final GrantedAuthority ga : auth.getAuthorities()) {
if (ga.getAuthority().equals(role)) {
return true;
}
}
return false;
}
For my test I have this JUnit test where I want to mock out Authentication.getAuthorities() so that containsRole will return true:
@Test
public void test() throws ServletException, IOException, CommerceCartRestorationException {
SecurityContext securityContextMock = mock(SecurityContext.class);
Authentication authenticationMock = mock(Authentication.class);
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("MyRole");
Collection<SimpleGrantedAuthority> authCollection = Collections.singleton(simpleGrantedAuthority);
when(authenticationMock.getAuthorities()).thenReturn(authCollection);
when(securityContextMock.getAuthentication()).thenReturn(authenticationMock);
SecurityContextHolder.setContext(securityContextMock);
testObj.doFilterInternal(httpServletRequestMock, httpServletResponseMock, filterChainMock);
}
I get a compiler error
Cannot resolve method 'thenReturn(Collection)'
on this line:
when(authenticationMock.getAuthorities()).thenReturn(authCollection);
getAuthorities returns this
Collection<? extends GrantedAuthority>
and SimpleGrantedAuthority implements the GrantedAuthority interface
So the question is why and how do I fix it?
I have seen similar questions with answers to add a dependency to spring-security-test and use @WithMockUser but using spring-security-test isn't an option I'm afraid
Authentication#getAuthorities
has return type Collection<? extends GrantedAuthority>
, which is a wildcard type. You don't know what the actual type is, so you cannot assign it a value or use it as a parameter in another method.
A simple, but ugly workaround is to cast to the raw collection type:
Mockito.when(authenticationMock.getAuthorities())
.thenReturn((Collection) authorityCollection);
But a more sustainable solution is to not mock the Authentication
interface in the first place, but use a fake implementation that was specifically implemented to support testing: TestingAuthenticationToken
:
final Authentication authentication = new TestingAuthenticationToken(
null, // principal
null, // credentials
"MyRole"); // authority roles