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/01/29 17:51:03 UTC

syncope git commit: [SYNCOPE-620] Merging SYNCOPE-632

Repository: syncope
Updated Branches:
  refs/heads/2_0_X c42936baa -> 64fa513e1


[SYNCOPE-620] Merging SYNCOPE-632


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

Branch: refs/heads/2_0_X
Commit: 64fa513e11e28f8f24ddacf803e6036edaf78895
Parents: c42936b
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Jan 29 17:50:57 2015 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Jan 29 17:50:57 2015 +0100

----------------------------------------------------------------------
 .../apache/syncope/common/lib/to/MappingTO.java | 17 ++--
 .../fit/server/reference/AbstractITCase.java    | 27 ++++--
 .../fit/server/reference/ConnectorITCase.java   | 14 ++-
 .../fit/server/reference/RoleITCase.java        | 92 ++++++++++++++++++++
 .../fit/server/reference/UserSelfITCase.java    |  2 +-
 syncope620/pom.xml                              |  4 +-
 .../syncope/server/logic/ResourceLogic.java     |  4 +-
 .../data/AbstractAttributableDataBinder.java    | 27 +++++-
 .../java/data/RoleDataBinderImpl.java           | 21 +++--
 .../java/data/UserDataBinderImpl.java           | 28 +++---
 10 files changed, 187 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/64fa513e/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java
index 3d29914..aea9556 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java
@@ -46,18 +46,17 @@ public class MappingTO extends AbstractBaseBean {
         this.accountLink = accountLink;
     }
 
-    @SuppressWarnings("unchecked")
-    public <T extends MappingItemTO> T getAccountIdItem() {
-        T accountIdItem = null;
+    public MappingItemTO getAccountIdItem() {
+        MappingItemTO accountIdItem = null;
         for (MappingItemTO item : getItems()) {
             if (item.isAccountid()) {
-                accountIdItem = (T) item;
+                accountIdItem = item;
             }
         }
         return accountIdItem;
     }
 
-    protected <T extends MappingItemTO> boolean addAccountIdItem(final T accountIdItem) {
+    protected boolean addAccountIdItem(final MappingItemTO accountIdItem) {
         if (IntMappingType.UserVirtualSchema == accountIdItem.getIntMappingType()
                 || IntMappingType.RoleVirtualSchema == accountIdItem.getIntMappingType()
                 || IntMappingType.MembershipVirtualSchema == accountIdItem.getIntMappingType()
@@ -76,11 +75,9 @@ public class MappingTO extends AbstractBaseBean {
     }
 
     public boolean setAccountIdItem(final MappingItemTO accountIdItem) {
-        if (accountIdItem == null) {
-            return this.removeItem(getAccountIdItem());
-        } else {
-            return addAccountIdItem(accountIdItem);
-        }
+        return accountIdItem == null
+                ? removeItem(getAccountIdItem())
+                : addAccountIdItem(accountIdItem);
     }
 
     public MappingItemTO getPasswordItem() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/64fa513e/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/AbstractITCase.java
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/AbstractITCase.java b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/AbstractITCase.java
index 255666c..e1e5769 100644
--- a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/AbstractITCase.java
+++ b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/AbstractITCase.java
@@ -27,6 +27,7 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.UUID;
 import javax.naming.Context;
+import javax.naming.NamingException;
 import javax.naming.directory.InitialDirContext;
 import javax.sql.DataSource;
 import javax.ws.rs.core.Response;
@@ -339,12 +340,9 @@ public abstract class AbstractITCase {
         return getObject(response.getLocation(), ResourceService.class, ResourceTO.class);
     }
 
-    protected Object getLdapRemoteObject(final String objectDn) {
-        return getLdapRemoteObject(null, null, objectDn);
-    }
-
     @SuppressWarnings({ "unchecked", "rawtypes", "UseOfObsoleteCollectionType" })
-    protected Object getLdapRemoteObject(final String bindDn, final String bindPwd, final String objectDn) {
+    protected InitialDirContext getLdapResourceDirContext(final String bindDn, final String bindPwd)
+            throws NamingException {
         ResourceTO ldapRes = resourceService.read(RESOURCE_NAME_LDAP);
         final Map<String, ConnConfProperty> ldapConnConf =
                 connectorService.read(ldapRes.getConnectorId()).getConfigurationMap();
@@ -359,11 +357,28 @@ public abstract class AbstractITCase {
         env.put(Context.SECURITY_CREDENTIALS,
                 bindPwd == null ? ldapConnConf.get("credentials").getValues().get(0) : bindPwd);
 
+        return new InitialDirContext(env);
+    }
+
+    protected Object getLdapRemoteObject(final String bindDn, final String bindPwd, final String objectDn) {
+        InitialDirContext ctx = null;
         try {
-            final InitialDirContext ctx = new InitialDirContext(env);
+            ctx = getLdapResourceDirContext(bindDn, bindPwd);
             return ctx.lookup(objectDn);
         } catch (Exception e) {
             return null;
+        } finally {
+            if (ctx != null) {
+                try {
+                    ctx.close();
+                } catch (NamingException e) {
+                    // ignore
+                }
+            }
         }
     }
+
+    protected Object getLdapRemoteObject(final String objectDn) {
+        return getLdapRemoteObject(null, null, objectDn);
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/64fa513e/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/ConnectorITCase.java
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/ConnectorITCase.java b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/ConnectorITCase.java
index f426526..83e0832 100644
--- a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/ConnectorITCase.java
+++ b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/ConnectorITCase.java
@@ -285,7 +285,6 @@ public class ConnectorITCase extends AbstractITCase {
         // ----------------------------------
         // Retrieve a connector instance template.
         ConnInstanceTO connInstanceTO = connectorService.read(103L);
-
         assertNotNull(connInstanceTO);
 
         // check for resource
@@ -313,7 +312,7 @@ public class ConnectorITCase extends AbstractITCase {
 
         connInstanceTO = getObject(response.getLocation(), ConnectorService.class, ConnInstanceTO.class);
         assertNotNull(connInstanceTO);
-        assertTrue(connInstanceTO.getCapabilities().isEmpty());
+        assertFalse(connInstanceTO.getCapabilities().contains(ConnectorCapability.AUTHENTICATE));
 
         long connId = connInstanceTO.getKey();
 
@@ -337,26 +336,23 @@ public class ConnectorITCase extends AbstractITCase {
         // Check for spring bean.
         // ----------------------------------
         ConnInstanceTO connInstanceBean = connectorService.readByResource(resourceTO.getKey());
-
         assertNotNull(connInstanceBean);
-        assertTrue(connInstanceBean.getCapabilities().isEmpty());
+        assertFalse(connInstanceBean.getCapabilities().contains(ConnectorCapability.AUTHENTICATE));
         // ----------------------------------
 
         // ----------------------------------
         // Check for spring bean update after connector instance update.
         // ----------------------------------
-        connInstanceTO.getCapabilities().add(ConnectorCapability.SEARCH);
+        connInstanceTO.getCapabilities().add(ConnectorCapability.AUTHENTICATE);
 
         connectorService.update(connInstanceTO.getKey(), connInstanceTO);
         ConnInstanceTO actual = connectorService.read(connInstanceTO.getKey());
-
         assertNotNull(actual);
-        assertFalse(connInstanceTO.getCapabilities().isEmpty());
+        assertTrue(connInstanceTO.getCapabilities().contains(ConnectorCapability.AUTHENTICATE));
 
         // check for spring bean update
         connInstanceBean = connectorService.readByResource(resourceTO.getKey());
-
-        assertFalse(connInstanceBean.getCapabilities().isEmpty());
+        assertTrue(connInstanceBean.getCapabilities().contains(ConnectorCapability.AUTHENTICATE));
         // ----------------------------------
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/64fa513e/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/RoleITCase.java
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/RoleITCase.java b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/RoleITCase.java
index dbd9532..18646f5 100644
--- a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/RoleITCase.java
+++ b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/RoleITCase.java
@@ -29,6 +29,11 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.security.AccessControlException;
 import java.util.List;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+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.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -38,12 +43,16 @@ import org.apache.syncope.common.lib.mod.ReferenceMod;
 import org.apache.syncope.common.lib.mod.RoleMod;
 import org.apache.syncope.common.lib.to.BulkActionResult;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.MappingItemTO;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.to.RoleTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AttributableType;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.common.lib.types.ResourceAssociationActionType;
 import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
 import org.apache.syncope.common.lib.types.SchemaType;
@@ -794,4 +803,87 @@ public class RoleITCase extends AbstractITCase {
         assertNotNull(child.getPlainAttrMap().get("icon").getValues());
         assertEquals("parentIcon", child.getPlainAttrMap().get("icon").getValues().get(0));
     }
+
+    @Test
+    public void issueSYNCOPE632() {
+        RoleTO roleTO = null;
+        try {
+            // 1. create new LDAP resource having account id mapped to a derived attribute
+            ResourceTO newLDAP = resourceService.read(RESOURCE_NAME_LDAP);
+            newLDAP.setKey("new-ldap");
+            newLDAP.setPropagationPrimary(true);
+            MappingItemTO accountId = newLDAP.getRmapping().getAccountIdItem();
+            accountId.setIntMappingType(IntMappingType.RoleDerivedSchema);
+            accountId.setIntAttrName("displayProperty");
+            newLDAP.getRmapping().setAccountIdItem(accountId);
+            newLDAP.getRmapping().setAccountLink("'cn=' + displayProperty + ',ou=groups,o=isp'");
+
+            MappingItemTO description = new MappingItemTO();
+            description.setIntMappingType(IntMappingType.RoleId);
+            description.setExtAttrName("description");
+            description.setPurpose(MappingPurpose.BOTH);
+            newLDAP.getRmapping().addItem(description);
+
+            newLDAP = createResource(newLDAP);
+            assertNotNull(newLDAP);
+
+            // 2. create a role and give the resource created above
+            roleTO = buildRoleTO("lastRole");
+            roleTO.getRAttrTemplates().add("icon");
+            roleTO.getPlainAttrs().add(attrTO("icon", "anIcon"));
+            roleTO.getRAttrTemplates().add("show");
+            roleTO.getPlainAttrs().add(attrTO("show", "true"));
+            roleTO.getRDerAttrTemplates().add("displayProperty");
+            roleTO.getDerAttrs().add(attrTO("displayProperty", null));
+            roleTO.getResources().clear();
+            roleTO.getResources().add("new-ldap");
+
+            roleTO = createRole(roleTO);
+            assertNotNull(roleTO);
+
+            // 3. update the role
+            RoleMod roleMod = new RoleMod();
+            roleMod.setKey(roleTO.getKey());
+            roleMod.getPlainAttrsToRemove().add("icon");
+            roleMod.getPlainAttrsToUpdate().add(attrMod("icon", "anotherIcon"));
+
+            roleTO = updateRole(roleMod);
+            assertNotNull(roleTO);
+
+            // 4. check that a single group exists in LDAP for the role created and updated above
+            int entries = 0;
+            DirContext ctx = null;
+            try {
+                ctx = getLdapResourceDirContext(null, null);
+
+                SearchControls ctls = new SearchControls();
+                ctls.setReturningAttributes(new String[] { "*", "+" });
+                ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+                NamingEnumeration<SearchResult> result =
+                        ctx.search("ou=groups,o=isp", "(description=" + roleTO.getKey() + ")", ctls);
+                while (result.hasMore()) {
+                    result.next();
+                    entries++;
+                }
+            } catch (Exception e) {
+                // ignore
+            } finally {
+                if (ctx != null) {
+                    try {
+                        ctx.close();
+                    } catch (NamingException e) {
+                        // ignore
+                    }
+                }
+            }
+
+            assertEquals(1, entries);
+        } finally {
+            if (roleTO != null) {
+                roleService.delete(roleTO.getKey());
+            }
+            resourceService.delete("new-ldap");
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/64fa513e/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/UserSelfITCase.java
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/UserSelfITCase.java b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/UserSelfITCase.java
index 1847422..665e482 100644
--- a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/UserSelfITCase.java
+++ b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/UserSelfITCase.java
@@ -159,7 +159,7 @@ public class UserSelfITCase extends AbstractITCase {
     }
 
     @Test
-    public void updateWitApproval() {
+    public void updateWithApproval() {
         Assume.assumeTrue(ActivitiDetector.isActivitiEnabledForUsers(syncopeService));
 
         // 1. create user as admin

http://git-wip-us.apache.org/repos/asf/syncope/blob/64fa513e/syncope620/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/pom.xml b/syncope620/pom.xml
index 7abfd74..d911dd8 100644
--- a/syncope620/pom.xml
+++ b/syncope620/pom.xml
@@ -594,7 +594,7 @@ under the License.
       <dependency>
         <groupId>org.aspectj</groupId>
         <artifactId>aspectjweaver</artifactId>
-        <version>1.8.4</version>
+        <version>1.8.5</version>
       </dependency>
       
       <dependency>
@@ -940,7 +940,7 @@ under the License.
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-dependency-plugin</artifactId>
-          <version>2.9</version>
+          <version>2.10</version>
           <configuration>
             <outputDirectory>${bundles.directory}</outputDirectory>
             <artifactItems>

http://git-wip-us.apache.org/repos/asf/syncope/blob/64fa513e/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ResourceLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ResourceLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ResourceLogic.java
index 18c1f58..d5827b6 100644
--- a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ResourceLogic.java
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ResourceLogic.java
@@ -179,8 +179,8 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
 
         MappingItem accountIdItem = attrUtil.getAccountIdItem(resource);
         if (accountIdItem == null) {
-            throw new NotFoundException("AccountId mapping for " + type + " " + id + " on resource '" + resourceName
-                    + "'");
+            throw new NotFoundException(
+                    "AccountId mapping for " + type + " " + id + " on resource '" + resourceName + "'");
         }
         final String accountIdValue = MappingUtil.getAccountIdValue(
                 subject, resource, attrUtil.getAccountIdItem(resource));

http://git-wip-us.apache.org/repos/asf/syncope/blob/64fa513e/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/AbstractAttributableDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/AbstractAttributableDataBinder.java b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/AbstractAttributableDataBinder.java
index f7e75c0..d81e6ab 100644
--- a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/AbstractAttributableDataBinder.java
+++ b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/AbstractAttributableDataBinder.java
@@ -20,9 +20,11 @@ package org.apache.syncope.server.provisioning.java.data;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
@@ -86,6 +88,7 @@ import org.apache.syncope.common.lib.types.PropagationByResource;
 import org.apache.syncope.server.provisioning.java.VirAttrHandler;
 import org.apache.syncope.server.misc.MappingUtil;
 import org.apache.syncope.server.misc.jexl.JexlUtil;
+import org.apache.syncope.server.persistence.api.dao.NotFoundException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -215,7 +218,7 @@ abstract class AbstractAttributableDataBinder {
     }
 
     private boolean evaluateMandatoryCondition(final AttributableUtil attrUtil, final ExternalResource resource,
-            final Attributable<?,?,?> attributable, final String intAttrName, final IntMappingType intMappingType) {
+            final Attributable<?, ?, ?> attributable, final String intAttrName, final IntMappingType intMappingType) {
 
         boolean result = false;
 
@@ -751,4 +754,26 @@ 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()) {
+            if ((type == AttributableType.USER && resource.getUmapping() != null)
+                    || (type == AttributableType.ROLE && resource.getRmapping() != null)) {
+
+                MappingItem accountIdItem =
+                        attrUtilFactory.getInstance(type).getAccountIdItem(resource);
+                if (accountIdItem == null) {
+                    throw new NotFoundException(
+                            "AccountId mapping for " + type + " " + subject.getKey()
+                            + " on resource '" + resource.getKey() + "'");
+                }
+
+                accountIds.put(resource.getKey(), MappingUtil.getAccountIdValue(subject, resource, accountIdItem));
+            }
+        }
+
+        return accountIds;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/64fa513e/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/RoleDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/RoleDataBinderImpl.java b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/RoleDataBinderImpl.java
index 851799c..3004a99 100644
--- a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/RoleDataBinderImpl.java
+++ b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/RoleDataBinderImpl.java
@@ -20,7 +20,7 @@ package org.apache.syncope.server.provisioning.java.data;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
+import java.util.Map;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.mod.RoleMod;
@@ -198,7 +198,8 @@ public class RoleDataBinderImpl extends AbstractAttributableDataBinder implement
 
         SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
 
-        Set<String> currentResources = role.getResourceNames();
+        // fetch account ids before update
+        Map<String, String> oldAccountIds = getAccountIds(role, AttributableType.ROLE);
 
         // name
         SyncopeClientException invalidRoles = SyncopeClientException.build(ClientExceptionType.InvalidRoles);
@@ -207,10 +208,7 @@ public class RoleDataBinderImpl extends AbstractAttributableDataBinder implement
                     role.getParent() == null ? null : role.getParent().getKey());
             if (otherRole == null || role.equals(otherRole)) {
                 if (!roleMod.getName().equals(role.getName())) {
-                    propByRes.addAll(ResourceOperation.UPDATE, currentResources);
-                    for (String resource : currentResources) {
-                        propByRes.addOldAccountId(resource, role.getName());
-                    }
+                    propByRes.addAll(ResourceOperation.UPDATE, role.getResourceNames());
 
                     role.setName(roleMod.getName());
                 }
@@ -307,6 +305,17 @@ public class RoleDataBinderImpl extends AbstractAttributableDataBinder implement
         // attributes, derived attributes, virtual attributes and resources
         propByRes.merge(fill(role, roleMod, attrUtilFactory.getInstance(AttributableType.ROLE), scce));
 
+        // check if some account id was changed by the update above
+        Map<String, String> newAccountIds = getAccountIds(role, AttributableType.ROLE);
+        for (Map.Entry<String, String> entry : oldAccountIds.entrySet()) {
+            if (newAccountIds.containsKey(entry.getKey())
+                    && !entry.getValue().equals(newAccountIds.get(entry.getKey()))) {
+
+                propByRes.addOldAccountId(entry.getKey(), entry.getValue());
+                propByRes.add(ResourceOperation.UPDATE, entry.getKey());
+            }
+        }
+
         return propByRes;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/64fa513e/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/UserDataBinderImpl.java b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/UserDataBinderImpl.java
index 4fdb0b8..5a9448d 100644
--- a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/UserDataBinderImpl.java
+++ b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/data/UserDataBinderImpl.java
@@ -21,6 +21,7 @@ package org.apache.syncope.server.provisioning.java.data;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 import javax.annotation.Resource;
 import org.apache.commons.lang3.StringUtils;
@@ -33,13 +34,11 @@ import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AttributableType;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
-import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.server.persistence.api.dao.ConfDAO;
 import org.apache.syncope.server.persistence.api.dao.SecurityQuestionDAO;
 import org.apache.syncope.server.persistence.api.entity.DerAttr;
 import org.apache.syncope.server.persistence.api.entity.ExternalResource;
-import org.apache.syncope.server.persistence.api.entity.MappingItem;
 import org.apache.syncope.server.persistence.api.entity.PlainAttr;
 import org.apache.syncope.server.persistence.api.entity.VirAttr;
 import org.apache.syncope.server.persistence.api.entity.membership.MDerAttr;
@@ -210,6 +209,9 @@ public class UserDataBinderImpl extends AbstractAttributableDataBinder implement
 
         Set<String> currentResources = user.getResourceNames();
 
+        // fetch account ids before update
+        Map<String, String> oldAccountIds = getAccountIds(user, AttributableType.USER);
+
         // password
         if (StringUtils.isNotBlank(userMod.getPassword())) {
             setPassword(user, userMod.getPassword(), scce);
@@ -219,18 +221,9 @@ public class UserDataBinderImpl extends AbstractAttributableDataBinder implement
 
         // username
         if (userMod.getUsername() != null && !userMod.getUsername().equals(user.getUsername())) {
-            String oldUsername = user.getUsername();
-
-            user.setUsername(userMod.getUsername());
             propByRes.addAll(ResourceOperation.UPDATE, currentResources);
 
-            for (ExternalResource resource : user.getResources()) {
-                for (MappingItem mapItem : resource.getUmapping().getItems()) {
-                    if (mapItem.isAccountid() && mapItem.getIntMappingType() == IntMappingType.Username) {
-                        propByRes.addOldAccountId(resource.getKey(), oldUsername);
-                    }
-                }
-            }
+            user.setUsername(userMod.getUsername());
         }
 
         // security question / answer:
@@ -348,6 +341,17 @@ public class UserDataBinderImpl extends AbstractAttributableDataBinder implement
             propByRes.addAll(ResourceOperation.UPDATE, currentResources);
         }
 
+        // check if some account id was changed by the update above
+        Map<String, String> newAccountIds = getAccountIds(user, AttributableType.USER);
+        for (Map.Entry<String, String> entry : oldAccountIds.entrySet()) {
+            if (newAccountIds.containsKey(entry.getKey())
+                    && !entry.getValue().equals(newAccountIds.get(entry.getKey()))) {
+
+                propByRes.addOldAccountId(entry.getKey(), entry.getValue());
+                propByRes.add(ResourceOperation.UPDATE, entry.getKey());
+            }
+        }
+
         return propByRes;
     }