/* * Copyright (c) 2013, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.identity.application.authentication.framework.handler.claims.impl; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.CarbonException; import org.wso2.carbon.claim.mgt.ClaimManagementException; import org.wso2.carbon.claim.mgt.ClaimManagerHandler; import org.wso2.carbon.core.util.AnonymousSessionUtil; import org.wso2.carbon.identity.application.authentication.framework.ApplicationAuthenticator; import org.wso2.carbon.identity.application.authentication.framework.config.model.ApplicationConfig; import org.wso2.carbon.identity.application.authentication.framework.config.model.StepConfig; import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; import org.wso2.carbon.identity.application.authentication.framework.handler.claims.ClaimHandler; import org.wso2.carbon.identity.application.authentication.framework.internal.FrameworkServiceComponent; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; import org.wso2.carbon.identity.application.common.model.ClaimMapping; import org.wso2.carbon.identity.application.mgt.ApplicationConstants; import org.wso2.carbon.identity.core.util.IdentityCoreConstants; import org.wso2.carbon.identity.application.common.model.ClaimConfig; import org.wso2.carbon.identity.application.common.model.ServiceProvider; import org.wso2.carbon.user.api.ClaimManager; import org.wso2.carbon.user.api.RealmConfiguration; import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.api.UserStoreManager; import org.wso2.carbon.user.core.UserRealm; import org.wso2.carbon.user.core.UserStoreConfigConstants; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Iterator; import java.util.Set; public class DefaultClaimHandler implements ClaimHandler { public static final String SERVICE_PROVIDER_SUBJECT_CLAIM_VALUE = "ServiceProviderSubjectClaimValue"; private static final Log log = LogFactory.getLog(DefaultClaimHandler.class); private static volatile DefaultClaimHandler instance; public static DefaultClaimHandler getInstance() { if (instance == null) { synchronized (DefaultClaimHandler.class) { if (instance == null) { instance = new DefaultClaimHandler(); } } } return instance; } @Override public Map<String, String> handleClaimMappings(StepConfig stepConfig, AuthenticationContext context, Map<String, String> remoteClaims, boolean isFederatedClaims) throws FrameworkException { if (log.isDebugEnabled()) { logInput(remoteClaims, isFederatedClaims); } ApplicationConfig appConfig = context.getSequenceConfig().getApplicationConfig(); String spStandardDialect = getStandardDialect(context.getRequestType(), appConfig); Map<String, String> returningClaims = null; if (isFederatedClaims) { returningClaims = handleFederatedClaims(remoteClaims, spStandardDialect, stepConfig, context); } else { returningClaims = handleLocalClaims(spStandardDialect, stepConfig, context); } if (log.isDebugEnabled()) { logOutput(returningClaims, context); } return returningClaims; } /** * @param spStandardDialect * @param remoteClaims * @param stepConfig * @param context * @return * @throws FrameworkException */ protected Map<String, String> handleFederatedClaims(Map<String, String> remoteClaims, String spStandardDialect, StepConfig stepConfig, AuthenticationContext context) throws FrameworkException { ClaimMapping[] idPClaimMappings = context.getExternalIdP().getClaimMappings(); if (idPClaimMappings == null) { idPClaimMappings = new ClaimMapping[0]; } Map<String, String> spClaimMappings = context.getSequenceConfig().getApplicationConfig(). getClaimMappings(); if (spClaimMappings == null) { spClaimMappings = new HashMap<>(); } Map<String, String> carbonToStandardClaimMapping = new HashMap<>(); Map<String, String> spRequestedClaimMappings = context.getSequenceConfig().getApplicationConfig(). getRequestedClaimMappings(); if (StringUtils.isNotBlank(spStandardDialect) && !StringUtils.equals(spStandardDialect, ApplicationConstants .LOCAL_IDP_DEFAULT_CLAIM_DIALECT)) { carbonToStandardClaimMapping = getCarbonToStandardDialectMapping(spStandardDialect, context, spRequestedClaimMappings, context.getTenantDomain()); spRequestedClaimMappings = mapRequestClaimsInStandardDialect(spRequestedClaimMappings, carbonToStandardClaimMapping); } ApplicationAuthenticator authenticator = stepConfig. getAuthenticatedAutenticator().getApplicationAuthenticator(); String idPStandardDialect = authenticator.getClaimDialectURI(); boolean useDefaultIdpDialect = context.getExternalIdP().useDefaultLocalIdpDialect(); // set unfiltered remote claims as a property context.setProperty(FrameworkConstants.UNFILTERED_IDP_CLAIM_VALUES, remoteClaims); Map<String, String> localUnfilteredClaims = new HashMap<>(); Map<String, String> spUnfilteredClaims = new HashMap<>(); Map<String, String> spFilteredClaims = new HashMap<>(); // claim mapping from local IDP to remote IDP : local-claim-uri / idp-claim-uri Map<String, String> localToIdPClaimMap = null; Map<String, String> defaultValuesForClaims = new HashMap<>(); loadDefaultValuesForClaims(idPClaimMappings, defaultValuesForClaims); if (idPStandardDialect != null || useDefaultIdpDialect) { localToIdPClaimMap = getLocalToIdpClaimMappingWithStandardDialect(remoteClaims, idPClaimMappings, context, idPStandardDialect); } else if (idPClaimMappings.length > 0) { localToIdPClaimMap = FrameworkUtils.getClaimMappings(idPClaimMappings, true); } else { log.warn("Authenticator : " + authenticator.getFriendlyName() + " does not have " + "a standard dialect and IdP : " + context.getExternalIdP().getIdPName() + " does not have custom claim mappings. Cannot proceed with claim mappings"); return spFilteredClaims; } // Loop remote claims and map to local claims mapRemoteClaimsToLocalClaims(remoteClaims, localUnfilteredClaims, localToIdPClaimMap, defaultValuesForClaims); // set all locally mapped unfiltered remote claims as a property context.setProperty(FrameworkConstants.UNFILTERED_LOCAL_CLAIM_VALUES, localUnfilteredClaims); // claim mapping from local service provider to remote service provider. Map<String, String> localToSPClaimMappings = mapLocalSpClaimsToRemoteSPClaims(spStandardDialect, context, spClaimMappings); // Loop through <code>localToSPClaimMappings</code> and filter // <code>spUnfilteredClaims</code> and <code>spFilteredClaims</code> filterSPClaims(spRequestedClaimMappings, localUnfilteredClaims, spUnfilteredClaims, spFilteredClaims, localToSPClaimMappings); // set all service provider mapped unfiltered remote claims as a property context.setProperty(FrameworkConstants.UNFILTERED_SP_CLAIM_VALUES, spUnfilteredClaims); if (FrameworkConstants.RequestType.CLAIM_TYPE_OPENID.equals(context.getRequestType())) { spFilteredClaims = spUnfilteredClaims; } // set the subject claim URI as a property if (spStandardDialect != null) { setSubjectClaimForFederatedClaims(localUnfilteredClaims, spStandardDialect, context); } else { setSubjectClaimForFederatedClaims(spUnfilteredClaims, null, context); } return spFilteredClaims; } private void filterSPClaims(Map<String, String> spRequestedClaimMappings, Map<String, String> localUnfilteredClaims, Map<String, String> spUnfilteredClaims, Map<String, String> spFilteredClaims, Map<String, String> localToSPClaimMappings) { for (Entry<String, String> entry : localToSPClaimMappings.entrySet()) { String localClaimURI = entry.getKey(); String spClaimURI = entry.getValue(); String claimValue = localUnfilteredClaims.get(localClaimURI); if (claimValue != null) { spUnfilteredClaims.put(spClaimURI, claimValue); if (spRequestedClaimMappings.get(spClaimURI) != null) { spFilteredClaims.put(spClaimURI, claimValue); } } } } private Map<String, String> mapLocalSpClaimsToRemoteSPClaims(String spStandardDialect, AuthenticationContext context, Map<String, String> spClaimMappings) throws FrameworkException { Map<String, String> localToSPClaimMappings = null; if (spStandardDialect != null) { // passing null for keySet argument to get all claim mappings, // since we don't know required claim mappings in advance // Key:value -> carbon_dialect:standard_dialect try { localToSPClaimMappings = getClaimMappings(spStandardDialect, null, context.getTenantDomain(), true); } catch (Exception e) { throw new FrameworkException("Error occurred while getting all claim mappings from " + spStandardDialect + " dialect to " + ApplicationConstants.LOCAL_IDP_DEFAULT_CLAIM_DIALECT + " dialect for " + context.getTenantDomain() + " to handle federated claims", e); } } else if (!spClaimMappings.isEmpty()) { localToSPClaimMappings = FrameworkUtils.getLocalToSPClaimMappings(spClaimMappings); } else { // no standard dialect and no custom claim mappings throw new AssertionError("Authenticator Error! Authenticator does not have a " + "standard dialect and no custom claim mappings defined for IdP"); } return localToSPClaimMappings; } private void mapRemoteClaimsToLocalClaims(Map<String, String> remoteClaims, Map<String, String> localUnfilteredClaims, Map<String, String> localToIdPClaimMap, Map<String, String> defaultValuesForClaims) { for (Entry<String, String> entry : localToIdPClaimMap.entrySet()) { String localClaimURI = entry.getKey(); String claimValue = remoteClaims.get(localToIdPClaimMap.get(localClaimURI)); if (StringUtils.isEmpty(claimValue)) { claimValue = defaultValuesForClaims.get(localClaimURI); } if (!StringUtils.isEmpty(claimValue)) { localUnfilteredClaims.put(localClaimURI, claimValue); } } } private Map<String, String> getLocalToIdpClaimMappingWithStandardDialect(Map<String, String> remoteClaims, ClaimMapping[] idPClaimMappings, AuthenticationContext context, String idPStandardDialect) throws FrameworkException { Map<String, String> localToIdPClaimMap; if (idPStandardDialect == null) { idPStandardDialect = ApplicationConstants.LOCAL_IDP_DEFAULT_CLAIM_DIALECT; } try { localToIdPClaimMap = getClaimMappings(idPStandardDialect, remoteClaims.keySet(), context.getTenantDomain(), true); } catch (Exception e) { throw new FrameworkException("Error occurred while getting claim mappings for " + "received remote claims from " + idPStandardDialect + " dialect to " + ApplicationConstants.LOCAL_IDP_DEFAULT_CLAIM_DIALECT + " dialect for " + context.getTenantDomain() + " to handle federated claims", e); } // adding remote claims with default values also to the key set because they may not come from the federated IdP for(ClaimMapping claimMapping : idPClaimMappings){ if (StringUtils.isNotBlank(claimMapping.getDefaultValue()) && !localToIdPClaimMap.containsKey (claimMapping.getLocalClaim().getClaimUri())) { localToIdPClaimMap.put(claimMapping.getLocalClaim().getClaimUri(), claimMapping.getDefaultValue()); } } return localToIdPClaimMap; } private void loadDefaultValuesForClaims(ClaimMapping[] idPClaimMappings, Map<String, String> defaultValuesForClaims) { for (ClaimMapping claimMapping : idPClaimMappings) { String defaultValue = claimMapping.getDefaultValue(); if (defaultValue != null && !defaultValue.isEmpty()) { defaultValuesForClaims .put(claimMapping.getLocalClaim().getClaimUri(), defaultValue); } } } /** * @param context * @return * @throws FrameworkException */ protected Map<String, String> handleLocalClaims(String spStandardDialect, StepConfig stepConfig, AuthenticationContext context) throws FrameworkException { ApplicationConfig appConfig = context.getSequenceConfig().getApplicationConfig(); ServiceProvider serviceProvider = appConfig.getServiceProvider(); ClaimConfig claimConfig = serviceProvider.getClaimConfig(); boolean isLocalClaimDialect = claimConfig.isLocalClaimDialect(); Map<String, String> spToLocalClaimMappings = appConfig.getClaimMappings(); if (spToLocalClaimMappings == null) { spToLocalClaimMappings = new HashMap<>(); } Map<String, String> carbonToStandardClaimMapping = new HashMap<>(); Map<String, String> requestedClaimMappings = appConfig.getRequestedClaimMappings(); if (requestedClaimMappings == null) { requestedClaimMappings = new HashMap<>(); } AuthenticatedUser authenticatedUser = getAuthenticatedUser(stepConfig, context); String tenantDomain = authenticatedUser.getTenantDomain(); String tenantAwareUserName = authenticatedUser.getUserName(); UserRealm realm = getUserRealm(tenantDomain); if (realm == null) { log.warn("No valid tenant domain provider. No claims returned back"); return new HashMap<>(); } ClaimManager claimManager = getClaimManager(tenantDomain, realm); UserStoreManager userStore = getUserStoreManager(tenantDomain, realm, authenticatedUser.getUserStoreDomain()); // key:value -> carbon_dialect:claim_value Map<String, String> allLocalClaims; // If default dialect -> all non-null user claims // If custom dialect -> all non-null user claims that have been mapped to custom claims // key:value -> sp_dialect:claim_value Map<String, String> allSPMappedClaims = new HashMap<>(); // Requested claims only // key:value -> sp_dialect:claim_value Map<String, String> spRequestedClaims = new HashMap<>(); // Retrieve all non-null user claim values against local claim uris. allLocalClaims = retrieveAllNunNullUserClaimValues(authenticatedUser, tenantDomain, tenantAwareUserName, claimManager, userStore); context.setProperty(FrameworkConstants.UNFILTERED_LOCAL_CLAIM_VALUES, allLocalClaims); // if standard dialect get all claim mappings from standard dialect to carbon dialect spToLocalClaimMappings = getStanderDialectToCarbonMapping(spStandardDialect, context, spToLocalClaimMappings, tenantDomain); if (StringUtils.isNotBlank(spStandardDialect) && (!StringUtils.equals(spStandardDialect, ApplicationConstants .LOCAL_IDP_DEFAULT_CLAIM_DIALECT))) { carbonToStandardClaimMapping = getCarbonToStandardDialectMapping(spStandardDialect, context, spToLocalClaimMappings, tenantDomain); requestedClaimMappings = mapRequestClaimsInStandardDialect(requestedClaimMappings, carbonToStandardClaimMapping); } mapSPClaimsAndFilterRequestedClaims(spToLocalClaimMappings, requestedClaimMappings, allLocalClaims, allSPMappedClaims, spRequestedClaims); context.setProperty(FrameworkConstants.UNFILTERED_SP_CLAIM_VALUES, allSPMappedClaims); if (spStandardDialect != null) { setSubjectClaimForLocalClaims(tenantAwareUserName, userStore, allLocalClaims, spStandardDialect, context); } else { setSubjectClaimForLocalClaims(tenantAwareUserName, userStore, allSPMappedClaims, null, context); } if (FrameworkConstants.RequestType.CLAIM_TYPE_OPENID.equals(context.getRequestType())) { spRequestedClaims = allSPMappedClaims; } /* * This is a custom change added to pass 'MultipleAttributeSeparator' attribute value to other components, * since we can't get the logged in user in some situations. * * Following components affected from this change - * org.wso2.carbon.identity.application.authentication.endpoint * org.wso2.carbon.identity.provider * org.wso2.carbon.identity.oauth * org.wso2.carbon.identity.oauth.endpoint * org.wso2.carbon.identity.sso.saml * * TODO: Should use Map<String, List<String>> in future for claim mapping * */ addMultiAttributeSperatorToRequestedClaims(authenticatedUser, (org.wso2.carbon.user.core.UserStoreManager) userStore, spRequestedClaims); return spRequestedClaims; } private Map<String, String> mapRequestClaimsInStandardDialect(Map<String, String> requestedClaimMappings, Map<String, String> carbonToStandardClaimMapping) { Map<String, String> requestedClaimMappingsInStandardDialect = new HashMap<>(); if (requestedClaimMappings != null) { Iterator iterator = requestedClaimMappings.entrySet().iterator(); while (iterator.hasNext()) { Entry<String, String> mapping = (Entry) iterator.next(); String standardMappedClaim = carbonToStandardClaimMapping.get(mapping.getValue()); if (StringUtils.isNotBlank(standardMappedClaim)) { requestedClaimMappingsInStandardDialect.put(standardMappedClaim, mapping.getValue()); } } } return requestedClaimMappingsInStandardDialect; } private void addMultiAttributeSperatorToRequestedClaims(AuthenticatedUser authenticatedUser, org.wso2.carbon.user.core.UserStoreManager userStore, Map<String, String> spRequestedClaims) { if (!spRequestedClaims.isEmpty()) { RealmConfiguration realmConfiguration = userStore.getRealmConfiguration(); String claimSeparator = realmConfiguration.getUserStoreProperty(IdentityCoreConstants .MULTI_ATTRIBUTE_SEPARATOR); if (StringUtils.isNotBlank(claimSeparator)) { spRequestedClaims.put(IdentityCoreConstants.MULTI_ATTRIBUTE_SEPARATOR, claimSeparator); } } } private void mapSPClaimsAndFilterRequestedClaims(Map<String, String> spToLocalClaimMappings, Map<String, String> requestedClaimMappings, Map<String, String> allLocalClaims, Map<String, String> allSPMappedClaims, Map<String, String> spRequestedClaims) { for (Entry<String, String> entry : spToLocalClaimMappings.entrySet()) { String spClaimURI = entry.getKey(); String localClaimURI = entry.getValue(); String claimValue = allLocalClaims.get(localClaimURI); if (claimValue != null) { allSPMappedClaims.put(spClaimURI, claimValue); if (requestedClaimMappings.get(spClaimURI) != null) { spRequestedClaims.put(spClaimURI, claimValue); } } } } private Map<String, String> getStanderDialectToCarbonMapping(String spStandardDialect, AuthenticationContext context, Map<String, String> spToLocalClaimMappings, String tenantDomain) throws FrameworkException { if (spStandardDialect != null) { try { spToLocalClaimMappings = getClaimMappings(spStandardDialect, null, context.getTenantDomain(), false); } catch (Exception e) { throw new FrameworkException("Error occurred while getting all claim mappings from " + spStandardDialect + " dialect to " + ApplicationConstants.LOCAL_IDP_DEFAULT_CLAIM_DIALECT + " dialect for " + tenantDomain + " to handle local claims", e); } } return spToLocalClaimMappings; } private Map<String, String> getCarbonToStandardDialectMapping(String spStandardDialect, AuthenticationContext context, Map<String, String> spToLocalClaimMappings, String tenantDomain) throws FrameworkException { if (spStandardDialect != null) { try { spToLocalClaimMappings = getClaimMappings(spStandardDialect, null, context.getTenantDomain(), true); } catch (Exception e) { throw new FrameworkException("Error occurred while getting all claim mappings from " + ApplicationConstants.LOCAL_IDP_DEFAULT_CLAIM_DIALECT + " dialect to " + spStandardDialect+ " dialect for " + tenantDomain + " to handle local claims", e); } } return spToLocalClaimMappings; } private Map<String, String> retrieveAllNunNullUserClaimValues(AuthenticatedUser authenticatedUser, String tenantDomain, String tenantAwareUserName, ClaimManager claimManager, UserStoreManager userStore) throws FrameworkException { Map<String, String> allLocalClaims = new HashMap<>(); try { org.wso2.carbon.user.api.ClaimMapping[] claimMappings = claimManager .getAllClaimMappings(ApplicationConstants.LOCAL_IDP_DEFAULT_CLAIM_DIALECT); List<String> localClaimURIs = new ArrayList<>(); for (org.wso2.carbon.user.api.ClaimMapping mapping : claimMappings) { String claimURI = mapping.getClaim().getClaimUri(); localClaimURIs.add(claimURI); } allLocalClaims = userStore.getUserClaimValues(tenantAwareUserName, localClaimURIs.toArray(new String[localClaimURIs.size()]), null); } catch (UserStoreException e) { if (e.getMessage().contains("UserNotFound")) { if (log.isDebugEnabled()) { log.debug("User " + tenantAwareUserName + " not found in user store"); } } else { throw new FrameworkException("Error occurred while getting all user claims for " + authenticatedUser + " in " + tenantDomain, e); } } if (allLocalClaims == null) { allLocalClaims = new HashMap<>(); } return allLocalClaims; } private UserStoreManager getUserStoreManager(String tenantDomain, UserRealm realm, String userDomain) throws FrameworkException { UserStoreManager userStore = null; try { userStore = realm.getUserStoreManager(); if (StringUtils.isNotBlank(userDomain)) { userStore = realm.getUserStoreManager().getSecondaryUserStoreManager(userDomain); } if (userStore == null) { // To avoid NPEs throw new FrameworkException("Invalid user store domain name : " + userDomain + " in tenant : " + tenantDomain); } } catch (UserStoreException e) { throw new FrameworkException("Error occurred while retrieving the UserStoreManager " + "from Realm for " + tenantDomain + " to handle local claims", e); } return userStore; } private ClaimManager getClaimManager(String tenantDomain, UserRealm realm) throws FrameworkException { ClaimManager claimManager = null; try { claimManager = realm.getClaimManager(); } catch (UserStoreException e) { throw new FrameworkException("Error occurred while retrieving the ClaimManager " + "from Realm for " + tenantDomain + " to handle local claims", e); } return claimManager; } private UserRealm getUserRealm(String tenantDomain) throws FrameworkException { UserRealm realm; try { realm = AnonymousSessionUtil.getRealmByTenantDomain( FrameworkServiceComponent.getRegistryService(), FrameworkServiceComponent.getRealmService(), tenantDomain); } catch (CarbonException e) { throw new FrameworkException("Error occurred while retrieving the Realm for " + tenantDomain + " to handle local claims", e); } return realm; } private AuthenticatedUser getAuthenticatedUser(StepConfig stepConfig, AuthenticationContext context) { AuthenticatedUser authenticatedUser; if (stepConfig != null) { //calling from StepBasedSequenceHandler authenticatedUser = stepConfig.getAuthenticatedUser(); } else { //calling from RequestPathBasedSequenceHandler authenticatedUser = context.getSequenceConfig().getAuthenticatedUser(); } return authenticatedUser; } /** * Set federated subject's SP Subject Claim URI as a property */ private void setSubjectClaimForFederatedClaims(Map<String, String> attributesMap, String spStandardDialect, AuthenticationContext context) { String subjectURI = context.getSequenceConfig().getApplicationConfig().getSubjectClaimUri(); if (subjectURI != null && !subjectURI.isEmpty()) { if (spStandardDialect != null) { setSubjectClaim(null, null, attributesMap, spStandardDialect, context); if (context.getProperty(SERVICE_PROVIDER_SUBJECT_CLAIM_VALUE) == null) { log.warn("Subject claim could not be found amongst locally mapped " + "unfiltered remote claims"); } } else { setSubjectClaim(null, null, attributesMap, null, context); if (context.getProperty(SERVICE_PROVIDER_SUBJECT_CLAIM_VALUE) == null) { log.warn("Subject claim could not be found amongst service provider mapped " + "unfiltered remote claims"); } } } } /** * Set federated subject's SP Subject Claim URI as a property */ private void setSubjectClaimForLocalClaims(String tenantAwareUserId, UserStoreManager userStore, Map<String, String> attributesMap, String spStandardDialect, AuthenticationContext context) { String subjectURI = context.getSequenceConfig().getApplicationConfig().getSubjectClaimUri(); if (subjectURI != null && !subjectURI.isEmpty()) { if (spStandardDialect != null) { setSubjectClaim(tenantAwareUserId, userStore, attributesMap, spStandardDialect, context); if (context.getProperty(SERVICE_PROVIDER_SUBJECT_CLAIM_VALUE) == null) { log.warn("Subject claim could not be found amongst unfiltered local claims"); } } else { setSubjectClaim(tenantAwareUserId, userStore, attributesMap, null, context); if (context.getProperty(SERVICE_PROVIDER_SUBJECT_CLAIM_VALUE) == null) { log.warn("Subject claim could not be found amongst service provider mapped " + "unfiltered local claims"); } } } } /** * Set authenticated user's SP Subject Claim URI as a property */ private void setSubjectClaim(String tenantAwareUserId, UserStoreManager userStore, Map<String, String> attributesMap, String spStandardDialect, AuthenticationContext context) { String subjectURI = context.getSequenceConfig().getApplicationConfig().getSubjectClaimUri(); ApplicationConfig applicationConfig = context.getSequenceConfig().getApplicationConfig(); ServiceProvider serviceProvider = applicationConfig.getServiceProvider(); ClaimConfig claimConfig = serviceProvider.getClaimConfig(); boolean isLocalClaimDialect = claimConfig.isLocalClaimDialect(); Map<String, String> spToLocalClaimMappings = applicationConfig.getClaimMappings(); if (subjectURI != null) { if (!isLocalClaimDialect && spStandardDialect != null) { if (spToLocalClaimMappings != null) { subjectURI = spToLocalClaimMappings.get(subjectURI); } } if (attributesMap.get(subjectURI) != null) { context.setProperty(SERVICE_PROVIDER_SUBJECT_CLAIM_VALUE, attributesMap.get(subjectURI)); if (log.isDebugEnabled()) { log.debug("Setting \'ServiceProviderSubjectClaimValue\' property value from " + "attribute map " + attributesMap.get(subjectURI)); } } else { log.debug("Subject claim not found among attributes"); } // if federated case return if (tenantAwareUserId == null || userStore == null) { log.debug("Tenant aware username or user store \'NULL\'. Possibly federated case"); return; } // standard dialect if (spStandardDialect != null) { setSubjectClaimForStandardDialect(tenantAwareUserId, userStore, context, subjectURI); } } } private void setSubjectClaimForStandardDialect(String tenantAwareUserId, UserStoreManager userStore, AuthenticationContext context, String subjectURI) { try { String value = userStore.getUserClaimValue(tenantAwareUserId, subjectURI, null); if (value != null) { context.setProperty(SERVICE_PROVIDER_SUBJECT_CLAIM_VALUE, value); if (log.isDebugEnabled()) { log.debug("Setting \'ServiceProviderSubjectClaimValue\' property value " + "from user store " + value); } } else { if(log.isDebugEnabled()) { log.debug("Subject claim for " + tenantAwareUserId + " not found in user store"); } } } catch (UserStoreException e) { log.error("Error occurred while retrieving " + subjectURI + " claim value for user " + tenantAwareUserId, e); } } /** * @param otherDialect * @param keySet * @param tenantDomain * @param useLocalDialectAsKey * @return * @throws FrameworkException */ private Map<String, String> getClaimMappings(String otherDialect, Set<String> keySet, String tenantDomain, boolean useLocalDialectAsKey) throws FrameworkException { Map<String, String> claimMapping = null; try { claimMapping = ClaimManagerHandler.getInstance() .getMappingsMapFromOtherDialectToCarbon(otherDialect, keySet, tenantDomain, useLocalDialectAsKey); } catch (ClaimManagementException e) { throw new FrameworkException("Error while loading mappings.", e); } if (claimMapping == null) { claimMapping = new HashMap<>(); } return claimMapping; } /** * Returns the claim dialect URI based on the client type * * @param clientType * @param appConfig * @return standard dialect -> SP uses standard dialect; carbon or other * null -> SP uses custom dialect */ protected String getStandardDialect(String clientType, ApplicationConfig appConfig) { Map<String, String> claimMappings = appConfig.getClaimMappings(); if (FrameworkConstants.RequestType.CLAIM_TYPE_OIDC.equals(clientType)) { return "http://wso2.org/oidc/claim"; } else if (FrameworkConstants.RequestType.CLAIM_TYPE_STS.equals(clientType)) { return "http://schemas.xmlsoap.org/ws/2005/05/identity"; } else if (FrameworkConstants.RequestType.CLAIM_TYPE_OPENID.equals(clientType)) { return "http://axschema.org"; } else if (FrameworkConstants.RequestType.CLAIM_TYPE_SCIM.equals(clientType)) { return "urn:scim:schemas:core:1.0"; } else if (FrameworkConstants.RequestType.CLAIM_TYPE_WSO2.equals(clientType)) { return ApplicationConstants.LOCAL_IDP_DEFAULT_CLAIM_DIALECT; } else if (claimMappings == null || claimMappings.isEmpty()) { return ApplicationConstants.LOCAL_IDP_DEFAULT_CLAIM_DIALECT; } else { boolean isAtLeastOneNotEqual = false; for (Map.Entry<String, String> entry : claimMappings.entrySet()) { if (!entry.getKey().equals(entry.getValue())) { isAtLeastOneNotEqual = true; break; } } if (!isAtLeastOneNotEqual) { return ApplicationConstants.LOCAL_IDP_DEFAULT_CLAIM_DIALECT; } } return null; } private void logInput(Map<String, String> remoteClaims, boolean isFederatedClaims) { StringBuilder sb = new StringBuilder(); sb.append("["); if (remoteClaims != null) { for (Map.Entry<String, String> entry : remoteClaims.entrySet()) { sb.append(entry.getKey()); sb.append(":"); sb.append(entry.getValue()); sb.append(","); } } sb.append("]"); log.debug("Executing claim handler. isFederatedClaims = " + isFederatedClaims + " and remote claims = " + sb.toString()); } private void logOutput(Map<String, String> returningClaims, AuthenticationContext context) { StringBuilder sb = new StringBuilder(); sb.append("["); for (Map.Entry<String, String> entry : returningClaims.entrySet()) { sb.append(entry.getKey()); sb.append(":"); sb.append(entry.getValue()); sb.append(","); } sb.append("]"); log.debug("Returning claims from claim handler = " + sb.toString()); Map<String, String> claimsProperty = (Map<String, String>) context.getProperty(FrameworkConstants.UNFILTERED_IDP_CLAIM_VALUES); if (claimsProperty != null) { sb = new StringBuilder(); sb.append("["); for (Map.Entry<String, String> entry : claimsProperty.entrySet()) { sb.append(entry.getKey()); sb.append(":"); sb.append(entry.getValue()); sb.append(","); } sb.append("]"); } log.debug(FrameworkConstants.UNFILTERED_IDP_CLAIM_VALUES + " map property set to " + sb.toString()); claimsProperty = (Map<String, String>) context.getProperty(FrameworkConstants.UNFILTERED_LOCAL_CLAIM_VALUES); if (claimsProperty != null) { sb = new StringBuilder(); sb.append("["); for (Map.Entry<String, String> entry : claimsProperty.entrySet()) { sb.append(entry.getKey()); sb.append(":"); sb.append(entry.getValue()); sb.append(","); } sb.append("]"); } log.debug(FrameworkConstants.UNFILTERED_LOCAL_CLAIM_VALUES + " map property set to " + sb.toString()); claimsProperty = (Map<String, String>) context.getProperty(FrameworkConstants.UNFILTERED_SP_CLAIM_VALUES); if (claimsProperty != null) { sb = new StringBuilder(); sb.append("["); for (Map.Entry<String, String> entry : claimsProperty.entrySet()) { sb.append(entry.getKey()); sb.append(":"); sb.append(entry.getValue()); sb.append(","); } sb.append("]"); } log.debug(FrameworkConstants.UNFILTERED_SP_CLAIM_VALUES + " map property set to " + sb.toString()); } }