package org.gcube.keycloak.protocol.oidc.mapper; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; import org.junit.Test; import org.keycloak.models.AuthenticatedClientSessionModel; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientSessionContext; import org.keycloak.models.KeycloakContext; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.oidc.mappers.FullNameMapper; import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.representations.AccessToken; import org.mockito.Mockito; import jakarta.ws.rs.core.HttpHeaders; /** * Original code repo: https://github.com/mschwartau/keycloak-custom-protocol-mapper-example */ public class D4ScienceContextMapperTest { static final String HEADER_VALUE = "ginostilla"; @Test public void shouldTokenMapperDisplayCategory() { final String tokenMapperDisplayCategory = new FullNameMapper().getDisplayCategory(); assertThat(new D4ScienceContextMapper().getDisplayCategory()).isEqualTo(tokenMapperDisplayCategory); } @Test public void shouldHaveDisplayType() { assertThat(new D4ScienceContextMapper().getDisplayType()).isNotBlank(); } @Test public void shouldHaveHelpText() { assertThat(new D4ScienceContextMapper().getHelpText()).isNotBlank(); } @Test public void shouldHaveIdId() { assertThat(new D4ScienceContextMapper().getId()).isNotBlank(); } @Test public void shouldHaveProperties() { final List configPropertyNames = new D4ScienceContextMapper().getConfigProperties().stream() .map(ProviderConfigProperty::getName) .collect(Collectors.toList()); assertThat(configPropertyNames).containsExactlyInAnyOrder(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, OIDCAttributeMapperHelper.INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN, OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, D4ScienceContextMapper.HTTP_REQUEST_HEADER_NAME, D4ScienceContextMapper.NARROW_RESOURCE_ACCESS); } @Test public void shouldAddClaimAndNotNarrow() { final UserSessionModel session = givenUserSession(); final KeycloakSession keycloakSession = givenKeycloakSession(true); final AccessToken accessToken = transformAccessToken(session, keycloakSession, true, false); assertThat(accessToken.getAudience()[0]).isEqualTo(HEADER_VALUE); assertThat(accessToken.getResourceAccess().size()).isEqualTo(2); assertThat(accessToken.getResourceAccess().keySet()).contains(HEADER_VALUE); } @Test public void shouldAddClaimAndNarrow() { final UserSessionModel session = givenUserSession(); final KeycloakSession keycloakSession = givenKeycloakSession(true); final AccessToken accessToken = transformAccessToken(session, keycloakSession, true, true); assertThat(accessToken.getAudience()[0]).isEqualTo(HEADER_VALUE); assertThat(accessToken.getResourceAccess().size()).isEqualTo(1); assertThat(accessToken.getResourceAccess().keySet().iterator().next()).isEqualTo(HEADER_VALUE); } @Test public void shouldNotAddClaim() { final UserSessionModel session = givenUserSession(); final KeycloakSession keycloakSession = givenKeycloakSession(false); final AccessToken accessToken = transformAccessToken(session, keycloakSession, true, false); assertThat(accessToken.getAudience()).isNull(); } @Test public void shouldNotAddClaimAndLogWarning() { final UserSessionModel session = givenUserSession(); final KeycloakSession keycloakSession = givenKeycloakSession(true); final AccessToken accessToken = transformAccessToken(session, keycloakSession, false, false); assertThat(accessToken.getAudience()).isNull(); } private UserSessionModel givenUserSession() { UserSessionModel userSession = Mockito.mock(UserSessionModel.class); UserModel user = Mockito.mock(UserModel.class); when(userSession.getUser()).thenReturn(user); return userSession; } private KeycloakSession givenKeycloakSession(boolean withHeader) { ClientModel clientModel = Mockito.mock(ClientModel.class); when(clientModel.getName()).thenReturn("test-client-id"); KeycloakContext context = Mockito.mock(KeycloakContext.class); when(context.getClient()).thenReturn(clientModel); KeycloakSession keycloakSession = Mockito.mock(KeycloakSession.class); when(keycloakSession.getContext()).thenReturn(context); HttpHeaders headers = Mockito.mock(HttpHeaders.class); when(context.getRequestHeaders()).thenReturn(headers); if (withHeader) { when(headers.getHeaderString(D4ScienceContextMapper.DEFAULT_HEADER_NAME)).thenReturn(HEADER_VALUE); } else { when(headers.getHeaderString(D4ScienceContextMapper.DEFAULT_HEADER_NAME)).thenReturn(""); } return keycloakSession; } private AccessToken transformAccessToken(UserSessionModel userSessionModel, KeycloakSession keycloakSession, boolean withResourceAccess, boolean withNarrowRA) { final ProtocolMapperModel mappingModel = new ProtocolMapperModel(); mappingModel.setConfig(createConfig(withNarrowRA)); AccessToken at = new AccessToken(); if (withResourceAccess) { at.addAccess(HEADER_VALUE); at.addAccess(UUID.randomUUID().toString()); } return new D4ScienceContextMapper().transformAccessToken(at, mappingModel, keycloakSession, userSessionModel, givenClientSessionContext(keycloakSession)); } private ClientSessionContext givenClientSessionContext(KeycloakSession keycloakSession) { AuthenticatedClientSessionModel acsm = Mockito.mock(AuthenticatedClientSessionModel.class); ClientModel clientModel = keycloakSession.getContext().getClient(); when(acsm.getClient()).thenReturn(clientModel); ClientSessionContext csc = Mockito.mock(ClientSessionContext.class); when(csc.getClientSession()).thenReturn(acsm); return csc; } private Map createConfig(boolean narrowRA) { final Map config = new HashMap<>(); config.put(D4ScienceContextMapper.HTTP_REQUEST_HEADER_NAME, D4ScienceContextMapper.DEFAULT_HEADER_NAME); config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, D4ScienceContextMapper.DEFAULT_TOKEN_CLAIM); config.put(D4ScienceContextMapper.NARROW_RESOURCE_ACCESS, Boolean.toString(narrowRA)); config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true"); return config; } }