You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2015/09/25 16:43:33 UTC
[1/2] syncope git commit: [SYNCOPE-698] Implementation completed
Repository: syncope
Updated Branches:
refs/heads/master 5537d29e9 -> 72e6ceb06
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index 2568f45..4a203f9 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -156,6 +156,9 @@ abstract class AbstractAnyDataBinder {
@Autowired
protected ConnObjectUtils connObjectUtils;
+ @Autowired
+ protected MappingUtils mappingUtils;
+
protected void setRealm(final Any<?, ?, ?> any, final AnyPatch anyPatch) {
if (anyPatch.getRealm() != null && StringUtils.isNotBlank(anyPatch.getRealm().getValue())) {
Realm newRealm = realmDAO.find(anyPatch.getRealm().getValue());
@@ -231,11 +234,9 @@ abstract class AbstractAnyDataBinder {
&& (item.getPurpose() == MappingPurpose.PROPAGATION
|| item.getPurpose() == MappingPurpose.BOTH)) {
- List<PlainAttrValue> values = MappingUtils.getIntValues(
+ List<PlainAttrValue> values = mappingUtils.getIntValues(
provision, item, Collections.<Any<?, ?, ?>>singletonList(any), null);
- if ((values == null || values.isEmpty())
- && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) {
-
+ if (values.isEmpty() && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) {
missingAttrNames.add(item.getIntAttrName());
}
}
@@ -360,8 +361,8 @@ abstract class AbstractAnyDataBinder {
plainAttrDAO.delete(attr.getKey(), anyUtils.plainAttrClass());
for (ExternalResource resource : resources) {
- for (MappingItem mapItem : MappingUtils.getMappingItems(
- resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) {
+ for (MappingItem mapItem
+ : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
if (schema.getKey().equals(mapItem.getIntAttrName())
&& mapItem.getIntMappingType() == anyUtils.plainIntMappingType()) {
@@ -410,8 +411,8 @@ abstract class AbstractAnyDataBinder {
derAttrDAO.delete(attr);
for (ExternalResource resource : resources) {
- for (MappingItem mapItem : MappingUtils.getMappingItems(
- resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) {
+ for (MappingItem mapItem
+ : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
if (schema.getKey().equals(mapItem.getIntAttrName())
&& mapItem.getIntMappingType() == anyUtils.derIntMappingType()) {
@@ -704,7 +705,7 @@ abstract class AbstractAnyDataBinder {
+ " on resource '" + resource.getKey() + "'");
}
- connObjectKeys.put(resource.getKey(), MappingUtils.getConnObjectKeyValue(any, provision));
+ connObjectKeys.put(resource.getKey(), mappingUtils.getConnObjectKeyValue(any, provision));
}
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java
new file mode 100644
index 0000000..3810a87
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java
@@ -0,0 +1,40 @@
+/*
+ * 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.data;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
+
+/**
+ * Default (empty) implementation of {@link MappingItemTransformer}.
+ */
+public class DefaultMappingItemTransformer implements MappingItemTransformer {
+
+ @Override
+ public List<PlainAttrValue> beforePropagation(final List<PlainAttrValue> values) {
+ return values;
+ }
+
+ @Override
+ public List<Object> beforeSync(final List<Object> values) {
+ return values;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
index 4ccc0c4..69a2e9d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
@@ -22,13 +22,13 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
+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.lib.types.AuditElements;
import org.apache.syncope.common.lib.types.AuditElements.Result;
-import org.apache.syncope.common.lib.types.MappingPurpose;
import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
import org.apache.syncope.common.lib.types.TraceLevel;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
@@ -148,6 +148,27 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
return result;
}
+ /**
+ * Transform a
+ * <code>Collection</code> of {@link Attribute} instances into a {@link Map}. The key to each element in the map is
+ * the <i>name</i> of an
+ * <code>Attribute</code>. The value of each element in the map is the
+ * <code>Attribute</code> instance with that name. <br/> Different from the original because: <ul> <li>map keys are
+ * transformed toUpperCase()</li> <li>returned map is mutable</li> </ul>
+ *
+ * @param attributes set of attribute to transform to a map.
+ * @return a map of string and attribute.
+ *
+ * @see org.identityconnectors.framework.common.objects.AttributeUtil#toMap(java.util.Collection)
+ */
+ private Map<String, Attribute> toMap(final Collection<? extends Attribute> attributes) {
+ Map<String, Attribute> map = new HashMap<>();
+ for (Attribute attr : attributes) {
+ map.put(attr.getName().toUpperCase(), attr);
+ }
+ return map;
+ }
+
protected void createOrUpdate(
final PropagationTask task,
final ConnectorObject beforeObj,
@@ -155,10 +176,10 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
final Set<String> propagationAttempted) {
// set of attributes to be propagated
- final Set<Attribute> attributes = new HashSet<>(task.getAttributes());
+ Set<Attribute> attributes = new HashSet<>(task.getAttributes());
// check if there is any missing or null / empty mandatory attribute
- List<Object> mandatoryAttrNames = new ArrayList<>();
+ Set<Object> mandatoryAttrNames = new HashSet<>();
Attribute mandatoryMissing = AttributeUtil.find(MANDATORY_MISSING_ATTR_NAME, task.getAttributes());
if (mandatoryMissing != null) {
attributes.remove(mandatoryMissing);
@@ -200,8 +221,8 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
// 2. check wether anything is actually needing to be propagated, i.e. if there is attribute
// difference between beforeObj - just read above from the connector - and the values to be propagated
- Map<String, Attribute> originalAttrMap = connObjectUtils.toMap(beforeObj.getAttributes());
- Map<String, Attribute> updateAttrMap = connObjectUtils.toMap(attributes);
+ Map<String, Attribute> originalAttrMap = toMap(beforeObj.getAttributes());
+ Map<String, Attribute> updateAttrMap = toMap(attributes);
// Only compare attribute from beforeObj that are also being updated
Set<String> skipAttrNames = originalAttrMap.keySet();
@@ -527,7 +548,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
task.getOperation(),
new ObjectClass(task.getObjectClassName()),
new Uid(connObjectKey),
- connector.getOperationOptions(MappingUtils.getMappingItems(provision, MappingPurpose.PROPAGATION)));
+ connector.getOperationOptions(MappingUtils.getPropagationMappingItems(provision)));
} catch (TimeoutException toe) {
LOG.debug("Request timeout", toe);
throw toe;
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationActions.java
index 23726ed..157fdc1 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationActions.java
@@ -24,7 +24,7 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
import org.identityconnectors.framework.common.objects.ConnectorObject;
/**
- * Default (empty) implementation of PropagationActions.
+ * Default (empty) implementation of {@link PropagationActions}.
*/
public abstract class DefaultPropagationActions implements PropagationActions {
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java
index 7437241..22feb44 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java
@@ -77,7 +77,7 @@ public class DefaultPropagationReporter implements PropagationReporter {
for (PropagationTask propagationTask : tasks) {
if (!containsPropagationStatusTO(propagationTask.getResource().getKey())) {
- final PropagationStatus propagationStatusTO = new PropagationStatus();
+ PropagationStatus propagationStatusTO = new PropagationStatus();
propagationStatusTO.setResource(propagationTask.getResource().getKey());
propagationStatusTO.setStatus(PropagationTaskExecStatus.FAILURE);
propagationStatusTO.setFailureReason(
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
index b8bc838..ebf9c99 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
@@ -34,7 +34,6 @@ import org.apache.syncope.common.lib.patch.StringPatchItem;
import org.apache.syncope.common.lib.patch.UserPatch;
import org.apache.syncope.common.lib.to.AttrTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.MappingPurpose;
import org.apache.syncope.common.lib.types.PropagationByResource;
import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
@@ -106,6 +105,9 @@ public class PropagationManagerImpl implements PropagationManager {
@Autowired
protected VirAttrHandler virAttrHandler;
+ @Autowired
+ protected MappingUtils mappingUtils;
+
protected Any<?, ?, ?> find(final AnyTypeKind kind, final Long key) {
AnyDAO<? extends Any<?, ?, ?>> dao;
switch (kind) {
@@ -367,7 +369,7 @@ public class PropagationManagerImpl implements PropagationManager {
} else if (provision == null) {
LOG.error("No provision specified on resource {} for type {}, ignoring...",
resource, any.getType());
- } else if (MappingUtils.getMappingItems(provision, MappingPurpose.PROPAGATION).isEmpty()) {
+ } else if (MappingUtils.getPropagationMappingItems(provision).isEmpty()) {
LOG.warn("Requesting propagation for {} but no propagation mapping provided for {}",
any.getType(), resource);
} else {
@@ -382,7 +384,7 @@ public class PropagationManagerImpl implements PropagationManager {
task.setOperation(operation);
task.setOldConnObjectKey(propByRes.getOldConnObjectKey(resource.getKey()));
- Pair<String, Set<Attribute>> preparedAttrs = MappingUtils.prepareAttrs(
+ Pair<String, Set<Attribute>> preparedAttrs = mappingUtils.prepareAttrs(
any, password, changePwd, vAttrs, enable, provision);
task.setConnObjectKey(preparedAttrs.getKey());
@@ -390,7 +392,7 @@ public class PropagationManagerImpl implements PropagationManager {
// if so, add special attributes that will be evaluated by PropagationTaskExecutor
List<String> mandatoryMissing = new ArrayList<>();
List<String> mandatoryNullOrEmpty = new ArrayList<>();
- for (MappingItem item : MappingUtils.getMappingItems(provision, MappingPurpose.PROPAGATION)) {
+ for (MappingItem item : MappingUtils.getPropagationMappingItems(provision)) {
if (!item.isConnObjectKey()
&& JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
index 8aa37d3..94936eb 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
@@ -58,12 +58,16 @@ import org.identityconnectors.framework.common.objects.ConnectorObject;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.Uid;
import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHandler<PushTask, PushActions>
implements SyncopePushResultHandler {
+ @Autowired
+ protected MappingUtils mappingUtils;
+
protected abstract String getName(Any<?, ?, ?> any);
protected void deprovision(final Any<?, ?, ?> any) {
@@ -195,7 +199,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
// Try to read remote object BEFORE any actual operation
Provision provision = profile.getTask().getResource().getProvision(any.getType());
- String connObjecKey = MappingUtils.getConnObjectKeyValue(any, provision);
+ String connObjecKey = mappingUtils.getConnObjectKeyValue(any, provision);
ConnectorObject beforeObj = getRemoteObject(connObjecKey, provision.getObjectClass());
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
index 30d2879..2ca7eaa 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
@@ -201,7 +201,7 @@ public abstract class AbstractSyncResultHandler extends AbstractSyncopeResultHan
create(anyTO, actionedDelta, UnmatchingRule.toEventName(UnmatchingRule.PROVISION), result);
}
- return Collections.<ProvisioningResult>singletonList(result);
+ return Collections.singletonList(result);
}
private void create(
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java
index 1af195e..1ed0d2c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java
@@ -18,17 +18,19 @@
*/
package org.apache.syncope.core.provisioning.java.sync;
+import static org.apache.syncope.core.misc.MappingUtils.getMappingItemTransformers;
+
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.apache.syncope.common.lib.types.MappingPurpose;
import org.apache.syncope.core.misc.MappingUtils;
import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
import org.apache.syncope.core.provisioning.api.sync.SyncCorrelationRule;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.ConnectorObject;
@@ -46,41 +48,44 @@ public class PlainAttrsSyncCorrelationRule implements SyncCorrelationRule {
@Override
public SearchCond getSearchCond(final ConnectorObject connObj) {
- // search for external attribute's name/value of each specified name
- Map<String, Attribute> extValues = new HashMap<>();
-
- for (MappingItem item : MappingUtils.getMappingItems(provision, MappingPurpose.SYNCHRONIZATION)) {
- extValues.put(item.getIntAttrName(), connObj.getAttributeByName(item.getExtAttrName()));
+ Map<String, MappingItem> mappingItems = new HashMap<>();
+ for (MappingItem item : MappingUtils.getSyncMappingItems(provision)) {
+ mappingItems.put(item.getIntAttrName(), item);
}
- // search for user/group by attribute(s) specified in the policy
+ // search for anys by attribute(s) specified in the policy
SearchCond searchCond = null;
for (String schema : plainSchemaNames) {
- Attribute value = extValues.get(schema);
-
- if (value == null) {
+ Attribute attr = mappingItems.get(schema) == null
+ ? null
+ : connObj.getAttributeByName(mappingItems.get(schema).getExtAttrName());
+ if (attr == null) {
throw new IllegalArgumentException(
"Connector object does not contains the attributes to perform the search: " + schema);
}
+ List<Object> values = attr.getValue();
+ for (MappingItemTransformer transformer : getMappingItemTransformers(mappingItems.get(schema))) {
+ values = transformer.beforeSync(values);
+ }
+
AttributeCond.Type type;
String expression = null;
- if (value.getValue() == null || value.getValue().isEmpty()
- || (value.getValue().size() == 1 && value.getValue().get(0) == null)) {
-
+ if (values == null || values.isEmpty() || (values.size() == 1 && values.get(0) == null)) {
type = AttributeCond.Type.ISNULL;
} else {
type = AttributeCond.Type.EQ;
- expression = value.getValue().size() > 1
- ? value.getValue().toString()
- : value.getValue().get(0).toString();
+ expression = values.size() > 1
+ ? values.toString()
+ : values.get(0).toString();
}
SearchCond nodeCond;
- // users: just id or username can be selected to be used
- // groups: just id or name can be selected to be used
+ // users: just key or username can be selected
+ // groups: just key or name can be selected
+ // any objects: just key can be selected
if ("key".equalsIgnoreCase(schema)
|| "username".equalsIgnoreCase(schema) || "name".equalsIgnoreCase(schema)) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java
index 6fe699b..0c01254 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java
@@ -24,7 +24,6 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.MappingPurpose;
import org.apache.syncope.common.lib.policy.SyncPolicySpec;
import org.apache.syncope.core.misc.MappingUtils;
import org.apache.syncope.core.misc.serialization.POJOHelper;
@@ -49,6 +48,7 @@ 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.persistence.api.entity.user.User;
import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
import org.apache.syncope.core.provisioning.api.sync.SyncCorrelationRule;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeUtil;
@@ -128,7 +128,7 @@ public class SyncUtils {
return found.add(obj);
}
},
- connector.getOperationOptions(MappingUtils.getMappingItems(provision, MappingPurpose.SYNCHRONIZATION)));
+ connector.getOperationOptions(MappingUtils.getSyncMappingItems(provision)));
if (found.isEmpty()) {
LOG.debug("No {} found on {} with __NAME__ {}", provision.getObjectClass(), resource, name);
@@ -172,6 +172,15 @@ public class SyncUtils {
List<Long> result = new ArrayList<>();
MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
+
+ String transfUid = uid;
+ for (MappingItemTransformer transformer : MappingUtils.getMappingItemTransformers(connObjectKeyItem)) {
+ List<Object> output = transformer.beforeSync(Collections.<Object>singletonList(transfUid));
+ if (output != null && !output.isEmpty()) {
+ transfUid = output.get(0).toString();
+ }
+ }
+
switch (connObjectKeyItem.getIntMappingType()) {
case UserPlainSchema:
case GroupPlainSchema:
@@ -180,13 +189,13 @@ public class SyncUtils {
PlainSchema schema = plainSchemaDAO.find(connObjectKeyItem.getIntAttrName());
if (schema == null) {
- value.setStringValue(uid);
+ value.setStringValue(transfUid);
} else {
try {
- value.parseValue(schema, uid);
+ value.parseValue(schema, transfUid);
} catch (ParsingValidationException e) {
- LOG.error("While parsing provided __UID__ {}", uid, e);
- value.setStringValue(uid);
+ LOG.error("While parsing provided __UID__ {}", transfUid, e);
+ value.setStringValue(transfUid);
}
}
@@ -200,7 +209,7 @@ public class SyncUtils {
case UserDerivedSchema:
case GroupDerivedSchema:
case AnyObjectDerivedSchema:
- anys = getAnyDAO(connObjectKeyItem).findByDerAttrValue(connObjectKeyItem.getIntAttrName(), uid);
+ anys = getAnyDAO(connObjectKeyItem).findByDerAttrValue(connObjectKeyItem.getIntAttrName(), transfUid);
for (Any<?, ?, ?> any : anys) {
result.add(any.getKey());
}
@@ -209,21 +218,21 @@ public class SyncUtils {
case UserKey:
case GroupKey:
case AnyObjectKey:
- Any<?, ?, ?> any = getAnyDAO(connObjectKeyItem).find(Long.parseLong(uid));
+ Any<?, ?, ?> any = getAnyDAO(connObjectKeyItem).find(Long.parseLong(transfUid));
if (any != null) {
result.add(any.getKey());
}
break;
case Username:
- User user = userDAO.find(uid);
+ User user = userDAO.find(transfUid);
if (user != null) {
result.add(user.getKey());
}
break;
case GroupName:
- Group group = groupDAO.find(uid);
+ Group group = groupDAO.find(transfUid);
if (group != null) {
result.add(group.getKey());
}
@@ -240,12 +249,12 @@ public class SyncUtils {
final ConnectorObject connObj, final SyncCorrelationRule rule, final AnyTypeKind type) {
List<Long> result = new ArrayList<>();
-
- List<Any<?, ?, ?>> anys = searchDAO.search(
+ for (Any<?, ?, ?> any : searchDAO.search(
SyncopeConstants.FULL_ADMIN_REALMS,
rule.getSearchCond(connObj),
- Collections.<OrderByClause>emptyList(), type);
- for (Any<?, ?, ?> any : anys) {
+ Collections.<OrderByClause>emptyList(),
+ type)) {
+
result.add(any.getKey());
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java
new file mode 100644
index 0000000..c620541
--- /dev/null
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java
@@ -0,0 +1,55 @@
+/*
+ * 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.fit.core.reference;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.provisioning.java.data.DefaultMappingItemTransformer;
+
+public class PrefixMappingItemTransformer extends DefaultMappingItemTransformer {
+
+ public static final String PREFIX = "PREFIX_";
+
+ @Override
+ public List<PlainAttrValue> beforePropagation(final List<PlainAttrValue> values) {
+ if (values == null || values.isEmpty() || values.get(0).getStringValue() == null) {
+ return super.beforePropagation(values);
+ } else {
+ String value = values.get(0).getStringValue();
+ values.get(0).setStringValue(PREFIX + value);
+
+ return values;
+ }
+ }
+
+ @Override
+ public List<Object> beforeSync(final List<Object> values) {
+ if (values == null || values.isEmpty() || values.get(0) == null) {
+ return super.beforeSync(values);
+ } else {
+ List<Object> newValues = new ArrayList<>(values);
+ newValues.set(0, StringUtils.substringAfter(values.get(0).toString(), PREFIX));
+
+ return newValues;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
index eaff578..75049da 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
@@ -32,6 +32,7 @@ import java.util.Set;
import javax.ws.rs.core.Response;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
+import org.apache.commons.lang3.SerializationUtils;
import org.apache.syncope.client.lib.SyncopeClient;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.SyncopeConstants;
@@ -49,6 +50,7 @@ import org.apache.syncope.common.lib.to.ResourceTO;
import org.apache.syncope.common.lib.to.GroupTO;
import org.apache.syncope.common.lib.to.ProvisionTO;
import org.apache.syncope.common.lib.policy.SyncPolicyTO;
+import org.apache.syncope.common.lib.to.MappingItemTO;
import org.apache.syncope.common.lib.to.SyncTaskTO;
import org.apache.syncope.common.lib.to.TaskExecTO;
import org.apache.syncope.common.lib.to.UserTO;
@@ -356,47 +358,78 @@ public class SyncTaskITCase extends AbstractTaskITCase {
@Test
public void reconcileFromScriptedSQL() {
- // 0. reset sync token
+ // 0. reset sync token and set MappingItemTransformer
ResourceTO resource = resourceService.read(RESOURCE_NAME_DBSCRIPTED);
+ ResourceTO originalResource = SerializationUtils.clone(resource);
ProvisionTO provision = resource.getProvision("PRINTER");
assertNotNull(provision);
- provision.setSyncToken(null);
- resourceService.update(resource);
-
- // 1. create printer on external resource
- AnyObjectTO anyObjectTO = AnyObjectITCase.getSampleTO("sync");
- anyObjectTO = createAnyObject(anyObjectTO);
- assertNotNull(anyObjectTO);
-
- // 2. unlink any existing printer and delete from Syncope (printer is now only on external resource)
- PagedResult<AnyObjectTO> matchingPrinters = anyObjectService.search(
- SyncopeClient.getAnySearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
- fiql(SyncopeClient.getAnyObjectSearchConditionBuilder().type("PRINTER").and().
- is("location").equalTo("sync*").query()).build());
- assertTrue(matchingPrinters.getSize() > 0);
- for (AnyObjectTO printer : matchingPrinters.getResult()) {
- DeassociationPatch deassociationPatch = new DeassociationPatch();
- deassociationPatch.setKey(printer.getKey());
- deassociationPatch.setAction(ResourceDeassociationAction.UNLINK);
- deassociationPatch.getResources().add(RESOURCE_NAME_DBSCRIPTED);
- anyObjectService.deassociate(deassociationPatch);
- anyObjectService.delete(printer.getKey());
- }
+ try {
+ provision.setSyncToken(null);
+
+ MappingItemTO mappingItem = CollectionUtils.find(
+ provision.getMapping().getItems(), new Predicate<MappingItemTO>() {
+
+ @Override
+ public boolean evaluate(final MappingItemTO object) {
+ return "location".equals(object.getIntAttrName());
+ }
+ });
+ assertNotNull(mappingItem);
+ mappingItem.getMappingItemTransformerClassNames().clear();
+ mappingItem.getMappingItemTransformerClassNames().add(PrefixMappingItemTransformer.class.getName());
+
+ resourceService.update(resource);
+
+ // 1. create printer on external resource
+ AnyObjectTO anyObjectTO = AnyObjectITCase.getSampleTO("sync");
+ String originalLocation = anyObjectTO.getPlainAttrMap().get("location").getValues().get(0);
+ assertFalse(originalLocation.startsWith(PrefixMappingItemTransformer.PREFIX));
+
+ anyObjectTO = createAnyObject(anyObjectTO);
+ assertNotNull(anyObjectTO);
+
+ // 2. verify that PrefixMappingItemTransformer was applied during propagation
+ // (location starts with given prefix on external resource)
+ ConnObjectTO connObjectTO = resourceService.
+ readConnObject(RESOURCE_NAME_DBSCRIPTED, anyObjectTO.getType(), anyObjectTO.getKey());
+ assertFalse(anyObjectTO.getPlainAttrMap().get("location").getValues().get(0).
+ startsWith(PrefixMappingItemTransformer.PREFIX));
+ assertTrue(connObjectTO.getPlainAttrMap().get("location").getValues().get(0).
+ startsWith(PrefixMappingItemTransformer.PREFIX));
+
+ // 3. unlink any existing printer and delete from Syncope (printer is now only on external resource)
+ PagedResult<AnyObjectTO> matchingPrinters = anyObjectService.search(
+ SyncopeClient.getAnySearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
+ fiql(SyncopeClient.getAnyObjectSearchConditionBuilder().type("PRINTER").and().
+ is("location").equalTo("sync*").query()).build());
+ assertTrue(matchingPrinters.getSize() > 0);
+ for (AnyObjectTO printer : matchingPrinters.getResult()) {
+ DeassociationPatch deassociationPatch = new DeassociationPatch();
+ deassociationPatch.setKey(printer.getKey());
+ deassociationPatch.setAction(ResourceDeassociationAction.UNLINK);
+ deassociationPatch.getResources().add(RESOURCE_NAME_DBSCRIPTED);
+ anyObjectService.deassociate(deassociationPatch);
+ anyObjectService.delete(printer.getKey());
+ }
- // 3. synchronize
- execProvisioningTask(taskService, 28L, 50, false);
+ // 4. synchronize
+ execProvisioningTask(taskService, 28L, 50, false);
- // 4. verify that printer was re-created in Syncope
- matchingPrinters = anyObjectService.search(
- SyncopeClient.getAnySearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
- fiql(SyncopeClient.getAnyObjectSearchConditionBuilder().type("PRINTER").and().
- is("location").equalTo("sync*").query()).build());
- assertTrue(matchingPrinters.getSize() > 0);
+ // 5. verify that printer was re-created in Syncope (implies that location does not start with given prefix,
+ // hence PrefixMappingItemTransformer was applied during sync)
+ matchingPrinters = anyObjectService.search(
+ SyncopeClient.getAnySearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
+ fiql(SyncopeClient.getAnyObjectSearchConditionBuilder().type("PRINTER").and().
+ is("location").equalTo("sync*").query()).build());
+ assertTrue(matchingPrinters.getSize() > 0);
- // 5. verify that synctoken was updated
- assertNotNull(
- resourceService.read(RESOURCE_NAME_DBSCRIPTED).getProvision(anyObjectTO.getType()).getSyncToken());
+ // 6. verify that synctoken was updated
+ assertNotNull(
+ resourceService.read(RESOURCE_NAME_DBSCRIPTED).getProvision(anyObjectTO.getType()).getSyncToken());
+ } finally {
+ resourceService.update(originalResource);
+ }
}
@Test
[2/2] syncope git commit: [SYNCOPE-698] Implementation completed
Posted by il...@apache.org.
[SYNCOPE-698] Implementation completed
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/72e6ceb0
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/72e6ceb0
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/72e6ceb0
Branch: refs/heads/master
Commit: 72e6ceb0624a90a9b63bafce37c04104c7391d79
Parents: 5537d29
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Sep 25 16:43:23 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Sep 25 16:43:23 2015 +0200
----------------------------------------------------------------------
.../syncope/common/lib/to/MappingItemTO.java | 11 +-
.../apache/syncope/common/lib/to/SyncopeTO.java | 9 +
.../syncope/core/logic/ResourceLogic.java | 8 +-
.../apache/syncope/core/logic/SyncopeLogic.java | 25 +-
.../init/ClassPathScanImplementationLookup.java | 6 +
.../syncope/core/misc/ConnObjectUtils.java | 232 ++-------
.../apache/syncope/core/misc/MappingUtils.java | 501 +++++++++++++------
.../core/misc/security/AuthDataAccessor.java | 9 +-
.../serialization/GuardedStringSerializer.java | 4 +-
.../persistence/api/ImplementationLookup.java | 1 +
.../api/entity/resource/MappingItem.java | 3 +
.../jpa/entity/resource/JPAMappingItem.java | 22 +
.../entity/ExternalResourceValidator.java | 22 +
.../api/data/MappingItemTransformer.java | 47 ++
.../provisioning/java/AsyncConnectorFacade.java | 14 +-
.../provisioning/java/VirAttrHandlerImpl.java | 44 +-
.../java/data/AbstractAnyDataBinder.java | 19 +-
.../data/DefaultMappingItemTransformer.java | 40 ++
.../AbstractPropagationTaskExecutor.java | 33 +-
.../propagation/DefaultPropagationActions.java | 2 +-
.../propagation/DefaultPropagationReporter.java | 2 +-
.../propagation/PropagationManagerImpl.java | 10 +-
.../java/sync/AbstractPushResultHandler.java | 6 +-
.../java/sync/AbstractSyncResultHandler.java | 2 +-
.../sync/PlainAttrsSyncCorrelationRule.java | 41 +-
.../core/provisioning/java/sync/SyncUtils.java | 37 +-
.../reference/PrefixMappingItemTransformer.java | 55 ++
.../fit/core/reference/SyncTaskITCase.java | 101 ++--
28 files changed, 824 insertions(+), 482 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
index f252fbb..b838f6e 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
@@ -18,6 +18,8 @@
*/
package org.apache.syncope.common.lib.to;
+import java.util.ArrayList;
+import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.apache.syncope.common.lib.AbstractBaseBean;
@@ -64,10 +66,12 @@ public class MappingItemTO extends AbstractBaseBean {
private String mandatoryCondition = "false";
/**
- * Mapping purposes: SYNCHRONIZATION, PROPAGATION, BOTH, NONE.
+ * Mapping purposes.
*/
private MappingPurpose purpose;
+ private final List<String> mappingItemTransformerClassNames = new ArrayList<>();
+
public boolean isConnObjectKey() {
return connObjectKey;
}
@@ -131,4 +135,9 @@ public class MappingItemTO extends AbstractBaseBean {
public void setPurpose(final MappingPurpose purpose) {
this.purpose = purpose;
}
+
+ public List<String> getMappingItemTransformerClassNames() {
+ return mappingItemTransformerClassNames;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncopeTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncopeTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncopeTO.java
index 638f32f..f65badc 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncopeTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncopeTO.java
@@ -65,6 +65,8 @@ public class SyncopeTO extends AbstractBaseBean {
private final List<String> passwordRules = new ArrayList<>();
+ private final List<String> mappingItemTransformers = new ArrayList<>();
+
private final List<String> taskJobs = new ArrayList<>();
private final List<String> logicActions = new ArrayList<>();
@@ -163,6 +165,13 @@ public class SyncopeTO extends AbstractBaseBean {
return passwordRules;
}
+ @XmlElementWrapper(name = "mappingItemTransformers")
+ @XmlElement(name = "mappingItemTransformer")
+ @JsonProperty("mappingItemTransformers")
+ public List<String> getMappingItemTransformers() {
+ return mappingItemTransformers;
+ }
+
@XmlElementWrapper(name = "taskJobs")
@XmlElement(name = "taskJob")
@JsonProperty("taskJobs")
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index 7defb27..c3ce0c6 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -36,7 +36,6 @@ import org.apache.syncope.common.lib.to.ResourceTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.Entitlement;
-import org.apache.syncope.common.lib.types.MappingPurpose;
import org.apache.syncope.core.persistence.api.dao.DuplicateException;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
@@ -93,6 +92,9 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
private ConnObjectUtils connObjectUtils;
@Autowired
+ private MappingUtils mappingUtils;
+
+ @Autowired
private ConnectorFactory connFactory;
@PreAuthorize("hasRole('" + Entitlement.RESOURCE_CREATE + "')")
@@ -216,13 +218,13 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
throw new NotFoundException(
"ConnObjectKey mapping for " + init.getMiddle() + " " + anyKey + " on resource '" + key + "'");
}
- String connObjectKeyValue = MappingUtils.getConnObjectKeyValue(any, init.getRight());
+ String connObjectKeyValue = mappingUtils.getConnObjectKeyValue(any, init.getRight());
Connector connector = connFactory.getConnector(init.getLeft());
ConnectorObject connectorObject = connector.getObject(
init.getRight().getObjectClass(),
new Uid(connObjectKeyValue),
- connector.getOperationOptions(MappingUtils.getMappingItems(init.getRight(), MappingPurpose.BOTH)));
+ connector.getOperationOptions(MappingUtils.getBothMappingItems(init.getRight())));
if (connectorObject == null) {
throw new NotFoundException(
"Object " + connObjectKeyValue + " with class " + init.getRight().getObjectClass()
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
index 7f9b7c9..480efc1 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
@@ -82,7 +82,7 @@ public class SyncopeLogic extends AbstractLogic<SyncopeTO> {
private PasswordGenerator passwordGenerator;
@Autowired
- private ImplementationLookup implementationLookup;
+ private ImplementationLookup implLookup;
@Resource(name = "velocityResourceLoader")
private ResourceWithFallbackLoader resourceLoader;
@@ -128,17 +128,18 @@ public class SyncopeLogic extends AbstractLogic<SyncopeTO> {
syncopeTO.setVirAttrCache(virAttrCache.getClass().getName());
syncopeTO.setPasswordGenerator(passwordGenerator.getClass().getName());
- syncopeTO.getReportlets().addAll(implementationLookup.getClassNames(Type.REPORTLET));
- syncopeTO.getAccountRules().addAll(implementationLookup.getClassNames(Type.ACCOUNT_RULE));
- syncopeTO.getPasswordRules().addAll(implementationLookup.getClassNames(Type.PASSWORD_RULE));
- syncopeTO.getTaskJobs().addAll(implementationLookup.getClassNames(Type.TASKJOBDELEGATE));
- syncopeTO.getLogicActions().addAll(implementationLookup.getClassNames(Type.LOGIC_ACTIONS));
- syncopeTO.getPropagationActions().addAll(implementationLookup.getClassNames(Type.PROPAGATION_ACTIONS));
- syncopeTO.getSyncActions().addAll(implementationLookup.getClassNames(Type.SYNC_ACTIONS));
- syncopeTO.getPushActions().addAll(implementationLookup.getClassNames(Type.PUSH_ACTIONS));
- syncopeTO.getSyncCorrelationRules().addAll(implementationLookup.getClassNames(Type.SYNC_CORRELATION_RULE));
- syncopeTO.getPushCorrelationRules().addAll(implementationLookup.getClassNames(Type.PUSH_CORRELATION_RULE));
- syncopeTO.getValidators().addAll(implementationLookup.getClassNames(Type.VALIDATOR));
+ syncopeTO.getReportlets().addAll(implLookup.getClassNames(Type.REPORTLET));
+ syncopeTO.getAccountRules().addAll(implLookup.getClassNames(Type.ACCOUNT_RULE));
+ syncopeTO.getPasswordRules().addAll(implLookup.getClassNames(Type.PASSWORD_RULE));
+ syncopeTO.getMappingItemTransformers().addAll(implLookup.getClassNames(Type.MAPPING_ITEM_TRANSFORMER));
+ syncopeTO.getTaskJobs().addAll(implLookup.getClassNames(Type.TASKJOBDELEGATE));
+ syncopeTO.getLogicActions().addAll(implLookup.getClassNames(Type.LOGIC_ACTIONS));
+ syncopeTO.getPropagationActions().addAll(implLookup.getClassNames(Type.PROPAGATION_ACTIONS));
+ syncopeTO.getSyncActions().addAll(implLookup.getClassNames(Type.SYNC_ACTIONS));
+ syncopeTO.getPushActions().addAll(implLookup.getClassNames(Type.PUSH_ACTIONS));
+ syncopeTO.getSyncCorrelationRules().addAll(implLookup.getClassNames(Type.SYNC_CORRELATION_RULE));
+ syncopeTO.getPushCorrelationRules().addAll(implLookup.getClassNames(Type.PUSH_CORRELATION_RULE));
+ syncopeTO.getValidators().addAll(implLookup.getClassNames(Type.VALIDATOR));
Set<String> htmlTemplates = new HashSet<>();
Set<String> textTemplates = new HashSet<>();
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
index d68df96..5147a39 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
@@ -38,6 +38,7 @@ import org.apache.syncope.core.persistence.api.dao.AccountRuleConfClass;
import org.apache.syncope.core.persistence.api.dao.PasswordRule;
import org.apache.syncope.core.persistence.api.dao.PasswordRuleConfClass;
import org.apache.syncope.core.provisioning.api.LogicActions;
+import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
import org.apache.syncope.core.provisioning.api.job.SchedTaskJobDelegate;
import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
import org.apache.syncope.core.provisioning.api.sync.PushActions;
@@ -90,6 +91,7 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
scanner.addIncludeFilter(new AssignableTypeFilter(Reportlet.class));
scanner.addIncludeFilter(new AssignableTypeFilter(AccountRule.class));
scanner.addIncludeFilter(new AssignableTypeFilter(PasswordRule.class));
+ scanner.addIncludeFilter(new AssignableTypeFilter(MappingItemTransformer.class));
scanner.addIncludeFilter(new AssignableTypeFilter(SchedTaskJobDelegate.class));
scanner.addIncludeFilter(new AssignableTypeFilter(LogicActions.class));
scanner.addIncludeFilter(new AssignableTypeFilter(PropagationActions.class));
@@ -131,6 +133,10 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
}
}
+ if (MappingItemTransformer.class.isAssignableFrom(clazz) && !isAbsractClazz) {
+ classNames.get(Type.MAPPING_ITEM_TRANSFORMER).add(clazz.getName());
+ }
+
if (SchedTaskJobDelegate.class.isAssignableFrom(clazz) && !isAbsractClazz
&& !SyncJobDelegate.class.isAssignableFrom(clazz)
&& !PushJobDelegate.class.isAssignableFrom(clazz)) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
index 7c39bb7..f78cc31 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
@@ -21,11 +21,7 @@ package org.apache.syncope.core.misc;
import org.apache.syncope.core.misc.policy.InvalidPasswordRuleConf;
import org.apache.syncope.core.misc.security.SecureRandomUtils;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.AnyOperations;
import org.apache.syncope.common.lib.patch.AnyPatch;
@@ -37,17 +33,11 @@ import org.apache.syncope.common.lib.to.ConnObjectTO;
import org.apache.syncope.common.lib.to.GroupTO;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.AttrSchemaType;
-import org.apache.syncope.common.lib.types.MappingPurpose;
-import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
-import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
-import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.persistence.api.entity.task.SyncTask;
import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.misc.security.Encryptor;
@@ -71,6 +61,8 @@ public class ConnObjectUtils {
private static final Logger LOG = LoggerFactory.getLogger(ConnObjectUtils.class);
+ private static final Encryptor ENCRYPTOR = Encryptor.getInstance();
+
@Autowired
private TemplateUtils templateUtils;
@@ -84,12 +76,44 @@ public class ConnObjectUtils {
private ExternalResourceDAO resourceDAO;
@Autowired
- private PlainSchemaDAO plainSchemaDAO;
+ private PasswordGenerator passwordGenerator;
@Autowired
- private PasswordGenerator pwdGen;
+ private MappingUtils mappingUtils;
+
+ /**
+ * Extract password value from passed value (if instance of GuardedString or GuardedByteArray).
+ *
+ * @param pwd received from the underlying connector
+ * @return password value
+ */
+ public static String getPassword(final Object pwd) {
+ final StringBuilder result = new StringBuilder();
+
+ if (pwd instanceof GuardedString) {
+ ((GuardedString) pwd).access(new GuardedString.Accessor() {
+
+ @Override
+ public void access(final char[] clearChars) {
+ result.append(clearChars);
+ }
+ });
+ } else if (pwd instanceof GuardedByteArray) {
+ ((GuardedByteArray) pwd).access(new GuardedByteArray.Accessor() {
+
+ @Override
+ public void access(final byte[] clearBytes) {
+ result.append(new String(clearBytes));
+ }
+ });
+ } else if (pwd instanceof String) {
+ result.append((String) pwd);
+ } else {
+ result.append(pwd.toString());
+ }
- private final Encryptor encryptor = Encryptor.getInstance();
+ return result.toString();
+ }
/**
* Build a UserTO / GroupTO / AnyObjectTO out of connector object attributes and schema mapping.
@@ -131,7 +155,7 @@ public class ConnObjectUtils {
String password;
try {
- password = pwdGen.generate(ruleConfs);
+ password = passwordGenerator.generate(ruleConfs);
} catch (InvalidPasswordRuleConf e) {
LOG.error("Could not generate policy-compliant random password for {}", userTO, e);
@@ -167,7 +191,7 @@ public class ConnObjectUtils {
// update password if and only if password is really changed
User user = userDAO.authFind(key);
if (StringUtils.isBlank(((UserTO) updated).getPassword())
- || encryptor.verify(((UserTO) updated).getPassword(),
+ || ENCRYPTOR.verify(((UserTO) updated).getPassword(),
user.getCipherAlgorithm(), user.getPassword())) {
((UserTO) updated).setPassword(null);
@@ -190,127 +214,8 @@ public class ConnObjectUtils {
// 1. fill with data from connector object
anyTO.setRealm(syncTask.getDestinatioRealm().getFullPath());
- for (MappingItem item : MappingUtils.getMappingItems(provision, MappingPurpose.SYNCHRONIZATION)) {
- Attribute attr = obj.getAttributeByName(item.getExtAttrName());
-
- AttrTO attrTO;
- switch (item.getIntMappingType()) {
- case UserKey:
- case GroupKey:
- case AnyObjectKey:
- break;
-
- case Password:
- if (anyTO instanceof UserTO && attr != null && attr.getValue() != null
- && !attr.getValue().isEmpty()) {
-
- ((UserTO) anyTO).setPassword(getPassword(attr.getValue().get(0)));
- }
- break;
-
- case Username:
- if (anyTO instanceof UserTO) {
- ((UserTO) anyTO).setUsername(attr == null || attr.getValue().isEmpty()
- || attr.getValue().get(0) == null
- ? null
- : attr.getValue().get(0).toString());
- }
- break;
-
- case GroupName:
- if (anyTO instanceof GroupTO) {
- ((GroupTO) anyTO).setName(attr == null || attr.getValue().isEmpty()
- || attr.getValue().get(0) == null
- ? null
- : attr.getValue().get(0).toString());
- }
- break;
-
- case GroupOwnerSchema:
- if (anyTO instanceof GroupTO && attr != null) {
- // using a special attribute (with schema "", that will be ignored) for carrying the
- // GroupOwnerSchema value
- attrTO = new AttrTO();
- attrTO.setSchema(StringUtils.EMPTY);
- if (attr.getValue().isEmpty() || attr.getValue().get(0) == null) {
- attrTO.getValues().add(StringUtils.EMPTY);
- } else {
- attrTO.getValues().add(attr.getValue().get(0).toString());
- }
-
- ((GroupTO) anyTO).getPlainAttrs().add(attrTO);
- }
- break;
-
- case UserPlainSchema:
- case GroupPlainSchema:
- case AnyObjectPlainSchema:
- attrTO = new AttrTO();
- attrTO.setSchema(item.getIntAttrName());
-
- PlainSchema schema = plainSchemaDAO.find(item.getIntAttrName());
-
- for (Object value : attr == null || attr.getValue() == null
- ? Collections.emptyList()
- : attr.getValue()) {
-
- AttrSchemaType schemaType = schema == null ? AttrSchemaType.String : schema.getType();
- if (value != null) {
- final PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
- switch (schemaType) {
- case String:
- attrValue.setStringValue(value.toString());
- break;
-
- case Binary:
- attrValue.setBinaryValue((byte[]) value);
- break;
-
- default:
- try {
- attrValue.parseValue(schema, value.toString());
- } catch (ParsingValidationException e) {
- LOG.error("While parsing provided value {}", value, e);
- attrValue.setStringValue(value.toString());
- schemaType = AttrSchemaType.String;
- }
- break;
- }
- attrTO.getValues().add(attrValue.getValueAsString(schemaType));
- }
- }
-
- anyTO.getPlainAttrs().add(attrTO);
- break;
-
- case UserDerivedSchema:
- case GroupDerivedSchema:
- case AnyObjectDerivedSchema:
- attrTO = new AttrTO();
- attrTO.setSchema(item.getIntAttrName());
- anyTO.getDerAttrs().add(attrTO);
- break;
-
- case UserVirtualSchema:
- case GroupVirtualSchema:
- case AnyObjectVirtualSchema:
- attrTO = new AttrTO();
- attrTO.setSchema(item.getIntAttrName());
-
- for (Object value : attr == null || attr.getValue() == null
- ? Collections.emptyList()
- : attr.getValue()) {
-
- if (value != null) {
- attrTO.getValues().add(value.toString());
- }
- }
-
- anyTO.getVirAttrs().add(attrTO);
- break;
-
- default:
- }
+ for (MappingItem item : MappingUtils.getSyncMappingItems(provision)) {
+ mappingUtils.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), anyTO, anyUtils);
}
// 2. add data from defined template (if any)
@@ -320,40 +225,6 @@ public class ConnObjectUtils {
}
/**
- * Extract password value from passed value (if instance of GuardedString or GuardedByteArray).
- *
- * @param pwd received from the underlying connector
- * @return password value
- */
- public String getPassword(final Object pwd) {
- final StringBuilder result = new StringBuilder();
-
- if (pwd instanceof GuardedString) {
- ((GuardedString) pwd).access(new GuardedString.Accessor() {
-
- @Override
- public void access(final char[] clearChars) {
- result.append(clearChars);
- }
- });
- } else if (pwd instanceof GuardedByteArray) {
- ((GuardedByteArray) pwd).access(new GuardedByteArray.Accessor() {
-
- @Override
- public void access(final byte[] clearBytes) {
- result.append(new String(clearBytes));
- }
- });
- } else if (pwd instanceof String) {
- result.append((String) pwd);
- } else {
- result.append(pwd.toString());
- }
-
- return result.toString();
- }
-
- /**
* Get connector object TO from a connector object.
*
* @param connObject connector object.
@@ -385,25 +256,4 @@ public class ConnObjectUtils {
return connObjectTO;
}
-
- /**
- * Transform a
- * <code>Collection</code> of {@link Attribute} instances into a {@link Map}. The key to each element in the map is
- * the <i>name</i> of an
- * <code>Attribute</code>. The value of each element in the map is the
- * <code>Attribute</code> instance with that name. <br/> Different from the original because: <ul> <li>map keys are
- * transformed toUpperCase()</li> <li>returned map is mutable</li> </ul>
- *
- * @param attributes set of attribute to transform to a map.
- * @return a map of string and attribute.
- *
- * @see org.identityconnectors.framework.common.objects.AttributeUtil#toMap(java.util.Collection)
- */
- public Map<String, Attribute> toMap(final Collection<? extends Attribute> attributes) {
- final Map<String, Attribute> map = new HashMap<>();
- for (Attribute attr : attributes) {
- map.put(attr.getName().toUpperCase(), attr);
- }
- return map;
- }
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
index 2f0a0c5..085f07d 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
@@ -18,7 +18,6 @@
*/
package org.apache.syncope.core.misc;
-import org.apache.syncope.core.misc.policy.InvalidPasswordRuleConf;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -27,16 +26,24 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.ListUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.MapContext;
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.common.lib.patch.AttrPatch;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.common.lib.types.IntMappingType;
import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.core.misc.policy.InvalidPasswordRuleConf;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
@@ -53,17 +60,21 @@ import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
import org.apache.syncope.core.misc.security.Encryptor;
-import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
import org.apache.syncope.core.misc.jexl.JexlUtils;
import org.apache.syncope.core.misc.security.PasswordGenerator;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.persistence.api.entity.Schema;
import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.provisioning.api.VirAttrHandler;
+import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
import org.identityconnectors.framework.common.FrameworkUtil;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
@@ -72,14 +83,45 @@ import org.identityconnectors.framework.common.objects.Name;
import org.identityconnectors.framework.common.objects.OperationalAttributes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
-public final class MappingUtils {
+@Component
+public class MappingUtils {
private static final Logger LOG = LoggerFactory.getLogger(MappingUtils.class);
private static final Encryptor ENCRYPTOR = Encryptor.getInstance();
+ @Autowired
+ private UserDAO userDAO;
+
+ @Autowired
+ private AnyTypeDAO anyTypeDAO;
+
+ @Autowired
+ private PlainSchemaDAO plainSchemaDAO;
+
+ @Autowired
+ private VirSchemaDAO virSchemaDAO;
+
+ @Autowired
+ private VirAttrHandler virAttrHandler;
+
+ @Autowired
+ private VirAttrCache virAttrCache;
+
+ @Autowired
+ private PasswordGenerator passwordGenerator;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ @Autowired
+ private AnyUtilsFactory anyUtilsFactory;
+
public static <T extends MappingItem> Collection<T> getMatchingMappingItems(
final Collection<T> items, final IntMappingType type) {
@@ -116,6 +158,144 @@ public final class MappingUtils {
});
}
+ public static MappingItem getConnObjectKeyItem(final Provision provision) {
+ Mapping mapping = null;
+ if (provision != null) {
+ mapping = provision.getMapping();
+ }
+
+ return mapping == null
+ ? null
+ : mapping.getConnObjectKeyItem();
+ }
+
+ private static List<MappingItem> getMappingItems(final Provision provision, final MappingPurpose purpose) {
+ List<? extends MappingItem> items = Collections.<MappingItem>emptyList();
+ if (provision != null) {
+ items = provision.getMapping().getItems();
+ }
+
+ List<MappingItem> result = new ArrayList<>();
+
+ switch (purpose) {
+ case SYNCHRONIZATION:
+ for (MappingItem item : items) {
+ if (MappingPurpose.PROPAGATION != item.getPurpose()
+ && MappingPurpose.NONE != item.getPurpose()) {
+
+ result.add(item);
+ }
+ }
+ break;
+
+ case PROPAGATION:
+ for (MappingItem item : items) {
+ if (MappingPurpose.SYNCHRONIZATION != item.getPurpose()
+ && MappingPurpose.NONE != item.getPurpose()) {
+
+ result.add(item);
+ }
+ }
+ break;
+
+ case BOTH:
+ for (MappingItem item : items) {
+ if (MappingPurpose.NONE != item.getPurpose()) {
+ result.add(item);
+ }
+ }
+ break;
+
+ case NONE:
+ for (MappingItem item : items) {
+ if (MappingPurpose.NONE == item.getPurpose()) {
+ result.add(item);
+ }
+ }
+ break;
+
+ default:
+ }
+
+ return result;
+ }
+
+ public static List<MappingItem> getBothMappingItems(final Provision provision) {
+ return getMappingItems(provision, MappingPurpose.BOTH);
+ }
+
+ public static List<MappingItem> getPropagationMappingItems(final Provision provision) {
+ return getMappingItems(provision, MappingPurpose.PROPAGATION);
+ }
+
+ public static List<MappingItem> getSyncMappingItems(final Provision provision) {
+ return getMappingItems(provision, MappingPurpose.SYNCHRONIZATION);
+ }
+
+ /**
+ * Build __NAME__ for propagation. First look if there ia a defined connObjectLink for the given resource (and in
+ * this case evaluate as JEXL); otherwise, take given connObjectKey.
+ *
+ * @param any given any object
+ * @param provision external resource
+ * @param connObjectKey connector object key
+ * @return the value to be propagated as __NAME__
+ */
+ public static Name evaluateNAME(final Any<?, ?, ?> any, final Provision provision, final String connObjectKey) {
+ if (StringUtils.isBlank(connObjectKey)) {
+ // LOG error but avoid to throw exception: leave it to the external resource
+ LOG.error("Missing ConnObjectKey for '{}': ", provision.getResource());
+ }
+
+ // Evaluate connObjectKey expression
+ String connObjectLink = provision == null || provision.getMapping() == null
+ ? null
+ : provision.getMapping().getConnObjectLink();
+ String evalConnObjectLink = null;
+ if (StringUtils.isNotBlank(connObjectLink)) {
+ JexlContext jexlContext = new MapContext();
+ JexlUtils.addFieldsToContext(any, jexlContext);
+ JexlUtils.addPlainAttrsToContext(any.getPlainAttrs(), jexlContext);
+ JexlUtils.addDerAttrsToContext(any.getDerAttrs(), any.getPlainAttrs(), jexlContext);
+ evalConnObjectLink = JexlUtils.evaluate(connObjectLink, jexlContext);
+ }
+
+ // If connObjectLink evaluates to an empty string, just use the provided connObjectKey as Name(),
+ // otherwise evaluated connObjectLink expression is taken as Name().
+ Name name;
+ if (StringUtils.isBlank(evalConnObjectLink)) {
+ // add connObjectKey as __NAME__ attribute ...
+ LOG.debug("Add connObjectKey [{}] as __NAME__", connObjectKey);
+ name = new Name(connObjectKey);
+ } else {
+ LOG.debug("Add connObjectLink [{}] as __NAME__", evalConnObjectLink);
+ name = new Name(evalConnObjectLink);
+
+ // connObjectKey not propagated: it will be used to set the value for __UID__ attribute
+ LOG.debug("connObjectKey will be used just as __UID__ attribute");
+ }
+
+ return name;
+ }
+
+ public static List<MappingItemTransformer> getMappingItemTransformers(final MappingItem mappingItem) {
+ List<MappingItemTransformer> result = new ArrayList<>();
+
+ for (String className : mappingItem.getMappingItemTransformerClassNames()) {
+ try {
+ Class<?> transformerClass = ClassUtils.getClass(className);
+
+ result.add((MappingItemTransformer) ApplicationContextProvider.
+ getBeanFactory().
+ createBean(transformerClass, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false));
+ } catch (Exception e) {
+ LOG.error("Could not instantiate {}, ignoring...", className, e);
+ }
+ }
+
+ return result;
+ }
+
/**
* Prepare attributes for sending to a connector instance.
*
@@ -127,7 +307,8 @@ public final class MappingUtils {
* @param provision provision information
* @return connObjectLink + prepared attributes
*/
- public static Pair<String, Set<Attribute>> prepareAttrs(
+ @Transactional(readOnly = true)
+ public Pair<String, Set<Attribute>> prepareAttrs(
final Any<?, ?, ?> any,
final String password,
final boolean changePwd,
@@ -138,10 +319,6 @@ public final class MappingUtils {
LOG.debug("Preparing resource attributes for {} with provision {} for attributes {}",
any, provision, any.getPlainAttrs());
- DefaultListableBeanFactory beanFactory = ApplicationContextProvider.getBeanFactory();
- VirAttrCache virAttrCache = beanFactory.getBean(VirAttrCache.class);
- PasswordGenerator passwordGenerator = beanFactory.getBean(PasswordGenerator.class);
-
Set<Attribute> attributes = new HashSet<>();
String connObjectKey = null;
@@ -157,8 +334,7 @@ public final class MappingUtils {
virAttrCache.expire(any.getType().getKey(), any.getKey(), mapping.getIntAttrName());
}
- Pair<String, Attribute> preparedAttr = prepareAttr(
- provision, mapping, any, password, passwordGenerator, vAttrs);
+ Pair<String, Attribute> preparedAttr = prepareAttr(provision, mapping, any, password, vAttrs);
if (preparedAttr != null && preparedAttr.getKey() != null) {
connObjectKey = preparedAttr.getKey();
@@ -211,22 +387,16 @@ public final class MappingUtils {
* @param mapItem mapping item for the given attribute
* @param any any object
* @param password clear-text password
- * @param passwordGenerator password generator
* @param vAttrs virtual attributes to be managed
* @return connObjectLink + prepared attribute
*/
- @SuppressWarnings("unchecked")
- private static Pair<String, Attribute> prepareAttr(
+ private Pair<String, Attribute> prepareAttr(
final Provision provision, final MappingItem mapItem,
- final Any<?, ?, ?> any, final String password, final PasswordGenerator passwordGenerator,
+ final Any<?, ?, ?> any, final String password,
final Map<String, AttrPatch> vAttrs) {
List<Any<?, ?, ?>> anys = new ArrayList<>();
- DefaultListableBeanFactory beanFactory = ApplicationContextProvider.getBeanFactory();
- AnyUtilsFactory anyUtilsFactory = beanFactory.getBean(AnyUtilsFactory.class);
- VirAttrHandler virAttrHandler = beanFactory.getBean(VirAttrHandler.class);
-
switch (mapItem.getIntMappingType().getAnyTypeKind()) {
case USER:
if (any instanceof User) {
@@ -236,7 +406,6 @@ public final class MappingUtils {
case GROUP:
if (any instanceof User) {
- UserDAO userDAO = beanFactory.getBean(UserDAO.class);
for (Group group : userDAO.findAllGroups((User) any)) {
virAttrHandler.retrieveVirAttrValues(group);
anys.add(group);
@@ -266,7 +435,6 @@ public final class MappingUtils {
case UserPlainSchema:
case GroupPlainSchema:
case AnyObjectPlainSchema:
- PlainSchemaDAO plainSchemaDAO = beanFactory.getBean(PlainSchemaDAO.class);
schema = plainSchemaDAO.find(mapItem.getIntAttrName());
schemaType = schema == null ? AttrSchemaType.String : schema.getType();
break;
@@ -274,7 +442,6 @@ public final class MappingUtils {
case UserVirtualSchema:
case GroupVirtualSchema:
case AnyObjectVirtualSchema:
- VirSchemaDAO virSchemaDAO = beanFactory.getBean(VirSchemaDAO.class);
schema = virSchemaDAO.find(mapItem.getIntAttrName());
readOnlyVirSchema = (schema != null && schema.isReadonly());
schemaType = AttrSchemaType.String;
@@ -357,63 +524,16 @@ public final class MappingUtils {
return result;
}
- /**
- * Build __NAME__ for propagation. First look if there ia a defined connObjectLink for the given resource (and in
- * this case evaluate as JEXL); otherwise, take given connObjectKey.
- *
- * @param any given any object
- * @param provision external resource
- * @param connObjectKey connector object key
- * @return the value to be propagated as __NAME__
- */
- public static Name evaluateNAME(final Any<?, ?, ?> any, final Provision provision, final String connObjectKey) {
- if (StringUtils.isBlank(connObjectKey)) {
- // LOG error but avoid to throw exception: leave it to the external resource
- LOG.error("Missing ConnObjectKey for '{}': ", provision.getResource());
- }
-
- // Evaluate connObjectKey expression
- String connObjectLink = provision == null || provision.getMapping() == null
- ? null
- : provision.getMapping().getConnObjectLink();
- String evalConnObjectLink = null;
- if (StringUtils.isNotBlank(connObjectLink)) {
- JexlContext jexlContext = new MapContext();
- JexlUtils.addFieldsToContext(any, jexlContext);
- JexlUtils.addPlainAttrsToContext(any.getPlainAttrs(), jexlContext);
- JexlUtils.addDerAttrsToContext(any.getDerAttrs(), any.getPlainAttrs(), jexlContext);
- evalConnObjectLink = JexlUtils.evaluate(connObjectLink, jexlContext);
- }
-
- // If connObjectLink evaluates to an empty string, just use the provided connObjectKey as Name(),
- // otherwise evaluated connObjectLink expression is taken as Name().
- Name name;
- if (StringUtils.isBlank(evalConnObjectLink)) {
- // add connObjectKey as __NAME__ attribute ...
- LOG.debug("Add connObjectKey [{}] as __NAME__", connObjectKey);
- name = new Name(connObjectKey);
- } else {
- LOG.debug("Add connObjectLink [{}] as __NAME__", evalConnObjectLink);
- name = new Name(evalConnObjectLink);
-
- // connObjectKey not propagated: it will be used to set the value for __UID__ attribute
- LOG.debug("connObjectKey will be used just as __UID__ attribute");
- }
-
- return name;
- }
-
- private static String getGroupOwnerValue(final Provision provision, final Any<?, ?, ?> any) {
- Pair<String, Attribute> preparedAttr = prepareAttr(provision, getConnObjectKeyItem(provision),
- any, null, null, Collections.<String, AttrPatch>emptyMap());
+ private String getGroupOwnerValue(final Provision provision, final Any<?, ?, ?> any) {
+ Pair<String, Attribute> preparedAttr = prepareAttr(
+ provision, getConnObjectKeyItem(provision), any, null, Collections.<String, AttrPatch>emptyMap());
String connObjectKey = preparedAttr.getKey();
- final Name groupOwnerName = evaluateNAME(any, provision, connObjectKey);
- return groupOwnerName.getNameValue();
+ return evaluateNAME(any, provision, connObjectKey).getNameValue();
}
/**
- * Get attribute values.
+ * Get attribute values for the given {@link MappingItem} and any objects.
*
* @param provision provision information
* @param mappingItem mapping item
@@ -421,17 +541,15 @@ public final class MappingUtils {
* @param vAttrs virtual attributes to be managed
* @return attribute values.
*/
- public static List<PlainAttrValue> getIntValues(final Provision provision,
+ @Transactional(readOnly = true)
+ public List<PlainAttrValue> getIntValues(final Provision provision,
final MappingItem mappingItem, final List<Any<?, ?, ?>> anys, final Map<String, AttrPatch> vAttrs) {
LOG.debug("Get attributes for '{}' and mapping type '{}'", anys, mappingItem.getIntMappingType());
- EntityFactory entityFactory =
- ApplicationContextProvider.getBeanFactory().getBean(EntityFactory.class);
- AnyUtilsFactory anyUtilsFactory =
- ApplicationContextProvider.getBeanFactory().getBean(AnyUtilsFactory.class);
+ boolean transform = true;
+
List<PlainAttrValue> values = new ArrayList<>();
- PlainAttrValue attrValue;
switch (mappingItem.getIntMappingType()) {
case UserPlainSchema:
case GroupPlainSchema:
@@ -440,9 +558,15 @@ public final class MappingUtils {
PlainAttr<?> attr = any.getPlainAttr(mappingItem.getIntAttrName());
if (attr != null) {
if (attr.getUniqueValue() != null) {
- values.add(attr.getUniqueValue());
+ PlainAttrUniqueValue value = SerializationUtils.clone(attr.getUniqueValue());
+ value.setAttr(null);
+ values.add(value);
} else if (attr.getValues() != null) {
- values.addAll(attr.getValues());
+ for (PlainAttrValue value : attr.getValues()) {
+ PlainAttrValue shadow = SerializationUtils.clone(value);
+ shadow.setAttr(null);
+ values.add(shadow);
+ }
}
}
@@ -458,26 +582,27 @@ public final class MappingUtils {
case UserVirtualSchema:
case GroupVirtualSchema:
case AnyObjectVirtualSchema:
+ // virtual attributes don't get transformed
+ transform = false;
+
for (Any<?, ?, ?> any : anys) {
AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
- VirAttr<?> virAttr = any.getVirAttr(mappingItem.getIntAttrName());
- if (virAttr != null) {
+ VirAttr<?> attr = any.getVirAttr(mappingItem.getIntAttrName());
+ if (attr != null) {
if (vAttrs != null) {
if (vAttrs.containsKey(mappingItem.getIntAttrName())) {
- virAttr.getValues().clear();
- virAttr.getValues().addAll(
+ attr.getValues().clear();
+ attr.getValues().addAll(
vAttrs.get(mappingItem.getIntAttrName()).getAttrTO().getValues());
} else {
throw new IllegalArgumentException("Don't need to update virtual attribute '"
+ mappingItem.getIntAttrName() + "'");
}
}
- if (virAttr.getValues() != null) {
- for (String value : virAttr.getValues()) {
- attrValue = anyUtils.newPlainAttrValue();
- attrValue.setStringValue(value);
- values.add(attrValue);
- }
+ for (String value : attr.getValues()) {
+ PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+ attrValue.setStringValue(value);
+ values.add(attrValue);
}
}
@@ -486,7 +611,7 @@ public final class MappingUtils {
+ "\n* IntMappingType {}"
+ "\n* Attribute values {}",
any.getClass().getSimpleName(),
- virAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
+ attr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
}
break;
@@ -495,10 +620,10 @@ public final class MappingUtils {
case AnyObjectDerivedSchema:
for (Any<?, ?, ?> any : anys) {
AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
- DerAttr<?> derAttr = any.getDerAttr(mappingItem.getIntAttrName());
- if (derAttr != null) {
- attrValue = anyUtils.newPlainAttrValue();
- attrValue.setStringValue(derAttr.getValue(any.getPlainAttrs()));
+ DerAttr<?> attr = any.getDerAttr(mappingItem.getIntAttrName());
+ if (attr != null) {
+ PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+ attrValue.setStringValue(attr.getValue(any.getPlainAttrs()));
values.add(attrValue);
}
@@ -506,7 +631,7 @@ public final class MappingUtils {
+ "\n* IntAttrName {}"
+ "\n* IntMappingType {}"
+ "\n* Attribute values {}",
- derAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
+ attr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
}
break;
@@ -515,7 +640,7 @@ public final class MappingUtils {
case AnyObjectKey:
for (Any<?, ?, ?> any : anys) {
AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
- attrValue = anyUtils.newPlainAttrValue();
+ PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
attrValue.setStringValue(any.getKey().toString());
values.add(attrValue);
}
@@ -524,7 +649,7 @@ public final class MappingUtils {
case Username:
for (Any<?, ?, ?> any : anys) {
if (any instanceof User) {
- attrValue = entityFactory.newEntity(UPlainAttrValue.class);
+ UPlainAttrValue attrValue = entityFactory.newEntity(UPlainAttrValue.class);
attrValue.setStringValue(((User) any).getUsername());
values.add(attrValue);
}
@@ -534,7 +659,7 @@ public final class MappingUtils {
case GroupName:
for (Any<?, ?, ?> any : anys) {
if (any instanceof Group) {
- attrValue = entityFactory.newEntity(GPlainAttrValue.class);
+ GPlainAttrValue attrValue = entityFactory.newEntity(GPlainAttrValue.class);
attrValue.setStringValue(((Group) any).getName());
values.add(attrValue);
}
@@ -542,7 +667,6 @@ public final class MappingUtils {
break;
case GroupOwnerSchema:
- AnyTypeDAO anyTypeDAO = ApplicationContextProvider.getBeanFactory().getBean(AnyTypeDAO.class);
Mapping uMapping = provision.getAnyType().equals(anyTypeDAO.findUser())
? null
: provision.getMapping();
@@ -562,7 +686,7 @@ public final class MappingUtils {
}
if (StringUtils.isNotBlank(groupOwnerValue)) {
- attrValue = entityFactory.newEntity(GPlainAttrValue.class);
+ GPlainAttrValue attrValue = entityFactory.newEntity(GPlainAttrValue.class);
attrValue.setStringValue(groupOwnerValue);
values.add(attrValue);
}
@@ -573,9 +697,19 @@ public final class MappingUtils {
default:
}
- LOG.debug("Retrieved values '{}'", values);
+ LOG.debug("Values for propagation: {}", values);
- return values;
+ List<PlainAttrValue> transformed = values;
+ if (transform) {
+ for (MappingItemTransformer transformer : getMappingItemTransformers(mappingItem)) {
+ transformed = transformer.beforePropagation(transformed);
+ }
+ LOG.debug("Transformed values for propagation: {}", values);
+ } else {
+ LOG.debug("No transformation occurred");
+ }
+
+ return transformed;
}
/**
@@ -585,7 +719,8 @@ public final class MappingUtils {
* @param provision provision information
* @return connObjectKey internal value
*/
- public static String getConnObjectKeyValue(final Any<?, ?, ?> any, final Provision provision) {
+ @Transactional(readOnly = true)
+ public String getConnObjectKeyValue(final Any<?, ?, ?> any, final Provision provision) {
List<PlainAttrValue> values = getIntValues(provision, provision.getMapping().getConnObjectKeyItem(),
Collections.<Any<?, ?, ?>>singletonList(any), null);
return values == null || values.isEmpty()
@@ -593,71 +728,139 @@ public final class MappingUtils {
: values.get(0).getValueAsString();
}
- public static MappingItem getConnObjectKeyItem(final Provision provision) {
- Mapping mapping = null;
- if (provision != null) {
- mapping = provision.getMapping();
- }
-
- return mapping == null
- ? null
- : mapping.getConnObjectKeyItem();
- }
-
- public static List<MappingItem> getMappingItems(final Provision provision, final MappingPurpose purpose) {
- List<? extends MappingItem> items = Collections.<MappingItem>emptyList();
- if (provision != null) {
- items = provision.getMapping().getItems();
+ /**
+ * Set attribute values, according to the given {@link MappingItem}, to any object from attribute received from
+ * connector.
+ *
+ * @param <T> any object
+ * @param mappingItem mapping item
+ * @param attr attribute received from connector
+ * @param anyTO any object
+ * @param anyUtils any utils
+ */
+ @Transactional(readOnly = true)
+ public <T extends AnyTO> void setIntValues(
+ final MappingItem mappingItem, final Attribute attr, final T anyTO, final AnyUtils anyUtils) {
+
+ List<Object> values = null;
+ if (attr != null) {
+ values = attr.getValue();
+ for (MappingItemTransformer transformer : getMappingItemTransformers(mappingItem)) {
+ values = transformer.beforeSync(values);
+ }
}
+ values = ListUtils.emptyIfNull(values);
- List<MappingItem> result = new ArrayList<>();
+ switch (mappingItem.getIntMappingType()) {
+ case UserKey:
+ case GroupKey:
+ case AnyObjectKey:
+ break;
- switch (purpose) {
- case SYNCHRONIZATION:
- for (MappingItem item : items) {
- if (MappingPurpose.PROPAGATION != item.getPurpose()
- && MappingPurpose.NONE != item.getPurpose()) {
+ case Password:
+ if (anyTO instanceof UserTO && !values.isEmpty()) {
+ ((UserTO) anyTO).setPassword(ConnObjectUtils.getPassword(values.get(0)));
+ }
+ break;
- result.add(item);
- }
+ case Username:
+ if (anyTO instanceof UserTO) {
+ ((UserTO) anyTO).setUsername(values.isEmpty() || values.get(0) == null
+ ? null
+ : values.get(0).toString());
}
break;
- case PROPAGATION:
- for (MappingItem item : items) {
- if (MappingPurpose.SYNCHRONIZATION != item.getPurpose()
- && MappingPurpose.NONE != item.getPurpose()) {
+ case GroupName:
+ if (anyTO instanceof GroupTO) {
+ ((GroupTO) anyTO).setName(values.isEmpty() || values.get(0) == null
+ ? null
+ : values.get(0).toString());
+ }
+ break;
- result.add(item);
+ case GroupOwnerSchema:
+ if (anyTO instanceof GroupTO && attr != null) {
+ // using a special attribute (with schema "", that will be ignored) for carrying the
+ // GroupOwnerSchema value
+ AttrTO attrTO = new AttrTO();
+ attrTO.setSchema(StringUtils.EMPTY);
+ if (values.isEmpty() || values.get(0) == null) {
+ attrTO.getValues().add(StringUtils.EMPTY);
+ } else {
+ attrTO.getValues().add(values.get(0).toString());
}
+
+ ((GroupTO) anyTO).getPlainAttrs().add(attrTO);
}
break;
- case BOTH:
- for (MappingItem item : items) {
- if (MappingPurpose.NONE != item.getPurpose()) {
- result.add(item);
+ case UserPlainSchema:
+ case GroupPlainSchema:
+ case AnyObjectPlainSchema:
+ AttrTO attrTO = new AttrTO();
+ attrTO.setSchema(mappingItem.getIntAttrName());
+
+ PlainSchema schema = plainSchemaDAO.find(mappingItem.getIntAttrName());
+
+ for (Object value : values) {
+ AttrSchemaType schemaType = schema == null ? AttrSchemaType.String : schema.getType();
+ if (value != null) {
+ PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+ switch (schemaType) {
+ case String:
+ attrValue.setStringValue(value.toString());
+ break;
+
+ case Binary:
+ attrValue.setBinaryValue((byte[]) value);
+ break;
+
+ default:
+ try {
+ attrValue.parseValue(schema, value.toString());
+ } catch (ParsingValidationException e) {
+ LOG.error("While parsing provided value {}", value, e);
+ attrValue.setStringValue(value.toString());
+ schemaType = AttrSchemaType.String;
+ }
+ break;
+ }
+ attrTO.getValues().add(attrValue.getValueAsString(schemaType));
}
}
+
+ anyTO.getPlainAttrs().add(attrTO);
break;
- case NONE:
- for (MappingItem item : items) {
- if (MappingPurpose.NONE == item.getPurpose()) {
- result.add(item);
+ case UserDerivedSchema:
+ case GroupDerivedSchema:
+ case AnyObjectDerivedSchema:
+ attrTO = new AttrTO();
+ attrTO.setSchema(mappingItem.getIntAttrName());
+ anyTO.getDerAttrs().add(attrTO);
+ break;
+
+ case UserVirtualSchema:
+ case GroupVirtualSchema:
+ case AnyObjectVirtualSchema:
+ attrTO = new AttrTO();
+ attrTO.setSchema(mappingItem.getIntAttrName());
+
+ // virtual attributes don't get transformed, iterate over original attr.getValue()
+ for (Object value : (attr == null || attr.getValue() == null)
+ ? Collections.emptyList() : attr.getValue()) {
+
+ if (value != null) {
+ attrTO.getValues().add(value.toString());
}
}
+
+ anyTO.getVirAttrs().add(attrTO);
break;
default:
}
-
- return result;
}
- /**
- * Private default constructor, for static-only classes.
- */
- private MappingUtils() {
- }
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java b/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java
index ff9e646..10eb235 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java
@@ -72,6 +72,8 @@ public class AuthDataAccessor {
protected static final Logger LOG = LoggerFactory.getLogger(AuthDataAccessor.class);
+ protected static final Encryptor ENCRYPTOR = Encryptor.getInstance();
+
@Resource(name = "adminUser")
protected String adminUser;
@@ -102,7 +104,8 @@ public class AuthDataAccessor {
@Autowired
protected AuditManager auditManager;
- protected final Encryptor encryptor = Encryptor.getInstance();
+ @Autowired
+ protected MappingUtils mappingUtils;
@Transactional(readOnly = true)
public Domain findDomain(final String key) {
@@ -158,7 +161,7 @@ public class AuthDataAccessor {
}
protected boolean authenticate(final User user, final String password) {
- boolean authenticated = encryptor.verify(password, user.getCipherAlgorithm(), user.getPassword());
+ boolean authenticated = ENCRYPTOR.verify(password, user.getCipherAlgorithm(), user.getPassword());
LOG.debug("{} authenticated on internal storage: {}", user.getUsername(), authenticated);
for (Iterator<? extends ExternalResource> itor = getPassthroughResources(user).iterator();
@@ -167,7 +170,7 @@ public class AuthDataAccessor {
ExternalResource resource = itor.next();
String connObjectKey = null;
try {
- connObjectKey = MappingUtils.getConnObjectKeyValue(user, resource.getProvision(anyTypeDAO.findUser()));
+ connObjectKey = mappingUtils.getConnObjectKeyValue(user, resource.getProvision(anyTypeDAO.findUser()));
Uid uid = connFactory.getConnector(resource).authenticate(connObjectKey, password, null);
if (uid != null) {
authenticated = true;
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/misc/src/main/java/org/apache/syncope/core/misc/serialization/GuardedStringSerializer.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/serialization/GuardedStringSerializer.java b/core/misc/src/main/java/org/apache/syncope/core/misc/serialization/GuardedStringSerializer.java
index c86fb2e..5c780f0 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/serialization/GuardedStringSerializer.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/serialization/GuardedStringSerializer.java
@@ -60,14 +60,14 @@ class GuardedStringSerializer extends JsonSerializer<GuardedString> {
jgen.writeBooleanField("disposed", disposed);
final StringBuilder cleartext = new StringBuilder();
- ((GuardedString) source).access(new GuardedString.Accessor() {
+ source.access(new GuardedString.Accessor() {
@Override
public void access(final char[] clearChars) {
cleartext.append(clearChars);
}
});
- final byte[] encryptedBytes =
+ byte[] encryptedBytes =
EncryptorFactory.getInstance().getDefaultEncryptor().encrypt(cleartext.toString().getBytes());
jgen.writeStringField("encryptedBytes", Base64.encode(encryptedBytes));
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
index 530b406..fd349a9 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
@@ -33,6 +33,7 @@ public interface ImplementationLookup extends SyncopeLoader {
REPORTLET,
ACCOUNT_RULE,
PASSWORD_RULE,
+ MAPPING_ITEM_TRANSFORMER,
TASKJOBDELEGATE,
LOGIC_ACTIONS,
PROPAGATION_ACTIONS,
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
index 1a5380f..9f515ed 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.core.persistence.api.entity.resource;
+import java.util.List;
import org.apache.syncope.common.lib.types.IntMappingType;
import org.apache.syncope.common.lib.types.MappingPurpose;
import org.apache.syncope.core.persistence.api.entity.Entity;
@@ -56,4 +57,6 @@ public interface MappingItem extends Entity<Long> {
void setPassword(boolean password);
+ List<String> getMappingItemTransformerClassNames();
+
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
index ae9a117..8dba286 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
@@ -18,13 +18,19 @@
*/
package org.apache.syncope.core.persistence.jpa.entity.resource;
+import java.util.ArrayList;
+import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Cacheable;
+import javax.persistence.CollectionTable;
import javax.persistence.Column;
+import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
import javax.persistence.Id;
+import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.Max;
@@ -91,6 +97,16 @@ public class JPAMappingItem extends AbstractEntity<Long> implements MappingItem
@Enumerated(EnumType.STRING)
private MappingPurpose purpose;
+ /**
+ * (Optional) classes for MappingItem transformation.
+ */
+ @ElementCollection(fetch = FetchType.EAGER)
+ @Column(name = "transformerClassName")
+ @CollectionTable(name = "MappingItem_Transformer",
+ joinColumns =
+ @JoinColumn(name = "mappingItem_id", referencedColumnName = "id"))
+ private List<String> mappingItemTransformerClassNames = new ArrayList<>();
+
public JPAMappingItem() {
super();
@@ -214,4 +230,10 @@ public class JPAMappingItem extends AbstractEntity<Long> implements MappingItem
public void setPurpose(final MappingPurpose purpose) {
this.purpose = purpose;
}
+
+ @Override
+ public List<String> getMappingItemTransformerClassNames() {
+ return mappingItemTransformerClassNames;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
index 9ad2082..7879661 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
@@ -30,6 +30,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
public class ExternalResourceValidator extends AbstractValidator<ExternalResourceCheck, ExternalResource> {
@@ -106,6 +107,27 @@ public class ExternalResourceValidator extends AbstractValidator<ExternalResourc
isValid = false;
}
+ for (MappingItem item : mapping.getItems()) {
+ for (String className : item.getMappingItemTransformerClassNames()) {
+ Class<?> actionsClass = null;
+ boolean isAssignable = false;
+ try {
+ actionsClass = Class.forName(className);
+ isAssignable = MappingItemTransformer.class.isAssignableFrom(actionsClass);
+ } catch (Exception e) {
+ LOG.error("Invalid MappingItemTransformer specified: {}", className, e);
+ }
+
+ if (actionsClass == null || !isAssignable) {
+ context.buildConstraintViolationWithTemplate(
+ getTemplate(EntityViolationType.InvalidMapping,
+ "Invalid mapping item trasformer class name")).
+ addPropertyNode("mappingItemTransformerClassName").addConstraintViolation();
+ isValid = false;
+ }
+ }
+ }
+
return isValid;
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java
new file mode 100644
index 0000000..ae11199
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java
@@ -0,0 +1,47 @@
+/*
+ * 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.api.data;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+
+/**
+ * Transforms values to be propagated to (or synchronizing from) external resources right before they leave (or enter)
+ * the Syncope internal storage.
+ *
+ * These transformations are not applied to virtual attribute values.
+ */
+public interface MappingItemTransformer {
+
+ /**
+ * Invoked while preparing attribute values to be sent out to external resource during propagation.
+ *
+ * @param values original values
+ * @return transformed values
+ */
+ List<PlainAttrValue> beforePropagation(List<PlainAttrValue> values);
+
+ /**
+ * Invoked while reading attribute values from external resource during synchronization.
+ *
+ * @param values original values
+ * @return transformed values
+ */
+ List<Object> beforeSync(List<Object> values);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/AsyncConnectorFacade.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/AsyncConnectorFacade.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/AsyncConnectorFacade.java
index ae2d297..0b4340e 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/AsyncConnectorFacade.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/AsyncConnectorFacade.java
@@ -120,7 +120,7 @@ public class AsyncConnectorFacade {
Attribute attribute = null;
- final ConnectorObject object = connector.getObject(objectClass, uid, options);
+ ConnectorObject object = connector.getObject(objectClass, uid, options);
if (object == null) {
LOG.debug("Object for '{}' not found", uid.getUidValue());
} else {
@@ -137,9 +137,9 @@ public class AsyncConnectorFacade {
final Uid uid,
final OperationOptions options) {
- final Set<Attribute> attributes = new HashSet<>();
+ Set<Attribute> attributes = new HashSet<>();
- final ConnectorObject object = connector.getObject(objectClass, uid, options);
+ ConnectorObject object = connector.getObject(objectClass, uid, options);
if (object == null) {
LOG.debug("Object for '{}' not found", uid.getUidValue());
@@ -154,10 +154,10 @@ public class AsyncConnectorFacade {
@Async
public Future<Set<String>> getSchemaNames(final ConnectorFacade connector, final boolean includeSpecial) {
- final Set<String> schemaNames = new HashSet<>();
+ Set<String> schemaNames = new HashSet<>();
try {
- final Schema schema = connector.schema();
+ Schema schema = connector.schema();
for (ObjectClassInfo info : schema.getObjectClassInfo()) {
for (AttributeInfo attrInfo : info.getAttributeInfo()) {
if (includeSpecial || !AttributeUtil.isSpecialName(attrInfo.getName())) {
@@ -175,10 +175,10 @@ public class AsyncConnectorFacade {
@Async
public Future<Set<ObjectClass>> getSupportedObjectClasses(final ConnectorFacade connector) {
- final Set<ObjectClass> objectClasses = new HashSet<>();
+ Set<ObjectClass> objectClasses = new HashSet<>();
try {
- final Schema schema = connector.schema();
+ Schema schema = connector.schema();
for (ObjectClassInfo info : schema.getObjectClassInfo()) {
objectClasses.add(new ObjectClass(info.getType()));
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
index 3907700..3d60089 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
@@ -34,7 +34,6 @@ import org.apache.syncope.common.lib.patch.AttrPatch;
import org.apache.syncope.common.lib.to.AttrTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.IntMappingType;
-import org.apache.syncope.common.lib.types.MappingPurpose;
import org.apache.syncope.common.lib.types.PropagationByResource;
import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.core.misc.MappingUtils;
@@ -61,7 +60,6 @@ import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.ConnectorObject;
-import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.Uid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -102,6 +100,9 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
@Autowired
private VirAttrCache virAttrCache;
+ @Autowired
+ private MappingUtils mappingUtils;
+
@Override
public VirSchema getVirSchema(final String virSchemaName) {
VirSchema virtualSchema = null;
@@ -122,8 +123,8 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
final PropagationByResource propByRes) {
for (ExternalResource resource : resources) {
- for (MappingItem mapItem : MappingUtils.getMappingItems(
- resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) {
+ for (MappingItem mapItem
+ : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
if (schemaKey.equals(mapItem.getIntAttrName()) && mapItem.getIntMappingType() == mappingType) {
propByRes.add(ResourceOperation.UPDATE, resource.getKey());
@@ -232,8 +233,8 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
}
for (ExternalResource resource : externalResources) {
- for (MappingItem mapItem : MappingUtils.getMappingItems(
- resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) {
+ for (MappingItem mapItem
+ : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
if (virSchema.getKey().equals(mapItem.getIntAttrName())
&& mapItem.getIntMappingType() == anyUtils.virIntMappingType()) {
@@ -314,7 +315,7 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
LOG.debug("Search values into {},{}", resource, provision);
try {
- List<MappingItem> mappings = MappingUtils.getMappingItems(provision, MappingPurpose.BOTH);
+ List<MappingItem> mapItems = MappingUtils.getBothMappingItems(provision);
ConnectorObject connectorObject;
if (externalResources.containsKey(resource.getKey())) {
@@ -323,33 +324,26 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
LOG.debug("Perform connection to {}", resource.getKey());
String connObjectKey = MappingUtils.getConnObjectKeyItem(provision) == null
? null
- : MappingUtils.getConnObjectKeyValue(any, provision);
+ : mappingUtils.getConnObjectKeyValue(any, provision);
if (StringUtils.isBlank(connObjectKey)) {
throw new IllegalArgumentException("No ConnObjectKey found for " + resource.getKey());
}
Connector connector = connFactory.getConnector(resource);
-
- OperationOptions oo =
- connector.getOperationOptions(MappingUtils.getMatchingMappingItems(mappings, type));
-
- connectorObject =
- connector.getObject(provision.getObjectClass(), new Uid(connObjectKey), oo);
+ connectorObject = connector.getObject(
+ provision.getObjectClass(),
+ new Uid(connObjectKey),
+ connector.getOperationOptions(MappingUtils.getMatchingMappingItems(mapItems, type)));
externalResources.put(resource.getKey(), connectorObject);
}
if (connectorObject != null) {
- // ask for searched virtual attribute value
- Collection<MappingItem> virAttrMappings =
- MappingUtils.getMatchingMappingItems(mappings, schemaName, type);
-
- // the same virtual attribute could be mapped with one or more external attribute
- for (MappingItem mapping : virAttrMappings) {
- Attribute attribute = connectorObject.getAttributeByName(mapping.getExtAttrName());
-
- if (attribute != null && attribute.getValue() != null) {
- for (Object obj : attribute.getValue()) {
+ // the same virtual attribute could be mapped with one or more external attributes
+ for (MappingItem mapItem : MappingUtils.getMatchingMappingItems(mapItems, schemaName, type)) {
+ Attribute attr = connectorObject.getAttributeByName(mapItem.getExtAttrName());
+ if (attr != null && attr.getValue() != null) {
+ for (Object obj : attr.getValue()) {
if (obj != null) {
virAttr.getValues().add(obj.toString());
}
@@ -390,7 +384,7 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
public boolean evaluate(final ExternalResource resource) {
return resource.getProvision(anyType) != null
&& !MappingUtils.getMatchingMappingItems(
- MappingUtils.getMappingItems(resource.getProvision(anyType), MappingPurpose.BOTH),
+ MappingUtils.getBothMappingItems(resource.getProvision(anyType)),
attr.getSchema().getKey(), type).isEmpty();
}
});