/*
* Copyright (c) 2014, 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.provisioning;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.CarbonException;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.core.util.AnonymousSessionUtil;
import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException;
import org.wso2.carbon.identity.application.common.model.ClaimMapping;
import org.wso2.carbon.identity.application.common.model.IdentityProvider;
import org.wso2.carbon.identity.application.common.model.OutboundProvisioningConfig;
import org.wso2.carbon.identity.application.common.model.Property;
import org.wso2.carbon.identity.application.common.model.ProvisioningConnectorConfig;
import org.wso2.carbon.identity.application.common.model.RoleMapping;
import org.wso2.carbon.identity.application.common.model.ServiceProvider;
import org.wso2.carbon.identity.application.common.util.IdentityApplicationManagementUtil;
import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
import org.wso2.carbon.identity.provisioning.cache.ServiceProviderProvisioningConnectorCache;
import org.wso2.carbon.identity.provisioning.cache.ServiceProviderProvisioningConnectorCacheEntry;
import org.wso2.carbon.identity.provisioning.cache.ServiceProviderProvisioningConnectorCacheKey;
import org.wso2.carbon.identity.provisioning.dao.CacheBackedProvisioningMgtDAO;
import org.wso2.carbon.identity.provisioning.dao.ProvisioningManagementDAO;
import org.wso2.carbon.identity.provisioning.internal.IdentityProvisionServiceComponent;
import org.wso2.carbon.idp.mgt.IdentityProviderManagementException;
import org.wso2.carbon.idp.mgt.IdentityProviderManager;
import org.wso2.carbon.idp.mgt.util.IdPManagementUtil;
import org.wso2.carbon.registry.core.service.RegistryService;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.UserCoreConstants;
import org.wso2.carbon.user.core.UserRealm;
import org.wso2.carbon.user.core.UserStoreManager;
import org.wso2.carbon.user.core.claim.Claim;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.user.core.util.UserCoreUtil;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
*
*
*/
public class OutboundProvisioningManager {
private static final Log log = LogFactory.getLog(OutboundProvisioningManager.class);
private static CacheBackedProvisioningMgtDAO dao = new CacheBackedProvisioningMgtDAO(
new ProvisioningManagementDAO());
private static OutboundProvisioningManager provisioningManager = new OutboundProvisioningManager();
private OutboundProvisioningManager() {
}
/**
* @return
*/
public static OutboundProvisioningManager getInstance() {
return provisioningManager;
}
/**
* Get the tenant id of the given tenant domain.
*
* @param tenantDomain Tenant Domain
* @return Tenant Id of domain user belongs to.
* @throws IdentityApplicationManagementException Error when getting tenant id from tenant
* domain
*/
private static int getTenantIdOfDomain(String tenantDomain)
throws IdentityApplicationManagementException {
try {
return IdPManagementUtil.getTenantIdOfDomain(tenantDomain);
} catch (UserStoreException e) {
log.error(e.getMessage(), e);
String msg = "Error occurred while getting Tenant Id from Tenant domain "
+ tenantDomain;
throw new IdentityApplicationManagementException(msg);
}
}
/**
* TODO: Need to cache the output from this method.
*
* @return
* @throws UserStoreException
*/
private Map<String, RuntimeProvisioningConfig> getOutboundProvisioningConnectors(
ServiceProvider serviceProvider, String tenantDomainName) throws IdentityProvisioningException {
Map<String, RuntimeProvisioningConfig> connectors = new HashMap<>();
// maintain the provisioning connector cache in the super tenant.
// at the time of provisioning there may not be an authenticated user in the system -
// specially in the case of in-bound provisioning.
String tenantDomain = null;
int tenantId = -1234;
ServiceProviderProvisioningConnectorCacheKey key = null;
ServiceProviderProvisioningConnectorCacheEntry entry = null;
if (CarbonContext.getThreadLocalCarbonContext() != null) {
tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain();
tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
}
try {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext
.getThreadLocalCarbonContext();
carbonContext.setTenantId(MultitenantConstants.SUPER_TENANT_ID);
carbonContext.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
// reading from the cache
key = new ServiceProviderProvisioningConnectorCacheKey(serviceProvider.getApplicationName(), tenantDomain);
entry = ServiceProviderProvisioningConnectorCache.getInstance().getValueFromCache(key);
// cache hit
if (entry != null) {
if (log.isDebugEnabled()) {
log.debug("Provisioning cache HIT for " + serviceProvider + " of "
+ tenantDomainName);
}
return entry.getConnectors();
}
} finally {
PrivilegedCarbonContext.endTenantFlow();
if (tenantDomain != null) {
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain);
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId);
}
}
// NOW build the Map
// a list of registered provisioning connector factories.
Map<String, AbstractProvisioningConnectorFactory> registeredConnectorFactories = IdentityProvisionServiceComponent
.getConnectorFactories();
// get all registered list of out-bound provisioning connectors registered for the local
// service provider.
OutboundProvisioningConfig outboundProvisioningConfiguration = serviceProvider
.getOutboundProvisioningConfig();
if (outboundProvisioningConfiguration == null) {
if (log.isDebugEnabled()) {
log.debug("No outbound provisioning configuration defined for local service provider.");
}
// no out-bound provisioning configuration defined for local service provider.return an
// empty list.
return new HashMap<String, RuntimeProvisioningConfig>();
}
// get the list of registered provisioning identity providers in out-bound provisioning
// configuration.
IdentityProvider[] provisionningIdPList = outboundProvisioningConfiguration
.getProvisioningIdentityProviders();
if (provisionningIdPList != null && provisionningIdPList.length > 0) {
// we have a set of provisioning identity providers registered in our system.
for (IdentityProvider fIdP : provisionningIdPList) {
// iterate through the provisioning identity provider list to find out the default
// provisioning connector of each of the,
try {
AbstractOutboundProvisioningConnector connector;
ProvisioningConnectorConfig defaultConnector = fIdP
.getDefaultProvisioningConnectorConfig();
if (defaultConnector != null) {
// if no default provisioning connector defined for this identity provider,
// we can safely ignore it - need not to worry about provisioning.
String connectorType = fIdP.getDefaultProvisioningConnectorConfig()
.getName();
boolean enableJitProvisioning = false;
if (fIdP.getJustInTimeProvisioningConfig() != null
&& fIdP.getJustInTimeProvisioningConfig().isProvisioningEnabled()) {
enableJitProvisioning = true;
}
connector = getOutboundProvisioningConnector(fIdP,
registeredConnectorFactories, tenantDomainName,
enableJitProvisioning);
// add to the provisioning connectors list. there will be one item for each
// provisioning identity provider found in the out-bound provisioning
// configuration of the local service provider.
if (connector != null) {
RuntimeProvisioningConfig proConfig = new RuntimeProvisioningConfig();
proConfig
.setProvisioningConnectorEntry(new SimpleEntry<>(
connectorType, connector));
proConfig.setBlocking(defaultConnector.isBlocking());
connectors.put(fIdP.getIdentityProviderName(), proConfig);
}
}
} catch (IdentityProviderManagementException e) {
throw new IdentityProvisioningException("Error while retrieving idp configuration for "
+ fIdP.getIdentityProviderName(), e);
}
}
}
try {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext
.getThreadLocalCarbonContext();
carbonContext.setTenantId(MultitenantConstants.SUPER_TENANT_ID);
carbonContext.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
entry = new ServiceProviderProvisioningConnectorCacheEntry();
entry.setConnectors(connectors);
ServiceProviderProvisioningConnectorCache.getInstance().addToCache(key, entry);
} finally {
PrivilegedCarbonContext.endTenantFlow();
if (tenantDomain != null) {
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain);
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId);
}
}
if (log.isDebugEnabled()) {
log.debug("Entry added successfully ");
}
return connectors;
}
/**
* @param fIdP
* @param registeredConnectorFactories
* @param tenantDomainName
* @param enableJitProvisioning
* @return
* @throws IdentityProviderManagementException
* @throws UserStoreException
*/
private AbstractOutboundProvisioningConnector getOutboundProvisioningConnector(
IdentityProvider fIdP,
Map<String, AbstractProvisioningConnectorFactory> registeredConnectorFactories,
String tenantDomainName, boolean enableJitProvisioning)
throws IdentityProviderManagementException, IdentityProvisioningException {
String idpName = fIdP.getIdentityProviderName();
// name of the default provisioning connector.
String connectorType = fIdP.getDefaultProvisioningConnectorConfig().getName();
// get identity provider configuration.
fIdP = IdentityProviderManager.getInstance().getEnabledIdPByName(idpName, tenantDomainName);
if (fIdP == null) {
// This is an exceptional situation. If service provider has connected to an
// identity provider, that identity provider must be present in the system.
// If not its an exception.
throw new IdentityProvisioningException(
"Provisioning identity provider not available in the system. Idp Name : "
+ idpName);
}
// get a list of provisioning connectors associated with the provisioning
// identity provider.
ProvisioningConnectorConfig[] provisioningConfigs = fIdP.getProvisioningConnectorConfigs();
if (provisioningConfigs != null && provisioningConfigs.length > 0) {
for (ProvisioningConnectorConfig defaultProvisioningConfig : provisioningConfigs) {
if (!connectorType.equals(defaultProvisioningConfig.getName())
|| !defaultProvisioningConfig.isEnabled()) {
// we need to find the provisioning connector selected by the service provider.
continue;
}
// this is how we match the configuration to the runtime. the provisioning
// connector factory should be registered with the system, with the exact
// name available in the corresponding configuration.
AbstractProvisioningConnectorFactory factory = registeredConnectorFactories
.get(connectorType);
// get the provisioning properties associated with a given provisioning
// connector.
Property[] provisioningProperties = defaultProvisioningConfig
.getProvisioningProperties();
if (enableJitProvisioning) {
Property jitEnabled = new Property();
jitEnabled.setName(IdentityProvisioningConstants.JIT_PROVISIONING_ENABLED);
jitEnabled.setValue("1");
provisioningProperties = IdentityApplicationManagementUtil.concatArrays(
provisioningProperties, new Property[]{jitEnabled});
}
Property userIdClaimURL = new Property();
userIdClaimURL.setName("userIdClaimUri");
if (fIdP.getClaimConfig() != null && fIdP.getClaimConfig().getUserClaimURI() != null) {
userIdClaimURL.setValue(fIdP.getClaimConfig().getUserClaimURI());
} else {
userIdClaimURL.setValue("");
}
List<Property> provisioningPropertiesList = new ArrayList<>(Arrays.asList(provisioningProperties));
provisioningPropertiesList.add(userIdClaimURL);
provisioningProperties = new Property[provisioningPropertiesList.size()];
provisioningProperties = provisioningPropertiesList.toArray(provisioningProperties);
// get the runtime provisioning connector associate the provisioning
// identity provider. any given time, a given provisioning identity provider
// can only be associated with a single provisioning connector.
return factory.getConnector(idpName, provisioningProperties, tenantDomainName);
}
}
return null;
}
/**
* @param provisioningEntity
* @param serviceProviderIdentifier
* @param inboundClaimDialect
* @param tenantDomainName
* @param jitProvisioning
* @throws IdentityProvisioningException
*/
public void provision(ProvisioningEntity provisioningEntity, String serviceProviderIdentifier,
String inboundClaimDialect, String tenantDomainName, boolean jitProvisioning)
throws IdentityProvisioningException {
try {
if(provisioningEntity.getEntityName() == null) {
setProvisioningEntityName(provisioningEntity);
}
// get details about the service provider.any in-bound provisioning request via
// the SOAP based API (or the management console) - or SCIM API with HTTP Basic
// Authentication is considered as coming from the local service provider.
ServiceProvider serviceProvider = ApplicationManagementService.getInstance()
.getServiceProvider(serviceProviderIdentifier, tenantDomainName);
if (serviceProvider == null) {
throw new IdentityProvisioningException("Invalid service provider name : "
+ serviceProviderIdentifier);
}
ClaimMapping[] spClaimMappings = null;
// if we know the serviceProviderClaimDialect - we do not need to find it again.
if (inboundClaimDialect == null && serviceProvider.getClaimConfig() != null) {
spClaimMappings = serviceProvider.getClaimConfig().getClaimMappings();
}
// get all the provisioning connectors associated with local service provider for
// out-bound provisioning.
// TODO: stop loading connectors all the time.
Map<String, RuntimeProvisioningConfig> connectors = getOutboundProvisioningConnectors(
serviceProvider, tenantDomainName);
ProvisioningEntity outboundProEntity;
ExecutorService executors = null;
if (MapUtils.isNotEmpty(connectors)) {
executors = Executors.newFixedThreadPool(connectors.size());
}
for (Iterator<Entry<String, RuntimeProvisioningConfig>> iterator = connectors
.entrySet().iterator(); iterator.hasNext(); ) {
Entry<String, RuntimeProvisioningConfig> entry = iterator.next();
Entry<String, AbstractOutboundProvisioningConnector> connectorEntry = entry
.getValue().getProvisioningConnectorEntry();
AbstractOutboundProvisioningConnector connector = connectorEntry.getValue();
String connectorType = connectorEntry.getKey();
String idPName = entry.getKey();
IdentityProvider provisioningIdp = IdentityProviderManager.getInstance()
.getIdPByName(idPName, tenantDomainName);
if (provisioningIdp == null) {
// this is an exception if we cannot find the provisioning identity provider
// by its name.
throw new IdentityProvisioningException("Invalid identity provider name : "
+ idPName);
}
String outboundClaimDialect = connector.getClaimDialectUri();
if (outboundClaimDialect == null
&& (provisioningIdp.getClaimConfig() == null || provisioningIdp
.getClaimConfig().isLocalClaimDialect())) {
outboundClaimDialect = IdentityProvisioningConstants.WSO2_CARBON_DIALECT;
}
ClaimMapping[] idpClaimMappings = null;
if (provisioningIdp.getClaimConfig() != null) {
idpClaimMappings = provisioningIdp.getClaimConfig().getClaimMappings();
}
// TODO: this should happen asynchronously in a different thread.
// create a new provisioning entity object for each provisioning identity
// provider.
Map<ClaimMapping, List<String>> mapppedClaims;
// get mapped claims.
mapppedClaims = getMappedClaims(inboundClaimDialect, outboundClaimDialect,
provisioningEntity, spClaimMappings, idpClaimMappings, tenantDomainName);
if (provisioningIdp.getPermissionAndRoleConfig() != null) {
// update with mapped user groups.
updateProvisioningUserWithMappedRoles(provisioningEntity, provisioningIdp
.getPermissionAndRoleConfig().getRoleMappings());
}
// check whether we already have the provisioned identifier - if
// so set it.
ProvisionedIdentifier provisionedIdentifier;
provisionedIdentifier = getProvisionedEntityIdentifier(idPName, connectorType,
provisioningEntity, tenantDomainName);
ProvisioningOperation provisioningOp = provisioningEntity.getOperation();
if (ProvisioningOperation.DELETE.equals(provisioningOp) &&
(provisionedIdentifier == null || provisionedIdentifier.getIdentifier() == null)) {
//No provisioning identifier found. User has not outbound provisioned to this idp. So no need to
// send outbound delete request. Skip the flow
return;
}
if (provisionedIdentifier == null || provisionedIdentifier.getIdentifier() == null) {
provisioningOp = ProvisioningOperation.POST;
}
String[] provisionByRoleList = new String[0];
if (provisioningIdp.getProvisioningRole() != null) {
provisionByRoleList = provisioningIdp.getProvisioningRole().split(",");
}
if (provisioningEntity.getEntityType() == ProvisioningEntityType.GROUP && Arrays.asList
(provisionByRoleList).contains(provisioningEntity.getEntityName())) {
Map<ClaimMapping, List<String>> attributes = provisioningEntity.getAttributes();
List<String> newUsersList = attributes.get(ClaimMapping.build(
IdentityProvisioningConstants.NEW_USER_CLAIM_URI, null, null, false));
List<String> deletedUsersList = attributes.get(ClaimMapping.build(
IdentityProvisioningConstants.DELETED_USER_CLAIM_URI, null, null, false));
Map<ClaimMapping, List<String>> mappedUserClaims;
ProvisionedIdentifier provisionedUserIdentifier;
for (String user : newUsersList) {
ProvisioningEntity inboundProvisioningEntity = getInboundProvisioningEntity(provisioningEntity,
tenantDomainName, ProvisioningOperation.POST, user);
provisionedUserIdentifier = getProvisionedEntityIdentifier(idPName, connectorType,
inboundProvisioningEntity, tenantDomainName);
if (provisionedUserIdentifier != null && provisionedUserIdentifier.getIdentifier() != null) {
continue;
}
mappedUserClaims = getMappedClaims(inboundClaimDialect, outboundClaimDialect,
inboundProvisioningEntity, spClaimMappings, idpClaimMappings, tenantDomainName);
outboundProEntity = new ProvisioningEntity(ProvisioningEntityType.USER,
user, ProvisioningOperation.POST, mappedUserClaims);
Callable<Boolean> proThread = new ProvisioningThread(outboundProEntity,
tenantDomainName, connector, connectorType, idPName, dao);
outboundProEntity.setIdentifier(provisionedIdentifier);
outboundProEntity.setJitProvisioning(jitProvisioning);
boolean isBlocking = entry.getValue().isBlocking();
executeOutboundProvisioning(provisioningEntity, executors, connectorType, idPName, proThread, isBlocking);
}
for (String user : deletedUsersList) {
ProvisioningEntity inboundProvisioningEntity = getInboundProvisioningEntity(provisioningEntity,
tenantDomainName, ProvisioningOperation.DELETE, user);
provisionedUserIdentifier = getProvisionedEntityIdentifier(idPName, connectorType,
inboundProvisioningEntity, tenantDomainName);
if (provisionedUserIdentifier != null && provisionedUserIdentifier.getIdentifier() != null) {
mappedUserClaims = getMappedClaims(inboundClaimDialect, outboundClaimDialect,
inboundProvisioningEntity, spClaimMappings, idpClaimMappings, tenantDomainName);
outboundProEntity = new ProvisioningEntity(ProvisioningEntityType.USER,
user, ProvisioningOperation.DELETE, mappedUserClaims);
Callable<Boolean> proThread = new ProvisioningThread(outboundProEntity,
tenantDomainName, connector, connectorType, idPName, dao);
outboundProEntity.setIdentifier(provisionedUserIdentifier);
outboundProEntity.setJitProvisioning(jitProvisioning);
boolean isBlocking = entry.getValue().isBlocking();
executeOutboundProvisioning(provisioningEntity, executors, connectorType, idPName, proThread, isBlocking);
}
}
} else {
// see whether the given provisioning entity satisfies the conditions to be
// provisioned.
if (!canUserBeProvisioned(provisioningEntity, provisionByRoleList, tenantDomainName)) {
if (!canUserBeDeProvisioned(provisionedIdentifier)) {
continue;
} else {
// This is used when user removed from the provisioning role
provisioningOp = ProvisioningOperation.DELETE;
}
}
outboundProEntity = new ProvisioningEntity(provisioningEntity.getEntityType(),
provisioningEntity.getEntityName(), provisioningOp, mapppedClaims);
Callable<Boolean> proThread = new ProvisioningThread(outboundProEntity,
tenantDomainName, connector, connectorType, idPName, dao);
outboundProEntity.setIdentifier(provisionedIdentifier);
outboundProEntity.setJitProvisioning(jitProvisioning);
boolean isBlocking = entry.getValue().isBlocking();
executeOutboundProvisioning(provisioningEntity, executors, connectorType, idPName, proThread, isBlocking);
}
}
if (executors != null) {
executors.shutdown();
}
} catch (CarbonException | IdentityApplicationManagementException | IdentityProviderManagementException | UserStoreException e) {
throw new IdentityProvisioningException("Error occurred while checking for user " +
"provisioning", e);
}
}
private void executeOutboundProvisioning(ProvisioningEntity provisioningEntity, ExecutorService executors, String connectorType,
String idPName, Callable<Boolean> proThread, boolean isBlocking) throws IdentityProvisioningException {
if (!isBlocking) {
executors.submit(proThread);
} else {
try {
boolean success = proThread.call();
if (!success) {
if (executors != null) {
executors.shutdown();
}
throw new IdentityProvisioningException
(generateMessageOnFailureProvisioningOperation(idPName,
connectorType, provisioningEntity));
//DO Rollback
}
} catch (Exception e) { //call() of Callable interface throws this exception
handleException(idPName, connectorType, provisioningEntity, executors, e);
}
}
}
private ProvisioningEntity getInboundProvisioningEntity(ProvisioningEntity provisioningEntity,
String tenantDomain, ProvisioningOperation operation,
String userName) throws CarbonException,
UserStoreException {
Map<ClaimMapping, List<String>> outboundAttributes = new HashMap<>();
if (userName != null) {
outboundAttributes.put(ClaimMapping.build(
IdentityProvisioningConstants.USERNAME_CLAIM_URI, null, null, false),
Arrays.asList(new String[]{userName}));
}
List<String> roleListOfUser = getUserRoles(userName, tenantDomain);
if (roleListOfUser != null) {
outboundAttributes.put(ClaimMapping.build(
IdentityProvisioningConstants.GROUP_CLAIM_URI, null, null, false), roleListOfUser);
}
String domainAwareName = userName;
String domainName = getDomainFromName(provisioningEntity.getEntityName());
if (domainName != null && !domainName.equals(UserCoreConstants.INTERNAL_DOMAIN)) {
if (log.isDebugEnabled()) {
log.debug("Adding domain name : " + domainName + " to user : " + userName);
}
domainAwareName = UserCoreUtil.addDomainToName(userName, domainName);
}
ProvisioningEntity inboundProvisioningEntity = new ProvisioningEntity(
ProvisioningEntityType.USER, domainAwareName, operation, outboundAttributes);
inboundProvisioningEntity.setInboundAttributes(getUserClaims(userName, tenantDomain));
return inboundProvisioningEntity;
}
private String generateMessageOnFailureProvisioningOperation(String idPName,
String connectorType,
ProvisioningEntity provisioningEntity) {
if (log.isDebugEnabled()) {
String errMsg = "Provisioning failed for IDP = " + idPName + " " +
"Connector Type =" + connectorType + " ";
errMsg += " Provisioned entity name = " +
provisioningEntity.getEntityName() +
" For operation = " + provisioningEntity.getOperation() + " " +
"failed ";
log.error(errMsg);
}
return "Provisioning failed for IDP = " + idPName + " " +
"with Entity name=" + provisioningEntity.getEntityName();
}
/**
* @param provisioningEntity
* @param idPRoleMapping
*/
private void updateProvisioningUserWithMappedRoles(ProvisioningEntity provisioningEntity,
RoleMapping[] idPRoleMapping) {
if (provisioningEntity.getEntityType() != ProvisioningEntityType.USER
|| idPRoleMapping == null || idPRoleMapping.length == 0) {
return;
}
List<String> userGroups = getGroupNames(provisioningEntity.getAttributes());
if (CollectionUtils.isEmpty(userGroups)) {
return;
}
Map<String, String> mappedRoles = new HashMap<>();
for (RoleMapping mapping : idPRoleMapping) {
mappedRoles.put(mapping.getLocalRole().getLocalRoleName(), mapping.getRemoteRole());
}
List<String> mappedUserGroups = new ArrayList<>();
for (Iterator<String> iterator = userGroups.iterator(); iterator.hasNext(); ) {
String userGroup = iterator.next();
String mappedGroup = null;
if ((mappedGroup = mappedRoles.get(userGroup)) != null) {
mappedUserGroups.add(mappedGroup);
}
}
ProvisioningUtil.setClaimValue(IdentityProvisioningConstants.GROUP_CLAIM_URI,
provisioningEntity.getAttributes(), mappedUserGroups);
}
/**
* @param inboundClaimDialect
* @param outboundClaimDialect
* @param provisioningEntity
* @param spClaimMappings
* @param idpClaimMappings
* @return
* @throws IdentityApplicationManagementException
*/
private Map<ClaimMapping, List<String>> getMappedClaims(String inboundClaimDialect,
String outboundClaimDialect, ProvisioningEntity provisioningEntity,
ClaimMapping[] spClaimMappings, ClaimMapping[] idpClaimMappings, String tenantDomainName)
throws IdentityApplicationManagementException {
// if we have any in-bound attributes - need to convert those into out-bound
// attributes in a form understood by the external provisioning providers.
Map<String, String> inboundAttributes = provisioningEntity.getInboundAttributes();
if (outboundClaimDialect != null) {
// out-bound claim dialect is not provisioning provider specific. Its
// specific to the connector.
if (inboundClaimDialect == null) {
// in-bound claim dialect is service provider specific.
// we have read the claim mapping from service provider claim
// configuration.
return ProvisioningUtil.getMappedClaims(outboundClaimDialect,
inboundAttributes, spClaimMappings, provisioningEntity.getAttributes(),
tenantDomainName);
} else {
// in-bound claim dialect is not service provider specific.
// its been supplied by the corresponding in-bound provisioning servlet
// or listener.
return ProvisioningUtil.getMappedClaims(outboundClaimDialect,
inboundAttributes, inboundClaimDialect, provisioningEntity.getAttributes(),
tenantDomainName);
}
} else {
// out-bound claim dialect is provisioning provider specific.
// we have read the claim mapping from identity provider claim
// configuration
if (inboundClaimDialect == null) {
// in-bound claim dialect is service provider specific.
// we have read the claim mapping from service provider claim
// configuration.
return ProvisioningUtil.getMappedClaims(idpClaimMappings,
inboundAttributes, spClaimMappings, provisioningEntity.getAttributes());
} else {
// in-bound claim dialect is not service provider specific.
// its been supplied by the corresponding in-bound provisioning servlet
// or listener.
return ProvisioningUtil.getMappedClaims(idpClaimMappings,
inboundAttributes, inboundClaimDialect, provisioningEntity.getAttributes(),
tenantDomainName);
}
}
}
/**
* @param attributeMap
* @return
*/
protected List<String> getGroupNames(Map<ClaimMapping, List<String>> attributeMap) {
return ProvisioningUtil.getClaimValues(attributeMap,
IdentityProvisioningConstants.GROUP_CLAIM_URI, null);
}
/**
* @param attributeMap
* @return
*/
private String getUserName(Map<ClaimMapping, List<String>> attributeMap) {
List<String> userList = ProvisioningUtil.getClaimValues(attributeMap,
IdentityProvisioningConstants.USERNAME_CLAIM_URI, null);
if (CollectionUtils.isNotEmpty(userList)) {
return userList.get(0);
}
return null;
}
/**
* @param provisioningEntity
* @param provisionByRoleList
* @param tenantDomain
* @return
* @throws CarbonException
* @throws UserStoreException
*/
protected boolean canUserBeProvisioned(ProvisioningEntity provisioningEntity,
String[] provisionByRoleList, String tenantDomain) throws UserStoreException,
CarbonException {
if (provisioningEntity.getEntityType() != ProvisioningEntityType.USER
|| provisionByRoleList == null || provisionByRoleList.length == 0) {
// we apply restrictions only for users.
// if service provider's out-bound provisioning configuration does not define any roles
// to be provisioned then we apply no restrictions.
return true;
}
String userName = getUserName(provisioningEntity.getAttributes());
List<String> roleListOfUser = getUserRoles(userName, tenantDomain);
for (String provisionByRole : provisionByRoleList) {
if (roleListOfUser.contains(provisionByRole)) {
return true;
}
}
return false;
}
/**
* @param provisionedIdentifier
* @return
* @throws CarbonException
* @throws UserStoreException
*/
protected boolean canUserBeDeProvisioned(ProvisionedIdentifier provisionedIdentifier)
throws UserStoreException, CarbonException, IdentityApplicationManagementException {
// check whether we already have the provisioned identifier.current idp is not eligible to
// provisioning.
if (provisionedIdentifier != null && provisionedIdentifier.getIdentifier() != null) {
return true;
}
return false;
}
/**
* @param userName
* @param tenantDomain
* @return
* @throws CarbonException
* @throws UserStoreException
*/
private List<String> getUserRoles(String userName, String tenantDomain) throws CarbonException,
UserStoreException {
RegistryService registryService = IdentityProvisionServiceComponent.getRegistryService();
RealmService realmService = IdentityProvisionServiceComponent.getRealmService();
UserRealm realm = AnonymousSessionUtil.getRealmByTenantDomain(registryService,
realmService, tenantDomain);
UserStoreManager userstore = null;
userstore = realm.getUserStoreManager();
String[] newRoles = userstore.getRoleListOfUser(userName);
return Arrays.asList(newRoles);
}
/**
* @param userName
* @param tenantDomain
* @return
* @throws CarbonException
* @throws UserStoreException
*/
private Map<String, String> getUserClaims(String userName, String tenantDomain) throws CarbonException,
UserStoreException {
Map<String, String> inboundAttributes = new HashMap<>();
RegistryService registryService = IdentityProvisionServiceComponent.getRegistryService();
RealmService realmService = IdentityProvisionServiceComponent.getRealmService();
UserRealm realm = AnonymousSessionUtil.getRealmByTenantDomain(registryService,
realmService, tenantDomain);
UserStoreManager userstore = null;
userstore = realm.getUserStoreManager();
Claim[] claimArray = null;
try {
claimArray = userstore.getUserClaimValues(userName, null);
} catch (UserStoreException e) {
if (e.getMessage().contains("UserNotFound")) {
if (log.isDebugEnabled()) {
log.debug("User " + userName + " not found in user store");
}
} else {
throw e;
}
}
if (claimArray != null) {
for (Claim claim : claimArray) {
inboundAttributes.put(claim.getClaimUri(), claim.getValue());
}
}
return inboundAttributes;
}
private String getUserIdClaimValue(String userIdClaimURI, String tenantDomainName) {
return null;
}
/**
* @param idpName
* @param connectorType
* @param provisioningEntity
* @param tenantDomain
* @return
* @throws IdentityApplicationManagementException
*/
private ProvisionedIdentifier getProvisionedEntityIdentifier(String idpName,
String connectorType, ProvisioningEntity provisioningEntity, String tenantDomain)
throws IdentityApplicationManagementException {
int tenantId = getTenantIdOfDomain(tenantDomain);
return dao.getProvisionedIdentifier(idpName, connectorType, provisioningEntity, tenantId, tenantDomain);
}
private String getDomainFromName(String name) {
int index;
if ((index = name.indexOf("/")) > 0) {
String domain = name.substring(0, index);
return domain;
}
return UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME;
}
/**
* introduce extendability for handling provisioning exceptions
*
* @param idPName
* @param connectorType
* @param provisioningEntity
* @param executors
* @param e
*/
protected void handleException(String idPName, String connectorType, ProvisioningEntity provisioningEntity,
ExecutorService executors, Exception e) {
if (log.isDebugEnabled()) {
log.debug(generateMessageOnFailureProvisioningOperation(idPName, connectorType, provisioningEntity), e);
}
}
/**
* If ProvisioningEntity does not contains entity name, load it from from IDP_PROVISIONING_ENTITY table
* @param provisioningEntity
* @return
* @throws IdentityApplicationManagementException
*/
private ProvisioningEntity setProvisioningEntityName(ProvisioningEntity provisioningEntity)
throws IdentityApplicationManagementException {
String provisionedEntityName = dao.getProvisionedEntityNameByLocalId(
ProvisioningUtil.getAttributeValue(provisioningEntity, IdentityProvisioningConstants.ID_CLAIM_URI));
Map<org.wso2.carbon.identity.application.common.model.ClaimMapping, List<String>> attributeList =
provisioningEntity.getAttributes();
ProvisioningEntityType provisioningEntityType = provisioningEntity.getEntityType();
ProvisioningOperation provisioningOperation = provisioningEntity.getOperation();
if (ProvisioningEntityType.USER.equals(provisioningEntityType)) {
attributeList.put(org.wso2.carbon.identity.application.common.model.ClaimMapping
.build(IdentityProvisioningConstants.USERNAME_CLAIM_URI, null, null,
false), Arrays.asList(new String[] { provisionedEntityName }));
} else if (ProvisioningEntityType.GROUP.equals(provisioningEntityType)) {
if (ProvisioningOperation.PUT.equals(provisioningOperation)) {
String oldGroupName = provisionedEntityName;
String currentGroupName = ProvisioningUtil
.getAttributeValue(provisioningEntity, IdentityProvisioningConstants.GROUP_CLAIM_URI);
if (!oldGroupName.equals(currentGroupName)) {
attributeList.put(org.wso2.carbon.identity.application.common.model.ClaimMapping
.build(IdentityProvisioningConstants.OLD_GROUP_NAME_CLAIM_URI,
null, null, false),
Arrays.asList(new String[] { oldGroupName }));
attributeList.put(org.wso2.carbon.identity.application.common.model.ClaimMapping
.build(IdentityProvisioningConstants.NEW_GROUP_NAME_CLAIM_URI,
null, null, false),
Arrays.asList(new String[] { currentGroupName }));
}
} else if (ProvisioningOperation.PATCH.equals(provisioningOperation)) {
String oldGroupName = provisionedEntityName;
String currentGroupName = ProvisioningUtil
.getAttributeValue(provisioningEntity, IdentityProvisioningConstants.GROUP_CLAIM_URI);
if (currentGroupName == null) {
currentGroupName = oldGroupName;
}
if (!oldGroupName.equals(currentGroupName)) {
attributeList.put(org.wso2.carbon.identity.application.common.model.ClaimMapping
.build(IdentityProvisioningConstants.OLD_GROUP_NAME_CLAIM_URI,
null, null, false),
Arrays.asList(new String[] { oldGroupName }));
attributeList.put(org.wso2.carbon.identity.application.common.model.ClaimMapping
.build(IdentityProvisioningConstants.NEW_GROUP_NAME_CLAIM_URI,
null, null, false),
Arrays.asList(new String[] { currentGroupName }));
}
}
}
String userStoreDomain = ProvisioningUtil.getAttributeValue(provisioningEntity,
IdentityProvisioningConstants.USER_STORE_DOMAIN_CLAIM_URI);
if (log.isDebugEnabled()) {
log.debug("Adding domain name : " + userStoreDomain + " to name : " + provisionedEntityName);
}
provisioningEntity
.setEntityName(UserCoreUtil.addDomainToName(provisionedEntityName, userStoreDomain));
return provisioningEntity;
}
}