This is an automated email from the ASF dual-hosted git repository.
andrea-patricelli pushed a commit to branch 4_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/4_1_X by this push:
new de885c920b [SYNCOPE-1965] managed incremental setting of the
user/group manager to avoid unwanted removal (#1361)
de885c920b is described below
commit de885c920bfed22fc095c0386cd8afd9bd938393
Author: Andrea Patricelli <[email protected]>
AuthorDate: Mon Apr 27 09:00:43 2026 +0200
[SYNCOPE-1965] managed incremental setting of the user/group manager to
avoid unwanted removal (#1361)
---
.../apache/syncope/common/lib/AnyOperations.java | 29 ++++++++++--
.../apache/syncope/fit/core/UserIssuesITCase.java | 52 ++++++++++++++++++++++
2 files changed, 77 insertions(+), 4 deletions(-)
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 @@ public final class AnyOperations {
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.PropagationStatus;
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 class UserIssuesITCase extends AbstractITCase {
.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("[email protected]");
+ userCR.getResources().add(RESOURCE_NAME_TESTDB);
+ userCR.setPassword("Password123!");
+ userCR.setUManager(USER_SERVICE.read("puccini").getKey());
+ ProvisioningResult<UserTO> 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<GroupTO> 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());
+ }
}