diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java index 5fb557e829..19362b4ce6 100644 --- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java +++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java @@ -128,10 +128,31 @@ private static void diff( result.setRealm(replacePatchItem(updated.getRealm(), original.getRealm(), new StringReplacePatchItem())); // 2. manager - result.setUManager( - replacePatchItem(updated.getUManager(), original.getUManager(), new StringReplacePatchItem())); - result.setGManager( - replacePatchItem(updated.getGManager(), original.getGManager(), new StringReplacePatchItem())); + if (updated.getUManager() != null || original.getUManager() != null) { + StringReplacePatchItem uManager = new StringReplacePatchItem(); + if (updated.getUManager() == null) { + if (!incremental) { + uManager.setOperation(PatchOperation.DELETE); + result.setUManager(uManager); + } + } else if (!updated.getUManager().equals(original.getUManager())) { + uManager.setValue(updated.getUManager()); + result.setUManager(uManager); + } + } + + if (updated.getGManager() != null || original.getGManager() != null) { + StringReplacePatchItem gManager = new StringReplacePatchItem(); + if (updated.getGManager() == null) { + if (!incremental) { + gManager.setOperation(PatchOperation.DELETE); + result.setGManager(gManager); + } + } else if (!updated.getGManager().equals(original.getGManager())) { + gManager.setValue(updated.getGManager()); + result.setGManager(gManager); + } + } // 3. auxiliary classes result.getAuxClasses().clear(); diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java index 18cdf1b81e..8a175f0c28 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java @@ -72,6 +72,7 @@ import org.apache.syncope.common.lib.to.PropagationTaskTO; import org.apache.syncope.common.lib.to.Provision; import org.apache.syncope.common.lib.to.ProvisioningResult; +import org.apache.syncope.common.lib.to.PullTaskTO; import org.apache.syncope.common.lib.to.PushTaskTO; import org.apache.syncope.common.lib.to.RealmTO; import org.apache.syncope.common.lib.to.ReconStatus; @@ -1930,4 +1931,55 @@ public void issueSYNCOPE1906() { .build()).getResult().forEach(u -> deleteUser(u.getKey())); } } + + @Test + public void issueSYNCOPE1965() { + // 1. create a sample user with a manager and propagate on LDAP + UserCR userCR = UserITCase.getUniqueSample("issuesyncope1965@syncope.apache.org"); + userCR.getResources().add(RESOURCE_NAME_TESTDB); + userCR.setPassword("Password123!"); + userCR.setUManager(USER_SERVICE.read("puccini").getKey()); + ProvisioningResult pr = createUser(userCR); + assertEquals(ExecStatus.SUCCESS, pr.getPropagationStatuses().getFirst().getStatus()); + assertNotNull(pr.getEntity().getUManager()); + // 2. pull from resource-testdb + PullTaskTO pullTaskTO = new PullTaskTO(); + pullTaskTO.setPerformCreate(true); + pullTaskTO.setPerformUpdate(true); + pullTaskTO.setDestinationRealm(SyncopeConstants.ROOT_REALM); + pullTaskTO.setMatchingRule(MatchingRule.UPDATE); + pullTaskTO.setUnmatchingRule(UnmatchingRule.ASSIGN); + RECONCILIATION_SERVICE.pull( + new ReconQuery.Builder(AnyTypeKind.USER.name(), RESOURCE_NAME_TESTDB).anyKey(pr.getEntity().getKey()) + .build(), pullTaskTO); + // user manager should be kept + UserTO updatedUser = USER_SERVICE.read(pr.getEntity().getKey()); + assertNotNull(updatedUser.getUManager()); + assertEquals(USER_SERVICE.read("puccini").getKey(), updatedUser.getUManager()); + + // perform the same check on a group + GroupCR groupCR = GroupITCase.getSample("issue1965grp"); + groupCR.getResources().add(RESOURCE_NAME_LDAP); + groupCR.setGManager(GROUP_SERVICE.read("managingDirector").getKey()); + ProvisioningResult prGrp = createGroup(groupCR); + assertEquals(ExecStatus.SUCCESS, prGrp.getPropagationStatuses().getFirst().getStatus()); + assertNotNull(prGrp.getEntity().getGManager()); + assertEquals(GROUP_SERVICE.read("managingDirector").getKey(), prGrp.getEntity().getGManager()); + + // 2. pull from resource-ldap + pullTaskTO = new PullTaskTO(); + pullTaskTO.setPerformCreate(true); + pullTaskTO.setPerformUpdate(true); + pullTaskTO.getActions().add("LDAPMembershipPullActions"); + pullTaskTO.setDestinationRealm(SyncopeConstants.ROOT_REALM); + pullTaskTO.setMatchingRule(MatchingRule.UPDATE); + pullTaskTO.setUnmatchingRule(UnmatchingRule.ASSIGN); + RECONCILIATION_SERVICE.pull( + new ReconQuery.Builder(AnyTypeKind.USER.name(), RESOURCE_NAME_LDAP).anyKey(pr.getEntity().getKey()) + .build(), pullTaskTO); + // group manager should be kept + GroupTO updatedGrp = GROUP_SERVICE.read(prGrp.getEntity().getKey()); + assertNotNull(updatedGrp.getGManager()); + assertEquals(GROUP_SERVICE.read("managingDirector").getKey(), updatedGrp.getGManager()); + } }