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 b8ab58038c Ensure to check authorizations for Reconciliation methods
b8ab58038c is described below

commit b8ab58038c8f026ed3b5cf3bf548095c73b65e9a
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Wed Aug 12 16:54:13 2026 +0200

    Ensure to check authorizations for Reconciliation methods
---
 .../syncope/core/logic/ReconciliationLogic.java    | 76 ++++++++++++++--------
 .../apache/syncope/core/logic/ResourceLogic.java   | 14 ++--
 .../apache/syncope/core/logic/AbstractLogic.java   |  7 ++
 .../core/logic/AbstractTransactionalLogic.java     |  6 --
 4 files changed, 62 insertions(+), 41 deletions(-)

diff --git 
a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
 
b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
index e9a447f8f0..5280124af7 100644
--- 
a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
+++ 
b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
@@ -47,7 +47,6 @@ import org.apache.syncope.common.lib.types.MatchType;
 import org.apache.syncope.common.rest.api.beans.AbstractCSVSpec;
 import org.apache.syncope.common.rest.api.beans.CSVPullSpec;
 import org.apache.syncope.common.rest.api.beans.CSVPushSpec;
-import 
org.apache.syncope.core.logic.AbstractTransactionalLogic.ProvisioningInfo;
 import org.apache.syncope.core.persistence.api.dao.AnyDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
@@ -89,6 +88,7 @@ import 
org.apache.syncope.core.provisioning.java.pushpull.stream.StreamPushJobDe
 import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
 import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
 import org.apache.syncope.core.spring.security.AuthContextUtils;
+import 
org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
 import org.identityconnectors.framework.common.objects.ObjectClass;
@@ -161,23 +161,6 @@ public class ReconciliationLogic extends 
AbstractLogic<EntityTO> {
         this.ctx = ctx;
     }
 
-    protected ProvisioningInfo getProvisioningInfo(final String anyTypeKey, 
final String resourceKey) {
-        AnyType anyType = anyTypeDAO.findById(anyTypeKey).
-                orElseThrow(() -> new NotFoundException("AnyType " + 
anyTypeKey));
-
-        ExternalResource resource = resourceDAO.findById(resourceKey).
-                orElseThrow(() -> new NotFoundException("Resource '" + 
resourceKey));
-
-        Provision provision = resource.getProvisionByAnyType(anyType.getKey()).
-                orElseThrow(() -> new NotFoundException(
-                "Provision for " + anyType + " on Resource '" + resourceKey + 
"'"));
-        if (provision.getMapping() == null) {
-            throw new NotFoundException("Mapping for " + anyType + " on 
Resource '" + resourceKey + "'");
-        }
-
-        return new ProvisioningInfo(anyType, resource, provision);
-    }
-
     protected ConnObject getOnSyncope(
             final Item connObjectKeyItem,
             final String connObjectKeyValue,
@@ -244,6 +227,22 @@ public class ReconciliationLogic extends 
AbstractLogic<EntityTO> {
                 orElseThrow(() -> new NotFoundException(provision.getAnyType() 
+ " '" + anyKey + "'"));
     }
 
+    protected ProvisioningInfo getProvisioningInfo(final String anyTypeKey, 
final String resourceKey) {
+        AnyType anyType = anyTypeDAO.findById(anyTypeKey).
+                orElseThrow(() -> new NotFoundException("AnyType " + 
anyTypeKey));
+
+        ExternalResource resource = 
Optional.ofNullable(resourceDAO.authFind(resourceKey)).
+                orElseThrow(() -> new NotFoundException("Resource '" + 
resourceKey + '\''));
+        Provision provision = resource.getProvisionByAnyType(anyType.getKey()).
+                orElseThrow(() -> new NotFoundException(
+                "Provision for " + anyType + " on Resource '" + resourceKey + 
"'"));
+        if (provision.getMapping() == null) {
+            throw new NotFoundException("Mapping for " + anyType + " on 
Resource '" + resourceKey + "'");
+        }
+
+        return new ProvisioningInfo(anyType, resource, provision);
+    }
+
     @PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_GET_CONNOBJECT + "')")
     @Transactional(readOnly = true)
     public ReconStatus status(
@@ -407,6 +406,12 @@ public class ReconciliationLogic extends 
AbstractLogic<EntityTO> {
         return results;
     }
 
+    protected void securityChecks(final Set<String> realms, final String 
realm, final String resourceKey) {
+        if (!RealmUtils.SubtreePredicate.of(realms).test(realm)) {
+            throw new DelegatedAdministrationException(realm, 
ExternalResource.class.getSimpleName(), resourceKey);
+        }
+    }
+
     @PreAuthorize("hasRole('" + IdRepoEntitlement.TASK_EXECUTE + "')")
     @Transactional(readOnly = true)
     public List<ProvisioningReport> push(
@@ -418,6 +423,14 @@ public class ReconciliationLogic extends 
AbstractLogic<EntityTO> {
 
         ProvisioningInfo info = getProvisioningInfo(anyTypeKey, resourceKey);
 
+        Realm sourceRealm = Optional.ofNullable(pushTask.getSourceRealm()).
+                flatMap(realmSearchDAO::findByFullPath).
+                orElseThrow(() -> new NotFoundException("Realm " + 
pushTask.getSourceRealm()));
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                
AuthContextUtils.getAuthorizations().get(IdRepoEntitlement.TASK_EXECUTE),
+                sourceRealm.getFullPath());
+        securityChecks(effectiveRealms, sourceRealm.getFullPath(), null);
+
         SyncDeltaBuilder syncDeltaBuilder = syncDeltaBuilder(
                 info.resource(), info.provision(), filter, moreAttrsToGet);
 
@@ -478,11 +491,13 @@ public class ReconciliationLogic extends 
AbstractLogic<EntityTO> {
             final Set<String> moreAttrsToGet,
             final PullTaskTO pullTask) {
 
-        if (pullTask.getDestinationRealm() == null
-                || 
realmSearchDAO.findByFullPath(pullTask.getDestinationRealm()).isEmpty()) {
-
-            throw new NotFoundException("Realm " + 
pullTask.getDestinationRealm());
-        }
+        Realm destRealm = Optional.ofNullable(pullTask.getDestinationRealm()).
+                flatMap(realmSearchDAO::findByFullPath).
+                orElseThrow(() -> new NotFoundException("Realm " + 
pullTask.getDestinationRealm()));
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                
AuthContextUtils.getAuthorizations().get(IdRepoEntitlement.TASK_EXECUTE),
+                destRealm.getFullPath());
+        securityChecks(effectiveRealms, destRealm.getFullPath(), null);
 
         SyncopeClientException sce = 
SyncopeClientException.build(ClientExceptionType.Reconciliation);
         List<ProvisioningReport> results = new ArrayList<>();
@@ -606,7 +621,8 @@ public class ReconciliationLogic extends 
AbstractLogic<EntityTO> {
                 entitlement = IdRepoEntitlement.USER_SEARCH;
         }
 
-        Realm base = realmSearchDAO.findByFullPath(realm).
+        Realm base = Optional.ofNullable(realm).
+                flatMap(realmSearchDAO::findByFullPath).
                 orElseThrow(() -> new NotFoundException("Realm " + realm));
 
         Set<String> adminRealms = 
RealmUtils.getEffective(AuthContextUtils.getAuthorizations().get(entitlement), 
realm);
@@ -684,12 +700,16 @@ public class ReconciliationLogic extends 
AbstractLogic<EntityTO> {
         AnyType anyType = anyTypeDAO.findById(spec.getAnyTypeKey()).
                 orElseThrow(() -> new NotFoundException("AnyType " + 
spec.getAnyTypeKey()));
 
-        if (realmSearchDAO.findByFullPath(spec.getDestinationRealm()) == null) 
{
-            throw new NotFoundException("Realm " + spec.getDestinationRealm());
-        }
+        Realm destRealm = Optional.ofNullable(spec.getDestinationRealm()).
+                flatMap(realmSearchDAO::findByFullPath).
+                orElseThrow(() -> new NotFoundException("Realm " + 
spec.getDestinationRealm()));
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                
AuthContextUtils.getAuthorizations().get(IdRepoEntitlement.TASK_EXECUTE),
+                destRealm.getFullPath());
+        securityChecks(effectiveRealms, destRealm.getFullPath(), null);
 
         PullTaskTO pullTask = new PullTaskTO();
-        pullTask.setDestinationRealm(spec.getDestinationRealm());
+        pullTask.setDestinationRealm(destRealm.getFullPath());
         pullTask.setRemediation(spec.getRemediation());
         pullTask.setMatchingRule(spec.getMatchingRule());
         pullTask.setUnmatchingRule(spec.getUnmatchingRule());
diff --git 
a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java 
b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index cdc63781ab..f28f07591e 100644
--- 
a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ 
b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -107,12 +107,6 @@ public class ResourceLogic extends 
AbstractTransactionalLogic<ResourceTO> {
         this.anyUtilsFactory = anyUtilsFactory;
     }
 
-    protected void securityChecks(final Set<String> realms, final String 
realm, final String key) {
-        if (!RealmUtils.SubtreePredicate.of(realms).test(realm)) {
-            throw new DelegatedAdministrationException(realm, 
ExternalResource.class.getSimpleName(), key);
-        }
-    }
-
     protected ExternalResource doSave(final ExternalResource resource) {
         ExternalResource merged = resourceDAO.save(resource);
         try {
@@ -123,6 +117,12 @@ public class ResourceLogic extends 
AbstractTransactionalLogic<ResourceTO> {
         return merged;
     }
 
+    protected void securityChecks(final Set<String> realms, final String 
realm, final String resourceKey) {
+        if (!RealmUtils.SubtreePredicate.of(realms).test(realm)) {
+            throw new DelegatedAdministrationException(realm, 
ExternalResource.class.getSimpleName(), resourceKey);
+        }
+    }
+
     @PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_CREATE + "')")
     public ResourceTO create(final ResourceTO resourceTO) {
         if (StringUtils.isBlank(resourceTO.getKey())) {
@@ -373,7 +373,7 @@ public class ResourceLogic extends 
AbstractTransactionalLogic<ResourceTO> {
         ObjectClass objectClass;
         OperationOptions options;
         if (SyncopeConstants.REALM_ANYTYPE.equals(anyTypeKey)) {
-            resource = resourceDAO.findById(key).
+            resource = Optional.ofNullable(resourceDAO.authFind(key)).
                     orElseThrow(() -> new NotFoundException("Resource " + 
key));
             if (resource.getOrgUnit() == null) {
                 throw new NotFoundException("Realm provisioning for resource 
'" + key + '\'');
diff --git 
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractLogic.java
 
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractLogic.java
index 7452835f76..4120d56d9f 100644
--- 
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractLogic.java
+++ 
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractLogic.java
@@ -20,6 +20,9 @@ package org.apache.syncope.core.logic;
 
 import java.lang.reflect.Method;
 import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.syncope.common.lib.to.Provision;
+import org.apache.syncope.core.persistence.api.entity.AnyType;
+import org.apache.syncope.core.persistence.api.entity.ExternalResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.transaction.annotation.Transactional;
@@ -33,6 +36,10 @@ public abstract class AbstractLogic<T extends EntityTO> {
 
     protected static final Logger LOG = 
LoggerFactory.getLogger(AbstractLogic.class);
 
+    protected record ProvisioningInfo(AnyType anyType, ExternalResource 
resource, Provision provision) {
+
+    }
+
     /**
      * Resolves stored bean (if existing) referred by the given CUD method.
      * Read-only methods will be unresolved for performance reasons.
diff --git 
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractTransactionalLogic.java
 
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractTransactionalLogic.java
index 88cfb489fc..2208cc629e 100644
--- 
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractTransactionalLogic.java
+++ 
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractTransactionalLogic.java
@@ -19,9 +19,6 @@
 package org.apache.syncope.core.logic;
 
 import org.apache.syncope.common.lib.to.EntityTO;
-import org.apache.syncope.common.lib.to.Provision;
-import org.apache.syncope.core.persistence.api.entity.AnyType;
-import org.apache.syncope.core.persistence.api.entity.ExternalResource;
 import org.springframework.transaction.annotation.Transactional;
 
 /**
@@ -32,7 +29,4 @@ import 
org.springframework.transaction.annotation.Transactional;
 @Transactional(rollbackFor = { Throwable.class })
 public abstract class AbstractTransactionalLogic<T extends EntityTO> extends 
AbstractLogic<T> {
 
-    protected record ProvisioningInfo(AnyType anyType, ExternalResource 
resource, Provision provision) {
-
-    }
 }

Reply via email to