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 2017/09/08 13:42:03 UTC

[1/6] syncope git commit: Ensure (user)name is always not null before checking regexp

Repository: syncope
Updated Branches:
  refs/heads/2_0_X 2e705fd07 -> 34a3456e8
  refs/heads/master 6882751d2 -> 5295039bb


Ensure (user)name is always not null before checking regexp


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

Branch: refs/heads/2_0_X
Commit: 459b42adb619732ae35413934f33455f77f4aea6
Parents: 2e705fd
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Sep 8 10:43:08 2017 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Sep 8 10:43:08 2017 +0200

----------------------------------------------------------------------
 .../org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java  | 4 ++++
 .../persistence/jpa/validation/entity/AnyObjectValidator.java    | 2 +-
 .../core/persistence/jpa/validation/entity/GroupValidator.java   | 2 +-
 3 files changed, 6 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/459b42ad/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 e1bfaf1..3d14999 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
@@ -375,6 +375,10 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
         boolean suspend = false;
         boolean propagateSuspension = false;
         try {
+            if (user.getUsername() == null) {
+                throw new AccountPolicyException("Null username");
+            }
+
             if (adminUser.equals(user.getUsername()) || anonymousUser.equals(user.getUsername())) {
                 throw new AccountPolicyException("Not allowed: " + user.getUsername());
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/459b42ad/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyObjectValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyObjectValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyObjectValidator.java
index 67879b5..f63cb82 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyObjectValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyObjectValidator.java
@@ -28,7 +28,7 @@ public class AnyObjectValidator extends AbstractValidator<AnyObjectCheck, AnyObj
     public boolean isValid(final AnyObject anyObject, final ConstraintValidatorContext context) {
         context.disableDefaultConstraintViolation();
 
-        boolean isValid = KEY_PATTERN.matcher(anyObject.getName()).matches();
+        boolean isValid = anyObject.getName() != null && KEY_PATTERN.matcher(anyObject.getName()).matches();
 
         if (!isValid) {
             context.buildConstraintViolationWithTemplate(

http://git-wip-us.apache.org/repos/asf/syncope/blob/459b42ad/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GroupValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GroupValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GroupValidator.java
index 50ed3b9..65fcac7 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GroupValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GroupValidator.java
@@ -44,7 +44,7 @@ public class GroupValidator extends AbstractValidator<GroupCheck, Group> {
                     addPropertyNode("owner").addConstraintViolation();
         }
 
-        if (isValid && !KEY_PATTERN.matcher(group.getName()).matches()) {
+        if (isValid && (group.getName() == null || !KEY_PATTERN.matcher(group.getName()).matches())) {
             isValid = false;
 
             context.buildConstraintViolationWithTemplate(


[2/6] syncope git commit: White noise: ignore

Posted by il...@apache.org.
White noise: ignore


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

Branch: refs/heads/2_0_X
Commit: 659fe4a21b82e2dabb38901e70a473c15d995bbb
Parents: 459b42a
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Sep 8 10:43:29 2017 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Sep 8 10:43:29 2017 +0200

----------------------------------------------------------------------
 .../syncope/client/console/approvals/ApprovalDirectoryPanel.java  | 3 ++-
 .../test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/659fe4a2/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
index 42258ba..4b6272a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
@@ -323,6 +323,7 @@ public class ApprovalDirectoryPanel
                 final List<String> anyTypeClasses,
                 final UserFormLayoutInfo formLayoutInfo,
                 final PageReference pageRef) {
+
             super(previousUserTO, userTO, anyTypeClasses, formLayoutInfo, pageRef);
             this.formTO = formTO;
             this.target = target;
@@ -341,7 +342,6 @@ public class ApprovalDirectoryPanel
                 claimForm(restClient.getFormForUser(actual.getEntity().getKey()).getTaskId());
                 ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
             } else {
-
                 UserPatch patch = AnyOperations.diff(inner, formTO.getUserTO(), false);
 
                 if (StringUtils.isNotBlank(inner.getPassword())) {
@@ -362,6 +362,7 @@ public class ApprovalDirectoryPanel
                 }
 
             }
+
             return actual;
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/659fe4a2/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
index fc4877d..8de8265 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
@@ -154,7 +154,7 @@ public class UserWorkflowITCase extends AbstractITCase {
         userTO.getMemberships().add(
                 new MembershipTO.Builder().group("0cbcabd2-4410-4b6b-8f05-a052b451d18f").build());
 
-        // 1. create user with group 9 (and verify that no propagation occurred)
+        // 1. create user and verify that no propagation occurred)
         ProvisioningResult<UserTO> result = createUser(userTO);
         assertNotNull(result);
         userTO = result.getEntity();


[3/6] syncope git commit: [SYNCOPE-1206] At the end of update, explicitely process dynamic memberships for group resources

Posted by il...@apache.org.
[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ò <il...@apache.org>
Authored: Fri Sep 8 13:13:57 2017 +0200
Committer: Francesco Chicchiriccò <il...@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());
+    }
 }


[4/6] syncope git commit: Ensure (user)name is always not null before checking regexp

Posted by il...@apache.org.
Ensure (user)name is always not null before checking regexp


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

Branch: refs/heads/master
Commit: cf2c965a0ab2d69ef783f54d063057ec669f91dd
Parents: 6882751
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Sep 8 10:43:08 2017 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Sep 8 13:14:14 2017 +0200

----------------------------------------------------------------------
 .../org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java  | 4 ++++
 .../persistence/jpa/validation/entity/AnyObjectValidator.java    | 2 +-
 .../core/persistence/jpa/validation/entity/GroupValidator.java   | 2 +-
 3 files changed, 6 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/cf2c965a/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 02281fa..d4de448 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
@@ -363,6 +363,10 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
         boolean suspend = false;
         boolean propagateSuspension = false;
         try {
+            if (user.getUsername() == null) {
+                throw new AccountPolicyException("Null username");
+            }
+
             if (adminUser.equals(user.getUsername()) || anonymousUser.equals(user.getUsername())) {
                 throw new AccountPolicyException("Not allowed: " + user.getUsername());
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/cf2c965a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyObjectValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyObjectValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyObjectValidator.java
index 67879b5..f63cb82 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyObjectValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyObjectValidator.java
@@ -28,7 +28,7 @@ public class AnyObjectValidator extends AbstractValidator<AnyObjectCheck, AnyObj
     public boolean isValid(final AnyObject anyObject, final ConstraintValidatorContext context) {
         context.disableDefaultConstraintViolation();
 
-        boolean isValid = KEY_PATTERN.matcher(anyObject.getName()).matches();
+        boolean isValid = anyObject.getName() != null && KEY_PATTERN.matcher(anyObject.getName()).matches();
 
         if (!isValid) {
             context.buildConstraintViolationWithTemplate(

http://git-wip-us.apache.org/repos/asf/syncope/blob/cf2c965a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GroupValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GroupValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GroupValidator.java
index 50ed3b9..65fcac7 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GroupValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GroupValidator.java
@@ -44,7 +44,7 @@ public class GroupValidator extends AbstractValidator<GroupCheck, Group> {
                     addPropertyNode("owner").addConstraintViolation();
         }
 
-        if (isValid && !KEY_PATTERN.matcher(group.getName()).matches()) {
+        if (isValid && (group.getName() == null || !KEY_PATTERN.matcher(group.getName()).matches())) {
             isValid = false;
 
             context.buildConstraintViolationWithTemplate(


[6/6] syncope git commit: [SYNCOPE-1206] At the end of update, explicitely process dynamic memberships for group resources

Posted by il...@apache.org.
[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/5295039b
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/5295039b
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/5295039b

Branch: refs/heads/master
Commit: 5295039bb5443114822d288635589f8b24b43609
Parents: 19a0345
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Sep 8 13:13:57 2017 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Sep 8 15:41:54 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   | 46 ++++++++++++++++++--
 .../core/persistence/jpa/dao/JPAUserDAO.java    | 17 ++++++--
 .../entity/resource/JPAExternalResource.java    |  7 +--
 .../core/provisioning/api/MappingManager.java   | 15 +++----
 .../provisioning/java/MappingManagerImpl.java   | 17 ++++----
 .../java/data/AbstractAnyDataBinder.java        | 35 +++++++++------
 .../java/data/AnyObjectDataBinderImpl.java      | 38 +++++++++++++---
 .../java/data/UserDataBinderImpl.java           | 32 +++++++++++++-
 .../AbstractPropagationTaskExecutor.java        |  5 ++-
 .../propagation/PropagationManagerImpl.java     | 12 ++---
 .../pushpull/PlainAttrsPullCorrelationRule.java |  8 ++--
 .../java/pushpull/PullJobDelegate.java          |  2 +-
 .../provisioning/java/pushpull/PullUtils.java   |  3 +-
 .../java/utils/ConnObjectUtils.java             |  4 +-
 .../provisioning/java/utils/MappingUtils.java   | 26 ++---------
 .../syncope/fit/core/UserIssuesITCase.java      | 38 ++++++++++++++++
 21 files changed, 272 insertions(+), 97 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/5295039b/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 eccbd6d..16d2882 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
@@ -373,7 +373,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/5295039b/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/5295039b/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 4bc1488..1ee1cf1 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
@@ -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.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
@@ -51,16 +53,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/5295039b/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/5295039b/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 a595389..1aa14de 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
@@ -32,6 +32,7 @@ import java.util.stream.Collectors;
 import javax.persistence.NoResultException;
 import javax.persistence.Query;
 import javax.persistence.TypedQuery;
+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;
@@ -195,15 +196,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/5295039b/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 170915c..ae85977 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;
@@ -30,6 +31,7 @@ import java.util.stream.Collectors;
 import javax.persistence.NoResultException;
 import javax.persistence.Query;
 import javax.persistence.TypedQuery;
+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;
@@ -413,7 +415,16 @@ 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 = dynGroups.stream().collect(Collectors.toSet());
+
+        Set<String> after = new HashSet<>();
         findWithADynMemberships(anyObject.getType()).stream().map(memb -> {
             Query delete = entityManager().createNativeQuery(
                     "DELETE FROM " + ADYNMEMB_TABLE + " WHERE group_id=? AND any_id=?");
@@ -430,23 +441,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());
             }
             return memb;
         }).forEachOrdered(memb -> 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<>();
         dynGroups.forEach(group -> {
+            before.add(group.getKey());
+
             publisher.publishEvent(new AnyCreatedUpdatedEvent<>(this, group, AuthContextUtils.getDomain()));
         });
+
+        return before;
     }
 
     @Override
@@ -484,7 +504,16 @@ 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 = dynGroups.stream().collect(Collectors.toSet());
+
+        Set<String> after = new HashSet<>();
         findWithUDynMemberships().stream().map(memb -> {
             Query delete = entityManager().createNativeQuery(
                     "DELETE FROM " + UDYNMEMB_TABLE + " WHERE group_id=? AND any_id=?");
@@ -500,23 +529,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());
             }
             return memb;
         }).forEachOrdered(memb -> 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<>();
         dynGroups.forEach(group -> {
+            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/5295039b/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 d4de448..5b6998e 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
@@ -411,8 +411,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();
 
@@ -434,10 +433,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/5295039b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
index 511b586..6c34916 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.persistence.jpa.entity.resource;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
@@ -208,17 +209,17 @@ public class JPAExternalResource extends AbstractProvidedKeyEntity implements Ex
 
     @Override
     public Optional<? extends Provision> getProvision(final ObjectClass objectClass) {
-        return provisions.stream().filter(provision -> provision.getObjectClass().equals(objectClass)).findFirst();
+        return getProvisions().stream().filter(provision -> provision.getObjectClass().equals(objectClass)).findFirst();
     }
 
     @Override
     public Optional<? extends Provision> getProvision(final AnyType anyType) {
-        return provisions.stream().filter(provision -> provision.getAnyType().equals(anyType)).findFirst();
+        return getProvisions().stream().filter(provision -> provision.getAnyType().equals(anyType)).findFirst();
     }
 
     @Override
     public List<? extends Provision> getProvisions() {
-        return provisions;
+        return provisions == null ? Collections.emptyList() : provisions;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/5295039b/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 338a94e..a2e5c8e 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
@@ -28,9 +28,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;
 
@@ -55,7 +54,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
@@ -63,7 +62,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.
@@ -88,7 +87,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
@@ -97,16 +96,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/5295039b/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 b05e5b6..5e180ed 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
@@ -59,6 +59,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;
@@ -153,7 +154,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 {
@@ -214,7 +215,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":
@@ -242,7 +243,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();
@@ -769,7 +768,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/5295039b/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 a0620e6..fa838b7 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
@@ -201,7 +201,7 @@ abstract class AbstractAnyDataBinder {
     private List<String> evaluateMandatoryCondition(final Provision provision, final Any<?> any) {
         List<String> missingAttrNames = new ArrayList<>();
 
-        MappingUtils.getPropagationItems(provision).forEach(mapItem -> {
+        MappingUtils.getPropagationItems(provision.getMapping().getItems()).forEach(mapItem -> {
             IntAttrName intAttrName = intAttrNameParser.
                     parse(mapItem.getIntAttrName(), provision.getAnyType().getKind());
             if (intAttrName.getSchemaType() != null) {
@@ -215,7 +215,9 @@ abstract class AbstractAnyDataBinder {
         return missingAttrNames;
     }
 
-    private SyncopeClientException checkMandatoryOnResources(final Any<?> any, final Set<ExternalResource> resources) {
+    private SyncopeClientException checkMandatoryOnResources(
+            final Any<?> any, final Collection<? extends ExternalResource> resources) {
+
         SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
 
         resources.forEach(resource -> {
@@ -322,16 +324,21 @@ abstract class AbstractAnyDataBinder {
                 plainAttrDAO.delete(attr.getKey(), anyUtils.plainAttrClass());
         }
 
-        resources.forEach(resource -> {
-            MappingUtils.getPropagationItems(resource.getProvision(any.getType()).get()).stream().
-                    filter(item -> (schema.getKey().equals(item.getIntAttrName()))).
-                    forEachOrdered(item -> {
-                        propByRes.add(ResourceOperation.UPDATE, resource.getKey());
-                        if (item.isConnObjectKey() && !attr.getValuesAsStrings().isEmpty()) {
-                            propByRes.addOldConnObjectKey(resource.getKey(), attr.getValuesAsStrings().get(0));
-                        }
-                    });
-        });
+        resources.stream().
+                filter(resource -> (resource.getProvision(any.getType()).isPresent())
+                && resource.getProvision(any.getType()).get().getMapping() != null).
+                forEach(resource -> {
+                    MappingUtils.getPropagationItems(
+                            resource.getProvision(any.getType()).get().getMapping().getItems()).stream().
+                            filter(item -> (schema.getKey().equals(item.getIntAttrName()))).
+                            forEach(item -> {
+                                propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+
+                                if (item.isConnObjectKey() && !attr.getValuesAsStrings().isEmpty()) {
+                                    propByRes.addOldConnObjectKey(resource.getKey(), attr.getValuesAsStrings().get(0));
+                                }
+                            });
+                });
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -634,7 +641,7 @@ abstract class AbstractAnyDataBinder {
         Map<String, String> connObjectKeys = new HashMap<>();
 
         Iterable<? extends ExternalResource> iterable = anyUtils.getAllResources(any);
-        for (ExternalResource resource : iterable) {
+        anyUtils.getAllResources(any).forEach(resource -> {
             Optional<? extends Provision> provision = resource.getProvision(any.getType());
             if (provision.isPresent() && provision.get().getMapping() != null) {
                 Optional<MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision.get());
@@ -649,7 +656,7 @@ abstract class AbstractAnyDataBinder {
                     connObjectKeys.put(resource.getKey(), connObjectKey.get());
                 }
             }
-        }
+        });
 
         return connObjectKeys;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5295039b/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 40bb036..eafba37 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
@@ -27,6 +27,7 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 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;
@@ -389,10 +390,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);
@@ -408,7 +407,36 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
                     propByRes.add(ResourceOperation.UPDATE, entry.getKey());
                 });
 
-        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
+        dynGroupMembs.getLeft().stream().
+                filter(group -> !dynGroupMembs.getRight().contains(group)).
+                forEach(delete -> {
+                    groupDAO.find(delete).getResources().stream().
+                            filter(resource -> !propByRes.contains(resource.getKey())).
+                            forEach(resource -> {
+                                propByRes.add(ResourceOperation.DELETE, resource.getKey());
+                            });
+                });
+        dynGroupMembs.getLeft().stream().
+                filter(group -> dynGroupMembs.getRight().contains(group)).
+                forEach(update -> {
+                    groupDAO.find(update).getResources().stream().
+                            filter(resource -> !propByRes.contains(resource.getKey())).
+                            forEach(resource -> {
+                                propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+                            });
+                });
+        dynGroupMembs.getRight().stream().
+                filter(group -> !dynGroupMembs.getLeft().contains(group)).
+                forEach(create -> {
+                    groupDAO.find(create).getResources().stream().
+                            filter(resource -> !propByRes.contains(resource.getKey())).
+                            forEach(resource -> {
+                                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/5295039b/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 989a076..ce3a127 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,6 +29,7 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import javax.annotation.Resource;
 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;
@@ -511,7 +512,36 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
                     propByRes.add(ResourceOperation.UPDATE, entry.getKey());
                 });
 
-        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
+        dynGroupMembs.getLeft().stream().
+                filter(group -> !dynGroupMembs.getRight().contains(group)).
+                forEach(delete -> {
+                    groupDAO.find(delete).getResources().stream().
+                            filter(resource -> !propByRes.contains(resource.getKey())).
+                            forEach(resource -> {
+                                propByRes.add(ResourceOperation.DELETE, resource.getKey());
+                            });
+                });
+        dynGroupMembs.getLeft().stream().
+                filter(group -> dynGroupMembs.getRight().contains(group)).
+                forEach(update -> {
+                    groupDAO.find(update).getResources().stream().
+                            filter(resource -> !propByRes.contains(resource.getKey())).
+                            forEach(resource -> {
+                                propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+                            });
+                });
+        dynGroupMembs.getRight().stream().
+                filter(group -> !dynGroupMembs.getLeft().contains(group)).
+                forEach(create -> {
+                    groupDAO.find(create).getResources().stream().
+                            filter(resource -> !propByRes.contains(resource.getKey())).
+                            forEach(resource -> {
+                                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/5295039b/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 833edfc..9b1ab70 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
@@ -611,7 +611,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
                     AttributeBuilder.build(
                             MappingUtils.getConnObjectKeyItem(provision).get().getExtAttrName(), connObjectKey),
                     MappingUtils.buildOperationOptions(new IteratorChain<>(
-                            MappingUtils.getPropagationItems(provision).iterator(),
+                            MappingUtils.getPropagationItems(provision.getMapping().getItems()).iterator(),
                             linkingMappingItems.iterator())));
 
             for (MappingItem item : linkingMappingItems) {
@@ -657,7 +657,8 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
         try {
             obj = connector.getObject(new ObjectClass(task.getObjectClassName()),
                     AttributeBuilder.build(orgUnit.getConnObjectKeyItem().get().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/5295039b/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 14a8d5f..fb48708 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
@@ -52,7 +52,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;
@@ -360,12 +360,12 @@ public class PropagationManagerImpl implements PropagationManager {
 
         List<PropagationTask> tasks = new ArrayList<>();
 
-        for (Map.Entry<String, ResourceOperation> entry : propByRes.asMap().entrySet()) {
+        propByRes.asMap().entrySet().forEach(entry -> {
             ExternalResource resource = resourceDAO.find(entry.getKey());
             Provision provision = resource == null ? null : resource.getProvision(any.getType()).orElse(null);
-            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());
@@ -424,7 +424,7 @@ public class PropagationManagerImpl implements PropagationManager {
 
                 LOG.debug("PropagationTask created: {}", task);
             }
-        }
+        });
 
         return tasks;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5295039b/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/5295039b/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 eb94ba9..9c6f486 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/5295039b/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 ad431bf..15976b4 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
@@ -132,7 +132,8 @@ public class PullUtils {
         final List<ConnectorObject> found = new ArrayList<>();
         connector.search(provision.get().getObjectClass(),
                 new EqualsFilter(new Name(name)), obj -> found.add(obj),
-                MappingUtils.buildOperationOptions(MappingUtils.getPullItems(provision.get()).iterator()));
+                MappingUtils.buildOperationOptions(
+                        MappingUtils.getPullItems(provision.get().getMapping().getItems()).iterator()));
 
         if (found.isEmpty()) {
             LOG.debug("No {} found on {} with __NAME__ {}", provision.get().getObjectClass(), resource, name);

http://git-wip-us.apache.org/repos/asf/syncope/blob/5295039b/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 ca98f76..9f0bbd5 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
@@ -160,7 +160,7 @@ public class ConnObjectUtils {
     public RealmTO getRealmTO(final ConnectorObject obj, final PullTask task, final OrgUnit orgUnit) {
         RealmTO realmTO = new RealmTO();
 
-        MappingUtils.getPullItems(orgUnit).forEach(item -> {
+        MappingUtils.getPullItems(orgUnit.getItems()).forEach(item -> {
             mappingManager.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), realmTO);
         });
 
@@ -263,7 +263,7 @@ public class ConnObjectUtils {
 
         // 1. fill with data from connector object
         anyTO.setRealm(pullTask.getDestinatioRealm().getFullPath());
-        MappingUtils.getPullItems(provision).forEach(item -> {
+        MappingUtils.getPullItems(provision.getMapping().getItems()).forEach(item -> {
             mappingManager.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), anyTO, anyUtils);
         });
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5295039b/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 ebe4e2b..eee6d9a 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
@@ -19,7 +19,6 @@
 package org.apache.syncope.core.provisioning.java.utils;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -38,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;
@@ -69,34 +67,18 @@ public final class MappingUtils {
                 : mapping.getConnObjectKeyItem().get());
     }
 
-    public static List<? extends MappingItem> getPropagationItems(final Provision provision) {
-        return provision == null
-                ? Collections.emptyList()
-                : provision.getMapping().getItems().stream().
+    public static List<? extends Item> getPropagationItems(final List<? extends Item> items) {
+        return items.stream().
                         filter(item -> item.getPurpose() == MappingPurpose.PROPAGATION
                         || item.getPurpose() == MappingPurpose.BOTH).collect(Collectors.toList());
     }
 
-    public static List<? extends MappingItem> getPullItems(final Provision provision) {
-        return provision == null
-                ? Collections.emptyList()
-                : provision.getMapping().getItems().stream().
+    public static List<? extends Item> getPullItems(final List<? extends Item> items) {
+        return items.stream().
                         filter(item -> item.getPurpose() == MappingPurpose.PULL
                         || item.getPurpose() == MappingPurpose.BOTH).collect(Collectors.toList());
     }
 
-    public static List<? extends OrgUnitItem> getPropagationItems(final OrgUnit orgUnit) {
-        return orgUnit.getItems().stream().
-                filter(item -> item.getPurpose() == MappingPurpose.PROPAGATION
-                || item.getPurpose() == MappingPurpose.BOTH).collect(Collectors.toList());
-    }
-
-    public static List<? extends OrgUnitItem> getPullItems(final OrgUnit orgUnit) {
-        return orgUnit.getItems().stream().
-                filter(item -> item.getPurpose() == MappingPurpose.PULL
-                || item.getPurpose() == MappingPurpose.BOTH).collect(Collectors.toList());
-    }
-
     private static Name evaluateNAME(final String evalConnObjectLink, final String connObjectKey) {
         // If connObjectLink evaluates to an empty string, just use the provided connObjectKey as Name(),
         // otherwise evaluated connObjectLink expression is taken as Name().

http://git-wip-us.apache.org/repos/asf/syncope/blob/5295039b/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 e89d410..a21bfa5 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
@@ -39,8 +39,10 @@ import javax.sql.DataSource;
 import javax.ws.rs.core.GenericType;
 import org.apache.commons.lang3.tuple.Pair;
 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;
@@ -1390,4 +1392,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());
+    }
 }


[5/6] syncope git commit: White noise: ignore

Posted by il...@apache.org.
White noise: ignore


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

Branch: refs/heads/master
Commit: 19a0345f6d587e9f85f0106b4b28b95696a943d9
Parents: cf2c965
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Sep 8 10:43:29 2017 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Sep 8 13:14:19 2017 +0200

----------------------------------------------------------------------
 .../syncope/client/console/approvals/ApprovalDirectoryPanel.java  | 3 ++-
 .../test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/19a0345f/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
index d373588..5ace09c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
@@ -323,6 +323,7 @@ public class ApprovalDirectoryPanel
                 final List<String> anyTypeClasses,
                 final UserFormLayoutInfo formLayoutInfo,
                 final PageReference pageRef) {
+
             super(previousUserTO, userTO, anyTypeClasses, formLayoutInfo, pageRef);
             this.formTO = formTO;
             this.target = target;
@@ -341,7 +342,6 @@ public class ApprovalDirectoryPanel
                 claimForm(restClient.getFormForUser(actual.getEntity().getKey()).getTaskId());
                 ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
             } else {
-
                 UserPatch patch = AnyOperations.diff(inner, formTO.getUserTO(), false);
 
                 if (StringUtils.isNotBlank(inner.getPassword())) {
@@ -362,6 +362,7 @@ public class ApprovalDirectoryPanel
                 }
 
             }
+
             return actual;
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/19a0345f/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
index cc5e3c8..5670398 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
@@ -154,7 +154,7 @@ public class UserWorkflowITCase extends AbstractITCase {
         userTO.getMemberships().add(
                 new MembershipTO.Builder().group("0cbcabd2-4410-4b6b-8f05-a052b451d18f").build());
 
-        // 1. create user with group 9 (and verify that no propagation occurred)
+        // 1. create user and verify that no propagation occurred)
         ProvisioningResult<UserTO> result = createUser(userTO);
         assertNotNull(result);
         userTO = result.getEntity();