You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2015/05/08 17:03:06 UTC

[1/3] syncope git commit: [SYNCOPE-140] Implemented

Repository: syncope
Updated Branches:
  refs/heads/master 84028f115 -> 22839bf37


http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java
index de07e3b..2f4fd2d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java
@@ -20,8 +20,13 @@ package org.apache.syncope.core.provisioning.java.data;
 
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Transformer;
+import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.core.misc.search.SearchCondConverter;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.entity.DynRoleMembership;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Role;
@@ -42,6 +47,25 @@ public class RoleDataBinderImpl implements RoleDataBinder {
     @Autowired
     private EntityFactory entityFactory;
 
+    private void setDynMembership(final Role role, final String dynMembershipFIQL) {
+        SearchCond dynMembershipCond = SearchCondConverter.convert(dynMembershipFIQL);
+        if (!dynMembershipCond.isValid()) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSearchExpression);
+            sce.getElements().add(dynMembershipFIQL);
+            throw sce;
+        }
+
+        DynRoleMembership dynMembership;
+        if (role.getDynMembership() == null) {
+            dynMembership = entityFactory.newEntity(DynRoleMembership.class);
+            dynMembership.setRole(role);
+            role.setDynMembership(dynMembership);
+        } else {
+            dynMembership = role.getDynMembership();
+        }
+        dynMembership.setFIQLCond(dynMembershipFIQL);
+    }
+
     @Override
     public Role create(final RoleTO roleTO) {
         Role role = entityFactory.newEntity(Role.class);
@@ -65,6 +89,22 @@ public class RoleDataBinderImpl implements RoleDataBinder {
                 role.addRealm(realm);
             }
         }
+
+        // dynamic membership
+        if (role.getKey() == null && roleTO.getDynMembershipCond() != null) {
+            setDynMembership(role, roleTO.getDynMembershipCond());
+        } else {
+            if (role.getDynMembership() != null && roleTO.getDynMembershipCond() == null) {
+                role.setDynMembership(null);
+            } else if (role.getDynMembership() == null && roleTO.getDynMembershipCond() != null) {
+                setDynMembership(role, roleTO.getDynMembershipCond());
+            } else if (role.getDynMembership() != null && roleTO.getDynMembershipCond() != null
+                    && !role.getDynMembership().getFIQLCond().equals(roleTO.getDynMembershipCond())) {
+
+                role.getDynMembership().getUsers().clear();
+                setDynMembership(role, roleTO.getDynMembershipCond());
+            }
+        }
     }
 
     @Override
@@ -83,6 +123,10 @@ public class RoleDataBinderImpl implements RoleDataBinder {
             }
         }, roleTO.getRealms());
 
+        if (role.getDynMembership() != null) {
+            roleTO.setDynMembershipCond(role.getDynMembership().getFIQLCond());
+        }
+
         return roleTO;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/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 1b1508d..317fce2 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
@@ -18,8 +18,7 @@
  */
 package org.apache.syncope.core.provisioning.java.data;
 
-import static org.apache.syncope.core.provisioning.java.data.AbstractAttributableDataBinder.LOG;
-
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
@@ -226,7 +225,7 @@ public class UserDataBinderImpl extends AbstractAttributableDataBinder implement
 
         SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
 
-        Set<String> currentResources = user.getResourceNames();
+        Collection<String> currentResources = userDAO.findAllResourceNames(user);
 
         // fetch account ids before update
         Map<String, String> oldAccountIds = getAccountIds(user, AttributableType.USER);
@@ -421,11 +420,10 @@ public class UserDataBinderImpl extends AbstractAttributableDataBinder implement
 
         connObjectUtils.retrieveVirAttrValues(user, attrUtilsFactory.getInstance(AttributableType.USER));
         fillTO(userTO, user.getRealm().getFullPath(),
-                user.getPlainAttrs(), user.getDerAttrs(), user.getVirAttrs(), user.getResources());
+                user.getPlainAttrs(), user.getDerAttrs(), user.getVirAttrs(), userDAO.findAllResources(user));
 
-        MembershipTO membershipTO;
         for (Membership membership : user.getMemberships()) {
-            membershipTO = new MembershipTO();
+            MembershipTO membershipTO = new MembershipTO();
 
             // set sys info
             membershipTO.setCreator(membership.getCreator());
@@ -447,6 +445,22 @@ public class UserDataBinderImpl extends AbstractAttributableDataBinder implement
             userTO.getMemberships().add(membershipTO);
         }
 
+        // dynamic memberships
+        CollectionUtils.collect(userDAO.findDynRoleMemberships(user), new Transformer<Role, Long>() {
+
+            @Override
+            public Long transform(final Role role) {
+                return role.getKey();
+            }
+        }, userTO.getDynRoles());
+        CollectionUtils.collect(userDAO.findDynGroupMemberships(user), new Transformer<Group, Long>() {
+
+            @Override
+            public Long transform(final Group group) {
+                return group.getKey();
+            }
+        }, userTO.getDynGroups());
+
         return userTO;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/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 3856324..6408987 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
@@ -20,6 +20,7 @@ package org.apache.syncope.core.provisioning.java.propagation;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
@@ -50,6 +51,8 @@ import org.apache.syncope.core.misc.AuditManager;
 import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 import org.apache.syncope.core.misc.ConnObjectUtils;
 import org.apache.syncope.core.misc.ExceptionUtils2;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
 import org.identityconnectors.framework.common.exceptions.ConnectorException;
 import org.identityconnectors.framework.common.objects.Attribute;
@@ -280,7 +283,12 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
              * two different memberships with the same resource).
              */
             Subject<?, ?, ?> subject = getSubject(task);
-            if (subject == null || !subject.getResourceNames().contains(task.getResource().getKey())) {
+            Collection<String> resources = subject instanceof User
+                    ? userDAO.findAllResourceNames((User) subject)
+                    : subject instanceof Group
+                            ? ((Group) subject).getResourceNames()
+                            : Collections.<String>emptySet();
+            if (!resources.contains(task.getResource().getKey())) {
                 LOG.debug("Delete {} on {}", beforeObj.getUid(), task.getResource().getKey());
 
                 connector.delete(

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java
index 6600e44..c246d8f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java
@@ -71,7 +71,7 @@ public class LDAPMembershipPropagationActions extends DefaultPropagationActions
             User user = userDAO.find(task.getSubjectKey());
             if (user != null) {
                 List<String> groupAccountLinks = new ArrayList<>();
-                for (Group group : user.getGroups()) {
+                for (Group group : userDAO.findAllGroups(user)) {
                     if (group.getResourceNames().contains(task.getResource().getKey())
                             && StringUtils.isNotBlank(task.getResource().getGmapping().getAccountLink())) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/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 d7c59a4..2939095 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
@@ -264,7 +264,7 @@ public class PropagationManagerImpl implements PropagationManager {
             origPropByRes.merge(wfResult.getPropByRes());
 
             Set<String> pwdResourceNames = new HashSet<>(userMod.getPwdPropRequest().getResourceNames());
-            Set<String> currentResourceNames = userDAO.authFetch(userMod.getKey()).getResourceNames();
+            Collection<String> currentResourceNames = userDAO.findAllResourceNames(userDAO.authFetch(userMod.getKey()));
             pwdResourceNames.retainAll(currentResourceNames);
             PropagationByResource pwdPropByRes = new PropagationByResource();
             pwdPropByRes.addAll(ResourceOperation.UPDATE, pwdResourceNames);
@@ -312,8 +312,10 @@ public class PropagationManagerImpl implements PropagationManager {
                         : vAttrsToBeUpdated, attrUtilsFactory.getInstance(subject));
 
         // SYNCOPE-458 fill membership virtual attributes
+        Collection<String> resourceNames;
         if (subject instanceof User) {
-            final User user = (User) subject;
+            User user = (User) subject;
+            resourceNames = userDAO.findAllResourceNames(user);
             for (final Membership membership : user.getMemberships()) {
                 if (membership.getVirAttrs() != null && !membership.getVirAttrs().isEmpty()) {
                     final MembershipMod membershipMod = CollectionUtils.find(membershipsToAdd,
@@ -334,10 +336,12 @@ public class PropagationManagerImpl implements PropagationManager {
                     }
                 }
             }
+        } else {
+            resourceNames = subject.getResourceNames();
         }
 
         if (propByRes == null || propByRes.isEmpty()) {
-            localPropByRes.addAll(ResourceOperation.UPDATE, subject.getResourceNames());
+            localPropByRes.addAll(ResourceOperation.UPDATE, resourceNames);
         } else {
             localPropByRes.merge(propByRes);
         }
@@ -377,7 +381,7 @@ public class PropagationManagerImpl implements PropagationManager {
     public List<PropagationTask> getUserDeleteTasks(final Long userKey, final Collection<String> noPropResourceNames) {
 
         User user = userDAO.authFetch(userKey);
-        return getDeleteTaskIds(user, user.getResourceNames(), noPropResourceNames);
+        return getDeleteTaskIds(user, userDAO.findAllResourceNames(user), noPropResourceNames);
     }
 
     @Override
@@ -424,7 +428,7 @@ public class PropagationManagerImpl implements PropagationManager {
 
     protected List<PropagationTask> getDeleteTaskIds(
             final Subject<?, ?, ?> subject,
-            final Set<String> resourceNames,
+            final Collection<String> resourceNames,
             final Collection<String> noPropResourceNames) {
 
         final PropagationByResource propByRes = new PropagationByResource();

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
index 5a63f8e..e15f526 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
@@ -19,6 +19,7 @@
 package org.apache.syncope.core.provisioning.java.sync;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -43,6 +44,7 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.sync.ProvisioningResult;
 import org.apache.syncope.core.provisioning.api.sync.PushActions;
 import org.apache.syncope.core.misc.MappingUtils;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.provisioning.api.sync.IgnoreProvisionException;
 import org.apache.syncope.core.provisioning.api.sync.SyncopePushResultHandler;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
@@ -347,20 +349,21 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
             vattrToBeUpdated.add(mod);
         }
 
-        final boolean changepwd;
-
+        boolean changepwd;
+        Collection<String> resourceNames;
         if (sbj instanceof User) {
             changepwd = true;
+            resourceNames = userDAO.findAllResourceNames((User) sbj);
 
             // Search for memberships
             for (Membership membership : User.class.cast(sbj).getMemberships()) {
-                final MembershipMod membershipMod = new MembershipMod();
+                MembershipMod membershipMod = new MembershipMod();
                 membershipMod.setKey(membership.getKey());
                 membershipMod.setGroup(membership.getGroup().getKey());
 
                 for (VirAttr vattr : membership.getVirAttrs()) {
                     membVattrToBeRemoved.remove(vattr.getSchema().getKey());
-                    final AttrMod mod = new AttrMod();
+                    AttrMod mod = new AttrMod();
                     mod.setSchema(vattr.getSchema().getKey());
                     mod.getValuesToBeAdded().addAll(vattr.getValues());
                     membershipMod.getVirAttrsToUpdate().add(mod);
@@ -374,9 +377,10 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
             }
         } else {
             changepwd = false;
+            resourceNames = ((Group) sbj).getResourceNames();
         }
 
-        final List<String> noPropResources = new ArrayList<>(sbj.getResourceNames());
+        List<String> noPropResources = new ArrayList<>(resourceNames);
         noPropResources.remove(profile.getTask().getResource().getKey());
 
         final PropagationByResource propByRes = new PropagationByResource();

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
index a356ad8..1849bd6 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
@@ -295,7 +295,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
         }
 
         PropagationByResource propByRes = new PropagationByResource();
-        propByRes.set(ResourceOperation.CREATE, user.getResourceNames());
+        propByRes.set(ResourceOperation.CREATE, userDAO.findAllResourceNames(user));
 
         saveForFormSubmit(user, userTO.getPassword(), propByRes);
 
@@ -415,7 +415,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
         doExecuteTask(user, "delete", null);
 
         PropagationByResource propByRes = new PropagationByResource();
-        propByRes.set(ResourceOperation.DELETE, user.getResourceNames());
+        propByRes.set(ResourceOperation.DELETE, userDAO.findAllResourceNames(user));
 
         saveForFormSubmit(user, null, propByRes);
 
@@ -695,7 +695,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
                     taskCandidateOrAssigned(user.getKey().toString())));
 
             List<String> candidateGroups = new ArrayList<>();
-            for (Long groupId : user.getGroupKeys()) {
+            for (Long groupId : userDAO.findAllGroupKeys(user)) {
                 candidateGroups.add(groupId.toString());
             }
             if (!candidateGroups.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeGroupManager.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeGroupManager.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeGroupManager.java
index 0033824..b1f1c8c 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeGroupManager.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeGroupManager.java
@@ -67,7 +67,7 @@ public class SyncopeGroupManager implements GroupIdentityManager, SyncopeSession
         User user = userDAO.find(userId);
         if (user != null) {
             result = new ArrayList<>();
-            for (Long groupId : user.getGroupKeys()) {
+            for (Long groupId : userDAO.findAllGroupKeys(user)) {
                 result.add(new GroupEntity(groupId.toString()));
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeUserManager.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeUserManager.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeUserManager.java
index 72be4e3..2b568b1 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeUserManager.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeUserManager.java
@@ -75,7 +75,7 @@ public class SyncopeUserManager implements UserIdentityManager, SyncopeSession {
         org.apache.syncope.core.persistence.api.entity.user.User user = userDAO.find(userKey);
         if (user != null) {
             result = new ArrayList<>();
-            for (Long groupId : user.getGroupKeys()) {
+            for (Long groupId : userDAO.findAllGroupKeys(user)) {
                 result.add(new GroupEntity(groupId.toString()));
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeUserQueryImpl.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeUserQueryImpl.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeUserQueryImpl.java
index 55d8d5d..506455f 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeUserQueryImpl.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/SyncopeUserQueryImpl.java
@@ -141,7 +141,7 @@ public class SyncopeUserQueryImpl implements UserQuery {
             if (user == null) {
                 result = Collections.<User>emptyList();
             } else {
-                if (memberOf == null || user.getGroupKeys().contains(memberOf)) {
+                if (memberOf == null || userDAO.findAllGroupKeys(user).contains(memberOf)) {
                     result = Collections.singletonList(fromSyncopeUser(user));
                 }
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java
index 041234f..fa765ed 100644
--- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java
+++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java
@@ -44,7 +44,7 @@ public class DefaultGroupWorkflowAdapter extends AbstractGroupWorkflowAdapter {
         dataBinder.create(group, groupTO);
         group = groupDAO.save(group);
 
-        final PropagationByResource propByRes = new PropagationByResource();
+        PropagationByResource propByRes = new PropagationByResource();
         propByRes.set(ResourceOperation.CREATE, group.getResourceNames());
 
         return new WorkflowResult<>(group.getKey(), propByRes, "create");

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
index 6691541..78360a9 100644
--- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
+++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
@@ -87,7 +87,7 @@ public class DefaultUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
         user = userDAO.save(user);
 
         final PropagationByResource propByRes = new PropagationByResource();
-        propByRes.set(ResourceOperation.CREATE, user.getResourceNames());
+        propByRes.set(ResourceOperation.CREATE, userDAO.findAllResourceNames(user));
 
         return new WorkflowResult<Pair<Long, Boolean>>(
                 new ImmutablePair<>(user.getKey(), propagateEnable), propByRes, "create");

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserDeprovisionProcessor.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserDeprovisionProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserDeprovisionProcessor.java
index e59bec6..031e451 100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserDeprovisionProcessor.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserDeprovisionProcessor.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.core.provisioning.camel.processor;
 
-import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import org.apache.camel.Exchange;
@@ -59,10 +58,10 @@ public class UserDeprovisionProcessor implements Processor {
 
         User user = userDAO.authFetch(userKey);
 
-        Collection<String> noPropResourceNames = CollectionUtils.removeAll(user.getResourceNames(), resources);
-
-        List<PropagationTask> tasks =
-                propagationManager.getUserDeleteTasks(userKey, new HashSet<>(resources), noPropResourceNames);
+        List<PropagationTask> tasks = propagationManager.getUserDeleteTasks(
+                userKey,
+                new HashSet<>(resources),
+                CollectionUtils.removeAll(userDAO.findAllResourceNames(user), resources));
         PropagationReporter propagationReporter =
                 ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
         try {

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserStatusPropagationProcessor.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserStatusPropagationProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserStatusPropagationProcessor.java
index 0df97b8..cb0bb82 100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserStatusPropagationProcessor.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserStatusPropagationProcessor.java
@@ -26,6 +26,7 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.syncope.common.lib.mod.StatusMod;
 import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.WorkflowResult;
@@ -49,6 +50,9 @@ public class UserStatusPropagationProcessor implements Processor {
     @Autowired
     protected PropagationTaskExecutor taskExecutor;
 
+    @Autowired
+    protected UserDAO userDAO;
+    
     @SuppressWarnings("unchecked")
     @Override
     public void process(final Exchange exchange) {
@@ -58,7 +62,7 @@ public class UserStatusPropagationProcessor implements Processor {
         StatusMod statusMod = exchange.getProperty("statusMod", StatusMod.class);
 
         Collection<String> resourcesToBeExcluded =
-                CollectionUtils.removeAll(user.getResourceNames(), statusMod.getResourceNames());
+                CollectionUtils.removeAll(userDAO.findAllResourceNames(user), statusMod.getResourceNames());
 
         List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
                 user, statusMod.getType() != StatusMod.ModType.SUSPEND, resourcesToBeExcluded);

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/fit/core-reference/src/main/resources/userWorkflow.bpmn20.xml
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/resources/userWorkflow.bpmn20.xml b/fit/core-reference/src/main/resources/userWorkflow.bpmn20.xml
index d0b5604..9a6ee5b 100644
--- a/fit/core-reference/src/main/resources/userWorkflow.bpmn20.xml
+++ b/fit/core-reference/src/main/resources/userWorkflow.bpmn20.xml
@@ -34,10 +34,10 @@ under the License.
     <sequenceFlow id="flow2" sourceRef="create" targetRef="createGW"/>
     <exclusiveGateway id="createGW"/>
     <sequenceFlow id="createAsAnonymous2Approval" sourceRef="createGW" targetRef="createApproval">
-      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${wfExecutor == 'anonymous' || user.getGroupKeys().contains(9)}]]></conditionExpression>
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${wfExecutor == 'anonymous' || user.getStaticGroupKeys().contains(9)}]]></conditionExpression>
     </sequenceFlow>
     <sequenceFlow id="create2Activate" sourceRef="createGW" targetRef="enableGW">
-      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!user.getGroupKeys().contains(9)}]]></conditionExpression>
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!user.getStaticGroupKeys().contains(9)}]]></conditionExpression>
     </sequenceFlow>
     <userTask id="createApproval" name="Create approval" activiti:candidateGroups="7" activiti:formKey="createApproval">
       <extensionElements>
@@ -56,7 +56,7 @@ under the License.
     </sequenceFlow>
     <exclusiveGateway id="enableGW"/>
     <sequenceFlow id="createApprovalGW2OptIn" sourceRef="enableGW" targetRef="generateToken">
-      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${user.getGroupKeys().contains(11)}]]></conditionExpression>
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${user.getStaticGroupKeys().contains(11)}]]></conditionExpression>
     </sequenceFlow>
     <sequenceFlow id="createApprovalGW2Activate" sourceRef="enableGW" targetRef="activate">
       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${enabled == null}]]></conditionExpression>

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AbstractTaskITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AbstractTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AbstractTaskITCase.java
index 6545be5..5dc3f5c 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AbstractTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AbstractTaskITCase.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.fit.core.reference;
 
-import static org.apache.syncope.fit.core.reference.AbstractITCase.taskService;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ConfigurationITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ConfigurationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ConfigurationITCase.java
index 5dd5ce8..6ae349c 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ConfigurationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ConfigurationITCase.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.fit.core.reference;
 
-import static org.apache.commons.lang3.StringUtils.isEmpty;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -157,7 +156,7 @@ public class ConfigurationITCase extends AbstractITCase {
     }
 
     private static String[] substringsBetween(final String str, final String open, final String close) {
-        if (str == null || isEmpty(open) || isEmpty(close)) {
+        if (str == null || StringUtils.isEmpty(open) || StringUtils.isEmpty(close)) {
             return null;
         }
         final int strLen = str.length();

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
index 7071c22..9be9a28 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
@@ -35,6 +35,8 @@ import javax.naming.directory.DirContext;
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 import javax.ws.rs.core.Response;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Predicate;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.lib.SyncopeClient;
@@ -71,15 +73,15 @@ import org.junit.runners.MethodSorters;
 @FixMethodOrder(MethodSorters.JVM)
 public class GroupITCase extends AbstractITCase {
 
-    private GroupTO buildBasicGroupTO(final String name) {
+    public static GroupTO getBasicSampleTO(final String name) {
         GroupTO groupTO = new GroupTO();
         groupTO.setRealm("/");
         groupTO.setName(name + getUUIDString());
         return groupTO;
     }
 
-    private GroupTO buildGroupTO(final String name) {
-        GroupTO groupTO = buildBasicGroupTO(name);
+    public static GroupTO getSampleTO(final String name) {
+        GroupTO groupTO = getBasicSampleTO(name);
 
         groupTO.getGPlainAttrTemplates().add("icon");
         groupTO.getPlainAttrs().add(attrTO("icon", "anIcon"));
@@ -91,7 +93,7 @@ public class GroupITCase extends AbstractITCase {
     @Test
     @Ignore
     public void create() {
-        GroupTO groupTO = buildGroupTO("lastGroup");
+        GroupTO groupTO = getSampleTO("lastGroup");
         groupTO.getGVirAttrTemplates().add("rvirtualdata");
         groupTO.getVirAttrs().add(attrTO("rvirtualdata", "rvirtualvalue"));
         groupTO.setGroupOwner(8L);
@@ -185,14 +187,18 @@ public class GroupITCase extends AbstractITCase {
 
         List<GroupTO> groups = groupService2.own();
         assertNotNull(groups);
-        assertFalse(groups.isEmpty());
-        assertNotNull(groups.get(0).getPlainAttrs());
-        assertFalse(groups.get(0).getPlainAttrs().isEmpty());
+        assertTrue(CollectionUtils.exists(groups, new Predicate<GroupTO>() {
+
+            @Override
+            public boolean evaluate(final GroupTO group) {
+                return 1L == group.getKey();
+            }
+        }));
     }
 
     @Test
     public void update() {
-        GroupTO groupTO = buildGroupTO("latestGroup" + getUUIDString());
+        GroupTO groupTO = getSampleTO("latestGroup" + getUUIDString());
         groupTO.getGPlainAttrTemplates().add("show");
         groupTO = createGroup(groupTO);
 
@@ -204,9 +210,6 @@ public class GroupITCase extends AbstractITCase {
         groupMod.setName(modName);
         groupMod.getPlainAttrsToUpdate().add(attrMod("show", "FALSE"));
 
-        // change password policy inheritance
-        groupMod.setInheritPasswordPolicy(Boolean.FALSE);
-
         groupTO = updateGroup(groupMod);
 
         assertEquals(modName, groupTO.getName());
@@ -215,7 +218,7 @@ public class GroupITCase extends AbstractITCase {
 
     @Test
     public void updateRemovingVirAttribute() {
-        GroupTO groupTO = buildBasicGroupTO("withvirtual" + getUUIDString());
+        GroupTO groupTO = getBasicSampleTO("withvirtual" + getUUIDString());
         groupTO.getGVirAttrTemplates().add("rvirtualdata");
         groupTO.getVirAttrs().add(attrTO("rvirtualdata", null));
 
@@ -235,7 +238,7 @@ public class GroupITCase extends AbstractITCase {
 
     @Test
     public void updateRemovingDerAttribute() {
-        GroupTO groupTO = buildBasicGroupTO("withderived" + getUUIDString());
+        GroupTO groupTO = getBasicSampleTO("withderived" + getUUIDString());
         groupTO.getGDerAttrTemplates().add("rderivedschema");
         groupTO.getDerAttrs().add(attrTO("rderivedschema", null));
 
@@ -319,7 +322,7 @@ public class GroupITCase extends AbstractITCase {
 
     @Test
     public void unlink() {
-        GroupTO actual = createGroup(buildGroupTO("unlink"));
+        GroupTO actual = createGroup(getSampleTO("unlink"));
         assertNotNull(actual);
 
         assertNotNull(resourceService.getConnectorObject(RESOURCE_NAME_LDAP, SubjectType.GROUP, actual.getKey()));
@@ -338,7 +341,7 @@ public class GroupITCase extends AbstractITCase {
 
     @Test
     public void link() {
-        GroupTO groupTO = buildGroupTO("link");
+        GroupTO groupTO = getSampleTO("link");
         groupTO.getResources().clear();
 
         GroupTO actual = createGroup(groupTO);
@@ -369,7 +372,7 @@ public class GroupITCase extends AbstractITCase {
 
     @Test
     public void unassign() {
-        GroupTO actual = createGroup(buildGroupTO("unassign"));
+        GroupTO actual = createGroup(getSampleTO("unassign"));
         assertNotNull(actual);
 
         assertNotNull(resourceService.getConnectorObject(RESOURCE_NAME_LDAP, SubjectType.GROUP, actual.getKey()));
@@ -393,7 +396,7 @@ public class GroupITCase extends AbstractITCase {
 
     @Test
     public void assign() {
-        GroupTO groupTO = buildGroupTO("assign");
+        GroupTO groupTO = getSampleTO("assign");
         groupTO.getResources().clear();
 
         GroupTO actual = createGroup(groupTO);
@@ -418,7 +421,7 @@ public class GroupITCase extends AbstractITCase {
 
     @Test
     public void deprovision() {
-        GroupTO actual = createGroup(buildGroupTO("deprovision"));
+        GroupTO actual = createGroup(getSampleTO("deprovision"));
         assertNotNull(actual);
 
         assertNotNull(resourceService.getConnectorObject(RESOURCE_NAME_LDAP, SubjectType.GROUP, actual.getKey()));
@@ -442,7 +445,7 @@ public class GroupITCase extends AbstractITCase {
 
     @Test
     public void provision() {
-        GroupTO groupTO = buildGroupTO("assign" + getUUIDString());
+        GroupTO groupTO = getSampleTO("assign" + getUUIDString());
         groupTO.getResources().clear();
 
         GroupTO actual = createGroup(groupTO);
@@ -468,7 +471,7 @@ public class GroupITCase extends AbstractITCase {
 
     @Test
     public void deprovisionUnlinked() {
-        GroupTO groupTO = buildGroupTO("assign" + getUUIDString());
+        GroupTO groupTO = getSampleTO("assign" + getUUIDString());
         groupTO.getResources().clear();
 
         GroupTO actual = createGroup(groupTO);
@@ -517,7 +520,7 @@ public class GroupITCase extends AbstractITCase {
         schemaService.create(AttributableType.GROUP, SchemaType.PLAIN, badge);
 
         // 2. create a group *without* an attribute for that schema: it works
-        GroupTO groupTO = buildGroupTO("lastGroup");
+        GroupTO groupTO = getSampleTO("lastGroup");
         assertFalse(groupTO.getPlainAttrMap().containsKey(badge.getKey()));
         groupTO = createGroup(groupTO);
         assertNotNull(groupTO);
@@ -549,14 +552,16 @@ public class GroupITCase extends AbstractITCase {
     public void anonymous() {
         GroupService unauthenticated = clientFactory.createAnonymous().getService(GroupService.class);
         try {
-            unauthenticated.list(SyncopeClient.getSubjectSearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).build());
+            unauthenticated.
+                    list(SyncopeClient.getSubjectSearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).build());
             fail();
         } catch (AccessControlException e) {
             assertNotNull(e);
         }
 
         GroupService anonymous = clientFactory.create(ANONYMOUS_UNAME, ANONYMOUS_KEY).getService(GroupService.class);
-        assertFalse(anonymous.list(SyncopeClient.getSubjectSearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).build()).
+        assertFalse(anonymous.list(SyncopeClient.getSubjectSearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
+                build()).
                 getResult().isEmpty());
     }
 
@@ -565,7 +570,7 @@ public class GroupITCase extends AbstractITCase {
         SyncopeClient noContentclient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD);
         GroupService noContentService = noContentclient.prefer(GroupService.class, Preference.RETURN_NO_CONTENT);
 
-        GroupTO group = buildGroupTO("noContent");
+        GroupTO group = getSampleTO("noContent");
 
         Response response = noContentService.create(group);
         assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
@@ -613,7 +618,7 @@ public class GroupITCase extends AbstractITCase {
             assertNotNull(newLDAP);
 
             // 2. create a group and give the resource created above
-            groupTO = buildGroupTO("lastGroup" + getUUIDString());
+            groupTO = getSampleTO("lastGroup" + getUUIDString());
             groupTO.getGPlainAttrTemplates().add("icon");
             groupTO.getPlainAttrs().add(attrTO("icon", "anIcon"));
             groupTO.getGPlainAttrTemplates().add("show");
@@ -671,4 +676,23 @@ public class GroupITCase extends AbstractITCase {
             resourceService.delete("new-ldap");
         }
     }
+
+    @Test
+    public void dynMembership() {
+        assertTrue(userService.read(4L).getDynGroups().isEmpty());
+
+        GroupTO group = getBasicSampleTO("dynMembership");
+        group.setDynMembershipCond("cool==true");
+        group = createGroup(group);
+        assertNotNull(group);
+
+        assertTrue(userService.read(4L).getDynGroups().contains(group.getKey()));
+
+        GroupMod mod = new GroupMod();
+        mod.setKey(group.getKey());
+        mod.setDynMembershipCond("cool==false");
+        groupService.update(mod.getKey(), mod);
+
+        assertTrue(userService.read(4L).getDynGroups().isEmpty());
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/RoleITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/RoleITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/RoleITCase.java
index 0c1aa85..4d61644 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/RoleITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/RoleITCase.java
@@ -39,6 +39,15 @@ import org.junit.runners.MethodSorters;
 @FixMethodOrder(MethodSorters.JVM)
 public class RoleITCase extends AbstractITCase {
 
+    public static RoleTO getSampleRoleTO(final String name) {
+        RoleTO role = new RoleTO();
+        role.setName(name + getUUIDString());
+        role.getRealms().add("/even");
+        role.getEntitlements().add(Entitlement.LOG_SET_LEVEL);
+
+        return role;
+    }
+
     @Test
     public void list() {
         List<RoleTO> roleTOs = roleService.list();
@@ -56,15 +65,6 @@ public class RoleITCase extends AbstractITCase {
         assertTrue(roleTO.getEntitlements().contains(Entitlement.GROUP_READ));
     }
 
-    private RoleTO buildRoleTO(final String name) {
-        RoleTO role = new RoleTO();
-        role.setName(name + getUUIDString());
-        role.getRealms().add("/even");
-        role.getEntitlements().add(Entitlement.LOG_SET_LEVEL);
-
-        return role;
-    }
-
     @Test
     public void create() {
         RoleTO role = new RoleTO();
@@ -82,7 +82,7 @@ public class RoleITCase extends AbstractITCase {
 
     @Test
     public void update() {
-        RoleTO role = buildRoleTO("update");
+        RoleTO role = getSampleRoleTO("update");
         Response response = roleService.create(role);
 
         RoleTO actual = getObject(response.getLocation(), RoleService.class, RoleTO.class);
@@ -104,7 +104,7 @@ public class RoleITCase extends AbstractITCase {
 
     @Test
     public void delete() {
-        RoleTO role = buildRoleTO("delete");
+        RoleTO role = getSampleRoleTO("delete");
         Response response = roleService.create(role);
 
         RoleTO actual = getObject(response.getLocation(), RoleService.class, RoleTO.class);
@@ -119,4 +119,22 @@ public class RoleITCase extends AbstractITCase {
             assertEquals(ClientExceptionType.NotFound, e.getType());
         }
     }
+
+    @Test
+    public void dynMembership() {
+        assertTrue(userService.read(4L).getDynRoles().isEmpty());
+
+        RoleTO role = getSampleRoleTO("dynMembership");
+        role.setDynMembershipCond("cool==true");
+        Response response = roleService.create(role);
+        role = getObject(response.getLocation(), RoleService.class, RoleTO.class);
+        assertNotNull(role);
+
+        assertTrue(userService.read(4L).getDynRoles().contains(role.getKey()));
+
+        role.setDynMembershipCond("cool==false");
+        roleService.update(role.getKey(), role);
+
+        assertTrue(userService.read(4L).getDynGroups().isEmpty());
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SearchITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SearchITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SearchITCase.java
index b17d7f3..0f56510 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SearchITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SearchITCase.java
@@ -18,12 +18,14 @@
  */
 package org.apache.syncope.fit.core.reference;
 
+import static org.apache.syncope.fit.core.reference.AbstractITCase.userService;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Collection;
+import javax.ws.rs.core.Response;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.syncope.client.lib.SyncopeClient;
@@ -31,7 +33,9 @@ import org.apache.syncope.common.lib.CollectionUtils2;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.RoleTO;
 import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.rest.api.service.RoleService;
 import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runners.MethodSorters;
@@ -95,6 +99,89 @@ public class SearchITCase extends AbstractITCase {
     }
 
     @Test
+    public void searchByGroup() {
+        PagedResult<UserTO> matchedUsers = userService.search(
+                SyncopeClient.getSubjectSearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
+                fiql(SyncopeClient.getUserSearchConditionBuilder().inGroups(1L).query()).
+                build());
+        assertNotNull(matchedUsers);
+        assertFalse(matchedUsers.getResult().isEmpty());
+
+        assertTrue(CollectionUtils.exists(matchedUsers.getResult(), new Predicate<UserTO>() {
+
+            @Override
+            public boolean evaluate(final UserTO user) {
+                return user.getKey() == 1;
+            }
+        }));
+    }
+
+    @Test
+    public void searchByDynGroup() {
+        GroupTO group = GroupITCase.getBasicSampleTO("dynMembership");
+        group.setDynMembershipCond("cool==true");
+        group = createGroup(group);
+        assertNotNull(group);
+
+        PagedResult<UserTO> matchedUsers = userService.search(
+                SyncopeClient.getSubjectSearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
+                fiql(SyncopeClient.getUserSearchConditionBuilder().inGroups(group.getKey()).query()).
+                build());
+        assertNotNull(matchedUsers);
+        assertFalse(matchedUsers.getResult().isEmpty());
+
+        assertTrue(CollectionUtils.exists(matchedUsers.getResult(), new Predicate<UserTO>() {
+
+            @Override
+            public boolean evaluate(final UserTO user) {
+                return user.getKey() == 4;
+            }
+        }));
+    }
+
+    @Test
+    public void searchByRole() {
+        PagedResult<UserTO> matchedUsers = userService.search(
+                SyncopeClient.getSubjectSearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
+                fiql(SyncopeClient.getUserSearchConditionBuilder().inRoles(3L).query()).
+                build());
+        assertNotNull(matchedUsers);
+        assertFalse(matchedUsers.getResult().isEmpty());
+
+        assertTrue(CollectionUtils.exists(matchedUsers.getResult(), new Predicate<UserTO>() {
+
+            @Override
+            public boolean evaluate(final UserTO user) {
+                return user.getKey() == 1;
+            }
+        }));
+    }
+
+    @Test
+    public void searchByDynRole() {
+        RoleTO role = RoleITCase.getSampleRoleTO("dynMembership");
+        role.setDynMembershipCond("cool==true");
+        Response response = roleService.create(role);
+        role = getObject(response.getLocation(), RoleService.class, RoleTO.class);
+        assertNotNull(role);
+
+        PagedResult<UserTO> matchedUsers = userService.search(
+                SyncopeClient.getSubjectSearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
+                fiql(SyncopeClient.getUserSearchConditionBuilder().inRoles(role.getKey()).query()).
+                build());
+        assertNotNull(matchedUsers);
+        assertFalse(matchedUsers.getResult().isEmpty());
+
+        assertTrue(CollectionUtils.exists(matchedUsers.getResult(), new Predicate<UserTO>() {
+
+            @Override
+            public boolean evaluate(final UserTO user) {
+                return user.getKey() == 4;
+            }
+        }));
+    }
+
+    @Test
     public void searchUserByResourceName() {
         PagedResult<UserTO> matchedUsers = userService.search(
                 SyncopeClient.getSubjectSearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM).


[3/3] syncope git commit: [SYNCOPE-140] Implemented

Posted by il...@apache.org.
[SYNCOPE-140] Implemented


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

Branch: refs/heads/master
Commit: 22839bf376aa74544b5a18fee227d26f3e3a4f67
Parents: 84028f1
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri May 8 17:02:50 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri May 8 17:02:50 2015 +0200

----------------------------------------------------------------------
 .../common/lib/AttributableOperations.java      |   3 +
 .../apache/syncope/common/lib/mod/GroupMod.java |  97 +----------
 .../search/GroupFiqlSearchConditionBuilder.java |   2 +-
 .../syncope/common/lib/search/SpecialAttr.java  |   3 +-
 .../search/UserFiqlSearchConditionBuilder.java  |  26 ++-
 .../syncope/common/lib/search/UserProperty.java |   4 +
 .../apache/syncope/common/lib/to/GroupTO.java   |  10 ++
 .../apache/syncope/common/lib/to/RoleTO.java    |  10 ++
 .../apache/syncope/common/lib/to/UserTO.java    |  18 ++
 .../common/lib/types/PropagationByResource.java |   2 +-
 .../apache/syncope/core/logic/GroupLogic.java   |   2 +-
 .../apache/syncope/core/logic/LoggerLogic.java  |   2 -
 .../apache/syncope/core/logic/SyncopeLogic.java |   2 -
 .../apache/syncope/core/logic/UserLogic.java    |   4 +-
 .../syncope/core/misc/ConnObjectUtils.java      |  53 +++---
 .../apache/syncope/core/misc/MappingUtils.java  |  10 +-
 .../core/misc/search/SearchCondConverter.java   |  18 +-
 .../core/misc/search/SearchCondVisitor.java     |  17 +-
 .../core/misc/security/PasswordGenerator.java   |   6 +-
 .../security/SyncopeAuthenticationProvider.java |   6 +-
 .../misc/security/SyncopeGrantedAuthority.java  |  12 ++
 .../security/SyncopeUserDetailsService.java     |   5 +-
 .../misc/search/SearchCondConverterTest.java    |  21 ++-
 .../core/persistence/api/dao/GroupDAO.java      |   4 +
 .../core/persistence/api/dao/RoleDAO.java       |   3 +
 .../core/persistence/api/dao/UserDAO.java       |  17 ++
 .../persistence/api/dao/search/GroupCond.java   |  39 +++++
 .../api/dao/search/MembershipCond.java          |  42 -----
 .../persistence/api/dao/search/RoleCond.java    |  39 +++++
 .../persistence/api/dao/search/SearchCond.java  |  48 ++++--
 .../api/entity/DynGroupMembership.java          |  28 ++++
 .../persistence/api/entity/DynMembership.java   |  35 ++++
 .../api/entity/DynRoleMembership.java           |  26 +++
 .../core/persistence/api/entity/Role.java       |   3 +
 .../persistence/api/entity/group/Group.java     |   4 +
 .../core/persistence/api/entity/user/User.java  |  10 +-
 .../jpa/dao/JPAExternalResourceDAO.java         |  14 +-
 .../core/persistence/jpa/dao/JPAGroupDAO.java   |  30 +++-
 .../core/persistence/jpa/dao/JPARoleDAO.java    |  29 ++++
 .../jpa/dao/JPASubjectSearchDAO.java            |  57 ++++++-
 .../core/persistence/jpa/dao/JPATaskDAO.java    |   1 -
 .../core/persistence/jpa/dao/JPAUserDAO.java    | 103 +++++++++++-
 .../core/persistence/jpa/dao/SearchSupport.java |  12 ++
 .../jpa/entity/AbstractDynMembership.java       |  65 ++++++++
 .../persistence/jpa/entity/AbstractSubject.java |   9 +-
 .../jpa/entity/AnnotatedEntityListener.java     |   3 -
 .../jpa/entity/JPADynGroupMembership.java       |  77 +++++++++
 .../jpa/entity/JPADynRoleMembership.java        |  76 +++++++++
 .../jpa/entity/JPAEntityFactory.java            |   6 +
 .../core/persistence/jpa/entity/JPARole.java    |  17 ++
 .../persistence/jpa/entity/group/JPAGroup.java  |  22 ++-
 .../persistence/jpa/entity/user/JPAUser.java    |  43 +----
 .../jpa/validation/entity/UserValidator.java    |   8 +-
 .../resources/META-INF/spring-orm-oracle.xml    |  18 ++
 .../resources/META-INF/spring-orm-sqlserver.xml |  18 ++
 .../src/main/resources/META-INF/spring-orm.xml  |  22 ++-
 .../src/main/resources/views.xml                |  26 ++-
 .../core/persistence/jpa/entity/AttrTest.java   |  16 +-
 .../core/persistence/jpa/entity/RoleTest.java   |   4 -
 .../jpa/entity/SubjectSearchTest.java           |  56 ++++---
 .../persistence/jpa/relationship/GroupTest.java | 116 ++++++++++++-
 .../jpa/relationship/ResourceTest.java          |   2 +-
 .../persistence/jpa/relationship/RoleTest.java  | 163 +++++++++++++++++++
 .../jpa/relationship/SubjectSearchTest.java     |  53 +++++-
 .../java/DefaultUserProvisioningManager.java    |  12 +-
 .../core/provisioning/java/VirAttrHandler.java  |  11 +-
 .../data/AbstractAttributableDataBinder.java    |  38 +++--
 .../java/data/GroupDataBinderImpl.java          |  44 ++++-
 .../java/data/RoleDataBinderImpl.java           |  44 +++++
 .../java/data/UserDataBinderImpl.java           |  26 ++-
 .../AbstractPropagationTaskExecutor.java        |  10 +-
 .../LDAPMembershipPropagationActions.java       |   2 +-
 .../propagation/PropagationManagerImpl.java     |  14 +-
 .../java/sync/AbstractPushResultHandler.java    |  14 +-
 .../activiti/ActivitiUserWorkflowAdapter.java   |   6 +-
 .../workflow/activiti/SyncopeGroupManager.java  |   2 +-
 .../workflow/activiti/SyncopeUserManager.java   |   2 +-
 .../workflow/activiti/SyncopeUserQueryImpl.java |   2 +-
 .../java/DefaultGroupWorkflowAdapter.java       |   2 +-
 .../java/DefaultUserWorkflowAdapter.java        |   2 +-
 .../processor/UserDeprovisionProcessor.java     |   9 +-
 .../UserStatusPropagationProcessor.java         |   6 +-
 .../src/main/resources/userWorkflow.bpmn20.xml  |   6 +-
 .../fit/core/reference/AbstractTaskITCase.java  |   1 -
 .../fit/core/reference/ConfigurationITCase.java |   3 +-
 .../syncope/fit/core/reference/GroupITCase.java |  74 ++++++---
 .../syncope/fit/core/reference/RoleITCase.java  |  40 +++--
 .../fit/core/reference/SearchITCase.java        |  87 ++++++++++
 88 files changed, 1716 insertions(+), 438 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java b/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
index 248212c..6c250ef 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
@@ -405,6 +405,9 @@ public final class AttributableOperations {
         result.setUserOwner(new ReferenceMod(updated.getUserOwner()));
         result.setGroupOwner(new ReferenceMod(updated.getGroupOwner()));
 
+        // 4. dynMembershipCond
+        result.setDynMembershipCond(updated.getDynMembershipCond());
+
         return result;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/common/lib/src/main/java/org/apache/syncope/common/lib/mod/GroupMod.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/GroupMod.java b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/GroupMod.java
index c2b3b8a..5620fa1 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/GroupMod.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/GroupMod.java
@@ -39,20 +39,6 @@ public class GroupMod extends AbstractSubjectMod {
 
     private ReferenceMod groupOwner;
 
-    private Boolean inheritOwner;
-
-    private Boolean inheritTemplates;
-
-    private Boolean inheritPlainAttrs;
-
-    private Boolean inheritDerAttrs;
-
-    private Boolean inheritVirAttrs;
-
-    private Boolean inheritAccountPolicy;
-
-    private Boolean inheritPasswordPolicy;
-
     private boolean modGAttrTemplates;
 
     private final List<String> gPlainAttrTemplates = new ArrayList<>();
@@ -77,9 +63,7 @@ public class GroupMod extends AbstractSubjectMod {
 
     private final List<String> mVirAttrTemplates = new ArrayList<>();
 
-    private ReferenceMod passwordPolicy;
-
-    private ReferenceMod accountPolicy;
+    private String dynMembershipCond;
 
     public String getName() {
         return name;
@@ -105,46 +89,6 @@ public class GroupMod extends AbstractSubjectMod {
         this.groupOwner = groupOwner;
     }
 
-    public Boolean getInheritOwner() {
-        return inheritOwner;
-    }
-
-    public void setInheritOwner(final Boolean inheritOwner) {
-        this.inheritOwner = inheritOwner;
-    }
-
-    public Boolean getInheritTemplates() {
-        return inheritTemplates;
-    }
-
-    public void setInheritTemplates(final Boolean inheritTemplates) {
-        this.inheritTemplates = inheritTemplates;
-    }
-
-    public Boolean getInheritPlainAttrs() {
-        return inheritPlainAttrs;
-    }
-
-    public void setInheritPlainAttrs(final Boolean inheritAttrs) {
-        this.inheritPlainAttrs = inheritAttrs;
-    }
-
-    public Boolean getInheritDerAttrs() {
-        return inheritDerAttrs;
-    }
-
-    public void setInheritDerAttrs(final Boolean inheritDerAttrs) {
-        this.inheritDerAttrs = inheritDerAttrs;
-    }
-
-    public Boolean getInheritVirAttrs() {
-        return inheritVirAttrs;
-    }
-
-    public void setInheritVirAttrs(final Boolean inheritVirAttrs) {
-        this.inheritVirAttrs = inheritVirAttrs;
-    }
-
     public boolean isModGAttrTemplates() {
         return modGAttrTemplates;
     }
@@ -235,47 +179,20 @@ public class GroupMod extends AbstractSubjectMod {
         return mVirAttrTemplates;
     }
 
-    public ReferenceMod getPasswordPolicy() {
-        return passwordPolicy;
-    }
-
-    public void setPasswordPolicy(final ReferenceMod passwordPolicy) {
-        this.passwordPolicy = passwordPolicy;
-    }
-
-    public Boolean getInheritPasswordPolicy() {
-        return inheritPasswordPolicy;
-    }
-
-    public void setInheritPasswordPolicy(final Boolean inheritPasswordPolicy) {
-        this.inheritPasswordPolicy = inheritPasswordPolicy;
-    }
-
-    public ReferenceMod getAccountPolicy() {
-        return accountPolicy;
-    }
-
-    public void setAccountPolicy(final ReferenceMod accountPolicy) {
-        this.accountPolicy = accountPolicy;
-    }
-
-    public Boolean getInheritAccountPolicy() {
-        return inheritAccountPolicy;
+    public String getDynMembershipCond() {
+        return dynMembershipCond;
     }
 
-    public void setInheritAccountPolicy(final Boolean inheritAccountPolicy) {
-        this.inheritAccountPolicy = inheritAccountPolicy;
+    public void setDynMembershipCond(final String dynMembershipCond) {
+        this.dynMembershipCond = dynMembershipCond;
     }
 
     @JsonIgnore
     @Override
     public boolean isEmpty() {
         return super.isEmpty() && name == null && userOwner == null && groupOwner == null
-                && inheritTemplates == null && inheritOwner == null
-                && inheritAccountPolicy == null && inheritPasswordPolicy == null
-                && inheritPlainAttrs == null && inheritDerAttrs == null && inheritVirAttrs == null
-                && accountPolicy == null && passwordPolicy == null
                 && gPlainAttrTemplates.isEmpty() && gDerAttrTemplates.isEmpty() && gVirAttrTemplates.isEmpty()
-                && mPlainAttrTemplates.isEmpty() && mDerAttrTemplates.isEmpty() && mVirAttrTemplates.isEmpty();
+                && mPlainAttrTemplates.isEmpty() && mDerAttrTemplates.isEmpty() && mVirAttrTemplates.isEmpty()
+                && dynMembershipCond == null;
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java b/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java
index c8e9152..aaa56d7 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java
@@ -22,7 +22,7 @@ import java.util.Map;
 import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
 
 /**
- * Extends <tt>SyncopeFiqlSearchConditionBuilder</tt> by providing some additional facilities for searching
+ * Extends {@link AbstractFiqlSearchConditionBuilder} by providing some additional facilities for searching
  * groups in Syncope.
  */
 public class GroupFiqlSearchConditionBuilder extends AbstractFiqlSearchConditionBuilder {

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java b/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java
index 37b53ec..9877267 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java
@@ -26,7 +26,8 @@ public enum SpecialAttr {
 
     NULL("$null"),
     RESOURCES("$resources"),
-    GROUPS("$groups");
+    GROUPS("$groups"),
+    ROLES("$roles");
 
     private final String literal;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserFiqlSearchConditionBuilder.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserFiqlSearchConditionBuilder.java b/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserFiqlSearchConditionBuilder.java
index 020866d..802694e 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserFiqlSearchConditionBuilder.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserFiqlSearchConditionBuilder.java
@@ -23,7 +23,7 @@ import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
 import org.apache.cxf.jaxrs.ext.search.fiql.FiqlParser;
 
 /**
- * Extends <tt>SyncopeFiqlSearchConditionBuilder</tt> by providing some additional facilities for searching
+ * Extends {@link AbstractFiqlSearchConditionBuilder} by providing some additional facilities for searching
  * users in Syncope.
  */
 public class UserFiqlSearchConditionBuilder extends AbstractFiqlSearchConditionBuilder {
@@ -50,14 +50,20 @@ public class UserFiqlSearchConditionBuilder extends AbstractFiqlSearchConditionB
         return newBuilderInstance().is(SpecialAttr.GROUPS.toString()).inGroups(group, moreGroups);
     }
 
+    public CompleteCondition inRoles(final Long role, final Long... moreRoles) {
+        return newBuilderInstance().is(SpecialAttr.ROLES.toString()).inRoles(role, moreRoles);
+    }
+
     public CompleteCondition notInGroups(final Long group, final Long... moreGroups) {
         return newBuilderInstance().is(SpecialAttr.GROUPS.toString()).notInGroups(group, moreGroups);
     }
 
+    @Override
     public CompleteCondition hasResources(final String resource, final String... moreResources) {
         return newBuilderInstance().is(SpecialAttr.RESOURCES.toString()).hasResources(resource, moreResources);
     }
 
+    @Override
     public CompleteCondition hasNotResources(final String resource, final String... moreResources) {
         return newBuilderInstance().is(SpecialAttr.RESOURCES.toString()).hasNotResources(resource, moreResources);
     }
@@ -75,9 +81,9 @@ public class UserFiqlSearchConditionBuilder extends AbstractFiqlSearchConditionB
 
         @Override
         public UserProperty is(final String property) {
-            Builder b = new Builder(this);
-            b.result = property;
-            return b;
+            Builder builder = new Builder(this);
+            builder.result = property;
+            return builder;
         }
 
         @Override
@@ -91,5 +97,17 @@ public class UserFiqlSearchConditionBuilder extends AbstractFiqlSearchConditionB
             this.result = SpecialAttr.GROUPS.toString();
             return condition(FiqlParser.NEQ, group, (Object[]) moreGroups);
         }
+
+        @Override
+        public CompleteCondition inRoles(final Long role, final Long... moreRoles) {
+            this.result = SpecialAttr.ROLES.toString();
+            return condition(FiqlParser.EQ, role, (Object[]) moreRoles);
+        }
+
+        @Override
+        public CompleteCondition notInRoles(final Long role, final Long... moreRoles) {
+            this.result = SpecialAttr.ROLES.toString();
+            return condition(FiqlParser.NEQ, role, (Object[]) moreRoles);
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserProperty.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserProperty.java b/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserProperty.java
index fb4d7d6..5a659b7 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserProperty.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserProperty.java
@@ -26,4 +26,8 @@ public interface UserProperty extends SyncopeProperty {
 
     CompleteCondition notInGroups(Long group, Long... moreGroups);
 
+    CompleteCondition inRoles(Long role, Long... moreRoles);
+
+    CompleteCondition notInRoles(Long role, Long... moreRoles);
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/common/lib/src/main/java/org/apache/syncope/common/lib/to/GroupTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/GroupTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/GroupTO.java
index 029f8a8..da0bd2b 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/GroupTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/GroupTO.java
@@ -53,6 +53,8 @@ public class GroupTO extends AbstractSubjectTO {
 
     private final List<String> mVirAttrTemplates = new ArrayList<>();
 
+    private String dynMembershipCond;
+
     public String getName() {
         return name;
     }
@@ -119,4 +121,12 @@ public class GroupTO extends AbstractSubjectTO {
         return mVirAttrTemplates;
     }
 
+    public String getDynMembershipCond() {
+        return dynMembershipCond;
+    }
+
+    public void setDynMembershipCond(final String dynMembershipCond) {
+        this.dynMembershipCond = dynMembershipCond;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
index 95ef20d..1a12fdb 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
@@ -43,6 +43,8 @@ public class RoleTO extends AbstractBaseBean {
 
     private final List<String> realms = new ArrayList<>();
 
+    private String dynMembershipCond;
+
     public long getKey() {
         return key;
     }
@@ -73,4 +75,12 @@ public class RoleTO extends AbstractBaseBean {
         return realms;
     }
 
+    public String getDynMembershipCond() {
+        return dynMembershipCond;
+    }
+
+    public void setDynMembershipCond(final String dynMembershipCond) {
+        this.dynMembershipCond = dynMembershipCond;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/common/lib/src/main/java/org/apache/syncope/common/lib/to/UserTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/UserTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/UserTO.java
index 6597dc8..2feeffe 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/UserTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/UserTO.java
@@ -44,8 +44,12 @@ public class UserTO extends AbstractSubjectTO {
 
     private final List<Long> roles = new ArrayList<>();
 
+    private final List<Long> dynRoles = new ArrayList<>();
+
     private final List<MembershipTO> memberships = new ArrayList<>();
 
+    private final List<Long> dynGroups = new ArrayList<>();
+
     private String status;
 
     private String token;
@@ -79,6 +83,13 @@ public class UserTO extends AbstractSubjectTO {
         return roles;
     }
 
+    @XmlElementWrapper(name = "dynRoles")
+    @XmlElement(name = "role")
+    @JsonProperty("dynRoles")
+    public List<Long> getDynRoles() {
+        return dynRoles;
+    }
+
     @XmlElementWrapper(name = "memberships")
     @XmlElement(name = "membership")
     @JsonProperty("memberships")
@@ -103,6 +114,13 @@ public class UserTO extends AbstractSubjectTO {
         return result;
     }
 
+    @XmlElementWrapper(name = "dynGroups")
+    @XmlElement(name = "role")
+    @JsonProperty("dynGroups")
+    public List<Long> getDynGroups() {
+        return dynGroups;
+    }
+
     public String getStatus() {
         return status;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/common/lib/src/main/java/org/apache/syncope/common/lib/types/PropagationByResource.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/PropagationByResource.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/PropagationByResource.java
index f89f27e..014f52d 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/PropagationByResource.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/PropagationByResource.java
@@ -269,7 +269,7 @@ public class PropagationByResource implements Serializable {
      * @param type resource operation type
      * @param resourceNames to be set
      */
-    public final void set(final ResourceOperation type, final Set<String> resourceNames) {
+    public final void set(final ResourceOperation type, final Collection<String> resourceNames) {
 
         switch (type) {
             case CREATE:

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
index ec020ba..a3a3ab8 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
@@ -103,7 +103,7 @@ public class GroupLogic extends AbstractSubjectLogic<GroupTO, GroupMod> {
     @Transactional(readOnly = true)
     public List<GroupTO> own() {
         return CollectionUtils.collect(
-                userDAO.find(AuthContextUtils.getAuthenticatedUsername()).getGroups(),
+                userDAO.findAllGroups(userDAO.find(AuthContextUtils.getAuthenticatedUsername())),
                 new Transformer<Group, GroupTO>() {
 
                     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/logic/src/main/java/org/apache/syncope/core/logic/LoggerLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/LoggerLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/LoggerLogic.java
index f3c9e5d..d035301 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/LoggerLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/LoggerLogic.java
@@ -18,8 +18,6 @@
  */
 package org.apache.syncope.core.logic;
 
-import static org.apache.syncope.core.logic.AbstractLogic.LOG;
-
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
index 09c606a..72e03e5 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
@@ -18,8 +18,6 @@
  */
 package org.apache.syncope.core.logic;
 
-import static org.apache.syncope.core.logic.AbstractLogic.LOG;
-
 import java.io.IOException;
 import java.lang.reflect.Method;
 import java.net.URI;

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
index a261cd3..fc81696 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
@@ -361,9 +361,9 @@ public class UserLogic extends AbstractSubjectLogic<UserTO, UserMod> {
         final UserMod userMod = new UserMod();
         userMod.setKey(key);
         userMod.getResourcesToRemove().addAll(resources);
-        Long updatedId = provisioningManager.unlink(userMod);
+        Long updatedKey = provisioningManager.unlink(userMod);
 
-        return binder.getUserTO(updatedId);
+        return binder.getUserTO(updatedKey);
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
index 8553a0a..719a680 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
@@ -29,6 +29,8 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.AttributableOperations;
 import org.apache.syncope.common.lib.mod.AbstractAttributableMod;
@@ -554,16 +556,16 @@ public class ConnObjectUtils {
             // not cached ...
             LOG.debug("Need one or more remote connections");
 
-            final VirAttrCacheValue toBeCached = new VirAttrCacheValue();
+            VirAttrCacheValue toBeCached = new VirAttrCacheValue();
 
             // SYNCOPE-458 if virattr owner is a Membership, owner must become user involved in membership because 
             // membership mapping is contained in user mapping
-            final Subject<?, ?, ?> realOwner = owner instanceof Membership
+            Subject<?, ?, ?> realOwner = owner instanceof Membership
                     ? ((Membership) owner).getUser()
                     : (Subject) owner;
 
-            final Set<ExternalResource> targetResources = owner instanceof Membership
-                    ? getTargetResources(virAttr, type, attrUtils, realOwner.getResources())
+            Collection<ExternalResource> targetResources = owner instanceof Membership
+                    ? getTargetResources(virAttr, type, attrUtils, userDAO.findAllResources((User) realOwner))
                     : getTargetResources(virAttr, type, attrUtils);
 
             for (ExternalResource resource : targetResources) {
@@ -636,40 +638,29 @@ public class ConnObjectUtils {
         }
     }
 
-    private Set<ExternalResource> getTargetResources(
+    private Collection<ExternalResource> getTargetResources(
             final VirAttr attr, final IntMappingType type, final AttributableUtils attrUtils) {
 
-        final Set<ExternalResource> resources = new HashSet<>();
-
-        if (attr.getOwner() instanceof Subject) {
-            for (ExternalResource res : ((Subject<?, ?, ?>) attr.getOwner()).getResources()) {
-                if (!MappingUtils.getMatchingMappingItems(
-                        attrUtils.getMappingItems(res, MappingPurpose.BOTH),
-                        attr.getSchema().getKey(), type).isEmpty()) {
-
-                    resources.add(res);
-                }
-            }
-        }
-
-        return resources;
+        Iterable<? extends ExternalResource> iterable = attr.getOwner() instanceof User
+                ? userDAO.findAllResources((User) attr.getOwner())
+                : attr.getOwner() instanceof Group
+                        ? ((Group) attr.getOwner()).getResources()
+                        : Collections.<ExternalResource>emptySet();
+        return getTargetResources(attr, type, attrUtils, iterable);
     }
 
-    private Set<ExternalResource> getTargetResources(final VirAttr attr, final IntMappingType type,
-            final AttributableUtils attrUtils, final Set<? extends ExternalResource> ownerResources) {
-
-        final Set<ExternalResource> resources = new HashSet<>();
+    private Collection<ExternalResource> getTargetResources(final VirAttr attr, final IntMappingType type,
+            final AttributableUtils attrUtils, final Iterable<? extends ExternalResource> ownerResources) {
 
-        for (ExternalResource res : ownerResources) {
-            if (!MappingUtils.getMatchingMappingItems(
-                    attrUtils.getMappingItems(res, MappingPurpose.BOTH),
-                    attr.getSchema().getKey(), type).isEmpty()) {
+        return CollectionUtils.select(ownerResources, new Predicate<ExternalResource>() {
 
-                resources.add(res);
+            @Override
+            public boolean evaluate(final ExternalResource resource) {
+                return !MappingUtils.getMatchingMappingItems(
+                        attrUtils.getMappingItems(resource, MappingPurpose.BOTH),
+                        attr.getSchema().getKey(), type).isEmpty();
             }
-        }
-
-        return resources;
+        });
     }
 
     private void fillFromTemplate(final AbstractAttributableTO attributableTO, final AbstractAttributableTO template) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
index 535597a..009e881 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
@@ -72,6 +72,7 @@ import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
 import org.apache.syncope.core.misc.security.Encryptor;
 import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 import org.apache.syncope.core.misc.jexl.JexlUtils;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.identityconnectors.framework.common.FrameworkUtil;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeBuilder;
@@ -268,7 +269,8 @@ public final class MappingUtils {
 
             case GROUP:
                 if (subject instanceof User) {
-                    for (Group group : ((User) subject).getGroups()) {
+                    UserDAO userDAO = context.getBean(UserDAO.class);
+                    for (Group group : userDAO.findAllGroups((User) subject)) {
                         connObjectUtils.retrieveVirAttrValues(group, attrUtilsFactory.getInstance(group));
                         attributables.add(group);
                     }
@@ -655,16 +657,16 @@ public final class MappingUtils {
     /**
      * Get accountId internal value.
      *
-     * @param attributable attributable
+     * @param subject subject
      * @param accountIdItem accountId mapping item
      * @param resource external resource
      * @return accountId internal value
      */
-    public static String getAccountIdValue(final Attributable<?, ?, ?> attributable,
+    public static String getAccountIdValue(final Subject<?, ?, ?> subject,
             final ExternalResource resource, final MappingItem accountIdItem) {
 
         List<PlainAttrValue> values = getIntValues(resource, accountIdItem,
-                Collections.<Attributable<?, ?, ?>>singletonList(attributable), null, null, null, null);
+                Collections.<Attributable<?, ?, ?>>singletonList(subject), null, null, null, null);
         return values == null || values.isEmpty()
                 ? null
                 : values.get(0).getValueAsString();

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondConverter.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondConverter.java b/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondConverter.java
index 684592c..db3a80f 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondConverter.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondConverter.java
@@ -18,9 +18,12 @@
  */
 package org.apache.syncope.core.misc.search;
 
+import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.cxf.jaxrs.ext.search.SearchBean;
 import org.apache.cxf.jaxrs.ext.search.fiql.FiqlParser;
+import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.search.AbstractFiqlSearchConditionBuilder;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 
 /**
@@ -32,16 +35,23 @@ public final class SearchCondConverter {
      * Parses a FIQL expression into Syncope's <tt>SearchCond</tt>, using CXF's <tt>FiqlParser</tt>.
      *
      * @param fiqlExpression FIQL string
-     * @return <tt>SearchCond</tt> instance for given FIQL expression
+     * @return {@link SearchCond} instance for given FIQL expression
      * @see FiqlParser
      */
     public static SearchCond convert(final String fiqlExpression) {
         FiqlParser<SearchBean> fiqlParser = new FiqlParser<>(
                 SearchBean.class, AbstractFiqlSearchConditionBuilder.CONTEXTUAL_PROPERTIES);
 
-        SearchCondVisitor searchCondVisitor = new SearchCondVisitor();
-        searchCondVisitor.visit(fiqlParser.parse(fiqlExpression));
-        return searchCondVisitor.getQuery();
+        try {
+            SearchCondVisitor searchCondVisitor = new SearchCondVisitor();
+            searchCondVisitor.visit(fiqlParser.parse(fiqlExpression));
+            return searchCondVisitor.getQuery();
+        } catch (Exception e) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSearchExpression);
+            sce.getElements().add(fiqlExpression);
+            sce.getElements().add(ExceptionUtils.getRootCauseMessage(e));
+            throw sce;
+        }
     }
 
     private SearchCondConverter() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondVisitor.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondVisitor.java b/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondVisitor.java
index 1062a93..cebfb38 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondVisitor.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/search/SearchCondVisitor.java
@@ -31,8 +31,9 @@ import org.apache.syncope.common.lib.search.SpecialAttr;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
-import org.apache.syncope.core.persistence.api.dao.search.MembershipCond;
+import org.apache.syncope.core.persistence.api.dao.search.GroupCond;
 import org.apache.syncope.core.persistence.api.dao.search.ResourceCond;
+import org.apache.syncope.core.persistence.api.dao.search.RoleCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.dao.search.SubjectCond;
 
@@ -96,9 +97,15 @@ public class SearchCondVisitor extends AbstractSearchConditionVisitor<SearchBean
                 } else {
                     switch (specialAttrName) {
                         case GROUPS:
-                            MembershipCond membershipCond = new MembershipCond();
-                            membershipCond.setGroupId(Long.valueOf(value));
-                            leaf = SearchCond.getLeafCond(membershipCond);
+                            GroupCond groupCond = new GroupCond();
+                            groupCond.setGroupKey(Long.valueOf(value));
+                            leaf = SearchCond.getLeafCond(groupCond);
+                            break;
+
+                        case ROLES:
+                            RoleCond roleCond = new RoleCond();
+                            roleCond.setRoleKey(Long.valueOf(value));
+                            leaf = SearchCond.getLeafCond(roleCond);
                             break;
 
                         case RESOURCES:
@@ -156,7 +163,7 @@ public class SearchCondVisitor extends AbstractSearchConditionVisitor<SearchBean
     }
 
     private SearchCond visitCompount(final SearchCondition<SearchBean> sc) {
-        List<SearchCond> searchConds = new ArrayList<SearchCond>();
+        List<SearchCond> searchConds = new ArrayList<>();
         for (SearchCondition<SearchBean> searchCondition : sc.getSearchConditions()) {
             searchConds.add(searchCondition.getStatement() == null
                     ? visitCompount(searchCondition)

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/misc/src/main/java/org/apache/syncope/core/misc/security/PasswordGenerator.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/security/PasswordGenerator.java b/core/misc/src/main/java/org/apache/syncope/core/misc/security/PasswordGenerator.java
index 52b260e..d0501e4 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/security/PasswordGenerator.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/security/PasswordGenerator.java
@@ -28,6 +28,7 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.misc.policy.InvalidPasswordPolicySpecException;
 import org.apache.syncope.core.misc.policy.PolicyPattern;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -43,6 +44,9 @@ public class PasswordGenerator {
     private static final char[] SPECIAL_CHARS = { '!', 'ÂŁ', '%', '&', '(', ')', '?', '#', '$' };
 
     @Autowired
+    private UserDAO userDAO;
+
+    @Autowired
     private RealmDAO realmDAO;
 
     public String generate(final List<PasswordPolicySpec> ppSpecs)
@@ -68,7 +72,7 @@ public class PasswordGenerator {
             }
         }
 
-        for (ExternalResource resource : user.getResources()) {
+        for (ExternalResource resource : userDAO.findAllResources(user)) {
             if (resource.getPasswordPolicy() != null
                     && resource.getPasswordPolicy().getSpecification(PasswordPolicySpec.class) != null) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeAuthenticationProvider.java b/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeAuthenticationProvider.java
index 6d530ae..3ecdd1f 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeAuthenticationProvider.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeAuthenticationProvider.java
@@ -224,8 +224,8 @@ public class SyncopeAuthenticationProvider implements AuthenticationProvider {
     protected Set<? extends ExternalResource> getPassthroughResources(final User user) {
         Set<? extends ExternalResource> result = null;
 
-        // 1. look for directly assigned resources, pick the ones whose account policy has authentication resources
-        for (ExternalResource resource : user.getOwnResources()) {
+        // 1. look for assigned resources, pick the ones whose account policy has authentication resources
+        for (ExternalResource resource : userDAO.findAllResources(user)) {
             if (resource.getAccountPolicy() != null && !resource.getAccountPolicy().getResources().isEmpty()) {
                 if (result == null) {
                     result = resource.getAccountPolicy().getResources();
@@ -253,7 +253,7 @@ public class SyncopeAuthenticationProvider implements AuthenticationProvider {
         boolean authenticated = encryptor.verify(password, user.getCipherAlgorithm(), user.getPassword());
         LOG.debug("{} authenticated on internal storage: {}", user.getUsername(), authenticated);
 
-        final AttributableUtils attrUtils = attrUtilsFactory.getInstance(AttributableType.USER);
+        AttributableUtils attrUtils = attrUtilsFactory.getInstance(AttributableType.USER);
         for (Iterator<? extends ExternalResource> itor = getPassthroughResources(user).iterator();
                 itor.hasNext() && !authenticated;) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeGrantedAuthority.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeGrantedAuthority.java b/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeGrantedAuthority.java
index 78dccc4..f8f974b 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeGrantedAuthority.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeGrantedAuthority.java
@@ -25,6 +25,8 @@ import java.util.Set;
 import org.apache.commons.collections4.Closure;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.SetUtils;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.syncope.core.misc.RealmUtils;
 import org.springframework.security.core.GrantedAuthority;
 
@@ -68,4 +70,14 @@ public class SyncopeGrantedAuthority implements GrantedAuthority {
         return entitlement;
     }
 
+    @Override
+    public boolean equals(final Object obj) {
+        return EqualsBuilder.reflectionEquals(this, obj);
+    }
+
+    @Override
+    public int hashCode() {
+        return HashCodeBuilder.reflectionHashCode(this);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeUserDetailsService.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeUserDetailsService.java b/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeUserDetailsService.java
index 9b9ee5f..0d6ff52 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeUserDetailsService.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeUserDetailsService.java
@@ -81,8 +81,9 @@ public class SyncopeUserDetailsService implements UserDetailsService {
                 throw new UsernameNotFoundException("Could not find any user with id " + username);
             }
 
-            // Give entitlements as assigned by roles (with realms, where applicable)
-            for (final Role role : user.getRoles()) {
+            // Give entitlements as assigned by roles (with realms, where applicable) - assigned either
+            // statically and dynamically
+            for (final Role role : userDAO.findAllRoles(user)) {
                 CollectionUtils.forAllDo(role.getEntitlements(), new Closure<String>() {
 
                     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/misc/src/test/java/org/apache/syncope/core/misc/search/SearchCondConverterTest.java
----------------------------------------------------------------------
diff --git a/core/misc/src/test/java/org/apache/syncope/core/misc/search/SearchCondConverterTest.java b/core/misc/src/test/java/org/apache/syncope/core/misc/search/SearchCondConverterTest.java
index db222af..b3bc11e 100644
--- a/core/misc/src/test/java/org/apache/syncope/core/misc/search/SearchCondConverterTest.java
+++ b/core/misc/src/test/java/org/apache/syncope/core/misc/search/SearchCondConverterTest.java
@@ -23,8 +23,9 @@ import static org.junit.Assert.assertEquals;
 import org.apache.syncope.common.lib.search.SpecialAttr;
 import org.apache.syncope.common.lib.search.UserFiqlSearchConditionBuilder;
 import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
-import org.apache.syncope.core.persistence.api.dao.search.MembershipCond;
+import org.apache.syncope.core.persistence.api.dao.search.GroupCond;
 import org.apache.syncope.core.persistence.api.dao.search.ResourceCond;
+import org.apache.syncope.core.persistence.api.dao.search.RoleCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.dao.search.SubjectCond;
 import org.junit.Test;
@@ -86,9 +87,21 @@ public class SearchCondConverterTest {
         String fiqlExpression = new UserFiqlSearchConditionBuilder().inGroups(1L).query();
         assertEquals(SpecialAttr.GROUPS + "==1", fiqlExpression);
 
-        MembershipCond membCond = new MembershipCond();
-        membCond.setGroupId(1L);
-        SearchCond simpleCond = SearchCond.getLeafCond(membCond);
+        GroupCond groupCond = new GroupCond();
+        groupCond.setGroupKey(1L);
+        SearchCond simpleCond = SearchCond.getLeafCond(groupCond);
+
+        assertEquals(simpleCond, SearchCondConverter.convert(fiqlExpression));
+    }
+
+    @Test
+    public void roles() {
+        String fiqlExpression = new UserFiqlSearchConditionBuilder().inRoles(1L).query();
+        assertEquals(SpecialAttr.ROLES + "==1", fiqlExpression);
+
+        RoleCond roleCond = new RoleCond();
+        roleCond.setRoleKey(1L);
+        SearchCond simpleCond = SearchCond.getLeafCond(roleCond);
 
         assertEquals(simpleCond, SearchCondConverter.convert(fiqlExpression));
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/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 a81db9d..bcdd1ca 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
@@ -30,6 +30,7 @@ import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.group.GVirAttr;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.user.User;
 
 public interface GroupDAO extends SubjectDAO<GPlainAttr, GDerAttr, GVirAttr> {
 
@@ -72,4 +73,7 @@ public interface GroupDAO extends SubjectDAO<GPlainAttr, GDerAttr, GVirAttr> {
      * @return map containing pairs with user key and operations to be performed on those resources (DELETE, typically).
      */
     Map<Long, PropagationByResource> findUsersWithIndirectResources(Long groupKey);
+
+    void refreshDynMemberships(User user);
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RoleDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RoleDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RoleDAO.java
index 76723b0..d1a3101 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RoleDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RoleDAO.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.persistence.api.dao;
 import java.util.List;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.user.User;
 
 public interface RoleDAO extends DAO<Role, Long> {
 
@@ -37,4 +38,6 @@ public interface RoleDAO extends DAO<Role, Long> {
     void delete(Role role);
 
     void delete(Long key);
+
+    void refreshDynMemberships(User user);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/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 46388b3..469a98f 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
@@ -18,10 +18,13 @@
  */
 package org.apache.syncope.core.persistence.api.dao;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
 import org.apache.syncope.core.persistence.api.entity.user.UDerAttr;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
@@ -64,4 +67,18 @@ public interface UserDAO extends SubjectDAO<UPlainAttr, UDerAttr, UVirAttr> {
     User authFetch(Long key);
 
     User authFetch(String username);
+
+    List<Role> findDynRoleMemberships(User user);
+
+    List<Group> findDynGroupMemberships(User user);
+
+    Collection<Role> findAllRoles(User user);
+
+    Collection<Group> findAllGroups(User user);
+
+    Collection<Long> findAllGroupKeys(User user);
+
+    Collection<ExternalResource> findAllResources(User user);
+
+    Collection<String> findAllResourceNames(User user);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/GroupCond.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/GroupCond.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/GroupCond.java
new file mode 100644
index 0000000..3dbb9b0
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/GroupCond.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.dao.search;
+
+public class GroupCond extends AbstractSearchCond {
+
+    private static final long serialVersionUID = -728155256293925989L;
+
+    private Long groupKey;
+
+    public Long getGroupKey() {
+        return groupKey;
+    }
+
+    public void setGroupKey(final Long groupKey) {
+        this.groupKey = groupKey;
+    }
+
+    @Override
+    public final boolean isValid() {
+        return groupKey != null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/MembershipCond.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/MembershipCond.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/MembershipCond.java
deleted file mode 100644
index 6cbc6b3..0000000
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/MembershipCond.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.core.persistence.api.dao.search;
-
-/**
- * Search condition to be applied when searching for memberships.
- */
-public class MembershipCond extends AbstractSearchCond {
-
-    private static final long serialVersionUID = -728155256293925989L;
-
-    private Long groupId;
-
-    public Long getGroupId() {
-        return groupId;
-    }
-
-    public void setGroupId(final Long groupId) {
-        this.groupId = groupId;
-    }
-
-    @Override
-    public final boolean isValid() {
-        return groupId != null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/RoleCond.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/RoleCond.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/RoleCond.java
new file mode 100644
index 0000000..be6688f
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/RoleCond.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.dao.search;
+
+public class RoleCond extends AbstractSearchCond {
+
+    private static final long serialVersionUID = 3581958527829522490L;
+
+    private Long roleKey;
+
+    public Long getRoleKey() {
+        return roleKey;
+    }
+
+    public void setRoleKey(final Long roleKey) {
+        this.roleKey = roleKey;
+    }
+
+    @Override
+    public final boolean isValid() {
+        return roleKey != null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java
index 030a253..ab5b527 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/search/SearchCond.java
@@ -39,7 +39,9 @@ public class SearchCond extends AbstractSearchCond {
 
     private AttributeCond attributeCond;
 
-    private MembershipCond membershipCond;
+    private GroupCond groupCond;
+
+    private RoleCond roleCond;
 
     private ResourceCond resourceCond;
 
@@ -60,11 +62,20 @@ public class SearchCond extends AbstractSearchCond {
         return nodeCond;
     }
 
-    public static SearchCond getLeafCond(final MembershipCond membershipCond) {
+    public static SearchCond getLeafCond(final GroupCond groupCond) {
+        SearchCond nodeCond = new SearchCond();
+
+        nodeCond.type = Type.LEAF;
+        nodeCond.groupCond = groupCond;
+
+        return nodeCond;
+    }
+
+    public static SearchCond getLeafCond(final RoleCond roleCond) {
         SearchCond nodeCond = new SearchCond();
 
         nodeCond.type = Type.LEAF;
-        nodeCond.membershipCond = membershipCond;
+        nodeCond.roleCond = roleCond;
 
         return nodeCond;
     }
@@ -84,8 +95,14 @@ public class SearchCond extends AbstractSearchCond {
         return nodeCond;
     }
 
-    public static SearchCond getNotLeafCond(final MembershipCond membershipCond) {
-        SearchCond nodeCond = getLeafCond(membershipCond);
+    public static SearchCond getNotLeafCond(final GroupCond groupCond) {
+        SearchCond nodeCond = getLeafCond(groupCond);
+        nodeCond.type = Type.NOT_LEAF;
+        return nodeCond;
+    }
+
+    public static SearchCond getNotLeafCond(final RoleCond roleCond) {
+        SearchCond nodeCond = getLeafCond(roleCond);
         nodeCond.type = Type.NOT_LEAF;
         return nodeCond;
     }
@@ -155,12 +172,20 @@ public class SearchCond extends AbstractSearchCond {
         this.attributeCond = attributeCond;
     }
 
-    public MembershipCond getMembershipCond() {
-        return membershipCond;
+    public GroupCond getGroupCond() {
+        return groupCond;
+    }
+
+    public void setGroupCond(final GroupCond groupCond) {
+        this.groupCond = groupCond;
+    }
+
+    public RoleCond getRoleCond() {
+        return roleCond;
     }
 
-    public void setMembershipCond(final MembershipCond membershipCond) {
-        this.membershipCond = membershipCond;
+    public void setRoleCond(final RoleCond roleCond) {
+        this.roleCond = roleCond;
     }
 
     public ResourceCond getResourceCond() {
@@ -207,10 +232,11 @@ public class SearchCond extends AbstractSearchCond {
             case LEAF:
             case NOT_LEAF:
                 isValid = (subjectCond != null || attributeCond != null
-                        || membershipCond != null || resourceCond != null)
+                        || groupCond != null || roleCond != null || resourceCond != null)
                         && (subjectCond == null || subjectCond.isValid())
                         && (attributeCond == null || attributeCond.isValid())
-                        && (membershipCond == null || membershipCond.isValid())
+                        && (groupCond == null || groupCond.isValid())
+                        && (roleCond == null || roleCond.isValid())
                         && (resourceCond == null || resourceCond.isValid());
                 break;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynGroupMembership.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynGroupMembership.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynGroupMembership.java
new file mode 100644
index 0000000..8770e35
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynGroupMembership.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.entity;
+
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+
+public interface DynGroupMembership extends DynMembership {
+
+    Group getGroup();
+
+    void setGroup(Group role);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynMembership.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynMembership.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynMembership.java
new file mode 100644
index 0000000..2fbecc3
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynMembership.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.entity;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+
+public interface DynMembership extends Entity<Long> {
+
+    String getFIQLCond();
+
+    void setFIQLCond(String fiql);
+
+    boolean addUser(User user);
+
+    boolean removeUser(User user);
+
+    List<? extends User> getUsers();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynRoleMembership.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynRoleMembership.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynRoleMembership.java
new file mode 100644
index 0000000..5321434
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynRoleMembership.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.entity;
+
+public interface DynRoleMembership extends DynMembership {
+
+    Role getRole();
+
+    void setRole(Role role);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java
index 28b82d3..5a9fe86 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java
@@ -35,4 +35,7 @@ public interface Role extends Entity<Long> {
 
     List<? extends Realm> getRealms();
 
+    DynRoleMembership getDynMembership();
+
+    void setDynMembership(DynRoleMembership dynMembership);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/Group.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/Group.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/Group.java
index 6de9a81..f7959cd 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/Group.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/Group.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.persistence.api.entity.group;
 
 import java.util.List;
 import org.apache.syncope.core.persistence.api.entity.AttrTemplate;
+import org.apache.syncope.core.persistence.api.entity.DynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.Schema;
 import org.apache.syncope.core.persistence.api.entity.Subject;
 import org.apache.syncope.core.persistence.api.entity.user.User;
@@ -80,4 +81,7 @@ public interface Group extends Subject<GPlainAttr, GDerAttr, GVirAttr> {
     @Override
     List<? extends GVirAttr> getVirAttrs();
 
+    DynGroupMembership getDynMembership();
+
+    void setDynMembership(DynGroupMembership dynMembership);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
index 303d756..7349ecb 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
@@ -18,15 +18,13 @@
  */
 package org.apache.syncope.core.persistence.api.entity.user;
 
+import java.util.Collection;
 import java.util.Date;
 import java.util.List;
-import java.util.Set;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
-import org.apache.syncope.core.persistence.api.entity.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.Role;
 import org.apache.syncope.core.persistence.api.entity.Subject;
 import org.apache.syncope.core.persistence.api.entity.membership.Membership;
-import org.apache.syncope.core.persistence.api.entity.group.Group;
 
 public interface User extends Subject<UPlainAttr, UDerAttr, UVirAttr> {
 
@@ -56,16 +54,12 @@ public interface User extends Subject<UPlainAttr, UDerAttr, UVirAttr> {
 
     List<? extends Membership> getMemberships();
 
-    Set<? extends ExternalResource> getOwnResources();
+    Collection<Long> getStaticGroupKeys();
 
     String getPassword();
 
     List<String> getPasswordHistory();
 
-    Set<Long> getGroupKeys();
-
-    List<Group> getGroups();
-
     String getSecurityAnswer();
 
     SecurityQuestion getSecurityQuestion();

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
index c32324e..70f00f7 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
@@ -21,7 +21,6 @@ package org.apache.syncope.core.persistence.jpa.dao;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import javax.persistence.NoResultException;
 import javax.persistence.TypedQuery;
 import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.PolicyType;
@@ -69,18 +68,7 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource, String
 
     @Override
     public ExternalResource find(final String name) {
-        TypedQuery<ExternalResource> query = entityManager.createQuery("SELECT e FROM "
-                + JPAExternalResource.class.getSimpleName() + " e WHERE e.name = :name", ExternalResource.class);
-        query.setParameter("name", name);
-
-        ExternalResource result = null;
-        try {
-            result = query.getSingleResult();
-        } catch (NoResultException e) {
-            LOG.debug("No resource found with name {}", name, e);
-        }
-
-        return result;
+        return entityManager.find(JPAExternalResource.class, name);
     }
 
     private StringBuilder getByPolicyQuery(final PolicyType type) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/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 73fc456..4e6b985 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
@@ -29,6 +29,7 @@ import javax.persistence.Query;
 import javax.persistence.TypedQuery;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.types.AttributableType;
 import org.apache.syncope.common.lib.types.Entitlement;
 import org.apache.syncope.common.lib.types.ResourceOperation;
@@ -67,10 +68,12 @@ import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
 import org.apache.syncope.common.lib.types.PropagationByResource;
 import org.apache.syncope.common.lib.types.SubjectType;
 import org.apache.syncope.core.misc.RealmUtils;
+import org.apache.syncope.core.misc.search.SearchCondConverter;
 import org.apache.syncope.core.misc.security.AuthContextUtils;
 import org.apache.syncope.core.misc.security.UnauthorizedException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 @Repository
@@ -138,7 +141,7 @@ public class JPAGroupDAO extends AbstractSubjectDAO<GPlainAttr, GDerAttr, GVirAt
 
         StringBuilder queryString = new StringBuilder("SELECT e FROM ").append(JPAGroup.class.getSimpleName()).
                 append(" e WHERE e.userOwner=:owner ");
-        for (Long groupKey : owner.getGroupKeys()) {
+        for (Long groupKey : userDAO.findAllGroupKeys(owner)) {
             queryString.append("OR e.groupOwner.id=").append(groupKey).append(' ');
         }
 
@@ -239,6 +242,17 @@ public class JPAGroupDAO extends AbstractSubjectDAO<GPlainAttr, GDerAttr, GVirAt
 
     @Override
     public Group save(final Group group) {
+        // refresh dynaminc memberships
+        if (group.getDynMembership() != null) {
+            List<User> matchingUsers = searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS,
+                    SearchCondConverter.convert(group.getDynMembership().getFIQLCond()), SubjectType.USER);
+
+            group.getDynMembership().getUsers().clear();
+            for (User user : matchingUsers) {
+                group.getDynMembership().addUser(user);
+            }
+        }
+
         // remove plain attributes without a valid template
         List<GPlainAttr> rToBeDeleted = new ArrayList<>();
         for (final PlainAttr attr : group.getPlainAttrs()) {
@@ -387,7 +401,7 @@ public class JPAGroupDAO extends AbstractSubjectDAO<GPlainAttr, GDerAttr, GVirAt
 
             PropagationByResource propByRes = new PropagationByResource();
             for (ExternalResource resource : group.getResources()) {
-                if (!user.getOwnResources().contains(resource)) {
+                if (!user.getResources().contains(resource)) {
                     propByRes.add(ResourceOperation.DELETE, resource.getKey());
                 }
 
@@ -399,4 +413,16 @@ public class JPAGroupDAO extends AbstractSubjectDAO<GPlainAttr, GDerAttr, GVirAt
 
         return result;
     }
+
+    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
+    @Override
+    public void refreshDynMemberships(final User user) {
+        for (Group role : findAll(SyncopeConstants.FULL_ADMIN_REALMS, -1, -1)) {
+            if (role.getDynMembership() != null && !searchDAO.matches(user,
+                    SearchCondConverter.convert(role.getDynMembership().getFIQLCond()), SubjectType.USER)) {
+
+                role.getDynMembership().removeUser(user);
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
index 61be20f..c195bd9 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARoleDAO.java
@@ -21,13 +21,19 @@ package org.apache.syncope.core.persistence.jpa.dao;
 import java.util.List;
 import javax.persistence.NoResultException;
 import javax.persistence.TypedQuery;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.core.misc.search.SearchCondConverter;
 import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 import org.apache.syncope.core.persistence.api.dao.SubjectSearchDAO;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.JPARole;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
 
 @Repository
 public class JPARoleDAO extends AbstractDAO<Role, Long> implements RoleDAO {
@@ -73,6 +79,17 @@ public class JPARoleDAO extends AbstractDAO<Role, Long> implements RoleDAO {
 
     @Override
     public Role save(final Role role) {
+        // refresh dynaminc memberships
+        if (role.getDynMembership() != null) {
+            List<User> matchingUsers = searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS,
+                    SearchCondConverter.convert(role.getDynMembership().getFIQLCond()), SubjectType.USER);
+
+            role.getDynMembership().getUsers().clear();
+            for (User user : matchingUsers) {
+                role.getDynMembership().addUser(user);
+            }
+        }
+
         return entityManager.merge(role);
     }
 
@@ -91,4 +108,16 @@ public class JPARoleDAO extends AbstractDAO<Role, Long> implements RoleDAO {
         delete(role);
     }
 
+    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
+    @Override
+    public void refreshDynMemberships(final User user) {
+        for (Role role : findAll()) {
+            if (role.getDynMembership() != null && !searchDAO.matches(user,
+                    SearchCondConverter.convert(role.getDynMembership().getFIQLCond()), SubjectType.USER)) {
+
+                role.getDynMembership().removeUser(user);
+            }
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPASubjectSearchDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPASubjectSearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPASubjectSearchDAO.java
index 9cd381a..b4cbad8 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPASubjectSearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPASubjectSearchDAO.java
@@ -46,9 +46,10 @@ import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.dao.SubjectSearchDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
-import org.apache.syncope.core.persistence.api.dao.search.MembershipCond;
+import org.apache.syncope.core.persistence.api.dao.search.GroupCond;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.dao.search.ResourceCond;
+import org.apache.syncope.core.persistence.api.dao.search.RoleCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.dao.search.SubjectCond;
 import org.apache.syncope.core.persistence.api.entity.AttributableUtils;
@@ -418,8 +419,12 @@ public class JPASubjectSearchDAO extends AbstractDAO<Subject<?, ?, ?>, Long> imp
 
             case LEAF:
             case NOT_LEAF:
-                if (nodeCond.getMembershipCond() != null && SubjectType.USER == type) {
-                    query.append(getQuery(nodeCond.getMembershipCond(),
+                if (nodeCond.getGroupCond() != null && SubjectType.USER == type) {
+                    query.append(getQuery(nodeCond.getGroupCond(),
+                            nodeCond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
+                }
+                if (nodeCond.getRoleCond() != null && SubjectType.USER == type) {
+                    query.append(getQuery(nodeCond.getRoleCond(),
                             nodeCond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs));
                 }
                 if (nodeCond.getResourceCond() != null) {
@@ -456,7 +461,7 @@ public class JPASubjectSearchDAO extends AbstractDAO<Subject<?, ?, ?>, Long> imp
         return query;
     }
 
-    private String getQuery(final MembershipCond cond, final boolean not, final List<Object> parameters,
+    private String getQuery(final GroupCond cond, final boolean not, final List<Object> parameters,
             final SearchSupport svs) {
 
         StringBuilder query = new StringBuilder("SELECT DISTINCT subject_id FROM ").
@@ -470,7 +475,49 @@ public class JPASubjectSearchDAO extends AbstractDAO<Subject<?, ?, ?>, Long> imp
 
         query.append("SELECT DISTINCT subject_id ").append("FROM ").
                 append(svs.membership().name).append(" WHERE ").
-                append("group_id=?").append(setParameter(parameters, cond.getGroupId())).
+                append("group_id=?").append(setParameter(parameters, cond.getGroupKey())).
+                append(')');
+
+        if (not) {
+            query.append("AND subject_id NOT IN (");
+        } else {
+            query.append("OR subject_id IN (");
+        }
+
+        query.append("SELECT DISTINCT subject_id ").append("FROM ").
+                append(svs.dyngroupmembership().name).append(" WHERE ").
+                append("group_id=?").append(setParameter(parameters, cond.getGroupKey())).
+                append(')');
+
+        return query.toString();
+    }
+
+    private String getQuery(final RoleCond cond, final boolean not, final List<Object> parameters,
+            final SearchSupport svs) {
+
+        StringBuilder query = new StringBuilder("SELECT DISTINCT subject_id FROM ").
+                append(svs.field().name).append(" WHERE ");
+
+        if (not) {
+            query.append("subject_id NOT IN (");
+        } else {
+            query.append("subject_id IN (");
+        }
+
+        query.append("SELECT DISTINCT subject_id ").append("FROM ").
+                append(svs.role().name).append(" WHERE ").
+                append("role_id=?").append(setParameter(parameters, cond.getRoleKey())).
+                append(')');
+
+        if (not) {
+            query.append("AND subject_id NOT IN (");
+        } else {
+            query.append("OR subject_id IN (");
+        }
+
+        query.append("SELECT DISTINCT subject_id ").append("FROM ").
+                append(svs.dynrolemembership().name).append(" WHERE ").
+                append("role_id=?").append(setParameter(parameters, cond.getRoleKey())).
                 append(')');
 
         return query.toString();

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
index db0d6f2..d90ddbd 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
@@ -178,7 +178,6 @@ public class JPATaskDAO extends AbstractDAO<Task, Long> implements TaskDAO {
             public void execute(final Task input) {
                 delete(input.getKey());
             }
-
         });
     }
 }


[2/3] syncope git commit: [SYNCOPE-140] Implemented

Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/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 5264fcd..46b51dc 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
@@ -18,7 +18,10 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import javax.annotation.Resource;
@@ -26,6 +29,7 @@ import javax.persistence.NoResultException;
 import javax.persistence.TypedQuery;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
+import org.apache.commons.collections4.Transformer;
 import org.apache.syncope.common.lib.types.AttributableType;
 import org.apache.syncope.common.lib.types.Entitlement;
 import org.apache.syncope.common.lib.types.SubjectType;
@@ -47,8 +51,14 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
 import org.apache.syncope.core.misc.security.AuthContextUtils;
 import org.apache.syncope.core.misc.security.UnauthorizedException;
+import org.apache.syncope.core.persistence.api.dao.RoleDAO;
+import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.jpa.entity.JPADynGroupMembership;
+import org.apache.syncope.core.persistence.jpa.entity.JPADynRoleMembership;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 @Repository
@@ -57,6 +67,9 @@ public class JPAUserDAO extends AbstractSubjectDAO<UPlainAttr, UDerAttr, UVirAtt
     @Autowired
     private GroupDAO groupDAO;
 
+    @Autowired
+    private RoleDAO roleDAO;
+
     @Resource(name = "anonymousUser")
     private String anonymousUser;
 
@@ -187,12 +200,15 @@ public class JPAUserDAO extends AbstractSubjectDAO<UPlainAttr, UDerAttr, UVirAtt
 
     @Override
     public User save(final User user) {
-        final User merged = entityManager.merge(user);
+        User merged = entityManager.merge(user);
         for (VirAttr virAttr : merged.getVirAttrs()) {
             virAttr.getValues().clear();
             virAttr.getValues().addAll(user.getVirAttr(virAttr.getSchema().getKey()).getValues());
         }
 
+        roleDAO.refreshDynMemberships(merged);
+        groupDAO.refreshDynMemberships(merged);
+
         return merged;
     }
 
@@ -220,6 +236,13 @@ public class JPAUserDAO extends AbstractSubjectDAO<UPlainAttr, UDerAttr, UVirAtt
         }
         user.getMemberships().clear();
 
+        for (Role role : findDynRoleMemberships(user)) {
+            role.getDynMembership().removeUser(user);
+        }
+        for (Group group : findDynGroupMemberships(user)) {
+            group.getDynMembership().removeUser(user);
+        }
+
         entityManager.remove(user);
     }
 
@@ -277,4 +300,82 @@ public class JPAUserDAO extends AbstractSubjectDAO<UPlainAttr, UDerAttr, UVirAtt
         return user;
     }
 
+    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
+    @Override
+    public List<Role> findDynRoleMemberships(final User user) {
+        TypedQuery<Role> query = entityManager.createQuery(
+                "SELECT e.role FROM " + JPADynRoleMembership.class.getSimpleName()
+                + " e WHERE :user MEMBER OF e.users", Role.class);
+        query.setParameter("user", user);
+
+        return query.getResultList();
+    }
+
+    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
+    @Override
+    public List<Group> findDynGroupMemberships(final User user) {
+        TypedQuery<Group> query = entityManager.createQuery(
+                "SELECT e.group FROM " + JPADynGroupMembership.class.getSimpleName()
+                + " e WHERE :user MEMBER OF e.users", Group.class);
+        query.setParameter("user", user);
+
+        return query.getResultList();
+    }
+
+    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
+    @Override
+    public Collection<Role> findAllRoles(final User user) {
+        return CollectionUtils.union(user.getRoles(), findDynRoleMemberships(user));
+    }
+
+    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
+    @Override
+    public Collection<Group> findAllGroups(final User user) {
+        return CollectionUtils.union(
+                CollectionUtils.collect(user.getMemberships(), new Transformer<Membership, Group>() {
+
+                    @Override
+                    public Group transform(final Membership input) {
+                        return input.getGroup();
+                    }
+                }, new ArrayList<Group>()),
+                findDynGroupMemberships(user));
+    }
+
+    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
+    @Override
+    public Collection<Long> findAllGroupKeys(final User user) {
+        return CollectionUtils.collect(findAllGroups(user), new Transformer<Group, Long>() {
+
+            @Override
+            public Long transform(final Group input) {
+                return input.getKey();
+            }
+        });
+    }
+
+    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
+    @Override
+    public Collection<ExternalResource> findAllResources(final User user) {
+        Set<ExternalResource> result = new HashSet<>();
+        result.addAll(user.getResources());
+        for (Group group : findAllGroups(user)) {
+            result.addAll(group.getResources());
+        }
+
+        return result;
+    }
+
+    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
+    @Override
+    public Collection<String> findAllResourceNames(final User user) {
+        return CollectionUtils.collect(findAllResources(user), new Transformer<ExternalResource, String>() {
+
+            @Override
+            public String transform(final ExternalResource input) {
+                return input.getKey();
+            }
+        });
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
index 9e80ff7..11b3298 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
@@ -110,6 +110,18 @@ class SearchSupport {
         return new SearchView("svm", field().name + "_membership");
     }
 
+    public SearchView dyngroupmembership() {
+        return new SearchView("svdg", field().name + "_dyngroupmembership");
+    }
+
+    public SearchView role() {
+        return new SearchView("svr", field().name + "_role");
+    }
+
+    public SearchView dynrolemembership() {
+        return new SearchView("svdr", field().name + "_dynrolemembership");
+    }
+
     public SearchView nullAttr() {
         return new SearchView("svna", field().name + "_null_attr");
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDynMembership.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDynMembership.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDynMembership.java
new file mode 100644
index 0000000..6e47b34
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDynMembership.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.List;
+import javax.persistence.MappedSuperclass;
+import javax.validation.constraints.NotNull;
+import org.apache.syncope.core.persistence.api.entity.DynMembership;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
+
+@MappedSuperclass
+public abstract class AbstractDynMembership extends AbstractEntity<Long> implements DynMembership {
+
+    private static final long serialVersionUID = 921821654690948787L;
+
+    @NotNull
+    private String fiql;
+
+    @Override
+    public String getFIQLCond() {
+        return fiql;
+    }
+
+    @Override
+    public void setFIQLCond(final String fiql) {
+        this.fiql = fiql;
+    }
+
+    protected abstract List<JPAUser> internalGetUsers();
+
+    @Override
+    public boolean addUser(final User user) {
+        checkType(user, JPAUser.class);
+        return internalGetUsers().add((JPAUser) user);
+    }
+
+    @Override
+    public boolean removeUser(final User user) {
+        checkType(user, JPAUser.class);
+        return internalGetUsers().remove((JPAUser) user);
+    }
+
+    @Override
+    public List<? extends User> getUsers() {
+        return internalGetUsers();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractSubject.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractSubject.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractSubject.java
index b0a7ab4..166309f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractSubject.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractSubject.java
@@ -52,17 +52,18 @@ public abstract class AbstractSubject<P extends PlainAttr, D extends DerAttr, V
         this.realm = (JPARealm) realm;
     }
 
-    protected abstract Set<? extends ExternalResource> internalGetResources();
+    protected abstract Set<JPAExternalResource> internalGetResources();
 
     @Override
-    @SuppressWarnings("unchecked")
     public boolean addResource(final ExternalResource resource) {
-        return ((Set<ExternalResource>) internalGetResources()).add(resource);
+        checkType(resource, JPAExternalResource.class);
+        return internalGetResources().add((JPAExternalResource) resource);
     }
 
     @Override
     public boolean removeResource(final ExternalResource resource) {
-        return internalGetResources().remove(resource);
+        checkType(resource, JPAExternalResource.class);
+        return internalGetResources().remove((JPAExternalResource) resource);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AnnotatedEntityListener.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AnnotatedEntityListener.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AnnotatedEntityListener.java
index f814033..8a9547e 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AnnotatedEntityListener.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AnnotatedEntityListener.java
@@ -28,9 +28,6 @@ import org.slf4j.LoggerFactory;
 
 public class AnnotatedEntityListener {
 
-    /**
-     * Logger.
-     */
     private static final Logger LOG = LoggerFactory.getLogger(AnnotatedEntityListener.class);
 
     @PrePersist

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynGroupMembership.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynGroupMembership.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynGroupMembership.java
new file mode 100644
index 0000000..1f55348
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynGroupMembership.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import org.apache.syncope.core.persistence.api.entity.DynGroupMembership;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
+
+@Entity
+@Table(name = JPADynGroupMembership.TABLE)
+public class JPADynGroupMembership extends AbstractDynMembership implements DynGroupMembership {
+
+    private static final long serialVersionUID = -7336814163949640354L;
+
+    public static final String TABLE = "DynGroupMembership";
+
+    @Id
+    private Long id;
+
+    @OneToOne
+    private JPAGroup group;
+
+    @ManyToMany
+    @JoinTable(joinColumns =
+            @JoinColumn(name = "dynGroupMembership_id"),
+            inverseJoinColumns =
+            @JoinColumn(name = "user_id"))
+    private List<JPAUser> users = new ArrayList<>();
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    protected List<JPAUser> internalGetUsers() {
+        return users;
+    }
+
+    @Override
+    public Group getGroup() {
+        return group;
+    }
+
+    @Override
+    public void setGroup(final Group role) {
+        checkType(role, JPAGroup.class);
+        this.group = (JPAGroup) role;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynRoleMembership.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynRoleMembership.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynRoleMembership.java
new file mode 100644
index 0000000..4796abf
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADynRoleMembership.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import org.apache.syncope.core.persistence.api.entity.DynRoleMembership;
+import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
+
+@Entity
+@Table(name = JPADynRoleMembership.TABLE)
+public class JPADynRoleMembership extends AbstractDynMembership implements DynRoleMembership {
+
+    private static final long serialVersionUID = -7336814163949640354L;
+
+    public static final String TABLE = "DynRoleMembership";
+
+    @Id
+    private Long id;
+
+    @OneToOne
+    private JPARole role;
+
+    @ManyToMany
+    @JoinTable(joinColumns =
+            @JoinColumn(name = "dynRoleMembership_id"),
+            inverseJoinColumns =
+            @JoinColumn(name = "user_id"))
+    private List<JPAUser> users = new ArrayList<>();
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    protected List<JPAUser> internalGetUsers() {
+        return users;
+    }
+
+    @Override
+    public Role getRole() {
+        return role;
+    }
+
+    @Override
+    public void setRole(final Role role) {
+        checkType(role, JPARole.class);
+        this.role = (JPARole) role;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
index 3002dcc..048955b 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
@@ -21,6 +21,8 @@ package org.apache.syncope.core.persistence.jpa.entity;
 import org.apache.syncope.core.persistence.api.entity.AccountPolicy;
 import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.persistence.api.entity.ConnPoolConf;
+import org.apache.syncope.core.persistence.api.entity.DynGroupMembership;
+import org.apache.syncope.core.persistence.api.entity.DynRoleMembership;
 import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.ExternalResource;
@@ -265,6 +267,10 @@ public class JPAEntityFactory implements EntityFactory {
             result = (T) new JPASecurityQuestion();
         } else if (reference.equals(Logger.class)) {
             result = (T) new JPALogger();
+        } else if (reference.equals(DynRoleMembership.class)) {
+            result = (T) new JPADynRoleMembership();
+        } else if (reference.equals(DynGroupMembership.class)) {
+            result = (T) new JPADynGroupMembership();
         } else {
             throw new IllegalArgumentException("Could not find a JPA implementation of " + reference.getName());
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
index f88f430..0360f54 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
@@ -23,6 +23,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import javax.persistence.Cacheable;
+import javax.persistence.CascadeType;
 import javax.persistence.CollectionTable;
 import javax.persistence.Column;
 import javax.persistence.ElementCollection;
@@ -32,9 +33,11 @@ import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.JoinTable;
 import javax.persistence.ManyToMany;
+import javax.persistence.OneToOne;
 import javax.persistence.Table;
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
+import org.apache.syncope.core.persistence.api.entity.DynRoleMembership;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Role;
 
@@ -69,6 +72,10 @@ public class JPARole extends AbstractEntity<Long> implements Role {
     @Valid
     private List<JPARealm> realms = new ArrayList<>();
 
+    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "role")
+    @Valid
+    private JPADynRoleMembership dynMembership;
+
     @Override
     public Long getKey() {
         return id;
@@ -106,4 +113,14 @@ public class JPARole extends AbstractEntity<Long> implements Role {
         return realms;
     }
 
+    @Override
+    public DynRoleMembership getDynMembership() {
+        return dynMembership;
+    }
+
+    @Override
+    public void setDynMembership(final DynRoleMembership dynMembership) {
+        checkType(dynMembership, JPADynRoleMembership.class);
+        this.dynMembership = (JPADynRoleMembership) dynMembership;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
index 720b875..20e8808 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
@@ -33,6 +33,7 @@ import javax.persistence.JoinTable;
 import javax.persistence.ManyToMany;
 import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
 import javax.persistence.Table;
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
@@ -40,7 +41,7 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.Transformer;
 import org.apache.syncope.core.persistence.api.entity.AttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.DynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.Schema;
 import org.apache.syncope.core.persistence.api.entity.membership.MDerAttrTemplate;
 import org.apache.syncope.core.persistence.api.entity.membership.MPlainAttrTemplate;
@@ -55,6 +56,7 @@ import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.validation.entity.GroupCheck;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractSubject;
+import org.apache.syncope.core.persistence.jpa.entity.JPADynGroupMembership;
 import org.apache.syncope.core.persistence.jpa.entity.JPAExternalResource;
 import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMPlainAttrTemplate;
 import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMDerAttrTemplate;
@@ -131,6 +133,10 @@ public class JPAGroup extends AbstractSubject<GPlainAttr, GDerAttr, GVirAttr> im
     @Valid
     private Set<JPAExternalResource> resources;
 
+    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "group")
+    @Valid
+    private JPADynGroupMembership dynMembership;
+
     public JPAGroup() {
         super();
 
@@ -154,7 +160,7 @@ public class JPAGroup extends AbstractSubject<GPlainAttr, GDerAttr, GVirAttr> im
     }
 
     @Override
-    protected Set<? extends ExternalResource> internalGetResources() {
+    protected Set<JPAExternalResource> internalGetResources() {
         return resources;
     }
 
@@ -286,4 +292,16 @@ public class JPAGroup extends AbstractSubject<GPlainAttr, GDerAttr, GVirAttr> im
     public List<? extends GVirAttr> getVirAttrs() {
         return virAttrs;
     }
+
+    @Override
+    public DynGroupMembership getDynMembership() {
+        return dynMembership;
+    }
+
+    @Override
+    public void setDynMembership(final DynGroupMembership dynMembership) {
+        checkType(dynMembership, JPADynGroupMembership.class);
+        this.dynMembership = (JPADynGroupMembership) dynMembership;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
index 3170c14..029c96b 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.persistence.jpa.entity.user;
 
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collection;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
@@ -53,9 +54,7 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.Transformer;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
-import org.apache.syncope.core.persistence.api.entity.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.membership.Membership;
-import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
 import org.apache.syncope.core.persistence.api.entity.user.UDerAttr;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
@@ -71,9 +70,6 @@ import org.apache.syncope.core.misc.security.SecureRandomUtils;
 import org.apache.syncope.core.persistence.api.entity.Role;
 import org.apache.syncope.core.persistence.jpa.entity.JPARole;
 
-/**
- * JPA user bean.
- */
 @Entity
 @Table(name = JPAUser.TABLE)
 @Cacheable
@@ -206,7 +202,7 @@ public class JPAUser extends AbstractSubject<UPlainAttr, UDerAttr, UVirAttr> imp
     }
 
     @Override
-    protected Set<? extends ExternalResource> internalGetResources() {
+    protected Set<JPAExternalResource> internalGetResources() {
         return resources;
     }
 
@@ -256,44 +252,17 @@ public class JPAUser extends AbstractSubject<UPlainAttr, UDerAttr, UVirAttr> imp
     }
 
     @Override
-    public List<Group> getGroups() {
-        return CollectionUtils.collect(memberships, new Transformer<Membership, Group>() {
-
-            @Override
-            public Group transform(final Membership input) {
-                return input.getGroup();
-            }
-        }, new ArrayList<Group>());
-    }
-
-    @Override
-    public Set<Long> getGroupKeys() {
-        return CollectionUtils.collect(getGroups(), new Transformer<Group, Long>() {
+    public Collection<Long> getStaticGroupKeys() {
+        return CollectionUtils.collect(memberships, new Transformer<Membership, Long>() {
 
             @Override
-            public Long transform(final Group input) {
-                return input.getKey();
+            public Long transform(final Membership membership) {
+                return membership.getGroup().getKey();
             }
         }, new HashSet<Long>());
     }
 
     @Override
-    public Set<ExternalResource> getResources() {
-        Set<ExternalResource> result = new HashSet<>();
-        result.addAll(super.getResources());
-        for (Group group : getGroups()) {
-            result.addAll(group.getResources());
-        }
-
-        return result;
-    }
-
-    @Override
-    public Set<? extends ExternalResource> getOwnResources() {
-        return super.getResources();
-    }
-
-    @Override
     public String getPassword() {
         return password;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/UserValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/UserValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/UserValidator.java
index fac60cb..19fc7cf 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/UserValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/UserValidator.java
@@ -25,7 +25,6 @@ import javax.validation.ConstraintValidatorContext;
 import org.apache.syncope.common.lib.types.AccountPolicySpec;
 import org.apache.syncope.common.lib.types.EntityViolationType;
 import org.apache.syncope.common.lib.types.PasswordPolicySpec;
-import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
 import org.apache.syncope.core.persistence.api.entity.AccountPolicy;
 import org.apache.syncope.core.persistence.api.entity.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.PasswordPolicy;
@@ -36,6 +35,7 @@ import org.apache.syncope.core.misc.policy.AccountPolicyException;
 import org.apache.syncope.core.misc.policy.PasswordPolicyEnforcer;
 import org.apache.syncope.core.misc.policy.PolicyEvaluator;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -48,7 +48,7 @@ public class UserValidator extends AbstractValidator<UserCheck, User> {
     private String anonymousUser;
 
     @Autowired
-    private PolicyDAO policyDAO;
+    private UserDAO userDAO;
 
     @Autowired
     private RealmDAO realmDAO;
@@ -155,7 +155,7 @@ public class UserValidator extends AbstractValidator<UserCheck, User> {
         PasswordPolicy policy;
 
         // add resource policies
-        for (ExternalResource resource : user.getResources()) {
+        for (ExternalResource resource : userDAO.findAllResources(user)) {
             policy = resource.getPasswordPolicy();
             if (policy != null) {
                 policies.add(policy);
@@ -179,7 +179,7 @@ public class UserValidator extends AbstractValidator<UserCheck, User> {
         AccountPolicy policy;
 
         // add resource policies
-        for (ExternalResource resource : user.getResources()) {
+        for (ExternalResource resource : userDAO.findAllResources(user)) {
             policy = resource.getAccountPolicy();
             if (policy != null) {
                 policies.add(policy);

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
index 3a61895..8c58d33 100644
--- a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
+++ b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
@@ -57,6 +57,15 @@ under the License.
     </attributes>
   </entity>
 
+  <entity class="org.apache.syncope.core.persistence.jpa.entity.JPADynRoleMembership">
+    <attributes>
+      <id name="id">
+        <generated-value generator="SEQ_DynRoleMembership" strategy="TABLE"/>
+        <table-generator name="SEQ_DynRoleMembership" pk-column-value="SEQ_DynRoleMembership" initial-value="100"/>
+      </id>
+    </attributes>
+  </entity>
+
   <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUser">
     <attributes>
       <id name="id">
@@ -75,6 +84,15 @@ under the License.
     </attributes>
   </entity>
 
+  <entity class="org.apache.syncope.core.persistence.jpa.entity.JPADynGroupMembership">
+    <attributes>
+      <id name="id">
+        <generated-value generator="SEQ_DynGroupMembership" strategy="TABLE"/>
+        <table-generator name="SEQ_DynGroupMembership" pk-column-value="SEQ_DynGroupMembership" initial-value="100"/>
+      </id>
+    </attributes>
+  </entity>
+  
   <entity class="org.apache.syncope.core.persistence.jpa.entity.membership.JPAMembership">
     <attributes>
       <id name="id">

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
index 97af974..bd7f664 100644
--- a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
+++ b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
@@ -57,6 +57,15 @@ under the License.
     </attributes>
   </entity>
   
+  <entity class="org.apache.syncope.core.persistence.jpa.entity.JPADynRoleMembership">
+    <attributes>
+      <id name="id">
+        <generated-value generator="SEQ_DynRoleMembership" strategy="TABLE"/>
+        <table-generator name="SEQ_DynRoleMembership" pk-column-value="SEQ_DynRoleMembership" initial-value="100"/>
+      </id>
+    </attributes>
+  </entity>
+  
   <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUser">
     <attributes>
       <id name="id">
@@ -75,6 +84,15 @@ under the License.
     </attributes>
   </entity>
 
+  <entity class="org.apache.syncope.core.persistence.jpa.entity.JPADynGroupMembership">
+    <attributes>
+      <id name="id">
+        <generated-value generator="SEQ_DynGroupMembership" strategy="TABLE"/>
+        <table-generator name="SEQ_DynGroupMembership" pk-column-value="SEQ_DynGroupMembership" initial-value="100"/>
+      </id>
+    </attributes>
+  </entity>
+  
   <entity class="org.apache.syncope.core.persistence.jpa.entity.membership.JPAMembership">
     <attributes>
       <id name="id">

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml b/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
index 5921b94..5562674 100644
--- a/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
+++ b/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
@@ -56,7 +56,16 @@ under the License.
       </id>
     </attributes>
   </entity>
-
+  
+  <entity class="org.apache.syncope.core.persistence.jpa.entity.JPADynRoleMembership">
+    <attributes>
+      <id name="id">
+        <generated-value generator="SEQ_DynRoleMembership" strategy="TABLE"/>
+        <table-generator name="SEQ_DynRoleMembership" pk-column-value="SEQ_DynRoleMembership" initial-value="100"/>
+      </id>
+    </attributes>
+  </entity>
+  
   <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUser">
     <attributes>
       <id name="id">
@@ -74,7 +83,16 @@ under the License.
       </id>
     </attributes>
   </entity>
-
+  
+  <entity class="org.apache.syncope.core.persistence.jpa.entity.JPADynGroupMembership">
+    <attributes>
+      <id name="id">
+        <generated-value generator="SEQ_DynGroupMembership" strategy="TABLE"/>
+        <table-generator name="SEQ_DynGroupMembership" pk-column-value="SEQ_DynGroupMembership" initial-value="100"/>
+      </id>
+    </attributes>
+  </entity>
+  
   <entity class="org.apache.syncope.core.persistence.jpa.entity.membership.JPAMembership">
     <attributes>
       <id name="id">

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/main/resources/views.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/views.xml b/core/persistence-jpa/src/main/resources/views.xml
index 8cd392d..f7bce20 100644
--- a/core/persistence-jpa/src/main/resources/views.xml
+++ b/core/persistence-jpa/src/main/resources/views.xml
@@ -68,9 +68,29 @@ under the License.
   <entry key="user_search_membership">
     CREATE VIEW user_search_membership AS
 
-    SELECT m.user_id AS subject_id, r.id AS group_id, r.name AS group_name
-    FROM Membership m, SyncopeGroup r
-    WHERE m.group_id = r.id
+    SELECT m.user_id AS subject_id, g.id AS group_id, g.name AS group_name
+    FROM Membership m, SyncopeGroup g
+    WHERE m.group_id = g.id
+  </entry>
+  <entry key="user_search_dyngroupmembership">
+    CREATE VIEW user_search_dyngroupmembership AS
+
+    SELECT ds.user_id AS subject_id, d.group_id AS group_id
+    FROM DynGroupMembership d, DynGroupMembership_SyncopeUser ds
+    WHERE d.id = ds.dynGroupMembership_id
+  </entry>
+  <entry key="user_search_role">
+    CREATE VIEW user_search_role AS
+
+    SELECT ss.user_id AS subject_id, ss.role_id AS role_id
+    FROM SyncopeUser_SyncopeRole ss
+  </entry>
+  <entry key="user_search_dynrolemembership">
+    CREATE VIEW user_search_dynrolemembership AS
+
+    SELECT ds.user_id AS subject_id, d.role_id AS role_id
+    FROM DynRoleMembership d, DynRoleMembership_SyncopeUser ds
+    WHERE d.id = ds.dynRoleMembership_id
   </entry>
   <entry key="user_search_resource">
     CREATE VIEW user_search_resource AS

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/AttrTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/AttrTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/AttrTest.java
index 289f898..4ad4dd0 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/AttrTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/AttrTest.java
@@ -56,7 +56,7 @@ public class AttrTest extends AbstractTest {
     private PlainAttrDAO plainAttrDAO;
 
     @Autowired
-    private PlainSchemaDAO userSchemaDAO;
+    private PlainSchemaDAO plainSchemaDAO;
 
     @Test
     public void findById() {
@@ -78,7 +78,7 @@ public class AttrTest extends AbstractTest {
     public void save() throws ClassNotFoundException {
         User user = userDAO.find(1L);
 
-        UPlainSchema emailSchema = userSchemaDAO.find("email", UPlainSchema.class);
+        UPlainSchema emailSchema = plainSchemaDAO.find("email", UPlainSchema.class);
         assertNotNull(emailSchema);
 
         UPlainAttr attribute = entityFactory.newEntity(UPlainAttr.class);
@@ -106,7 +106,7 @@ public class AttrTest extends AbstractTest {
     public void saveWithEnum() throws ClassNotFoundException {
         User user = userDAO.find(1L);
 
-        UPlainSchema gender = userSchemaDAO.find("gender", UPlainSchema.class);
+        UPlainSchema gender = plainSchemaDAO.find("gender", UPlainSchema.class);
         assertNotNull(gender);
         assertNotNull(gender.getType());
         assertNotNull(gender.getEnumerationValues());
@@ -140,10 +140,10 @@ public class AttrTest extends AbstractTest {
     public void validateAndSave() {
         User user = userDAO.find(1L);
 
-        final UPlainSchema emailSchema = userSchemaDAO.find("email", UPlainSchema.class);
+        final UPlainSchema emailSchema = plainSchemaDAO.find("email", UPlainSchema.class);
         assertNotNull(emailSchema);
 
-        final UPlainSchema fullnameSchema = userSchemaDAO.find("fullname", UPlainSchema.class);
+        final UPlainSchema fullnameSchema = plainSchemaDAO.find("fullname", UPlainSchema.class);
         assertNotNull(fullnameSchema);
 
         UPlainAttr attribute = entityFactory.newEntity(UPlainAttr.class);
@@ -176,7 +176,7 @@ public class AttrTest extends AbstractTest {
     public void saveWithEncrypted() throws Exception {
         User user = userDAO.find(1L);
 
-        final UPlainSchema obscureSchema = userSchemaDAO.find("obscure", UPlainSchema.class);
+        final UPlainSchema obscureSchema = plainSchemaDAO.find("obscure", UPlainSchema.class);
         assertNotNull(obscureSchema);
         assertNotNull(obscureSchema.getSecretKey());
         assertNotNull(obscureSchema.getCipherAlgorithm());
@@ -200,7 +200,7 @@ public class AttrTest extends AbstractTest {
     public void saveWithBinary() throws UnsupportedEncodingException {
         User user = userDAO.find(1L);
 
-        final UPlainSchema photoSchema = userSchemaDAO.find("photo", UPlainSchema.class);
+        final UPlainSchema photoSchema = plainSchemaDAO.find("photo", UPlainSchema.class);
         assertNotNull(photoSchema);
         assertNotNull(photoSchema.getMimeType());
 
@@ -229,7 +229,7 @@ public class AttrTest extends AbstractTest {
 
         plainAttrDAO.delete(attribute.getKey(), UPlainAttr.class);
 
-        UPlainSchema schema = userSchemaDAO.find(attrSchemaName, UPlainSchema.class);
+        UPlainSchema schema = plainSchemaDAO.find(attrSchemaName, UPlainSchema.class);
         assertNotNull("user attribute schema deleted when deleting values", schema);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/RoleTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/RoleTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/RoleTest.java
index a7bf883..7a20e89 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/RoleTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/RoleTest.java
@@ -28,7 +28,6 @@ import java.util.List;
 import org.apache.syncope.common.lib.types.Entitlement;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.dao.RoleDAO;
-import org.apache.syncope.core.persistence.api.dao.SubjectSearchDAO;
 import org.apache.syncope.core.persistence.api.entity.Role;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
 import org.junit.Test;
@@ -42,9 +41,6 @@ public class RoleTest extends AbstractTest {
     private RoleDAO roleDAO;
 
     @Autowired
-    private SubjectSearchDAO searchDAO;
-
-    @Autowired
     private RealmDAO realmDAO;
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/SubjectSearchTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/SubjectSearchTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/SubjectSearchTest.java
index d0a6d0c..22e7494 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/SubjectSearchTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/entity/SubjectSearchTest.java
@@ -36,9 +36,10 @@ import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.SubjectSearchDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
-import org.apache.syncope.core.persistence.api.dao.search.MembershipCond;
+import org.apache.syncope.core.persistence.api.dao.search.GroupCond;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.dao.search.ResourceCond;
+import org.apache.syncope.core.persistence.api.dao.search.RoleCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.dao.search.SubjectCond;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
@@ -65,14 +66,16 @@ public class SubjectSearchTest extends AbstractTest {
         User user = userDAO.find(1L);
         assertNotNull(user);
 
-        MembershipCond membershipCond = new MembershipCond();
-        membershipCond.setGroupId(5L);
+        GroupCond groupCond = new GroupCond();
+        groupCond.setGroupKey(5L);
+        assertFalse(searchDAO.matches(user, SearchCond.getLeafCond(groupCond), SubjectType.USER));
 
-        assertFalse(searchDAO.matches(user, SearchCond.getLeafCond(membershipCond), SubjectType.USER));
+        groupCond.setGroupKey(1L);
+        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(groupCond), SubjectType.USER));
 
-        membershipCond.setGroupId(1L);
-
-        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(membershipCond), SubjectType.USER));
+        RoleCond roleCond = new RoleCond();
+        roleCond.setRoleKey(3L);
+        assertTrue(searchDAO.matches(user, SearchCond.getLeafCond(roleCond), SubjectType.USER));
     }
 
     @Test
@@ -93,15 +96,15 @@ public class SubjectSearchTest extends AbstractTest {
         fullnameLeafCond.setSchema("fullname");
         fullnameLeafCond.setExpression("%o%");
 
-        MembershipCond membershipCond = new MembershipCond();
-        membershipCond.setGroupId(1L);
+        GroupCond groupCond = new GroupCond();
+        groupCond.setGroupKey(1L);
 
         AttributeCond loginDateCond = new AttributeCond(AttributeCond.Type.EQ);
         loginDateCond.setSchema("loginDate");
         loginDateCond.setExpression("2009-05-26");
 
         SearchCond subCond = SearchCond.getAndCond(SearchCond.getLeafCond(fullnameLeafCond), SearchCond.getLeafCond(
-                membershipCond));
+                groupCond));
 
         assertTrue(subCond.isValid());
 
@@ -157,15 +160,15 @@ public class SubjectSearchTest extends AbstractTest {
         fullnameLeafCond.setSchema("fullname");
         fullnameLeafCond.setExpression("%o%");
 
-        MembershipCond membershipCond = new MembershipCond();
-        membershipCond.setGroupId(1L);
+        GroupCond groupCond = new GroupCond();
+        groupCond.setGroupKey(1L);
 
         AttributeCond loginDateCond = new AttributeCond(AttributeCond.Type.EQ);
         loginDateCond.setSchema("loginDate");
         loginDateCond.setExpression("2009-05-26");
 
         SearchCond subCond = SearchCond.getAndCond(
-                SearchCond.getLeafCond(fullnameLeafCond), SearchCond.getLeafCond(membershipCond));
+                SearchCond.getLeafCond(fullnameLeafCond), SearchCond.getLeafCond(groupCond));
 
         assertTrue(subCond.isValid());
 
@@ -187,25 +190,36 @@ public class SubjectSearchTest extends AbstractTest {
     }
 
     @Test
-    public void searchByMembership() {
-        MembershipCond membershipCond = new MembershipCond();
-        membershipCond.setGroupId(1L);
+    public void searchByGroup() {
+        GroupCond groupCond = new GroupCond();
+        groupCond.setGroupKey(1L);
 
         List<User> users = searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS,
-                SearchCond.getLeafCond(membershipCond), SubjectType.USER);
+                SearchCond.getLeafCond(groupCond), SubjectType.USER);
         assertNotNull(users);
         assertEquals(2, users.size());
 
-        membershipCond = new MembershipCond();
-        membershipCond.setGroupId(5L);
+        groupCond = new GroupCond();
+        groupCond.setGroupKey(5L);
 
         users = searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS,
-                SearchCond.getNotLeafCond(membershipCond), SubjectType.USER);
+                SearchCond.getNotLeafCond(groupCond), SubjectType.USER);
         assertNotNull(users);
         assertEquals(5, users.size());
     }
 
     @Test
+    public void searchByRole() {
+        RoleCond roleCond = new RoleCond();
+        roleCond.setRoleKey(3L);
+
+        List<User> users = searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS,
+                SearchCond.getLeafCond(roleCond), SubjectType.USER);
+        assertNotNull(users);
+        assertEquals(1, users.size());
+    }
+
+    @Test
     public void searchByIsNull() {
         AttributeCond coolLeafCond = new AttributeCond(AttributeCond.Type.ISNULL);
         coolLeafCond.setSchema("cool");
@@ -233,11 +247,9 @@ public class SubjectSearchTest extends AbstractTest {
         ws1.setResourceName("ws-target-resource-list-mappings-2");
 
         SearchCond searchCondition = SearchCond.getAndCond(SearchCond.getNotLeafCond(ws2), SearchCond.getLeafCond(ws1));
-
         assertTrue(searchCondition.isValid());
 
         List<User> users = searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS, searchCondition, SubjectType.USER);
-
         assertNotNull(users);
         assertEquals(1, users.size());
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/GroupTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/GroupTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/GroupTest.java
index 251296a..d6d99ce 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/GroupTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/GroupTest.java
@@ -24,19 +24,32 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
+import org.apache.syncope.common.lib.types.AttributableType;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
 import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.DynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.group.GPlainSchema;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainSchema;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.apache.syncope.core.persistence.jpa.entity.JPADynGroupMembership;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
@@ -45,12 +58,18 @@ import org.springframework.transaction.annotation.Transactional;
 public class GroupTest extends AbstractTest {
 
     @Autowired
+    private EntityManager entityManager;
+
+    @Autowired
     private UserDAO userDAO;
 
     @Autowired
     private GroupDAO groupDAO;
 
     @Autowired
+    private RealmDAO realmDAO;
+
+    @Autowired
     private PlainSchemaDAO plainSchemaDAO;
 
     @Autowired
@@ -68,6 +87,7 @@ public class GroupTest extends AbstractTest {
         assertNotNull("did not find expected user", user);
 
         Group group = entityFactory.newEntity(Group.class);
+        group.setRealm(realmDAO.getRoot());
         group.setName("error");
         group.setUserOwner(user);
         group.setGroupOwner(root);
@@ -98,9 +118,103 @@ public class GroupTest extends AbstractTest {
         groupDAO.flush();
 
         assertNull(groupDAO.find(2L));
-        assertEquals(userDAO.find(2L).getGroups().size(), 2);
+        assertEquals(userDAO.findAllGroups(userDAO.find(2L)).size(), 2);
         assertNull(plainAttrDAO.find(700L, GPlainAttr.class));
         assertNull(plainAttrValueDAO.find(41L, GPlainAttrValue.class));
         assertNotNull(plainSchemaDAO.find("icon", GPlainSchema.class));
     }
+
+    /**
+     * Static copy of {@link org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO} method with same signature:
+     * required for avoiding creating of a new transaction - good for general use case but bad for the way how
+     * this test class is architected.
+     */
+    private Collection<Group> findDynGroupMemberships(final User user) {
+        TypedQuery<Group> query = entityManager.createQuery(
+                "SELECT e.group FROM " + JPADynGroupMembership.class.getSimpleName()
+                + " e WHERE :user MEMBER OF e.users", Group.class);
+        query.setParameter("user", user);
+
+        return query.getResultList();
+    }
+
+    @Test
+    public void dynMembership() {
+        // 0. create user matching the condition below
+        User user = entityFactory.newEntity(User.class);
+        user.setUsername("username");
+        user.setRealm(realmDAO.find("/even/two"));
+
+        UPlainAttr attribute = entityFactory.newEntity(UPlainAttr.class);
+        attribute.setSchema(plainSchemaDAO.find("cool", UPlainSchema.class));
+        attribute.setOwner(user);
+        attribute.addValue("true", attrUtilsFactory.getInstance(AttributableType.USER));
+        user.addPlainAttr(attribute);
+
+        user = userDAO.save(user);
+        Long newUserKey = user.getKey();
+        assertNotNull(newUserKey);
+
+        // 1. create group with dynamic membership
+        Group group = entityFactory.newEntity(Group.class);
+        group.setRealm(realmDAO.getRoot());
+        group.setName("new");
+
+        DynGroupMembership dynMembership = entityFactory.newEntity(DynGroupMembership.class);
+        dynMembership.setFIQLCond("cool==true");
+        dynMembership.setGroup(group);
+
+        group.setDynMembership(dynMembership);
+
+        Group actual = groupDAO.save(group);
+        assertNotNull(actual);
+
+        groupDAO.flush();
+
+        // 2. verify that dynamic membership is there
+        actual = groupDAO.find(actual.getKey());
+        assertNotNull(actual);
+        assertNotNull(actual.getDynMembership());
+        assertNotNull(actual.getDynMembership().getKey());
+        assertEquals(actual, actual.getDynMembership().getGroup());
+
+        // 3. verify that expected users have the created group dynamically assigned
+        assertEquals(2, actual.getDynMembership().getUsers().size());
+        assertEquals(new HashSet<>(Arrays.asList(4L, newUserKey)),
+                CollectionUtils.collect(actual.getDynMembership().getUsers(), new Transformer<User, Long>() {
+
+                    @Override
+                    public Long transform(final User input) {
+                        return input.getKey();
+                    }
+                }, new HashSet<Long>()));
+
+        user = userDAO.find(4L);
+        assertNotNull(user);
+        Collection<Group> dynGroupMemberships = findDynGroupMemberships(user);
+        assertEquals(1, dynGroupMemberships.size());
+        assertTrue(dynGroupMemberships.contains(actual.getDynMembership().getGroup()));
+
+        // 4. delete the new user and verify that dynamic membership was updated
+        userDAO.delete(newUserKey);
+
+        userDAO.flush();
+
+        actual = groupDAO.find(actual.getKey());
+        assertEquals(1, actual.getDynMembership().getUsers().size());
+        assertEquals(4L, actual.getDynMembership().getUsers().get(0).getKey(), 0);
+
+        // 5. delete group and verify that dynamic membership was also removed
+        Long dynMembershipKey = actual.getDynMembership().getKey();
+
+        groupDAO.delete(actual);
+
+        groupDAO.flush();
+
+        assertNull(entityManager.find(JPADynGroupMembership.class, dynMembershipKey));
+
+        dynGroupMemberships = findDynGroupMemberships(user);
+        assertTrue(dynGroupMemberships.isEmpty());
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/ResourceTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/ResourceTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/ResourceTest.java
index d9e1864..868f104 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/ResourceTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/ResourceTest.java
@@ -225,7 +225,7 @@ public class ResourceTest extends AbstractTest {
         for (Long id : userIds) {
             User actualUser = userDAO.find(id);
             assertNotNull(actualUser);
-            for (ExternalResource res : actualUser.getResources()) {
+            for (ExternalResource res : userDAO.findAllResources(actualUser)) {
                 assertFalse(res.getKey().equalsIgnoreCase(resource.getKey()));
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/RoleTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/RoleTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/RoleTest.java
new file mode 100644
index 0000000..52e3451
--- /dev/null
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/RoleTest.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.relationship;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.Entitlement;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.RoleDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.DynRoleMembership;
+import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainSchema;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.apache.syncope.core.persistence.jpa.entity.JPADynRoleMembership;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+public class RoleTest extends AbstractTest {
+
+    @Autowired
+    private EntityManager entityManager;
+
+    @Autowired
+    private RoleDAO roleDAO;
+
+    @Autowired
+    private RealmDAO realmDAO;
+
+    @Autowired
+    private PlainSchemaDAO plainSchemaDAO;
+
+    @Autowired
+    private UserDAO userDAO;
+
+    /**
+     * Static copy of {@link org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO} method with same signature:
+     * required for avoiding creating new transaction - good for general use case but bad for the way how
+     * this test class is architected.
+     */
+    private Collection<Role> findDynRoleMemberships(final User user) {
+        TypedQuery<Role> query = entityManager.createQuery(
+                "SELECT e.role FROM " + JPADynRoleMembership.class.getSimpleName()
+                + " e WHERE :user MEMBER OF e.users", Role.class);
+        query.setParameter("user", user);
+
+        return query.getResultList();
+    }
+
+    @Test
+    public void dynMembership() {
+        // 0. create user matching the condition below
+        User user = entityFactory.newEntity(User.class);
+        user.setUsername("username");
+        user.setRealm(realmDAO.find("/even/two"));
+
+        UPlainAttr attribute = entityFactory.newEntity(UPlainAttr.class);
+        attribute.setSchema(plainSchemaDAO.find("cool", UPlainSchema.class));
+        attribute.setOwner(user);
+        attribute.addValue("true", attrUtilsFactory.getInstance(AttributableType.USER));
+        user.addPlainAttr(attribute);
+
+        user = userDAO.save(user);
+        Long newUserKey = user.getKey();
+        assertNotNull(newUserKey);
+
+        // 1. create role with dynamic membership
+        Role role = entityFactory.newEntity(Role.class);
+        role.setName("new");
+        role.addRealm(realmDAO.getRoot());
+        role.addRealm(realmDAO.find("/even/two"));
+        role.getEntitlements().add(Entitlement.LOG_LIST);
+        role.getEntitlements().add(Entitlement.LOG_SET_LEVEL);
+
+        DynRoleMembership dynMembership = entityFactory.newEntity(DynRoleMembership.class);
+        dynMembership.setFIQLCond("cool==true");
+        dynMembership.setRole(role);
+
+        role.setDynMembership(dynMembership);
+
+        Role actual = roleDAO.save(role);
+        assertNotNull(actual);
+
+        roleDAO.flush();
+
+        // 2. verify that dynamic membership is there
+        actual = roleDAO.find(actual.getKey());
+        assertNotNull(actual);
+        assertNotNull(actual.getDynMembership());
+        assertNotNull(actual.getDynMembership().getKey());
+        assertEquals(actual, actual.getDynMembership().getRole());
+
+        // 3. verify that expected users have the created role dynamically assigned
+        assertEquals(2, actual.getDynMembership().getUsers().size());
+        assertEquals(new HashSet<>(Arrays.asList(4L, newUserKey)),
+                CollectionUtils.collect(actual.getDynMembership().getUsers(), new Transformer<User, Long>() {
+
+                    @Override
+                    public Long transform(final User input) {
+                        return input.getKey();
+                    }
+                }, new HashSet<Long>()));
+
+        user = userDAO.find(4L);
+        assertNotNull(user);
+        Collection<Role> dynRoleMemberships = findDynRoleMemberships(user);
+        assertEquals(1, dynRoleMemberships.size());
+        assertTrue(dynRoleMemberships.contains(actual.getDynMembership().getRole()));
+
+        // 4. delete the new user and verify that dynamic membership was updated
+        userDAO.delete(newUserKey);
+
+        userDAO.flush();
+
+        actual = roleDAO.find(actual.getKey());
+        assertEquals(1, actual.getDynMembership().getUsers().size());
+        assertEquals(4L, actual.getDynMembership().getUsers().get(0).getKey(), 0);
+
+        // 5. delete role and verify that dynamic membership was also removed
+        Long dynMembershipKey = actual.getDynMembership().getKey();
+
+        roleDAO.delete(actual);
+
+        roleDAO.flush();
+
+        assertNull(entityManager.find(JPADynRoleMembership.class, dynMembershipKey));
+
+        dynRoleMemberships = findDynRoleMemberships(user);
+        assertTrue(dynRoleMemberships.isEmpty());
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/SubjectSearchTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/SubjectSearchTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/SubjectSearchTest.java
index d3eb0be..025d7cc 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/SubjectSearchTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/relationship/SubjectSearchTest.java
@@ -26,11 +26,17 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.types.Entitlement;
 import org.apache.syncope.common.lib.types.SubjectType;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 import org.apache.syncope.core.persistence.api.dao.SubjectSearchDAO;
 import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
+import org.apache.syncope.core.persistence.api.dao.search.RoleCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.entity.DynRoleMembership;
+import org.apache.syncope.core.persistence.api.entity.Role;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
@@ -47,6 +53,12 @@ public class SubjectSearchTest extends AbstractTest {
     @Autowired
     private SubjectSearchDAO searchDAO;
 
+    @Autowired
+    private RealmDAO realmDAO;
+
+    @Autowired
+    private RoleDAO roleDAO;
+
     @Test
     public void issueSYNCOPE95() {
         Set<Group> groups = new HashSet<>(groupDAO.findAll(SyncopeConstants.FULL_ADMIN_REALMS, 1, 100));
@@ -55,18 +67,49 @@ public class SubjectSearchTest extends AbstractTest {
         }
         groupDAO.flush();
 
-        final AttributeCond coolLeafCond = new AttributeCond(AttributeCond.Type.EQ);
+        AttributeCond coolLeafCond = new AttributeCond(AttributeCond.Type.EQ);
         coolLeafCond.setSchema("cool");
         coolLeafCond.setExpression("true");
 
-        final SearchCond cond = SearchCond.getLeafCond(coolLeafCond);
+        SearchCond cond = SearchCond.getLeafCond(coolLeafCond);
         assertTrue(cond.isValid());
 
-        final List<User> users =
-                searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS, cond, SubjectType.USER);
+        List<User> users = searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS, cond, SubjectType.USER);
         assertNotNull(users);
         assertEquals(1, users.size());
 
-        assertEquals(Long.valueOf(4L), users.get(0).getKey());
+        assertEquals(4L, users.get(0).getKey(), 0);
+    }
+
+    @Test
+    public void searchByDynMembership() {
+        // 1. create role with dynamic membership
+        Role role = entityFactory.newEntity(Role.class);
+        role.setName("new");
+        role.addRealm(realmDAO.getRoot());
+        role.addRealm(realmDAO.find("/even/two"));
+        role.getEntitlements().add(Entitlement.LOG_LIST);
+        role.getEntitlements().add(Entitlement.LOG_SET_LEVEL);
+
+        DynRoleMembership dynMembership = entityFactory.newEntity(DynRoleMembership.class);
+        dynMembership.setFIQLCond("cool==true");
+        dynMembership.setRole(role);
+
+        role.setDynMembership(dynMembership);
+
+        role = roleDAO.save(role);
+        assertNotNull(role);
+
+        roleDAO.flush();
+
+        // 2. search user by this dynamic role
+        RoleCond roleCond = new RoleCond();
+        roleCond.setRoleKey(role.getKey());
+
+        List<User> users = searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS,
+                SearchCond.getLeafCond(roleCond), SubjectType.USER);
+        assertNotNull(users);
+        assertEquals(1, users.size());
+        assertEquals(4L, users.get(0).getKey(), 0);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
index ce28830..c1eff8c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
@@ -230,7 +230,7 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
 
     protected List<PropagationStatus> propagateStatus(final User user, final StatusMod statusMod) {
         Collection<String> noPropResourceNames =
-                CollectionUtils.removeAll(user.getResourceNames(), statusMod.getResourceNames());
+                CollectionUtils.removeAll(userDAO.findAllResourceNames(user), statusMod.getResourceNames());
 
         List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
                 user, statusMod.getType() != StatusMod.ModType.SUSPEND, noPropResourceNames);
@@ -269,11 +269,11 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
     public List<PropagationStatus> deprovision(final Long userKey, final Collection<String> resources) {
         final User user = userDAO.authFetch(userKey);
 
-        Collection<String> noPropResourceNames = CollectionUtils.removeAll(user.getResourceNames(), resources);
-
-        final List<PropagationTask> tasks =
-                propagationManager.getUserDeleteTasks(userKey, new HashSet<>(resources), noPropResourceNames);
-        final PropagationReporter propagationReporter =
+        List<PropagationTask> tasks = propagationManager.getUserDeleteTasks(
+                userKey,
+                new HashSet<>(resources),
+                CollectionUtils.removeAll(userDAO.findAllResourceNames(user), resources));
+        PropagationReporter propagationReporter =
                 ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
         try {
             taskExecutor.execute(tasks, propagationReporter);

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java
index 6354041..14c00c7 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java
@@ -51,6 +51,7 @@ import org.apache.syncope.core.persistence.api.entity.group.GVirAttrTemplate;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
 import org.apache.syncope.core.persistence.api.entity.user.UVirSchema;
+import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -132,11 +133,13 @@ public class VirAttrHandler {
 
         PropagationByResource propByRes = new PropagationByResource();
 
-        final Set<ExternalResource> externalResources = new HashSet<>();
-        if (attributable instanceof Subject) {
-            externalResources.addAll(((Subject<?, ?, ?>) attributable).getResources());
+        Set<ExternalResource> externalResources = new HashSet<>();
+        if (attributable instanceof User) {
+            externalResources.addAll(userDAO.findAllResources((User) attributable));
+        } else if (attributable instanceof Group) {
+            externalResources.addAll(((Group) attributable).getResources());
         } else if (attributable instanceof Membership) {
-            externalResources.addAll(((Membership) attributable).getUser().getResources());
+            externalResources.addAll(userDAO.findAllResources(((Membership) attributable).getUser()));
             externalResources.addAll(((Membership) attributable).getGroup().getResources());
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java
index 6264379..b94ffa2 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java
@@ -91,6 +91,7 @@ import org.apache.syncope.core.misc.jexl.JexlUtils;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 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.user.User;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -240,7 +241,7 @@ abstract class AbstractAttributableDataBinder {
         Collection<MappingItem> mappings = MappingUtils.getMatchingMappingItems(
                 attrUtils.getMappingItems(resource, MappingPurpose.PROPAGATION), intAttrName, intMappingType);
         for (Iterator<MappingItem> itor = mappings.iterator(); itor.hasNext() && !result;) {
-            final MappingItem mapping = itor.next();
+            MappingItem mapping = itor.next();
             result |= JexlUtils.evaluateMandatoryCondition(mapping.getMandatoryCondition(), attributable);
         }
 
@@ -252,15 +253,17 @@ abstract class AbstractAttributableDataBinder {
 
         boolean result = false;
 
-        if (attributable instanceof Subject) {
-            for (Iterator<? extends ExternalResource> itor =
-                    ((Subject<?, ?, ?>) attributable).getResources().iterator(); itor.hasNext() && !result;) {
-
-                final ExternalResource resource = itor.next();
-                if (resource.isEnforceMandatoryCondition()) {
-                    result |= evaluateMandatoryCondition(
-                            attrUtils, resource, attributable, intAttrName, intMappingType);
-                }
+        Iterable<? extends ExternalResource> iterable = attributable instanceof User
+                ? userDAO.findAllResources((User) attributable)
+                : attributable instanceof Group
+                        ? ((Group) attributable).getResources()
+                        : Collections.<ExternalResource>emptySet();
+
+        for (Iterator<? extends ExternalResource> itor = iterable.iterator(); itor.hasNext() && !result;) {
+            ExternalResource resource = itor.next();
+            if (resource.isEnforceMandatoryCondition()) {
+                result |= evaluateMandatoryCondition(
+                        attrUtils, resource, attributable, intAttrName, intMappingType);
             }
         }
 
@@ -427,11 +430,13 @@ abstract class AbstractAttributableDataBinder {
             LOG.debug("Resources to be added:\n{}", propByRes);
         }
 
-        final Set<ExternalResource> externalResources = new HashSet<>();
-        if (attributable instanceof Subject) {
-            externalResources.addAll(((Subject<?, ?, ?>) attributable).getResources());
+        Set<ExternalResource> externalResources = new HashSet<>();
+        if (attributable instanceof User) {
+            externalResources.addAll(userDAO.findAllResources((User) attributable));
+        } else if (attributable instanceof Group) {
+            externalResources.addAll(((Group) attributable).getResources());
         } else if (attributable instanceof Membership) {
-            externalResources.addAll(((Membership) attributable).getUser().getResources());
+            externalResources.addAll(userDAO.findAllResources(((Membership) attributable).getUser()));
             externalResources.addAll(((Membership) attributable).getGroup().getResources());
         }
 
@@ -777,7 +782,10 @@ abstract class AbstractAttributableDataBinder {
     protected Map<String, String> getAccountIds(final Subject<?, ?, ?> subject, final AttributableType type) {
         Map<String, String> accountIds = new HashMap<>();
 
-        for (ExternalResource resource : subject.getResources()) {
+        Iterable<? extends ExternalResource> iterable = subject instanceof User
+                ? userDAO.findAllResources((User) subject)
+                : ((Group) subject).getResources();
+        for (ExternalResource resource : iterable) {
             if ((type == AttributableType.USER && resource.getUmapping() != null)
                     || (type == AttributableType.GROUP && resource.getGmapping() != null)) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/22839bf3/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
index 6cadc9d..efe7771 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
@@ -18,8 +18,6 @@
  */
 package org.apache.syncope.core.provisioning.java.data;
 
-import static org.apache.syncope.core.provisioning.java.data.AbstractAttributableDataBinder.LOG;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -49,6 +47,9 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.common.lib.types.PropagationByResource;
 import org.apache.syncope.core.provisioning.api.data.GroupDataBinder;
 import org.apache.syncope.core.misc.ConnObjectUtils;
+import org.apache.syncope.core.misc.search.SearchCondConverter;
+import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.entity.DynGroupMembership;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
@@ -89,6 +90,25 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
         }
     }
 
+    private void setDynMembership(final Group group, final String dynMembershipFIQL) {
+        SearchCond dynMembershipCond = SearchCondConverter.convert(dynMembershipFIQL);
+        if (!dynMembershipCond.isValid()) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSearchExpression);
+            sce.getElements().add(dynMembershipFIQL);
+            throw sce;
+        }
+
+        DynGroupMembership dynMembership;
+        if (group.getDynMembership() == null) {
+            dynMembership = entityFactory.newEntity(DynGroupMembership.class);
+            dynMembership.setGroup(group);
+            group.setDynMembership(dynMembership);
+        } else {
+            dynMembership = group.getDynMembership();
+        }
+        dynMembership.setFIQLCond(dynMembershipFIQL);
+    }
+
     @Override
     public Group create(final Group group, final GroupTO groupTO) {
         SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
@@ -132,6 +152,10 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
             }
         }
 
+        if (groupTO.getDynMembershipCond() != null) {
+            setDynMembership(group, groupTO.getDynMembershipCond());
+        }
+
         return group;
     }
 
@@ -202,6 +226,18 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
             }
         }
 
+        // dynamic membership
+        if (group.getDynMembership() != null && groupMod.getDynMembershipCond() == null) {
+            group.setDynMembership(null);
+        } else if (group.getDynMembership() == null && groupMod.getDynMembershipCond() != null) {
+            setDynMembership(group, groupMod.getDynMembershipCond());
+        } else if (group.getDynMembership() != null && groupMod.getDynMembershipCond() != null
+                && !group.getDynMembership().getFIQLCond().equals(groupMod.getDynMembershipCond())) {
+
+            group.getDynMembership().getUsers().clear();
+            setDynMembership(group, groupMod.getDynMembershipCond());
+        }
+
         return propByRes;
     }
 
@@ -251,6 +287,10 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
             groupTO.getMVirAttrTemplates().add(template.getSchema().getKey());
         }
 
+        if (group.getDynMembership() != null) {
+            groupTO.setDynMembershipCond(group.getDynMembership().getFIQLCond());
+        }
+
         return groupTO;
     }