Search code examples
spring-securitymockitojunit4

How do I mock Authentication.getAuthorities()


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


Solution

  • 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