Package org.apache.syncope.core.propagation.impl

Source Code of org.apache.syncope.core.propagation.impl.PropagationManager

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF 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.apache.syncope.core.propagation.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.syncope.common.mod.AttributeMod;
import org.apache.syncope.common.mod.MembershipMod;
import org.apache.syncope.common.mod.UserMod;
import org.apache.syncope.common.to.AttributeTO;
import org.apache.syncope.common.to.MembershipTO;
import org.apache.syncope.common.types.AttributableType;
import org.apache.syncope.common.types.MappingPurpose;
import org.apache.syncope.common.types.ResourceOperation;
import org.apache.syncope.core.connid.ConnObjectUtil;
import org.apache.syncope.core.persistence.beans.AbstractMappingItem;
import org.apache.syncope.core.persistence.beans.AbstractSubject;
import org.apache.syncope.core.persistence.beans.AbstractVirAttr;
import org.apache.syncope.core.persistence.beans.ExternalResource;
import org.apache.syncope.core.persistence.beans.PropagationTask;
import org.apache.syncope.core.persistence.beans.membership.Membership;
import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
import org.apache.syncope.core.persistence.dao.NotFoundException;
import org.apache.syncope.core.persistence.dao.ResourceDAO;
import org.apache.syncope.core.propagation.PropagationByResource;
import org.apache.syncope.core.propagation.PropagationTaskExecutor;
import org.apache.syncope.core.rest.controller.UnauthorizedRoleException;
import org.apache.syncope.core.rest.data.AbstractAttributableDataBinder;
import org.apache.syncope.core.rest.data.RoleDataBinder;
import org.apache.syncope.core.rest.data.UserDataBinder;
import org.apache.syncope.core.util.AttributableUtil;
import org.apache.syncope.core.util.jexl.JexlUtil;
import org.apache.syncope.core.util.MappingUtil;
import org.apache.syncope.core.workflow.WorkflowResult;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
import org.identityconnectors.framework.common.objects.AttributeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

/**
* Manage the data propagation to external resources.
*/
@Transactional(rollbackFor = { Throwable.class })
public class PropagationManager {

    /**
     * Logger.
     */
    protected static final Logger LOG = LoggerFactory.getLogger(PropagationManager.class);

    /**
     * User DataBinder.
     */
    @Autowired
    private UserDataBinder userDataBinder;

    /**
     * User DataBinder.
     */
    @Autowired
    private RoleDataBinder roleDataBinder;

    /**
     * Resource DAO.
     */
    @Autowired
    private ResourceDAO resourceDAO;

    /**
     * ConnObjectUtil.
     */
    @Autowired
    private ConnObjectUtil connObjectUtil;

    /**
     * Create the user on every associated resource.
     *
     * @param wfResult user to be propagated (and info associated), as per result from workflow
     * @param password to be set
     * @param vAttrs virtual attributes to be set
     * @param membershipTOs user memberships
     * @return list of propagation tasks
     * @throws NotFoundException if user is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given user
     */
    public List<PropagationTask> getUserCreateTaskIds(final WorkflowResult<Map.Entry<Long, Boolean>> wfResult,
            final String password, final List<AttributeTO> vAttrs, final List<MembershipTO> membershipTOs)
            throws NotFoundException, UnauthorizedRoleException {

        return getUserCreateTaskIds(wfResult, password, vAttrs, null, membershipTOs);
    }

    /**
     * Create the user on every associated resource.
     *
     * @param wfResult user to be propagated (and info associated), as per result from workflow
     * @param password to be set
     * @param vAttrs virtual attributes to be set
     * @param noPropResourceNames external resources not to be considered for propagation
     * @param membershipTOs user memberships
     * @return list of propagation tasks
     * @throws NotFoundException if user is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given user
     */
    public List<PropagationTask> getUserCreateTaskIds(final WorkflowResult<Map.Entry<Long, Boolean>> wfResult,
            final String password, final Collection<AttributeTO> vAttrs,
            final Set<String> noPropResourceNames, final List<MembershipTO> membershipTOs)
            throws NotFoundException, UnauthorizedRoleException {

        return getUserCreateTaskIds(
                wfResult.getResult().getKey(),
                wfResult.getResult().getValue(),
                wfResult.getPropByRes(),
                password,
                vAttrs,
                membershipTOs,
                noPropResourceNames);
    }

    public List<PropagationTask> getUserCreateTaskIds(
            final Long id,
            final Boolean enabled,
            final PropagationByResource propByRes,
            final String password,
            final Collection<AttributeTO> vAttrs,
            final Collection<MembershipTO> membershipTOs,
            final Collection<String> noPropResourceNames)
            throws NotFoundException, UnauthorizedRoleException {

        SyncopeUser user = userDataBinder.getUserFromId(id);
        if (vAttrs != null && !vAttrs.isEmpty()) {
            userDataBinder.fillVirtual(user, vAttrs, AttributableUtil.getInstance(AttributableType.USER));

        }
        for (Membership membership : user.getMemberships()) {
            MembershipTO membershipTO;
            if (membership.getVirAttrs() != null && !membership.getVirAttrs().isEmpty()) {
                membershipTO = findMembershipTO(membership, membershipTOs);
                if (membershipTO != null) {
                    userDataBinder.fillVirtual(membership, membershipTO.getVirAttrs(), AttributableUtil.getInstance(
                            AttributableType.MEMBERSHIP));
                }
            }
        }
        return getCreateTaskIds(user, password, enabled, propByRes, noPropResourceNames);
    }

    /**
     * Create the role on every associated resource.
     *
     * @param wfResult user to be propagated (and info associated), as per result from workflow
     * @param vAttrs virtual attributes to be set
     * @return list of propagation tasks
     * @throws NotFoundException if role is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given role
     */
    public List<PropagationTask> getRoleCreateTaskIds(final WorkflowResult<Long> wfResult,
            final List<AttributeTO> vAttrs)
            throws NotFoundException, UnauthorizedRoleException {

        return getRoleCreateTaskIds(wfResult, vAttrs, null);
    }

    /**
     * Create the role on every associated resource.
     *
     * @param wfResult role to be propagated (and info associated), as per result from workflow
     * @param vAttrs virtual attributes to be set
     * @param noPropResourceNames external resources performing not to be considered for propagation
     * @return list of propagation tasks
     * @throws NotFoundException if role is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given role
     */
    public List<PropagationTask> getRoleCreateTaskIds(
            final WorkflowResult<Long> wfResult,
            final Collection<AttributeTO> vAttrs,
            final Collection<String> noPropResourceNames)
            throws NotFoundException, UnauthorizedRoleException {
        return getRoleCreateTaskIds(wfResult.getResult(), vAttrs, wfResult.getPropByRes(), noPropResourceNames);
    }

    /**
     * Create the role on every associated resource.
     *
     * @param id role id
     * @param vAttrs virtual attributes to be set
     * @param propByRes operation to be performed per resource
     * @param noPropResourceNames external resources performing not to be considered for propagation
     * @return list of propagation tasks
     * @throws NotFoundException if role is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given role
     */
    public List<PropagationTask> getRoleCreateTaskIds(
            final Long id,
            final Collection<AttributeTO> vAttrs,
            final PropagationByResource propByRes,
            final Collection<String> noPropResourceNames)
            throws NotFoundException, UnauthorizedRoleException {

        SyncopeRole role = roleDataBinder.getRoleFromId(id);
        if (vAttrs != null && !vAttrs.isEmpty()) {
            roleDataBinder.fillVirtual(role, vAttrs, AttributableUtil.getInstance(AttributableType.ROLE));
        }

        return getCreateTaskIds(role, null, null, propByRes, noPropResourceNames);
    }

    protected List<PropagationTask> getCreateTaskIds(final AbstractSubject subject,
            final String password, final Boolean enable,
            final PropagationByResource propByRes,
            final Collection<String> noPropResourceNames) {

        if (propByRes == null || propByRes.isEmpty()) {
            return Collections.<PropagationTask>emptyList();
        }

        if (noPropResourceNames != null) {
            propByRes.get(ResourceOperation.CREATE).removeAll(noPropResourceNames);
        }

        return createTasks(subject, password, true, null, null, null, null, enable, false, propByRes);
    }

    /**
     * Performs update on each resource associated to the user excluding the specified into 'resourceNames' parameter.
     *
     * @param user to be propagated
     * @param enable whether user must be enabled or not
     * @param noPropResourceNames external resource names not to be considered for propagation
     * @return list of propagation tasks
     * @throws NotFoundException if user is not found
     */
    public List<PropagationTask> getUserUpdateTaskIds(final SyncopeUser user, final Boolean enable,
            final Set<String> noPropResourceNames)
            throws NotFoundException {

        return getUpdateTaskIds(
                user, // SyncopeUser to be updated on external resources
                null, // no password
                false,
                enable, // status to be propagated
                Collections.<String>emptySet(), // no virtual attributes to be managed
                Collections.<AttributeMod>emptySet(), // no virtual attributes to be managed
                null, // no propagation by resources
                noPropResourceNames,
                Collections.<MembershipMod>emptySet());
    }

    /**
     * Performs update on each resource associated to the user.
     *
     * @param wfResult user to be propagated (and info associated), as per result from workflow
     * @param changePwd whether password should be included for propagation attributes or not
     * @param noPropResourceNames external resources not to be considered for propagation
     * @return list of propagation tasks
     * @throws NotFoundException if user is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given user
     */
    public List<PropagationTask> getUserUpdateTaskIds(final WorkflowResult<Map.Entry<UserMod, Boolean>> wfResult,
            final boolean changePwd, final Collection<String> noPropResourceNames)
            throws NotFoundException, UnauthorizedRoleException {

        SyncopeUser user = userDataBinder.getUserFromId(wfResult.getResult().getKey().getId());
        return getUpdateTaskIds(user,
                wfResult.getResult().getKey().getPassword(),
                changePwd,
                wfResult.getResult().getValue(),
                wfResult.getResult().getKey().getVirAttrsToRemove(),
                wfResult.getResult().getKey().getVirAttrsToUpdate(),
                wfResult.getPropByRes(),
                noPropResourceNames,
                wfResult.getResult().getKey().getMembershipsToAdd());
    }

    public List<PropagationTask> getUserUpdateTaskIds(final WorkflowResult<Map.Entry<UserMod, Boolean>> wfResult) {
        UserMod userMod = wfResult.getResult().getKey();

        // Propagate password update only to requested resources
        List<PropagationTask> tasks = new ArrayList<PropagationTask>();
        if (userMod.getPwdPropRequest() == null) {
            // a. no specific password propagation request: generate propagation tasks for any resource associated
            tasks = getUserUpdateTaskIds(wfResult, true, null);
        } else {
            // b. generate the propagation task list in two phases: first the ones containing password,
            // the the rest (with no password)
            final PropagationByResource origPropByRes = new PropagationByResource();
            origPropByRes.merge(wfResult.getPropByRes());

            Set<String> pwdResourceNames = new HashSet<String>(userMod.getPwdPropRequest().getResourceNames());
            Set<String> currentResourceNames = userDataBinder.getResourceNamesForUserId(userMod.getId());
            pwdResourceNames.retainAll(currentResourceNames);
            PropagationByResource pwdPropByRes = new PropagationByResource();
            pwdPropByRes.addAll(ResourceOperation.UPDATE, pwdResourceNames);
            if (!pwdPropByRes.isEmpty()) {
                Set<String> toBeExcluded = new HashSet<String>(currentResourceNames);
                toBeExcluded.addAll(userMod.getResourcesToAdd());
                toBeExcluded.removeAll(pwdResourceNames);
                tasks.addAll(getUserUpdateTaskIds(wfResult, true, toBeExcluded));
            }

            final PropagationByResource nonPwdPropByRes = new PropagationByResource();
            nonPwdPropByRes.merge(origPropByRes);
            nonPwdPropByRes.removeAll(pwdResourceNames);
            nonPwdPropByRes.purge();
            if (!nonPwdPropByRes.isEmpty()) {
                tasks.addAll(getUserUpdateTaskIds(wfResult, false, pwdResourceNames));
            }
        }

        return tasks;
    }

    /**
     * Performs update on each resource associated to the role.
     *
     * @param wfResult role to be propagated (and info associated), as per result from workflow
     * @param vAttrsToBeRemoved virtual attributes to be removed
     * @param vAttrsToBeUpdated virtual attributes to be added
     * @return list of propagation tasks
     * @throws NotFoundException if role is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given role
     */
    public List<PropagationTask> getRoleUpdateTaskIds(final WorkflowResult<Long> wfResult,
            final Set<String> vAttrsToBeRemoved, final Set<AttributeMod> vAttrsToBeUpdated)
            throws NotFoundException, UnauthorizedRoleException {

        return getRoleUpdateTaskIds(wfResult, vAttrsToBeRemoved, vAttrsToBeUpdated, null);
    }

    /**
     * Performs update on each resource associated to the role.
     *
     * @param wfResult role to be propagated (and info associated), as per result from workflow
     * @param vAttrsToBeRemoved virtual attributes to be removed
     * @param vAttrsToBeUpdated virtual attributes to be added
     * @param noPropResourceNames external resource names not to be considered for propagation
     * @return list of propagation tasks
     * @throws NotFoundException if role is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given role
     */
    public List<PropagationTask> getRoleUpdateTaskIds(final WorkflowResult<Long> wfResult,
            final Set<String> vAttrsToBeRemoved, final Set<AttributeMod> vAttrsToBeUpdated,
            final Set<String> noPropResourceNames)
            throws NotFoundException, UnauthorizedRoleException {

        SyncopeRole role = roleDataBinder.getRoleFromId(wfResult.getResult());
        return getUpdateTaskIds(role, null, false, null,
                vAttrsToBeRemoved, vAttrsToBeUpdated, wfResult.getPropByRes(), noPropResourceNames,
                Collections.<MembershipMod>emptySet());
    }

    public List<PropagationTask> getUpdateTaskIds(final AbstractSubject subject,
            final String password, final boolean changePwd, final Boolean enable,
            final Set<String> vAttrsToBeRemoved, final Set<AttributeMod> vAttrsToBeUpdated,
            final PropagationByResource propByRes, final Collection<String> noPropResourceNames,
            final Set<MembershipMod> membershipsToAdd)
            throws NotFoundException {

        AbstractAttributableDataBinder binder = subject instanceof SyncopeUser
                ? userDataBinder : roleDataBinder;

        PropagationByResource localPropByRes = binder.fillVirtual(subject, vAttrsToBeRemoved == null
                ? Collections.<String>emptySet()
                : vAttrsToBeRemoved, vAttrsToBeUpdated == null
                ? Collections.<AttributeMod>emptySet()
                : vAttrsToBeUpdated, AttributableUtil.getInstance(subject));

        // SYNCOPE-458 fill membership virtual attributes
        if (subject instanceof SyncopeUser) {
            final SyncopeUser user = (SyncopeUser) subject;
            for (Membership membership : user.getMemberships()) {
                if (membership.getVirAttrs() != null && !membership.getVirAttrs().isEmpty()) {
                    final MembershipMod membershipMod = findMembershipMod(membership, membershipsToAdd);
                    if (membershipMod != null) {
                        binder.fillVirtual(membership, membershipMod.getVirAttrsToRemove() == null
                                ? Collections.<String>emptySet()
                                : membershipMod.getVirAttrsToRemove(),
                                membershipMod.getVirAttrsToUpdate() == null ? Collections.<AttributeMod>emptySet()
                                : membershipMod.getVirAttrsToUpdate(), AttributableUtil.getInstance(
                                AttributableType.MEMBERSHIP));
                    }
                }
            }
        }

        if (propByRes == null || propByRes.isEmpty()) {
            localPropByRes.addAll(ResourceOperation.UPDATE, subject.getResourceNames());
        } else {
            localPropByRes.merge(propByRes);
        }

        if (noPropResourceNames != null) {
            localPropByRes.removeAll(noPropResourceNames);
        }

        Map<String, AttributeMod> vAttrsToBeUpdatedMap = null;
        if (vAttrsToBeUpdated != null) {
            vAttrsToBeUpdatedMap = new HashMap<String, AttributeMod>();
            for (AttributeMod attrMod : vAttrsToBeUpdated) {
                vAttrsToBeUpdatedMap.put(attrMod.getSchema(), attrMod);
            }
        }

        // SYNCOPE-458 fill membership virtual attributes to be updated map
        Map<String, AttributeMod> membVAttrsToBeUpdatedMap = new HashMap<String, AttributeMod>();
        for (MembershipMod membershipMod : membershipsToAdd) {
            for (AttributeMod attrMod : membershipMod.getVirAttrsToUpdate()) {
                membVAttrsToBeUpdatedMap.put(attrMod.getSchema(), attrMod);
            }
        }

        // SYNCOPE-458 fill membership virtual attributes to be removed set
        final Set<String> membVAttrsToBeRemoved = new HashSet<String>();
        for (MembershipMod membershipMod : membershipsToAdd) {
            membVAttrsToBeRemoved.addAll(membershipMod.getVirAttrsToRemove());
        }

        return createTasks(subject, password, changePwd,
                vAttrsToBeRemoved, vAttrsToBeUpdatedMap, membVAttrsToBeRemoved, membVAttrsToBeUpdatedMap, enable, false,
                localPropByRes);
    }

    /**
     * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
     * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
     * the creation fails onto a mandatory resource.
     *
     * @param userId to be deleted
     * @return list of propagation tasks
     * @throws NotFoundException if user is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given user
     */
    public List<PropagationTask> getUserDeleteTaskIds(final Long userId)
            throws NotFoundException, UnauthorizedRoleException {

        return getUserDeleteTaskIds(userId, Collections.<String>emptySet());
    }

    /**
     * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
     * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
     * the creation fails onto a mandatory resource.
     *
     * @param userId to be deleted
     * @param noPropResourceName name of external resource not to be considered for propagation
     * @return list of propagation tasks
     * @throws NotFoundException if user is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given user
     */
    public List<PropagationTask> getUserDeleteTaskIds(final Long userId, final String noPropResourceName)
            throws NotFoundException, UnauthorizedRoleException {
        return getUserDeleteTaskIds(userId, Collections.<String>singleton(noPropResourceName));
    }

    /**
     * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
     * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
     * the creation fails onto a mandatory resource.
     *
     * @param userId to be deleted
     * @param noPropResourceNames name of external resources not to be considered for propagation
     * @return list of propagation tasks
     * @throws NotFoundException if user is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given user
     */
    public List<PropagationTask> getUserDeleteTaskIds(final Long userId, final Collection<String> noPropResourceNames)
            throws NotFoundException, UnauthorizedRoleException {

        SyncopeUser user = userDataBinder.getUserFromId(userId);
        return getDeleteTaskIds(user, user.getResourceNames(), noPropResourceNames);
    }

    /**
     * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
     * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
     * the creation fails onto a mandatory resource.
     *
     * @param userId to be deleted
     * @param noPropResourceNames name of external resources not to be considered for propagation
     * @return list of propagation tasks
     * @throws NotFoundException if user is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given user
     */
    public List<PropagationTask> getUserDeleteTaskIds(
            final Long userId, final Set<String> resourceNames, final Collection<String> noPropResourceNames)
            throws NotFoundException, UnauthorizedRoleException {

        SyncopeUser user = userDataBinder.getUserFromId(userId);
        return getDeleteTaskIds(user, resourceNames, noPropResourceNames);
    }

    /**
     * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
     * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
     * the creation fails onto a mandatory resource.
     *
     * @param wfResult user to be propagated (and info associated), as per result from workflow
     * @return list of propagation tasks
     */
    public List<PropagationTask> getUserDeleteTaskIds(final WorkflowResult<Long> wfResult) {
        SyncopeUser user = userDataBinder.getUserFromId(wfResult.getResult());
        return createTasks(user, null, false, null, null, null, null, false, true, wfResult.getPropByRes());
    }

    /**
     * Perform delete on each resource associated to the role. It is possible to ask for a mandatory provisioning for
     * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
     * the creation fails onto a mandatory resource.
     *
     * @param roleId to be deleted
     * @return list of propagation tasks
     * @throws NotFoundException if role is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given role
     */
    public List<PropagationTask> getRoleDeleteTaskIds(final Long roleId)
            throws NotFoundException, UnauthorizedRoleException {

        return getRoleDeleteTaskIds(roleId, Collections.<String>emptySet());
    }

    /**
     * Perform delete on each resource associated to the role. It is possible to ask for a mandatory provisioning for
     * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
     * the creation fails onto a mandatory resource.
     *
     * @param roleId to be deleted
     * @param noPropResourceName name of external resource not to be considered for propagation
     * @return list of propagation tasks
     * @throws NotFoundException if role is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given role
     */
    public List<PropagationTask> getRoleDeleteTaskIds(final Long roleId, final String noPropResourceName)
            throws NotFoundException, UnauthorizedRoleException {

        return getRoleDeleteTaskIds(roleId, Collections.<String>singleton(noPropResourceName));
    }

    /**
     * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
     * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
     * the creation fails onto a mandatory resource.
     *
     * @param roleId to be deleted
     * @param noPropResourceNames name of external resources not to be considered for propagation
     * @return list of propagation tasks
     * @throws NotFoundException if role is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given role
     */
    public List<PropagationTask> getRoleDeleteTaskIds(final Long roleId, final Collection<String> noPropResourceNames)
            throws NotFoundException, UnauthorizedRoleException {

        SyncopeRole role = roleDataBinder.getRoleFromId(roleId);
        return getDeleteTaskIds(role, role.getResourceNames(), noPropResourceNames);
    }

    /**
     * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
     * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
     * the creation fails onto a mandatory resource.
     *
     * @param roleId to be deleted
     * @param noPropResourceNames name of external resources not to be considered for propagation
     * @return list of propagation tasks
     * @throws NotFoundException if role is not found
     * @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given role
     */
    public List<PropagationTask> getRoleDeleteTaskIds(
            final Long roleId, final Set<String> resourceNames, final Collection<String> noPropResourceNames)
            throws NotFoundException, UnauthorizedRoleException {

        SyncopeRole role = roleDataBinder.getRoleFromId(roleId);
        return getDeleteTaskIds(role, resourceNames, noPropResourceNames);
    }

    protected List<PropagationTask> getDeleteTaskIds(
            final AbstractSubject subject,
            final Set<String> resourceNames,
            final Collection<String> noPropResourceNames) {

        final PropagationByResource propByRes = new PropagationByResource();
        propByRes.set(ResourceOperation.DELETE, resourceNames);
        if (noPropResourceNames != null && !noPropResourceNames.isEmpty()) {
            propByRes.get(ResourceOperation.DELETE).removeAll(noPropResourceNames);
        }
        return createTasks(subject, null, false, null, null, null, null, false, true, propByRes);
    }

    /**
     * Create propagation tasks.
     *
     * @param <T> user / role
     * @param subject user / role to be provisioned
     * @param password cleartext password to be provisioned
     * @param changePwd whether password should be included for propagation attributes or not
     * @param vAttrsToBeRemoved virtual attributes to be removed
     * @param vAttrsToBeUpdated virtual attributes to be added
     * @param membVAttrsToBeRemoved membership virtual attributes to be removed
     * @param membVAttrsToBeUpdatedMap membership virtual attributes to be added
     * @param enable whether user must be enabled or not
     * @param deleteOnResource whether user / role must be deleted anyway from external resource or not
     * @param propByRes operation to be performed per resource
     * @return list of propagation tasks created
     */
    protected <T extends AbstractSubject> List<PropagationTask> createTasks(final T subject,
            final String password, final boolean changePwd,
            final Set<String> vAttrsToBeRemoved, final Map<String, AttributeMod> vAttrsToBeUpdated,
            final Set<String> membVAttrsToBeRemoved, final Map<String, AttributeMod> membVAttrsToBeUpdatedMap,
            final Boolean enable, final boolean deleteOnResource, final PropagationByResource propByRes) {

        LOG.debug("Provisioning subject {}:\n{}", subject, propByRes);

        final AttributableUtil attrUtil = AttributableUtil.getInstance(subject);

        if (!propByRes.get(ResourceOperation.CREATE).isEmpty()
                && vAttrsToBeRemoved != null && vAttrsToBeUpdated != null) {

            connObjectUtil.retrieveVirAttrValues(subject, attrUtil);

            // update vAttrsToBeUpdated as well
            for (AbstractVirAttr virAttr : subject.getVirAttrs()) {
                final String schema = virAttr.getSchema().getName();

                final AttributeMod attributeMod = new AttributeMod();
                attributeMod.setSchema(schema);
                attributeMod.getValuesToBeAdded().addAll(virAttr.getValues());

                vAttrsToBeUpdated.put(schema, attributeMod);
            }
        }

        // Avoid duplicates - see javadoc
        propByRes.purge();
        LOG.debug("After purge: {}", propByRes);

        final List<PropagationTask> tasks = new ArrayList<PropagationTask>();

        for (ResourceOperation operation : ResourceOperation.values()) {
            for (String resourceName : propByRes.get(operation)) {
                final ExternalResource resource = resourceDAO.find(resourceName);
                if (resource == null) {
                    LOG.error("Invalid resource name specified: {}, ignoring...", resourceName);
                } else if (attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION).isEmpty()) {
                    LOG.warn("Requesting propagation for {} but no propagation mapping provided for {}",
                            attrUtil.getType(), resource);
                } else {
                    PropagationTask task = new PropagationTask();
                    task.setResource(resource);
                    task.setObjectClassName(connObjectUtil.fromAttributable(subject).getObjectClassValue());
                    task.setSubjectType(attrUtil.getType());
                    if (!deleteOnResource) {
                        task.setSubjectId(subject.getId());
                    }
                    task.setPropagationOperation(operation);
                    task.setPropagationMode(resource.getPropagationMode());
                    task.setOldAccountId(propByRes.getOldAccountId(resource.getName()));

                    Map.Entry<String, Set<Attribute>> preparedAttrs = MappingUtil.prepareAttributes(attrUtil, subject,
                            password, changePwd, vAttrsToBeRemoved, vAttrsToBeUpdated, membVAttrsToBeRemoved,
                            membVAttrsToBeUpdatedMap, enable, resource);
                    task.setAccountId(preparedAttrs.getKey());

                    // Check if any of mandatory attributes (in the mapping) is missing or not received any value:
                    // if so, add special attributes that will be evaluated by PropagationTaskExecutor
                    List<String> mandatoryMissing = new ArrayList<String>();
                    List<String> mandatoryNullOrEmpty = new ArrayList<String>();
                    for (AbstractMappingItem item : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
                        if (!item.isAccountid()
                                && JexlUtil.evaluateMandatoryCondition(item.getMandatoryCondition(), subject)) {

                            Attribute attr = AttributeUtil.find(item.getExtAttrName(), preparedAttrs.getValue());
                            if (attr == null) {
                                mandatoryMissing.add(item.getExtAttrName());
                            } else if (attr.getValue() == null || attr.getValue().isEmpty()) {
                                mandatoryNullOrEmpty.add(item.getExtAttrName());
                            }
                        }
                    }
                    if (!mandatoryMissing.isEmpty()) {
                        preparedAttrs.getValue().add(AttributeBuilder.build(
                                PropagationTaskExecutor.MANDATORY_MISSING_ATTR_NAME, mandatoryMissing));
                    }
                    if (!mandatoryNullOrEmpty.isEmpty()) {
                        preparedAttrs.getValue().add(AttributeBuilder.build(
                                PropagationTaskExecutor.MANDATORY_NULL_OR_EMPTY_ATTR_NAME, mandatoryNullOrEmpty));
                    }

                    task.setAttributes(preparedAttrs.getValue());
                    tasks.add(task);

                    LOG.debug("PropagationTask created: {}", task);
                }
            }
        }

        return tasks;
    }

    private MembershipTO findMembershipTO(final Membership membership, final Collection<MembershipTO> memberships) {
        for (MembershipTO membershipTO : memberships) {
            if (membershipTO.getRoleId() == membership.getSyncopeRole().getId()) {
                return membershipTO;
            }
        }
        LOG.error("No MembershipTO found for membership {}", membership);
        return null;
    }

    private MembershipMod findMembershipMod(final Membership membership, final Set<MembershipMod> membershipMods) {
        for (MembershipMod membershipMod : membershipMods) {
            if (membershipMod.getRole() == membership.getSyncopeRole().getId()) {
                return membershipMod;
            }
        }
        LOG.error("No MembershipMod found for membership {}", membership);
        return null;
    }
}
TOP

Related Classes of org.apache.syncope.core.propagation.impl.PropagationManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.