I came across this similar question but I do not want to use the suggested external library.
Well, you'd better reconsider that.
Are you using the deprecated Keycloak adapters?
If yes, and if you still don't want to use spring-addons-keycloak
, you'll have to manualy populate test security context with a KeycloakAuthenticationToken
instance or mock:
@Test
public void test() {
final var principal = mock(Principal.class);
when(principal.getName()).thenReturn("user");
final var account = mock(OidcKeycloakAccount.class);
when(account.getRoles()).thenReturn(Set.of("offline_access", "uma_authorization"));
when(account.getPrincipal()).thenReturn(principal);
final var authentication = mock(KeycloakAuthenticationToken.class);
when(authentication.getAccount()).thenReturn(account);
// post(...).with(authentication(authentication))
// limits to testing secured @Controller with MockMvc
// I prefer to set security context directly instead:
SecurityContextHolder.getContext().setAuthentication(authentication);
//TODO: invoque mockmvc to test @Controller or test any other type of @Component as usual
}
You'll soon understand why this @WithMockKeycloakAuth
was created.
If you already migrated to something else than Keycloak adapters, solution with manualy setting test-security context still applies, just adapt the Authentication
instance. If your authentication type is JwtAuthenticationToken
, you can use either:
@Test
void testWithPostProcessor() throws Exception {
mockMvc.perform(get("/greet").with(jwt().jwt(jwt -> {
jwt.claim("preferred_username", "Tonton Pirate");
}).authorities(List.of(new SimpleGrantedAuthority("NICE_GUY"), new SimpleGrantedAuthority("AUTHOR")))))
.andExpect(status().isOk())
.andExpect(content().string("Hi Tonton Pirate! You are granted with: [NICE_GUY, AUTHOR]."));
}
@Test
@WithMockJwtAuth(authorities = { "NICE_GUY", "AUTHOR" }, claims = @OpenIdClaims(preferredUsername = "Tonton Pirate"))
void testWithPostProcessor() throws Exception {
mockMvc.perform(get("/greet"))
.andExpect(status().isOk())
.andExpect(content().string("Hi Tonton Pirate! You are granted with: [NICE_GUY, AUTHOR]."));
}
Note that only second option will work if you want to unit-test a secured @Component
that is not a @Controller
(a @Service
or @Repository
for instance).
My two cent advices:
- drop Keycloak adapters now: it will disapear soon, is not adapted to boot 2.7+ (web-security config should not extend
WebSecurityConfigurerAdapter
any more) and is way too adherent to Keycloak. Just have a look at this tutorial to see how easy it can be to configure and unit-test a JWT resource-server (with identities issued by Keycloak or any other OIDC authorization-server)
- if your team does not let you abandon Keycloak adapters yet, use
@WithMockKeycloakAuth
, you'll save tones of time and your test code will be way more readable.