0

I have a Spring Boot based app that us using ISAM Authentication from an external provider. I have a rest/json endpoint /actuator/health that returns different data depending on if the user is authenticated or not.

How can I mock authentication during unit testing to ensure my configuration is correct?

In setup(), I've tried setting a token manually, and overriding AuthorizationService to return true.

@Before
public void setUp() throws Exception
{
   mockMvc = webAppContextSetup(wac).apply(springSecurity()).build();

   List roles = Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));

   UsernamePasswordAuthenticationToken auth =
           new UsernamePasswordAuthenticationToken("dave", "secret",
                                                   roles);

   if (!auth.isAuthenticated()) { fail("NOT AUTHENTICATED!"); }

   SecurityContextHolder.getContext().setAuthentication(auth);

   //fake logged in
   when(authorizationService.isCurrentUserAuthorized(anyString(),
                                                     anyString(),
                                                     ArgumentMatchers.any(ResourceType.class),
                                                     ArgumentMatchers.any(ActionType.class)))
     .thenReturn(true);
}

However, when I run

Authentication auth = SecurityContextHolder.getContext().getAuthentication();

if (!auth.isAuthenticated()) { fail("NOT AUTHENTICATED!"); }

UsernamePasswordAuthenticationToken authToken =
              (UsernamePasswordAuthenticationToken)auth;

mockMvc.perform(get("/health_secure")
                  .principal(auth)
                  .header("Authorization", "Bearer " + token))
       .andDo(print())
       .andExpect(status().isOk())
       .andExpect(forwardedUrl("/actuator/health"));

I get:

"error":"invalid_token","error_description":"Cannot convert access token to JSON"
Raystorm
  • 6,180
  • 4
  • 35
  • 62

2 Answers2

0

Great answer right here. Since spring security does not create a request-scoped bean, create one yourself and inject it in places where you need it. This gives you opportunity to mock it yourself.

Something like this?:

@Service
@RequiredArgsConstructor
public class UserService {

    public Principal getPrincipal() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    public Optional<String> getCurrentLogin() {
        Principal principal = getPrincipal();
        if (principal == null)
            return Optional.empty();
        return Optional.ofNullable(principal.getName());
    }

}
Alan Sereb
  • 2,358
  • 2
  • 17
  • 31
0

My application Authenticates with ISAM/OAuth2

I was hoping to just Override the AuthenticationManager or the OAuth2AuthenticationManager

I found a slightly lower level solution.

NOTE: I would love to see a solution at the AuthenticationManager level.

I had to override the ResourceServerTokenServices bean to mock my fake Auth Data.

I added a setAuth() method to my @Before method.

   //"constants" for fake auth values
   private static final String user = "MyUser";
   private static final String token = "MyTokenString";

   //TokenServices to validate/convert ISAM Bearer Token
   @MockBean ResourceServerTokenServices tokenServices;

   private Authentication setAuth() throws Exception
   {
      UsernamePasswordAuthenticationToken auth =
              new UsernamePasswordAuthenticationToken(user, token,
                                                      Collections.emptyList());

      if (!auth.isAuthenticated()) { fail("NOT AUTHENTICATED!"); }

      SecurityContextHolder.getContext().setAuthentication(auth);

      DefaultOAuth2AccessToken mockTokenImpl = new DefaultOAuth2AccessToken(user);
      mockTokenImpl.setScope(Collections.singleton("authenticate:applications"));
      mockTokenImpl.setTokenType("Bearer");

      when(tokenServices.readAccessToken(anyString())).thenReturn(mockTokenImpl);

      OAuth2Authentication oa2Auth = mock(OAuth2Authentication.class);
      when(oa2Auth.getPrincipal()).thenReturn(user);
      when(oa2Auth.getCredentials()).thenReturn(token);
      when(oa2Auth.getUserAuthentication()).thenReturn(auth);
      when(oa2Auth.isAuthenticated()).thenReturn(true);

      OAuth2Request oa2Req = mock(OAuth2Request.class);
      when(oa2Auth.getOAuth2Request()).thenReturn(oa2Req);

      when(tokenServices.loadAuthentication(anyString())).thenReturn(oa2Auth);

      return auth;
   }

This Method Configures tokenServices to have all the necessary info to fake it's way through authenticate() with Springs OAuth2AuthenticationManager class.

Raystorm
  • 6,180
  • 4
  • 35
  • 62