This is an automated email from the ASF dual-hosted git repository.

ilgrosso 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 e64b2ee986 [SYNCOPE-1921] LDAPMembershipPropagationActions preserves 
external group memberships (#1362)
e64b2ee986 is described below

commit e64b2ee986f30673416cf578e6705fdfaf795045
Author: Oleg Zimakov <[email protected]>
AuthorDate: Mon Apr 27 02:49:22 2026 -0700

    [SYNCOPE-1921] LDAPMembershipPropagationActions preserves external group 
memberships (#1362)
---
 .../LDAPMembershipPropagationActions.java          |  5 ++
 .../syncope/fit/core/PropagationTaskITCase.java    | 80 ++++++++++++++++++++++
 2 files changed, 85 insertions(+)

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 d4c5f310e4..634c5afe1f 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
@@ -87,6 +87,11 @@ public class LDAPMembershipPropagationActions implements 
PropagationActions {
         return "ldapGroups";
     }
 
+    @Override
+    public Set<String> moreAttrsToGet(final Optional<PropagationTaskInfo> 
taskInfo, final Provision provision) {
+        return Set.of(getGroupMembershipAttrName());
+    }
+
     protected String evaluateGroupConnObjectLink(final String 
connObjectLinkTemplate, final Group group) {
         LOG.debug("Evaluating connObjectLink for {}", group);
 
diff --git 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
index c8e251048f..24308696e0 100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
@@ -976,6 +976,86 @@ public class PropagationTaskITCase extends 
AbstractTaskITCase {
         }
     }
 
+    @Test
+    public void issueSYNCOPE1921() {
+        ResourceTO ldap = RESOURCE_SERVICE.read(RESOURCE_NAME_LDAP);
+        UserTO userTO = null;
+        try {
+            // 1. clone the LDAP resource (which has 
LDAPMembershipPropagationActions configured)
+            // but do NOT add ldapGroups to the user mapping - rely solely on 
the propagation action
+            Provision provisionGroup =
+                    
SerializationUtils.clone(ldap.getProvision(AnyTypeKind.GROUP.name()).orElse(null));
+            assertNotNull(provisionGroup);
+
+            Provision provisionUser =
+                    
SerializationUtils.clone(ldap.getProvision(AnyTypeKind.USER.name()).orElse(null));
+            assertNotNull(provisionUser);
+            provisionUser.getMapping().getItems().removeIf(item -> 
"mail".equals(item.getExtAttrName()));
+
+            ldap.getProvisions().clear();
+            ldap.getProvisions().add(provisionUser);
+            ldap.getProvisions().add(provisionGroup);
+            ldap.setKey(RESOURCE_NAME_LDAP + "1921" + getUUIDString());
+            RESOURCE_SERVICE.create(ldap);
+
+            // 2. create group with the new resource assigned
+            GroupCR groupCR = new GroupCR();
+            groupCR.setName("SYNCOPEGROUP1921-" + getUUIDString());
+            groupCR.setRealm(SyncopeConstants.ROOT_REALM);
+            groupCR.getResources().add(ldap.getKey());
+
+            GroupTO groupTO = createGroup(groupCR).getEntity();
+            assertNotNull(groupTO);
+
+            // 3. create user with the new resource and group membership
+            UserCR userCR = 
UserITCase.getUniqueSample("[email protected]");
+            userCR.getResources().clear();
+            userCR.getResources().add(ldap.getKey());
+            userCR.getMemberships().add(new 
MembershipTO.Builder(groupTO.getKey()).build());
+
+            userTO = createUser(userCR).getEntity();
+            assertNotNull(userTO);
+
+            // 4. deassociate and delete group from Syncope, leaving the LDAP 
group entry orphaned
+            ResourceDR resourceDR = new 
ResourceDR.Builder().key(groupTO.getKey()).
+                    
action(ResourceDeassociationAction.UNLINK).resource(ldap.getKey()).build();
+
+            GROUP_SERVICE.deassociate(resourceDR);
+            GROUP_SERVICE.delete(groupTO.getKey());
+
+            // 5. create a new group and assign user to it
+            GroupCR newGroupCR = new GroupCR();
+            newGroupCR.setName("NEWSYNCOPEGROUP1921-" + getUUIDString());
+            newGroupCR.setRealm(SyncopeConstants.ROOT_REALM);
+            newGroupCR.getResources().add(ldap.getKey());
+
+            GroupTO newGroupTO = createGroup(newGroupCR).getEntity();
+            assertNotNull(newGroupTO);
+
+            UserUR userUR = new UserUR();
+            userUR.setKey(userTO.getKey());
+            userUR.getMemberships().add(
+                    new 
MembershipUR.Builder(newGroupTO.getKey()).operation(PatchOperation.ADD_REPLACE).build());
+            USER_SERVICE.update(userUR);
+
+            // 6. verify that the orphaned group membership was preserved 
during propagation
+            ConnObject connObject =
+                    RESOURCE_SERVICE.readConnObject(ldap.getKey(), 
AnyTypeKind.USER.name(), userTO.getKey());
+            assertNotNull(connObject);
+            assertTrue(connObject.getAttr("ldapGroups").isPresent());
+            assertEquals(2, 
connObject.getAttr("ldapGroups").orElseThrow().getValues().size());
+        } finally {
+            try {
+                RESOURCE_SERVICE.delete(ldap.getKey());
+                if (userTO != null) {
+                    USER_SERVICE.delete(userTO.getKey());
+                }
+            } catch (Exception ignore) {
+                // ignore
+            }
+        }
+    }
+
     @Test
     public void issueSYNCOPE1751() {
         // 1. Create a Group with a resource assigned

Reply via email to