package org.gcube.keycloak.protocol.oidc.mapper; import java.util.ArrayList; import java.util.List; import org.jboss.logging.Logger; import org.keycloak.models.ClientSessionContext; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper; import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper; import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.representations.AccessToken; import org.keycloak.representations.IDToken; public class D4ScienceContextMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper { private static final Logger logger = Logger.getLogger(D4ScienceContextMapper.class); private static final List configProperties = new ArrayList<>(); // Assuring that the mapper is executed as last private static final int PRIORITY = Integer.MAX_VALUE; private static final String DISPLAY_TYPE = "OIDC D4Science Context Mapper"; private static final String PROVIDER_ID = "oidc-d4scince-context-mapper"; public static final String HEADER_NAME = "X-D4Science-Context"; // public static final String HEADER_NAME = "X-Infrastructure-Context"; // public static final String HEADER_NAME = "X-Infra-Context"; static { OIDCAttributeMapperHelper.addTokenClaimNameConfig(configProperties); OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, D4ScienceContextMapper.class); } @Override public String getDisplayCategory() { return TOKEN_MAPPER_CATEGORY; } @Override public int getPriority() { return PRIORITY; } @Override public String getDisplayType() { return DISPLAY_TYPE; } @Override public String getHelpText() { return "Maps the D4Science context audience by reading the '" + HEADER_NAME + "' header and sets it as the configured token claim"; } @Override public List getConfigProperties() { return configProperties; } @Override public String getId() { return PROVIDER_ID; } @Override protected void setClaim(final IDToken token, final ProtocolMapperModel mappingModel, final UserSessionModel userSession, final KeycloakSession keycloakSession, final ClientSessionContext clientSessionCtx) { // Since only the OIDCAccessTokenMapper interface is implemented, we are almost sure that // the token object is an AccessToken but adding a specific check anyway if (token instanceof AccessToken) { logger.debugf("Looking for the '%s' header", HEADER_NAME); String requestedD4SContext = keycloakSession.getContext().getRequestHeaders().getHeaderString(HEADER_NAME); if (requestedD4SContext != null && !"".equals(requestedD4SContext)) { logger.debugf("Checking resource access for the requested context: %s", requestedD4SContext); if (((AccessToken) token).getResourceAccess().containsKey(requestedD4SContext)) { logger.debugf("Mapping it as the configured claim: %s", mappingModel.getConfig().get(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME)); OIDCAttributeMapperHelper.mapClaim(token, mappingModel, requestedD4SContext); } else { logger.warnf("Requested context '%s' is not accessible to the client: %s", requestedD4SContext, clientSessionCtx.getClientSession().getClient().getName()); } } } } }