syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ilgro...@apache.org
Subject [3/6] syncope git commit: [SYNCOPE-1206] At the end of update, explicitely process dynamic memberships for group resources
Date Fri, 08 Sep 2017 13:42:05 GMT
[SYNCOPE-1206] At the end of update, explicitely process dynamic memberships for group resources


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/34a3456e
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/34a3456e
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/34a3456e

Branch: refs/heads/2_0_X
Commit: 34a3456e866eee91cf898f2fef5885332509ee84
Parents: 659fe4a
Author: Francesco Chicchiriccò <ilgrosso@apache.org>
Authored: Fri Sep 8 13:13:57 2017 +0200
Committer: Francesco Chicchiriccò <ilgrosso@apache.org>
Committed: Fri Sep 8 13:13:57 2017 +0200

----------------------------------------------------------------------
 .../syncope/core/logic/ResourceLogic.java       |  2 +-
 .../core/persistence/api/dao/AnyObjectDAO.java  |  3 ++
 .../core/persistence/api/dao/GroupDAO.java      | 38 +++++++++++---
 .../core/persistence/api/dao/UserDAO.java       |  3 ++
 .../persistence/jpa/dao/JPAAnyObjectDAO.java    | 18 +++++--
 .../core/persistence/jpa/dao/JPAGroupDAO.java   | 52 ++++++++++++++++++--
 .../core/persistence/jpa/dao/JPAUserDAO.java    | 17 +++++--
 .../core/provisioning/api/MappingManager.java   | 15 +++---
 .../provisioning/java/MappingManagerImpl.java   | 17 +++----
 .../java/data/AbstractAnyDataBinder.java        | 19 ++++---
 .../java/data/AnyObjectDataBinderImpl.java      | 33 +++++++++++--
 .../java/data/UserDataBinderImpl.java           | 27 +++++++++-
 .../AbstractPropagationTaskExecutor.java        |  5 +-
 .../propagation/PropagationManagerImpl.java     | 10 ++--
 .../pushpull/PlainAttrsPullCorrelationRule.java |  8 +--
 .../java/pushpull/PullJobDelegate.java          |  2 +-
 .../provisioning/java/pushpull/PullUtils.java   |  2 +-
 .../java/utils/ConnObjectUtils.java             |  7 ++-
 .../provisioning/java/utils/MappingUtils.java   | 33 +++----------
 .../syncope/fit/core/UserIssuesITCase.java      | 38 ++++++++++++++
 20 files changed, 257 insertions(+), 92 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/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 3f2ff75..24136aa 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
@@ -386,7 +386,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
 
             objectClass = resource.getOrgUnit().getObjectClass();
             options = MappingUtils.buildOperationOptions(
-                    MappingUtils.getPropagationItems(resource.getOrgUnit()).iterator());
+                    MappingUtils.getPropagationItems(resource.getOrgUnit().getItems()).iterator());
         } else {
             Triple<ExternalResource, AnyType, Provision> init = connObjectInit(key, anyTypeKey);
             resource = init.getLeft();

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
index 3749440..518575b 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
@@ -21,6 +21,8 @@ package org.apache.syncope.core.persistence.api.dao;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ARelationship;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
@@ -51,4 +53,5 @@ public interface AnyObjectDAO extends AnyDAO<AnyObject> {
 
     Collection<ExternalResource> findAllResources(AnyObject anyObject);
 
+    Pair<Set<String>, Set<String>> saveAndGetDynGroupMembs(AnyObject anyObject);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/GroupDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/GroupDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/GroupDAO.java
index 580fe32..08548b4 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/GroupDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/GroupDAO.java
@@ -20,6 +20,8 @@ package org.apache.syncope.core.persistence.api.dao;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
@@ -48,16 +50,40 @@ public interface GroupDAO extends AnyDAO<Group> {
 
     void clearADynMembers(Group group);
 
-    void refreshDynMemberships(AnyObject anyObject);
-
-    void removeDynMemberships(AnyObject anyObject);
+    /**
+     * Evaluates all the dynamic group membership conditions against the given anyObject (invoked during save).
+     *
+     * @param anyObject anyObject being saved
+     * @return pair of groups dynamically assigned before and after refresh
+     */
+    Pair<Set<String>, Set<String>> refreshDynMemberships(AnyObject anyObject);
+
+    /**
+     * Removes the dynamic group memberships of the given anyObject (invoked during delete).
+     *
+     * @param anyObject anyObject being deleted
+     * @return groups dynamically assigned before refresh
+     */
+    Set<String> removeDynMemberships(AnyObject anyObject);
 
     List<String> findUDynMembers(Group group);
 
     void clearUDynMembers(Group group);
 
-    void refreshDynMemberships(User user);
-
-    void removeDynMemberships(User user);
+    /**
+     * Evaluates all the dynamic group membership conditions against the given user (invoked during save).
+     *
+     * @param user user being saved
+     * @return pair of groups dynamically assigned before and after refresh
+     */
+    Pair<Set<String>, Set<String>> refreshDynMemberships(User user);
+
+    /**
+     * Removes the dynamic group memberships of the given anyObject (invoked during delete).
+     *
+     * @param user user being deleted
+     * @return groups dynamically assigned before refresh
+     */
+    Set<String> removeDynMemberships(User user);
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
index 7f1932a..13d7c77 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.persistence.api.dao;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.core.persistence.api.entity.Role;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
@@ -55,4 +56,6 @@ public interface UserDAO extends AnyDAO<User> {
     Collection<ExternalResource> findAllResources(User user);
 
     Pair<Boolean, Boolean> enforcePolicies(User user);
+
+    Pair<Set<String>, Set<String>> saveAndGetDynGroupMembs(User user);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
index 32c655c..1c2aaf4 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
@@ -36,6 +36,7 @@ import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.SetUtils;
 import org.apache.commons.collections4.Transformer;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.types.AnyEntitlement;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.core.spring.security.AuthContextUtils;
@@ -202,15 +203,24 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
         return query.getResultList();
     }
 
-    @Override
-    public AnyObject save(final AnyObject anyObject) {
+    private Pair<AnyObject, Pair<Set<String>, Set<String>>> doSave(final AnyObject anyObject) {
         AnyObject merged = super.save(anyObject);
         publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, merged, AuthContextUtils.getDomain()));
 
-        groupDAO().refreshDynMemberships(merged);
+        Pair<Set<String>, Set<String>> dynGroupMembs = groupDAO().refreshDynMemberships(merged);
         dynRealmDAO().refreshDynMemberships(merged);
 
-        return merged;
+        return Pair.of(merged, dynGroupMembs);
+    }
+
+    @Override
+    public AnyObject save(final AnyObject anyObject) {
+        return doSave(anyObject).getLeft();
+    }
+
+    @Override
+    public Pair<Set<String>, Set<String>> saveAndGetDynGroupMembs(final AnyObject anyObject) {
+        return doSave(anyObject).getRight();
     }
 
     private List<ARelationship> findARelationships(final AnyObject anyObject) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index dca8d69..03c7d6a 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -23,6 +23,7 @@ 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;
@@ -33,6 +34,7 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.SetUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -419,7 +421,19 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
 
     @Transactional
     @Override
-    public void refreshDynMemberships(final AnyObject anyObject) {
+    public Pair<Set<String>, Set<String>> refreshDynMemberships(final AnyObject anyObject) {
+        Query dynGroupsQuery = entityManager().createNativeQuery(
+                "SELECT group_id FROM " + ADYNMEMB_TABLE + " WHERE any_id=?");
+        dynGroupsQuery.setParameter(1, anyObject.getKey());
+        @SuppressWarnings("unchecked")
+        List<String> dynGroups = dynGroupsQuery.getResultList();
+
+        Set<String> before = new HashSet<>();
+        for (String dynGroup : dynGroups) {
+            before.add(dynGroup);
+        }
+
+        Set<String> after = new HashSet<>();
         for (ADynGroupMembership memb : findWithADynMemberships(anyObject.getType())) {
             Query delete = entityManager().createNativeQuery(
                     "DELETE FROM " + ADYNMEMB_TABLE + " WHERE group_id=? AND any_id=?");
@@ -437,23 +451,32 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
                 insert.setParameter(2, anyObject.getKey());
                 insert.setParameter(3, memb.getGroup().getKey());
                 insert.executeUpdate();
+
+                after.add(memb.getGroup().getKey());
             }
 
             publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, memb.getGroup(), AuthContextUtils.getDomain()));
         }
+
+        return Pair.of(before, after);
     }
 
     @Override
-    public void removeDynMemberships(final AnyObject anyObject) {
+    public Set<String> removeDynMemberships(final AnyObject anyObject) {
         List<Group> dynGroups = anyObjectDAO().findDynGroups(anyObject.getKey());
 
         Query delete = entityManager().createNativeQuery("DELETE FROM " + ADYNMEMB_TABLE + " WHERE any_id=?");
         delete.setParameter(1, anyObject.getKey());
         delete.executeUpdate();
 
+        Set<String> before = new HashSet<>();
         for (Group group : dynGroups) {
+            before.add(group.getKey());
+
             publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, group, AuthContextUtils.getDomain()));
         }
+
+        return before;
     }
 
     @Override
@@ -494,7 +517,19 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
 
     @Transactional
     @Override
-    public void refreshDynMemberships(final User user) {
+    public Pair<Set<String>, Set<String>> refreshDynMemberships(final User user) {
+        Query dynGroupsQuery = entityManager().createNativeQuery(
+                "SELECT group_id FROM " + UDYNMEMB_TABLE + " WHERE any_id=?");
+        dynGroupsQuery.setParameter(1, user.getKey());
+        @SuppressWarnings("unchecked")
+        List<String> dynGroups = dynGroupsQuery.getResultList();
+
+        Set<String> before = new HashSet<>();
+        for (String dynGroup : dynGroups) {
+            before.add(dynGroup);
+        }
+
+        Set<String> after = new HashSet<>();
         for (UDynGroupMembership memb : findWithUDynMemberships()) {
             Query delete = entityManager().createNativeQuery(
                     "DELETE FROM " + UDYNMEMB_TABLE + " WHERE group_id=? AND any_id=?");
@@ -511,23 +546,32 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
                 insert.setParameter(1, user.getKey());
                 insert.setParameter(2, memb.getGroup().getKey());
                 insert.executeUpdate();
+
+                after.add(memb.getGroup().getKey());
             }
 
             publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, memb.getGroup(), AuthContextUtils.getDomain()));
         }
+
+        return Pair.of(before, after);
     }
 
     @Override
-    public void removeDynMemberships(final User user) {
+    public Set<String> removeDynMemberships(final User user) {
         List<Group> dynGroups = userDAO().findDynGroups(user.getKey());
 
         Query delete = entityManager().createNativeQuery("DELETE FROM " + UDYNMEMB_TABLE + " WHERE any_id=?");
         delete.setParameter(1, user.getKey());
         delete.executeUpdate();
 
+        Set<String> before = new HashSet<>();
         for (Group group : dynGroups) {
+            before.add(group.getKey());
+
             publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, group, AuthContextUtils.getDomain()));
         }
+
+        return before;
     }
 
     @Transactional(readOnly = true)

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
index 3d14999..f5bbd7f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
@@ -423,8 +423,7 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
         return ImmutablePair.of(suspend, propagateSuspension);
     }
 
-    @Override
-    public User save(final User user) {
+    private Pair<User, Pair<Set<String>, Set<String>>> doSave(final User user) {
         // 1. save clear password value before save
         String clearPwd = user.getClearPassword();
 
@@ -446,10 +445,20 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
         publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, merged, AuthContextUtils.getDomain()));
 
         roleDAO.refreshDynMemberships(merged);
-        groupDAO().refreshDynMemberships(merged);
+        Pair<Set<String>, Set<String>> dynGroupMembs = groupDAO().refreshDynMemberships(merged);
         dynRealmDAO().refreshDynMemberships(merged);
 
-        return merged;
+        return Pair.of(merged, dynGroupMembs);
+    }
+
+    @Override
+    public User save(final User user) {
+        return doSave(user).getLeft();
+    }
+
+    @Override
+    public Pair<Set<String>, Set<String>> saveAndGetDynGroupMembs(final User user) {
+        return doSave(user).getRight();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
index daa09e2..b62e221 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
@@ -27,9 +27,8 @@ import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.Realm;
-import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Item;
 import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
-import org.apache.syncope.core.persistence.api.entity.resource.OrgUnitItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.identityconnectors.framework.common.objects.Attribute;
 
@@ -54,7 +53,7 @@ public interface MappingManager {
     String getConnObjectKeyValue(Realm realm, OrgUnit orgUnit);
 
     /**
-     * Get attribute values for the given {@link MappingItem} and any object.
+     * Get attribute values for the given {@link Item} and any object.
      *
      * @param provision provision information
      * @param mapItem mapping item
@@ -62,7 +61,7 @@ public interface MappingManager {
      * @param any any object
      * @return attribute values.
      */
-    List<PlainAttrValue> getIntValues(Provision provision, MappingItem mapItem, IntAttrName intAttrName, Any<?> any);
+    List<PlainAttrValue> getIntValues(Provision provision, Item mapItem, IntAttrName intAttrName, Any<?> any);
 
     /**
      * Prepare attributes for sending to a connector instance.
@@ -87,7 +86,7 @@ public interface MappingManager {
     Pair<String, Set<Attribute>> prepareAttrs(Realm realm, OrgUnit orgUnit);
 
     /**
-     * Set attribute values, according to the given {@link MappingItem}, to any object from attribute received from
+     * Set attribute values, according to the given {@link Item}, to any object from attribute received from
      * connector.
      *
      * @param <T> any object
@@ -96,16 +95,16 @@ public interface MappingManager {
      * @param anyTO any object
      * @param anyUtils any utils
      */
-    <T extends AnyTO> void setIntValues(MappingItem mapItem, Attribute attr, T anyTO, AnyUtils anyUtils);
+    <T extends AnyTO> void setIntValues(Item mapItem, Attribute attr, T anyTO, AnyUtils anyUtils);
 
     /**
-     * Set attribute values, according to the given {@link OrgUnitItem}, to realm from attribute received from
+     * Set attribute values, according to the given {@link Item}, to realm from attribute received from
      * connector.
      *
      * @param orgUnitItem mapping item
      * @param attr attribute received from connector
      * @param realmTO realm
      */
-    void setIntValues(OrgUnitItem orgUnitItem, Attribute attr, RealmTO realmTO);
+    void setIntValues(Item orgUnitItem, Attribute attr, RealmTO realmTO);
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
index 1a47080..80a74b9 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
@@ -60,6 +60,7 @@ import org.apache.syncope.core.persistence.api.entity.Schema;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.resource.Item;
 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.OrgUnit;
@@ -154,7 +155,7 @@ public class MappingManagerImpl implements MappingManager {
         Set<Attribute> attributes = new HashSet<>();
         String connObjectKey = null;
 
-        for (MappingItem mapItem : MappingUtils.getPropagationItems(provision)) {
+        for (Item mapItem : MappingUtils.getPropagationItems(provision.getMapping().getItems())) {
             LOG.debug("Processing expression '{}'", mapItem.getIntAttrName());
 
             try {
@@ -215,7 +216,7 @@ public class MappingManagerImpl implements MappingManager {
         return Pair.of(connObjectKey, attributes);
     }
 
-    private String getIntValue(final Realm realm, final OrgUnitItem orgUnitItem) {
+    private String getIntValue(final Realm realm, final Item orgUnitItem) {
         String value = null;
         switch (orgUnitItem.getIntAttrName()) {
             case "key":
@@ -243,7 +244,7 @@ public class MappingManagerImpl implements MappingManager {
         Set<Attribute> attributes = new HashSet<>();
         String connObjectKey = null;
 
-        for (OrgUnitItem orgUnitItem : MappingUtils.getPropagationItems(orgUnit)) {
+        for (Item orgUnitItem : MappingUtils.getPropagationItems(orgUnit.getItems())) {
             LOG.debug("Processing expression '{}'", orgUnitItem.getIntAttrName());
 
             String value = getIntValue(realm, orgUnitItem);
@@ -293,7 +294,7 @@ public class MappingManagerImpl implements MappingManager {
      * @return connObjectKey + prepared attribute
      */
     private Pair<String, Attribute> prepareAttr(
-            final Provision provision, final MappingItem mapItem, final Any<?> any, final String password) {
+            final Provision provision, final Item mapItem, final Any<?> any, final String password) {
 
         IntAttrName intAttrName =
                 intAttrNameParser.parse(mapItem.getIntAttrName(), provision.getAnyType().getKind());
@@ -386,7 +387,7 @@ public class MappingManagerImpl implements MappingManager {
     @Override
     public List<PlainAttrValue> getIntValues(
             final Provision provision,
-            final MappingItem mapItem,
+            final Item mapItem,
             final IntAttrName intAttrName,
             final Any<?> any) {
 
@@ -606,9 +607,7 @@ public class MappingManagerImpl implements MappingManager {
 
     @Transactional(readOnly = true)
     @Override
-    public void setIntValues(
-            final MappingItem mapItem, final Attribute attr, final AnyTO anyTO, final AnyUtils anyUtils) {
-
+    public void setIntValues(final Item mapItem, final Attribute attr, final AnyTO anyTO, final AnyUtils anyUtils) {
         List<Object> values = null;
         if (attr != null) {
             values = attr.getValue();
@@ -768,7 +767,7 @@ public class MappingManagerImpl implements MappingManager {
     }
 
     @Override
-    public void setIntValues(final OrgUnitItem orgUnitItem, final Attribute attr, final RealmTO realmTO) {
+    public void setIntValues(final Item orgUnitItem, final Attribute attr, final RealmTO realmTO) {
         List<Object> values = null;
         if (attr != null) {
             values = attr.getValue();

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/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 e271654..5b8d693 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
@@ -70,6 +70,7 @@ import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.resource.Item;
 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.DerAttrHandler;
@@ -202,7 +203,7 @@ abstract class AbstractAnyDataBinder {
     private List<String> evaluateMandatoryCondition(final Provision provision, final Any<?> any) {
         List<String> missingAttrNames = new ArrayList<>();
 
-        for (MappingItem mapItem : MappingUtils.getPropagationItems(provision)) {
+        for (Item mapItem : MappingUtils.getPropagationItems(provision.getMapping().getItems())) {
             IntAttrName intAttrName =
                     intAttrNameParser.parse(mapItem.getIntAttrName(), provision.getAnyType().getKind());
             if (intAttrName.getSchemaType() != null) {
@@ -322,12 +323,18 @@ abstract class AbstractAnyDataBinder {
         }
 
         for (ExternalResource resource : resources) {
-            for (MappingItem item : MappingUtils.getPropagationItems(resource.getProvision(any.getType()))) {
-                if (schema.getKey().equals(item.getIntAttrName())) {
-                    propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+            if (resource.getProvision(any.getType()) != null
+                    && resource.getProvision(any.getType()).getMapping() != null) {
 
-                    if (item.isConnObjectKey() && !attr.getValuesAsStrings().isEmpty()) {
-                        propByRes.addOldConnObjectKey(resource.getKey(), attr.getValuesAsStrings().get(0));
+                for (Item item : MappingUtils.getPropagationItems(
+                        resource.getProvision(any.getType()).getMapping().getItems())) {
+
+                    if (schema.getKey().equals(item.getIntAttrName())) {
+                        propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+
+                        if (item.isConnObjectKey() && !attr.getValuesAsStrings().isEmpty()) {
+                            propByRes.addOldConnObjectKey(resource.getKey(), attr.getValuesAsStrings().get(0));
+                        }
                     }
                 }
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
index b6d5574..c2983e4 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
@@ -25,8 +25,10 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.SetUtils;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.patch.AnyObjectPatch;
@@ -411,10 +413,8 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
         propByRes.addAll(ResourceOperation.DELETE, toBeDeprovisioned);
         propByRes.addAll(ResourceOperation.UPDATE, toBeProvisioned);
 
-        /**
-         * In case of new memberships all the current resources have to be updated in order to propagate new group and
-         * membership attribute values.
-         */
+        // In case of new memberships all current resources need to be updated in order to propagate new group
+        // attribute values.
         if (!toBeDeprovisioned.isEmpty() || !toBeProvisioned.isEmpty()) {
             currentResources.removeAll(toBeDeprovisioned);
             propByRes.addAll(ResourceOperation.UPDATE, currentResources);
@@ -431,7 +431,30 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
             }
         }
 
-        anyObjectDAO.save(anyObject);
+        Pair<Set<String>, Set<String>> dynGroupMembs = anyObjectDAO.saveAndGetDynGroupMembs(anyObject);
+
+        // finally check if any resource assignment is to be processed due to dynamic group membership change
+        for (String delete : SetUtils.difference(dynGroupMembs.getLeft(), dynGroupMembs.getRight())) {
+            for (ExternalResource resource : groupDAO.find(delete).getResources()) {
+                if (!propByRes.contains(resource.getKey())) {
+                    propByRes.add(ResourceOperation.DELETE, resource.getKey());
+                }
+            }
+        }
+        for (String update : SetUtils.intersection(dynGroupMembs.getLeft(), dynGroupMembs.getRight())) {
+            for (ExternalResource resource : groupDAO.find(update).getResources()) {
+                if (!propByRes.contains(resource.getKey())) {
+                    propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+                }
+            }
+        }
+        for (String create : SetUtils.difference(dynGroupMembs.getRight(), dynGroupMembs.getLeft())) {
+            for (ExternalResource resource : groupDAO.find(create).getResources()) {
+                if (!propByRes.contains(resource.getKey())) {
+                    propByRes.add(ResourceOperation.CREATE, resource.getKey());
+                }
+            }
+        }
 
         // Throw composite exception if there is at least one element set in the composing exceptions
         if (scce.hasExceptions()) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index b046089..ff53e1b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -29,8 +29,10 @@ import javax.annotation.Resource;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
+import org.apache.commons.collections4.SetUtils;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.patch.AttrPatch;
@@ -528,7 +530,30 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             }
         }
 
-        userDAO.save(user);
+        Pair<Set<String>, Set<String>> dynGroupMembs = userDAO.saveAndGetDynGroupMembs(user);
+
+        // finally check if any resource assignment is to be processed due to dynamic group membership change
+        for (String delete : SetUtils.difference(dynGroupMembs.getLeft(), dynGroupMembs.getRight())) {
+            for (ExternalResource resource : groupDAO.find(delete).getResources()) {
+                if (!propByRes.contains(resource.getKey())) {
+                    propByRes.add(ResourceOperation.DELETE, resource.getKey());
+                }
+            }
+        }
+        for (String update : SetUtils.intersection(dynGroupMembs.getLeft(), dynGroupMembs.getRight())) {
+            for (ExternalResource resource : groupDAO.find(update).getResources()) {
+                if (!propByRes.contains(resource.getKey())) {
+                    propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+                }
+            }
+        }
+        for (String create : SetUtils.difference(dynGroupMembs.getRight(), dynGroupMembs.getLeft())) {
+            for (ExternalResource resource : groupDAO.find(create).getResources()) {
+                if (!propByRes.contains(resource.getKey())) {
+                    propByRes.add(ResourceOperation.CREATE, resource.getKey());
+                }
+            }
+        }
 
         // Throw composite exception if there is at least one element set in the composing exceptions
         if (scce.hasExceptions()) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/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 395a5a8..02bb8b7 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
@@ -613,7 +613,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
                     AttributeBuilder.build(
                             MappingUtils.getConnObjectKeyItem(provision).getExtAttrName(), connObjectKey),
                     MappingUtils.buildOperationOptions(IteratorUtils.chainedIterator(
-                            MappingUtils.getPropagationItems(provision).iterator(),
+                            MappingUtils.getPropagationItems(provision.getMapping().getItems()).iterator(),
                             linkingMappingItems.iterator())));
 
             for (MappingItem item : linkingMappingItems) {
@@ -659,7 +659,8 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
         try {
             obj = connector.getObject(new ObjectClass(task.getObjectClassName()),
                     AttributeBuilder.build(orgUnit.getConnObjectKeyItem().getExtAttrName(), connObjectKey),
-                    MappingUtils.buildOperationOptions(MappingUtils.getPropagationItems(orgUnit).iterator()));
+                    MappingUtils.buildOperationOptions(
+                            MappingUtils.getPropagationItems(orgUnit.getItems()).iterator()));
         } catch (TimeoutException toe) {
             LOG.debug("Request timeout", toe);
             throw toe;

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/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 fdeb848..c2228a7 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
@@ -54,7 +54,7 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 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.resource.Item;
 import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.provisioning.api.MappingManager;
@@ -368,9 +368,9 @@ public class PropagationManagerImpl implements PropagationManager {
         for (Map.Entry<String, ResourceOperation> entry : propByRes.asMap().entrySet()) {
             ExternalResource resource = resourceDAO.find(entry.getKey());
             Provision provision = resource == null ? null : resource.getProvision(any.getType());
-            List<? extends MappingItem> mappingItems = provision == null
-                    ? Collections.<MappingItem>emptyList()
-                    : MappingUtils.getPropagationItems(provision);
+            List<? extends Item> mappingItems = provision == null
+                    ? Collections.<Item>emptyList()
+                    : MappingUtils.getPropagationItems(provision.getMapping().getItems());
 
             if (resource == null) {
                 LOG.error("Invalid resource name specified: {}, ignoring...", entry.getKey());
@@ -400,7 +400,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 : mappingItems) {
+                for (Item item : mappingItems) {
                     if (!item.isConnObjectKey()
                             && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
index 81bfd70..1874e6a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
@@ -25,7 +25,7 @@ import java.util.Map;
 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.Item;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
@@ -46,8 +46,8 @@ public class PlainAttrsPullCorrelationRule implements PullCorrelationRule {
 
     @Override
     public SearchCond getSearchCond(final ConnectorObject connObj) {
-        Map<String, MappingItem> mappingItems = new HashMap<>();
-        for (MappingItem item : MappingUtils.getPullItems(provision)) {
+        Map<String, Item> mappingItems = new HashMap<>();
+        for (Item item : MappingUtils.getPullItems(provision.getMapping().getItems())) {
             mappingItems.put(item.getIntAttrName(), item);
         }
 
@@ -55,7 +55,7 @@ public class PlainAttrsPullCorrelationRule implements PullCorrelationRule {
         SearchCond searchCond = null;
 
         for (String schema : plainSchemaNames) {
-            MappingItem mappingItem = mappingItems.get(schema);
+            Item mappingItem = mappingItems.get(schema);
             Attribute attr = mappingItem == null
                     ? null
                     : connObj.getAttributeByName(mappingItem.getExtAttrName());

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
index 3520db0..b0c2370 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
@@ -152,7 +152,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
         if (pullTask.getResource().getOrgUnit() != null) {
             OrgUnit orgUnit = pullTask.getResource().getOrgUnit();
             OperationOptions options = MappingUtils.buildOperationOptions(
-                    MappingUtils.getPullItems(orgUnit).iterator());
+                    MappingUtils.getPullItems(orgUnit.getItems()).iterator());
 
             SyncopePullResultHandler rhandler = (SyncopePullResultHandler) ApplicationContextProvider.getBeanFactory().
                     createBean(RealmPullResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
index 7dee306..3503c9b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
@@ -139,7 +139,7 @@ public class PullUtils {
             public boolean handle(final ConnectorObject obj) {
                 return found.add(obj);
             }
-        }, MappingUtils.buildOperationOptions(MappingUtils.getPullItems(provision).iterator()));
+        }, MappingUtils.buildOperationOptions(MappingUtils.getPullItems(provision.getMapping().getItems()).iterator()));
 
         if (found.isEmpty()) {
             LOG.debug("No {} found on {} with __NAME__ {}", provision.getObjectClass(), resource, name);

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
index 249e488..c6db575 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
@@ -35,15 +35,14 @@ import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
 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.user.User;
 import org.apache.syncope.core.spring.security.Encryptor;
 import org.apache.syncope.core.spring.security.PasswordGenerator;
 import org.apache.syncope.core.spring.security.SecureRandomUtils;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.resource.Item;
 import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
-import org.apache.syncope.core.persistence.api.entity.resource.OrgUnitItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.api.entity.task.PullTask;
 import org.apache.syncope.core.provisioning.api.MappingManager;
@@ -165,7 +164,7 @@ public class ConnObjectUtils {
     public RealmTO getRealmTO(final ConnectorObject obj, final PullTask task, final OrgUnit orgUnit) {
         RealmTO realmTO = new RealmTO();
 
-        for (OrgUnitItem item : MappingUtils.getPullItems(orgUnit)) {
+        for (Item item : MappingUtils.getPullItems(orgUnit.getItems())) {
             mappingManager.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), realmTO);
         }
 
@@ -268,7 +267,7 @@ public class ConnObjectUtils {
 
         // 1. fill with data from connector object
         anyTO.setRealm(pullTask.getDestinatioRealm().getFullPath());
-        for (MappingItem item : MappingUtils.getPullItems(provision)) {
+        for (Item item : MappingUtils.getPullItems(provision.getMapping().getItems())) {
             mappingManager.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), anyTO, anyUtils);
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
index ce794af..ba2c7a4 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
@@ -37,7 +37,6 @@ import org.apache.syncope.core.persistence.api.entity.resource.Item;
 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.OrgUnit;
-import org.apache.syncope.core.persistence.api.entity.resource.OrgUnitItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.provisioning.java.data.JEXLItemTransformerImpl;
 import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
@@ -68,41 +67,21 @@ public final class MappingUtils {
                 : mapping.getConnObjectKeyItem();
     }
 
-    public static List<? extends MappingItem> getPropagationItems(final Provision provision) {
-        return ListUtils.select(provision.getMapping().getItems(), new Predicate<MappingItem>() {
+    public static List<? extends Item> getPropagationItems(final List<? extends Item> items) {
+        return ListUtils.select(items, new Predicate<Item>() {
 
             @Override
-            public boolean evaluate(final MappingItem item) {
+            public boolean evaluate(final Item item) {
                 return item.getPurpose() == MappingPurpose.PROPAGATION || item.getPurpose() == MappingPurpose.BOTH;
             }
         });
     }
 
-    public static List<? extends MappingItem> getPullItems(final Provision provision) {
-        return ListUtils.select(provision.getMapping().getItems(), new Predicate<MappingItem>() {
+    public static List<? extends Item> getPullItems(final List<? extends Item> items) {
+        return ListUtils.select(items, new Predicate<Item>() {
 
             @Override
-            public boolean evaluate(final MappingItem item) {
-                return item.getPurpose() == MappingPurpose.PULL || item.getPurpose() == MappingPurpose.BOTH;
-            }
-        });
-    }
-
-    public static List<? extends OrgUnitItem> getPropagationItems(final OrgUnit orgUnit) {
-        return ListUtils.select(orgUnit.getItems(), new Predicate<OrgUnitItem>() {
-
-            @Override
-            public boolean evaluate(final OrgUnitItem item) {
-                return item.getPurpose() == MappingPurpose.PROPAGATION || item.getPurpose() == MappingPurpose.BOTH;
-            }
-        });
-    }
-
-    public static List<? extends OrgUnitItem> getPullItems(final OrgUnit orgUnit) {
-        return ListUtils.select(orgUnit.getItems(), new Predicate<OrgUnitItem>() {
-
-            @Override
-            public boolean evaluate(final OrgUnitItem item) {
+            public boolean evaluate(final Item item) {
                 return item.getPurpose() == MappingPurpose.PULL || item.getPurpose() == MappingPurpose.BOTH;
             }
         });

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a3456e/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
index b7b5a83..a708cb2 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
@@ -40,8 +40,10 @@ import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.cxf.common.util.Base64Utility;
 import org.apache.cxf.helpers.IOUtils;
+import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.patch.MembershipPatch;
 import org.apache.syncope.common.lib.patch.PasswordPatch;
 import org.apache.syncope.common.lib.patch.StringPatchItem;
@@ -1394,4 +1396,40 @@ public class UserIssuesITCase extends AbstractITCase {
         assertEquals(RESOURCE_NAME_DBVIRATTR, result.getPropagationStatuses().get(1).getResource());
         assertEquals(PropagationTaskExecStatus.SUCCESS, result.getPropagationStatuses().get(1).getStatus());
     }
+
+    @Test
+    public void issueSYNCOPE1206() {
+        // 1. create group with dynamic user condition 'cool==true'
+        GroupTO dynGroup = GroupITCase.getSampleTO("syncope1206");
+        dynGroup.setUDynMembershipCond(
+                SyncopeClient.getUserSearchConditionBuilder().is("cool").equalTo("true").query());
+        dynGroup = createGroup(dynGroup).getEntity();
+        assertNotNull(dynGroup);
+        assertTrue(dynGroup.getResources().contains(RESOURCE_NAME_LDAP));
+
+        // 2. create user (no value for cool, no dynamic membership, no propagation to LDAP)
+        UserTO userTO = UserITCase.getUniqueSampleTO("syncope1206@apache.org");
+        userTO.getResources().clear();
+
+        ProvisioningResult<UserTO> result = createUser(userTO);
+        assertTrue(result.getPropagationStatuses().isEmpty());
+
+        // 3. update user to match the dynamic condition: expect propagation to LDAP
+        UserPatch userPatch = new UserPatch();
+        userPatch.setKey(result.getEntity().getKey());
+        userPatch.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO("cool", "true")).build());
+
+        result = updateUser(userPatch);
+        assertEquals(1, result.getPropagationStatuses().size());
+        assertEquals(RESOURCE_NAME_LDAP, result.getPropagationStatuses().get(0).getResource());
+
+        // 4. update again user to not match the dynamic condition any more: expect propagation to LDAP
+        userPatch = new UserPatch();
+        userPatch.setKey(result.getEntity().getKey());
+        userPatch.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO("cool", "false")).build());
+
+        result = updateUser(userPatch);
+        assertEquals(1, result.getPropagationStatuses().size());
+        assertEquals(RESOURCE_NAME_LDAP, result.getPropagationStatuses().get(0).getResource());
+    }
 }


Mime
View raw message