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