This is an automated email from the ASF dual-hosted git repository.
andreapatricelli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new 4b13569785 SYNCOPE-1853 avoid unwanted user/any deprovision on group
delete (#958) (#961)
4b13569785 is described below
commit 4b13569785933e6ab0e795ac2931374c4fd1e398
Author: Andrea Patricelli <[email protected]>
AuthorDate: Tue Jan 21 09:26:36 2025 +0100
SYNCOPE-1853 avoid unwanted user/any deprovision on group delete (#958)
(#961)
* [SYNCOPE-1853] Avoid unwanted user/any object propagation on group delete
---
.../java/data/GroupDataBinderImpl.java | 12 +++--
.../apache/syncope/fit/core/UserIssuesITCase.java | 58 ++++++++++++++++++++++
2 files changed, 67 insertions(+), 3 deletions(-)
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
index 655bf6f449..2d3dc57590 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
@@ -48,13 +48,13 @@ import
org.apache.syncope.core.persistence.api.dao.RealmSearchDAO;
import org.apache.syncope.core.persistence.api.dao.RelationshipTypeDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
-import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyType;
import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.DerSchema;
import org.apache.syncope.core.persistence.api.entity.DynGroupMembership;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
import
org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership;
@@ -445,11 +445,17 @@ public class GroupDataBinderImpl extends
AbstractAnyDataBinder implements GroupD
}
protected static void populateTransitiveResources(
- final Group group, final Any<?> any, final Map<String,
PropagationByResource<String>> result) {
+ final Group group,
+ final GroupableRelatable<?, ?, ?, ?, ?> any,
+ final Map<String, PropagationByResource<String>> result) {
PropagationByResource<String> propByRes = new
PropagationByResource<>();
group.getResources().forEach(resource -> {
- if (!any.getResources().contains(resource)) {
+ // exclude from propagation those objects that have that resource
assigned by some other membership(s)
+ if (!any.getResources().contains(resource) &&
any.getMemberships().stream()
+ .filter(otherGrpMemb ->
!otherGrpMemb.getRightEnd().equals(group))
+ .noneMatch(otherGrpMemb ->
otherGrpMemb.getRightEnd().getResources().stream()
+ .anyMatch(r ->
resource.getKey().equals(r.getKey())))) {
propByRes.add(ResourceOperation.DELETE, resource.getKey());
}
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 13eee4c164..466e417577 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
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.fit.core;
+import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
@@ -40,6 +41,8 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
import javax.naming.NamingException;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.cxf.helpers.IOUtils;
@@ -71,6 +74,7 @@ import org.apache.syncope.common.lib.to.Mapping;
import org.apache.syncope.common.lib.to.MembershipTO;
import org.apache.syncope.common.lib.to.PlainSchemaTO;
import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
import org.apache.syncope.common.lib.to.ProvisioningResult;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.common.lib.to.RealmTO;
@@ -93,6 +97,7 @@ import org.apache.syncope.common.lib.types.PatchOperation;
import org.apache.syncope.common.lib.types.PolicyType;
import org.apache.syncope.common.lib.types.ResourceAssociationAction;
import org.apache.syncope.common.lib.types.ResourceDeassociationAction;
+import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.common.lib.types.SchemaType;
import org.apache.syncope.common.lib.types.StatusRType;
import org.apache.syncope.common.lib.types.TaskType;
@@ -100,6 +105,7 @@ import org.apache.syncope.common.lib.types.UnmatchingRule;
import org.apache.syncope.common.rest.api.RESTHeaders;
import org.apache.syncope.common.rest.api.beans.RealmQuery;
import org.apache.syncope.common.rest.api.beans.ReconQuery;
+import org.apache.syncope.common.rest.api.beans.TaskQuery;
import org.apache.syncope.common.rest.api.service.UserService;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
import
org.apache.syncope.core.provisioning.java.propagation.DBPasswordPropagationActions;
@@ -1839,4 +1845,56 @@ public class UserIssuesITCase extends AbstractITCase {
jdbcTemplate.update("DELETE FROM TESTPULL WHERE USERNAME =
'rossini'");
}
}
+
+ @Test
+ void issueSYNCOPE1853() {
+ GroupTO cGroupForPropagation = createGroup(
+ new GroupCR.Builder(SyncopeConstants.ROOT_REALM,
"cGroupForPropagation")
+ .resource(RESOURCE_NAME_LDAP)
+ .build()).getEntity();
+ GroupTO dGroupForPropagation = createGroup(
+ new GroupCR.Builder(SyncopeConstants.ROOT_REALM,
"dGroupForPropagation")
+ .resource(RESOURCE_NAME_LDAP)
+ .build()).getEntity();
+ // 1. assign both groups cGroupForPropagation and dGroupForPropagation
with resource-csv to bellini
+ updateUser(new
UserUR.Builder("c9b2dec2-00a7-4855-97c0-d854842b4b24").memberships(
+ new
MembershipUR.Builder(cGroupForPropagation.getKey()).build(),
+ new
MembershipUR.Builder(dGroupForPropagation.getKey()).build()).build());
+ // 2. assign cGroupForPropagation also to vivaldi
+ updateUser(new
UserUR.Builder("b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee").membership(
+ new
MembershipUR.Builder(dGroupForPropagation.getKey()).build()).build());
+ // 3. propagation tasks cleanup
+ TASK_SERVICE.search(
+ new TaskQuery.Builder(TaskType.PROPAGATION)
+ .anyTypeKind(AnyTypeKind.USER)
+ .resource(RESOURCE_NAME_LDAP)
+
.entityKey("c9b2dec2-00a7-4855-97c0-d854842b4b24")
+ .build()).getResult()
+ .forEach(pt -> TASK_SERVICE.delete(TaskType.PROPAGATION,
pt.getKey()));
+ TASK_SERVICE.search(
+ new TaskQuery.Builder(TaskType.PROPAGATION)
+ .anyTypeKind(AnyTypeKind.USER)
+ .resource(RESOURCE_NAME_LDAP)
+
.entityKey("b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee")
+ .build()).getResult()
+ .forEach(pt -> TASK_SERVICE.delete(TaskType.PROPAGATION,
pt.getKey()));
+ // 4. delete group cGroupForPropagation: no deprovision should be
fired on bellini, since there is already
+ // bGroupForPropagation, deprovision instead must be fired for vivaldi
+ GROUP_SERVICE.delete(cGroupForPropagation.getKey());
+ await().during(5, TimeUnit.SECONDS).atMost(10,
TimeUnit.SECONDS).until(() -> TASK_SERVICE.search(
+ new TaskQuery.Builder(TaskType.PROPAGATION)
+ .anyTypeKind(AnyTypeKind.USER)
+ .resource(RESOURCE_NAME_LDAP)
+
.entityKey("c9b2dec2-00a7-4855-97c0-d854842b4b24").build())
+ .getResult().stream().map(PropagationTaskTO.class::cast)
+ .collect(Collectors.toList()).stream().noneMatch(pt ->
ResourceOperation.DELETE == pt.getOperation()));
+ GROUP_SERVICE.delete(dGroupForPropagation.getKey());
+ await().atMost(10, TimeUnit.SECONDS).until(() -> TASK_SERVICE.search(
+ new TaskQuery.Builder(TaskType.PROPAGATION)
+ .anyTypeKind(AnyTypeKind.USER)
+ .resource(RESOURCE_NAME_LDAP)
+
.entityKey("b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee").build())
+ .getResult().stream().map(PropagationTaskTO.class::cast)
+ .collect(Collectors.toList()).stream().anyMatch(pt ->
ResourceOperation.DELETE == pt.getOperation()));
+ }
}