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 fd550644dc Permission check on Delegations
fd550644dc is described below

commit fd550644dc24af555ddab49916954b9f03186f1f
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Wed Aug 12 18:40:23 2026 +0200

    Permission check on Delegations
---
 .../syncope/core/logic/AuthProfileLogic.java       |  6 ++-
 .../apache/syncope/core/logic/DelegationLogic.java | 22 +++++----
 .../java/data/DelegationDataBinderImpl.java        | 56 ++++++++++++++--------
 .../java/data/ResourceDataBinderImpl.java          |  8 +---
 .../security/DelegatedAdministrationException.java |  5 --
 5 files changed, 54 insertions(+), 43 deletions(-)

diff --git 
a/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthProfileLogic.java
 
b/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthProfileLogic.java
index a14c3eec84..712ffe012e 100644
--- 
a/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthProfileLogic.java
+++ 
b/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthProfileLogic.java
@@ -19,6 +19,7 @@
 package org.apache.syncope.core.logic;
 
 import java.util.List;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.AuthProfileTO;
 import org.apache.syncope.common.lib.types.AMEntitlement;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
@@ -89,7 +90,8 @@ public class AuthProfileLogic extends 
AbstractAuthProfileLogic {
         authProfileDAO.findByOwner(AuthContextUtils.getUsername()).
                 filter(authProfile -> 
authProfile.getKey().equals(authProfileTO.getKey())
                 && authProfile.getOwner().equals(authProfileTO.getOwner())).
-                orElseThrow(() -> new 
DelegatedAdministrationException(AnyTypeKind.USER, authProfileTO.getOwner()));
+                orElseThrow(() -> new DelegatedAdministrationException(
+                SyncopeConstants.ROOT_REALM, AnyTypeKind.USER.name(), 
authProfileTO.getOwner()));
 
         update(authProfileTO);
     }
@@ -103,6 +105,6 @@ public class AuthProfileLogic extends 
AbstractAuthProfileLogic {
     public void selfDelete() {
         
authProfileDAO.deleteById(authProfileDAO.findByOwner(AuthContextUtils.getUsername()).
                 orElseThrow(() -> new DelegatedAdministrationException(
-                AnyTypeKind.USER, AuthContextUtils.getUsername())).getKey());
+                SyncopeConstants.ROOT_REALM, AnyTypeKind.USER.name(), 
AuthContextUtils.getUsername())).getKey());
     }
 }
diff --git 
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/DelegationLogic.java
 
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/DelegationLogic.java
index 0b3593a70a..3eaa6156fd 100644
--- 
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/DelegationLogic.java
+++ 
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/DelegationLogic.java
@@ -20,7 +20,7 @@ package org.apache.syncope.core.logic;
 
 import java.lang.reflect.Method;
 import java.util.List;
-import java.util.stream.Stream;
+import java.util.Set;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.DelegationTO;
@@ -30,6 +30,7 @@ import 
org.apache.syncope.core.persistence.api.dao.DelegationDAO;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.Delegation;
+import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.data.DelegationDataBinder;
 import org.apache.syncope.core.spring.security.AuthContextUtils;
 import 
org.apache.syncope.core.spring.security.DelegatedAdministrationException;
@@ -55,12 +56,13 @@ public class DelegationLogic extends 
AbstractTransactionalLogic<DelegationTO> {
     }
 
     protected void securityChecks(final String delegating, final String 
entitlement) {
-        if (!AuthContextUtils.getAuthorizations().containsKey(entitlement)
+        Set<String> realms = 
AuthContextUtils.getAuthorizations().getOrDefault(entitlement, Set.of());
+
+        if (realms.isEmpty()
                 && (delegating == null || 
!delegating.equals(userDAO.findKey(AuthContextUtils.getUsername()).
                         orElseThrow(() -> new NotFoundException("Could not 
find authenticated user"))))) {
 
-            throw new DelegatedAdministrationException(
-                    SyncopeConstants.ROOT_REALM, AnyTypeKind.USER.name(), 
delegating);
+            throw new DelegatedAdministrationException(realms.toString(), 
AnyTypeKind.USER.name(), delegating);
         }
     }
 
@@ -78,14 +80,14 @@ public class DelegationLogic extends 
AbstractTransactionalLogic<DelegationTO> {
     @PreAuthorize("isAuthenticated()")
     @Transactional(readOnly = true)
     public List<DelegationTO> list() {
-        Stream<DelegationTO> delegations = 
delegationDAO.findAll().stream().map(binder::getDelegationTO);
-
-        if 
(!AuthContextUtils.getAuthorizations().containsKey(IdRepoEntitlement.DELEGATION_LIST))
 {
-            String authUserKey = 
userDAO.findKey(AuthContextUtils.getUsername()).orElse(null);
-            delegations = delegations.filter(delegation -> 
delegation.getDelegating().equals(authUserKey));
+        if 
(AuthContextUtils.getAuthorizations().containsKey(IdRepoEntitlement.DELEGATION_LIST))
 {
+            return 
delegationDAO.findAll().stream().map(binder::getDelegationTO).toList();
         }
 
-        return delegations.toList();
+        User delegating = 
userDAO.findByUsername(AuthContextUtils.getUsername()).
+                orElseThrow(() -> new NotFoundException("User " + 
AuthContextUtils.getUsername()));
+
+        return 
delegationDAO.findByDelegating(delegating).stream().map(binder::getDelegationTO).toList();
     }
 
     @PreAuthorize("isAuthenticated()")
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DelegationDataBinderImpl.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DelegationDataBinderImpl.java
index 8a0ce23e34..6b204553b1 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DelegationDataBinderImpl.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DelegationDataBinderImpl.java
@@ -18,20 +18,24 @@
  */
 package org.apache.syncope.core.provisioning.java.data;
 
-import java.util.Iterator;
-import java.util.stream.Collectors;
+import java.util.Set;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.DelegationTO;
 import org.apache.syncope.common.lib.to.RoleTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.IdRepoEntitlement;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.Delegation;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Role;
 import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.api.utils.RealmUtils;
 import org.apache.syncope.core.provisioning.api.data.DelegationDataBinder;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import 
org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -75,29 +79,43 @@ public class DelegationDataBinderImpl implements 
DelegationDataBinder {
         delegation.setStart(delegationTO.getStart());
         delegation.setEnd(delegationTO.getEnd());
 
+        String entitlement = delegation.getKey() == null
+                ? IdRepoEntitlement.DELEGATION_CREATE
+                : IdRepoEntitlement.DELEGATION_UPDATE;
+        Set<String> allowedRealms = 
AuthContextUtils.getAuthorizations().get(entitlement);
+
         // 1. add or update all (valid) roles from TO
-        delegationTO.getRoles().forEach(roleTO -> {
-            if (roleTO == null) {
+        delegationTO.getRoles().forEach(roleKey -> {
+            if (roleKey == null) {
                 LOG.error("Null {}", RoleTO.class.getSimpleName());
             } else {
-                Role role = roleDAO.findById(roleTO).
-                        orElseThrow(() -> {
-                            SyncopeClientException sce = 
SyncopeClientException.build(ClientExceptionType.InvalidRole);
-                            sce.getElements().add("Role " + roleTO + " not 
found");
-                            return sce;
-                        });
-
-                delegation.add(role);
+                Role role = roleDAO.findById(roleKey).orElseThrow(() -> {
+                    SyncopeClientException sce = 
SyncopeClientException.build(ClientExceptionType.InvalidRole);
+                    sce.getElements().add("Role " + roleKey + " not found");
+                    return sce;
+                });
+
+                if (delegation.getDelegating().getRoles().contains(role)) {
+                    if (role.getRealms().stream().
+                            anyMatch(realm -> 
!RealmUtils.getEffective(allowedRealms, realm.getFullPath()).isEmpty())) {
+
+                        delegation.add(role);
+                    } else {
+                        throw new DelegatedAdministrationException(
+                                
role.getRealms().stream().map(Realm::getKey).toList().toString(),
+                                Role.class.getSimpleName(),
+                                role.getKey());
+                    }
+                } else {
+                    SyncopeClientException sce = 
SyncopeClientException.build(ClientExceptionType.InvalidRole);
+                    sce.getElements().add("Role " + roleKey + " not owned by 
delegating User");
+                    throw sce;
+                }
             }
         });
 
         // 2. remove all roles not contained in the TO
-        for (Iterator<? extends Role> itor = delegation.getRoles().iterator(); 
itor.hasNext();) {
-            Role role = itor.next();
-            if (delegationTO.getRoles().stream().noneMatch(roleKey -> 
roleKey.equals(role.getKey()))) {
-                itor.remove();
-            }
-        }
+        delegation.getRoles().removeIf(role -> 
!delegationTO.getRoles().contains(role.getKey()));
 
         return delegation;
     }
@@ -111,7 +129,7 @@ public class DelegationDataBinderImpl implements 
DelegationDataBinder {
         delegationTO.setDelegated(delegation.getDelegated().getKey());
         delegationTO.setStart(delegation.getStart());
         delegationTO.setEnd(delegation.getEnd());
-        
delegationTO.getRoles().addAll(delegation.getRoles().stream().map(Role::getKey).collect(Collectors.toSet()));
+        
delegationTO.getRoles().addAll(delegation.getRoles().stream().map(Role::getKey).toList());
 
         return delegationTO;
     }
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index a954aadafa..9d6bb0009b 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.core.provisioning.java.data;
 
 import java.text.ParseException;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
 import java.util.stream.Stream;
@@ -219,12 +218,7 @@ public class ResourceDataBinderImpl implements 
ResourceDataBinder {
         });
 
         // 2. remove all provisions not contained in the TO
-        for (Iterator<Provision> itor = resource.getProvisions().iterator(); 
itor.hasNext();) {
-            Provision provision = itor.next();
-            if (resourceTO.getProvision(provision.getAnyType()).isEmpty()) {
-                itor.remove();
-            }
-        }
+        resource.getProvisions().removeIf(provision -> 
resourceTO.getProvision(provision.getAnyType()).isEmpty());
 
         // 3. orgUnit
         if (resourceTO.getOrgUnit() == null && resource.getOrgUnit() != null) {
diff --git 
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
 
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
index 779f89e2f4..fc1eb31a73 100644
--- 
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
+++ 
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.core.spring.security;
 
 import java.util.Optional;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
 
 public class DelegatedAdministrationException extends RuntimeException {
 
@@ -29,8 +28,4 @@ public class DelegatedAdministrationException extends 
RuntimeException {
         super("Missing entitlement or realm administration under " + realm + " 
for "
                 + Optional.ofNullable(key).map(s -> type + ' ' + 
s).orElseGet(() -> "new " + type));
     }
-
-    public DelegatedAdministrationException(final AnyTypeKind type, final 
String key) {
-        super("The requested UPDATE would alter the set of dynamic realms for 
" + type + ' ' + key);
-    }
 }

Reply via email to