/* * 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.provisioning.java.pushpull; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.collections4.IteratorUtils; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.common.lib.policy.PullPolicySpec; import org.apache.syncope.core.spring.ApplicationContextProvider; import org.apache.syncope.core.persistence.api.dao.GroupDAO; import org.apache.syncope.core.persistence.api.dao.NotFoundException; import org.apache.syncope.core.persistence.api.dao.UserDAO; import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO; import org.apache.syncope.core.persistence.api.entity.VirSchema; import org.apache.syncope.core.persistence.api.entity.group.Group; import org.apache.syncope.core.persistence.api.entity.resource.MappingItem; import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit; import org.apache.syncope.core.persistence.api.entity.resource.Provision; import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask; import org.apache.syncope.core.provisioning.api.Connector; import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.apache.syncope.core.provisioning.api.pushpull.ReconciliationFilterBuilder; import org.apache.syncope.core.persistence.api.entity.task.PullTask; import org.apache.syncope.core.provisioning.api.pushpull.AnyObjectPullResultHandler; import org.apache.syncope.core.provisioning.api.pushpull.PullActions; import org.apache.syncope.core.provisioning.api.pushpull.GroupPullResultHandler; import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullExecutor; import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullResultHandler; import org.apache.syncope.core.provisioning.api.pushpull.UserPullResultHandler; import org.apache.syncope.core.provisioning.java.utils.MappingUtils; import org.identityconnectors.framework.common.objects.ObjectClass; import org.identityconnectors.framework.common.objects.OperationOptions; import org.identityconnectors.framework.common.objects.SyncToken; public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> implements SyncopePullExecutor { @Autowired private UserDAO userDAO; @Autowired private GroupDAO groupDAO; @Autowired private VirSchemaDAO virSchemaDAO; @Autowired private PullUtils pullUtils; private final Map<ObjectClass, SyncToken> latestSyncTokens = new HashMap<>(); @Override public void setLatestSyncToken(final ObjectClass objectClass, final SyncToken latestSyncToken) { latestSyncTokens.put(objectClass, latestSyncToken); } private void setGroupOwners(final GroupPullResultHandler ghandler) { for (Map.Entry<String, String> entry : ghandler.getGroupOwnerMap().entrySet()) { Group group = groupDAO.find(entry.getKey()); if (group == null) { throw new NotFoundException("Group " + entry.getKey()); } if (StringUtils.isBlank(entry.getValue())) { group.setGroupOwner(null); group.setUserOwner(null); } else { String userKey = pullUtils.findMatchingAnyKey( anyTypeDAO.findUser(), entry.getValue(), ghandler.getProfile().getTask().getResource(), ghandler.getProfile().getConnector()); if (userKey == null) { String groupKey = pullUtils.findMatchingAnyKey( anyTypeDAO.findGroup(), entry.getValue(), ghandler.getProfile().getTask().getResource(), ghandler.getProfile().getConnector()); if (groupKey != null) { group.setGroupOwner(groupDAO.find(groupKey)); } } else { group.setUserOwner(userDAO.find(userKey)); } } groupDAO.save(group); } } @Override protected String doExecuteProvisioning( final PullTask pullTask, final Connector connector, final boolean dryRun) throws JobExecutionException { LOG.debug("Executing pull on {}", pullTask.getResource()); List<PullActions> actions = new ArrayList<>(); for (String className : pullTask.getActionsClassNames()) { try { Class<?> actionsClass = Class.forName(className); PullActions pullActions = (PullActions) ApplicationContextProvider.getBeanFactory(). createBean(actionsClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true); actions.add(pullActions); } catch (Exception e) { LOG.warn("Class '{}' not found", className, e); } } ProvisioningProfile<PullTask, PullActions> profile = new ProvisioningProfile<>(connector, pullTask); profile.getActions().addAll(actions); profile.setDryRun(dryRun); profile.setResAct(getPullPolicySpec(pullTask).getConflictResolutionAction()); latestSyncTokens.clear(); if (!profile.isDryRun()) { for (PullActions action : actions) { action.beforeAll(profile); } } // First OrgUnits... if (pullTask.getResource().getOrgUnit() != null) { OrgUnit orgUnit = pullTask.getResource().getOrgUnit(); OperationOptions options = MappingUtils.buildOperationOptions(orgUnit); SyncopePullResultHandler rhandler = (SyncopePullResultHandler) ApplicationContextProvider.getBeanFactory(). createBean(RealmPullResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false); rhandler.setProfile(profile); rhandler.setPullExecutor(this); try { switch (pullTask.getPullMode()) { case INCREMENTAL: if (!dryRun) { latestSyncTokens.put(orgUnit.getObjectClass(), orgUnit.getSyncToken()); } connector.sync( orgUnit.getObjectClass(), orgUnit.getSyncToken(), rhandler, options); if (!dryRun) { orgUnit.setSyncToken(latestSyncTokens.get(orgUnit.getObjectClass())); resourceDAO.save(orgUnit.getResource()); } break; case FILTERED_RECONCILIATION: ReconciliationFilterBuilder filterBuilder = (ReconciliationFilterBuilder) ApplicationContextProvider.getBeanFactory(). createBean(Class.forName(pullTask.getReconciliationFilterBuilderClassName()), AbstractBeanDefinition.AUTOWIRE_BY_NAME, false); connector.filteredReconciliation(orgUnit.getObjectClass(), filterBuilder, rhandler, options); break; case FULL_RECONCILIATION: default: connector.fullReconciliation(orgUnit.getObjectClass(), rhandler, options); break; } } catch (Throwable t) { throw new JobExecutionException("While pulling from connector", t); } } // ...then provisions for any types AnyObjectPullResultHandler ahandler = (AnyObjectPullResultHandler) ApplicationContextProvider.getBeanFactory(). createBean(AnyObjectPullResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false); ahandler.setProfile(profile); ahandler.setPullExecutor(this); UserPullResultHandler uhandler = (UserPullResultHandler) ApplicationContextProvider.getBeanFactory(). createBean(UserPullResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false); uhandler.setProfile(profile); uhandler.setPullExecutor(this); GroupPullResultHandler ghandler = (GroupPullResultHandler) ApplicationContextProvider.getBeanFactory(). createBean(GroupPullResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false); ghandler.setProfile(profile); ghandler.setPullExecutor(this); for (Provision provision : pullTask.getResource().getProvisions()) { if (provision.getMapping() != null) { SyncopePullResultHandler handler; switch (provision.getAnyType().getKind()) { case USER: handler = uhandler; break; case GROUP: handler = ghandler; break; case ANY_OBJECT: default: handler = ahandler; } try { Set<MappingItem> linkinMappingItems = new HashSet<>(); for (VirSchema virSchema : virSchemaDAO.findByProvision(provision)) { linkinMappingItems.add(virSchema.asLinkingMappingItem()); } Iterator<MappingItem> mapItems = IteratorUtils.chainedIterator( provision.getMapping().getItems().iterator(), linkinMappingItems.iterator()); OperationOptions options = MappingUtils.buildOperationOptions(mapItems); switch (pullTask.getPullMode()) { case INCREMENTAL: if (!dryRun) { latestSyncTokens.put(provision.getObjectClass(), provision.getSyncToken()); } connector.sync( provision.getObjectClass(), provision.getSyncToken(), handler, options); if (!dryRun) { provision.setSyncToken(latestSyncTokens.get(provision.getObjectClass())); resourceDAO.save(provision.getResource()); } break; case FILTERED_RECONCILIATION: ReconciliationFilterBuilder filterBuilder = (ReconciliationFilterBuilder) ApplicationContextProvider.getBeanFactory(). createBean(Class.forName(pullTask.getReconciliationFilterBuilderClassName()), AbstractBeanDefinition.AUTOWIRE_BY_NAME, false); connector.filteredReconciliation(provision.getObjectClass(), filterBuilder, handler, options); break; case FULL_RECONCILIATION: default: connector.fullReconciliation(provision.getObjectClass(), handler, options); break; } } catch (Throwable t) { throw new JobExecutionException("While pulling from connector", t); } } } try { setGroupOwners(ghandler); } catch (Exception e) { LOG.error("While setting group owners", e); } if (!profile.isDryRun()) { for (PullActions action : actions) { action.afterAll(profile); } } String result = createReport(profile.getResults(), pullTask.getResource(), dryRun); LOG.debug("Pull result: {}", result); return result; } private PullPolicySpec getPullPolicySpec(final ProvisioningTask task) { PullPolicySpec pullPolicySpec; if (task instanceof PullTask) { pullPolicySpec = task.getResource().getPullPolicy() == null ? null : task.getResource().getPullPolicy().getSpecification(); } else { pullPolicySpec = null; } // step required because the call <policy>.getSpecification() could return a null value return pullPolicySpec == null ? new PullPolicySpec() : pullPolicySpec; } }