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 a08c3dd5ae Ensure consistency of startsWith predicates about Realms
(#1489)
a08c3dd5ae is described below
commit a08c3dd5ae02247b84b1eb1c002c26be4d5e6279
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Wed Aug 12 11:07:43 2026 +0200
Ensure consistency of startsWith predicates about Realms (#1489)
---
.../apache/syncope/core/logic/ConnectorLogic.java | 4 +--
.../apache/syncope/core/logic/ResourceLogic.java | 5 ++--
.../org/apache/syncope/core/logic/RealmLogic.java | 8 +++---
.../org/apache/syncope/core/logic/TaskLogic.java | 5 ++--
.../core/persistence/api/utils/RealmUtils.java | 31 +++++++++++++---------
.../core/persistence/api/utils/RealmUtilsTest.java | 12 ++++-----
.../jpa/dao/AbstractJPAAnySearchDAO.java | 2 +-
.../jpa/dao/repo/AnyObjectRepoExtImpl.java | 2 +-
.../jpa/dao/repo/ConnInstanceRepoExtImpl.java | 9 ++++---
.../jpa/dao/repo/ExternalResourceRepoExtImpl.java | 5 ++--
.../persistence/jpa/dao/repo/GroupRepoExtImpl.java | 2 +-
.../persistence/jpa/dao/repo/UserRepoExtImpl.java | 2 +-
.../persistence/neo4j/dao/Neo4jAnySearchDAO.java | 2 +-
.../neo4j/dao/repo/AnyObjectRepoExtImpl.java | 2 +-
.../neo4j/dao/repo/ConnInstanceRepoExtImpl.java | 11 ++++----
.../dao/repo/ExternalResourceRepoExtImpl.java | 5 ++--
.../neo4j/dao/repo/GroupRepoExtImpl.java | 2 +-
.../neo4j/dao/repo/UserRepoExtImpl.java | 2 +-
.../dao/ElasticsearchAnySearchDAO.java | 2 +-
.../opensearch/dao/OpenSearchAnySearchDAO.java | 2 +-
20 files changed, 62 insertions(+), 53 deletions(-)
diff --git
a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
index 8441ba8109..9b955043dc 100644
---
a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
+++
b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
@@ -80,8 +80,8 @@ public class ConnectorLogic extends
AbstractTransactionalLogic<ConnInstanceTO> {
this.binder = binder;
}
- protected void securityChecks(final Set<String> effectiveRealms, final
String realm, final String key) {
- if (effectiveRealms.stream().noneMatch(realm::startsWith)) {
+ protected void securityChecks(final Set<String> realms, final String
realm, final String key) {
+ if (!RealmUtils.SubtreePredicate.of(realms).test(realm)) {
throw new DelegatedAdministrationException(realm,
ConnInstance.class.getSimpleName(), key);
}
}
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 9346f71f6d..cdc63781ab 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,9 +107,8 @@ public class ResourceLogic extends
AbstractTransactionalLogic<ResourceTO> {
this.anyUtilsFactory = anyUtilsFactory;
}
- protected void securityChecks(final Set<String> effectiveRealms, final
String realm, final String key) {
- boolean authorized =
effectiveRealms.stream().anyMatch(realm::startsWith);
- if (!authorized) {
+ 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);
}
}
diff --git
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
index bf297dac35..f8c9bc57d6 100644
---
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
+++
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
@@ -50,6 +50,7 @@ import
org.apache.syncope.core.persistence.api.entity.ExternalResource;
import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.persistence.api.search.SyncopePage;
+import org.apache.syncope.core.persistence.api.utils.RealmUtils;
import org.apache.syncope.core.provisioning.api.PropagationByResource;
import org.apache.syncope.core.provisioning.api.data.RealmDataBinder;
import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
@@ -110,9 +111,8 @@ public class RealmLogic extends
AbstractTransactionalLogic<RealmTO> {
this.taskExecutor = taskExecutor;
}
- protected void securityChecks(final Set<String> effectiveRealms, final
String realm) {
- boolean authorized =
effectiveRealms.stream().anyMatch(realm::startsWith);
- if (!authorized) {
+ protected void securityChecks(final Set<String> realms, final String
realm) {
+ if (!RealmUtils.SubtreePredicate.of(realms).test(realm)) {
throw new DelegatedAdministrationException(
realm, User.class.getSimpleName(),
AuthContextUtils.getUsername());
}
@@ -143,7 +143,7 @@ public class RealmLogic extends
AbstractTransactionalLogic<RealmTO> {
getOrDefault(IdRepoEntitlement.REALM_SEARCH, Set.of());
List<RealmTO> result = realmSearchDAO.search(baseRealms,
effectiveCond, pageable).stream().
map(realm -> binder.getRealmTO(
- realm, authorizations.stream().anyMatch(auth ->
realm.getFullPath().startsWith(auth)))).
+ realm,
RealmUtils.SubtreePredicate.of(authorizations).test(realm.getFullPath()))).
sorted(Comparator.comparing(RealmTO::getFullPath)).
toList();
diff --git
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
index b4219713f0..b2356237e5 100644
---
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
+++
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
@@ -65,6 +65,7 @@ import
org.apache.syncope.core.persistence.api.entity.task.TaskUtils;
import org.apache.syncope.core.persistence.api.entity.task.TaskUtilsFactory;
import org.apache.syncope.core.persistence.api.search.SyncopePage;
import org.apache.syncope.core.persistence.api.utils.ExceptionUtils2;
+import org.apache.syncope.core.persistence.api.utils.RealmUtils;
import org.apache.syncope.core.provisioning.api.data.TaskDataBinder;
import org.apache.syncope.core.provisioning.api.job.JobManager;
import org.apache.syncope.core.provisioning.api.job.JobNamer;
@@ -127,8 +128,8 @@ public class TaskLogic extends
AbstractExecutableLogic<TaskTO> {
}
protected void securityChecks(final String entitlement, final String
realm) {
- Set<String> authRealms =
AuthContextUtils.getAuthorizations().getOrDefault(entitlement, Set.of());
- if (authRealms.isEmpty() ||
authRealms.stream().noneMatch(realm::startsWith)) {
+ Set<String> realms =
AuthContextUtils.getAuthorizations().getOrDefault(entitlement, Set.of());
+ if (!RealmUtils.SubtreePredicate.of(realms).test(realm)) {
throw new DelegatedAdministrationException(realm,
MacroTask.class.getSimpleName(), null);
}
}
diff --git
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/utils/RealmUtils.java
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/utils/RealmUtils.java
index 2c450abba3..e887f400b0 100644
---
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/utils/RealmUtils.java
+++
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/utils/RealmUtils.java
@@ -28,8 +28,8 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
-import java.util.stream.Collectors;
import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.lang3.Strings;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
@@ -53,9 +53,9 @@ public class RealmUtils {
boolean dontAdd = false;
Set<String> toRemove = new HashSet<>();
for (String realm : realms) {
- if (newRealm.startsWith(realm)) {
+ if (subtree(newRealm, realm)) {
dontAdd = true;
- } else if (realm.startsWith(newRealm)) {
+ } else if (subtree(realm, newRealm)) {
toRemove.add(realm);
}
}
@@ -86,31 +86,36 @@ public class RealmUtils {
}
}
- private static class StartsWithPredicate implements Predicate<String> {
+ public static final class SubtreePredicate implements Predicate<String> {
- private final Collection<String> targets;
+ public static SubtreePredicate of(final Collection<String> targets) {
+ return new SubtreePredicate(targets);
+ }
+
+ private final Collection<String> candidates;
- StartsWithPredicate(final Collection<String> targets) {
- this.targets = targets;
+ private SubtreePredicate(final Collection<String> candidates) {
+ this.candidates = candidates;
}
@Override
public boolean test(final String realm) {
- return targets.stream().anyMatch(realm::startsWith);
+ return candidates.stream().anyMatch(candidate -> subtree(realm,
candidate));
}
}
+ public static boolean subtree(final String realm, final String prefix) {
+ return realm.equals(prefix) ||
realm.startsWith(Strings.CS.appendIfMissing(prefix, "/"));
+ }
+
public static Set<String> getEffective(final Set<String> allowedRealms,
final String requestedRealm) {
NormalizedRealms normalized = NormalizedRealms.of(allowedRealms);
Set<String> requested = Set.of(requestedRealm);
- StartsWithPredicate normalizedFilter = new
StartsWithPredicate(normalized.realms());
- StartsWithPredicate requestedFilter = new
StartsWithPredicate(requested);
-
Set<String> effective = new HashSet<>();
-
effective.addAll(requested.stream().filter(normalizedFilter).collect(Collectors.toSet()));
-
effective.addAll(normalized.realms().stream().filter(requestedFilter).collect(Collectors.toSet()));
+
effective.addAll(requested.stream().filter(SubtreePredicate.of(normalized.realms())).toList());
+
effective.addAll(normalized.realms().stream().filter(SubtreePredicate.of(requested)).toList());
// includes manager
effective.addAll(normalized.managerRealms());
diff --git
a/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/utils/RealmUtilsTest.java
b/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/utils/RealmUtilsTest.java
index 2e9ce5ea51..e930384b6f 100644
---
a/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/utils/RealmUtilsTest.java
+++
b/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/utils/RealmUtilsTest.java
@@ -50,16 +50,16 @@ public class RealmUtilsTest extends AbstractTest {
@Test
public void normalizingAddTo() {
Set<String> realms = new HashSet<>();
- realms.add("realm1");
- realms.add("realm2");
- String newRealm = "realm123";
+ realms.add("/realm1");
+ realms.add("/realm2");
+ String newRealm = "/realm1/23";
assertFalse(RealmUtils.normalizingAddTo(realms, newRealm));
assertEquals(2, realms.size());
realms.clear();
- realms.add("testRealm1");
- realms.add("realm2");
- newRealm = "test";
+ realms.add("/test/realm1");
+ realms.add("/realm2");
+ newRealm = "/test";
assertTrue(RealmUtils.normalizingAddTo(realms, newRealm));
assertEquals(2, realms.size());
}
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAAnySearchDAO.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAAnySearchDAO.java
index 53892a8393..1a9e660d58 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAAnySearchDAO.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAAnySearchDAO.java
@@ -660,7 +660,7 @@ abstract class AbstractJPAAnySearchDAO extends
AbstractAnySearchDAO {
stream().map(Realm::getKey).toList());
}));
} else {
- if (adminRealms.stream().anyMatch(r ->
r.startsWith(base.getFullPath()))) {
+ if
(RealmUtils.SubtreePredicate.of(adminRealms).test(base.getFullPath())) {
realmKeys.add(base.getKey());
}
}
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AnyObjectRepoExtImpl.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AnyObjectRepoExtImpl.java
index f0785ef732..7f723271b3 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AnyObjectRepoExtImpl.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AnyObjectRepoExtImpl.java
@@ -131,7 +131,7 @@ public class AnyObjectRepoExtImpl extends
AbstractAnyRepoExt<AnyObject> implemen
// 2. check if anyObject is in Realm (or descendants) for which
AuthContextUtils.getUsername() owns entitlement
if (!authorized) {
- authorized = authRealms.stream().anyMatch(realm::startsWith);
+ authorized =
RealmUtils.SubtreePredicate.of(authRealms).test(realm);
}
if (!authorized) {
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/ConnInstanceRepoExtImpl.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/ConnInstanceRepoExtImpl.java
index a865725bcc..ca29d7947c 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/ConnInstanceRepoExtImpl.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/ConnInstanceRepoExtImpl.java
@@ -26,10 +26,12 @@ import org.apache.syncope.common.lib.types.IdMEntitlement;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.entity.ConnInstance;
import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+import org.apache.syncope.core.persistence.api.utils.RealmUtils;
import org.apache.syncope.core.persistence.jpa.entity.JPAConnInstance;
import org.apache.syncope.core.spring.security.AuthContextUtils;
import
org.apache.syncope.core.spring.security.DelegatedAdministrationException;
import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
public class ConnInstanceRepoExtImpl implements ConnInstanceRepoExt {
@@ -51,9 +53,8 @@ public class ConnInstanceRepoExtImpl implements
ConnInstanceRepoExt {
}
Set<String> authRealms =
AuthContextUtils.getAuthorizations().get(IdMEntitlement.CONNECTOR_READ);
- if (authRealms == null || authRealms.isEmpty()
- || authRealms.stream().noneMatch(
- realm ->
connInstance.getAdminRealm().getFullPath().startsWith(realm))) {
+ if (CollectionUtils.isEmpty(authRealms)
+ ||
!RealmUtils.SubtreePredicate.of(authRealms).test(connInstance.getAdminRealm().getFullPath()))
{
throw new DelegatedAdministrationException(
connInstance.getAdminRealm().getFullPath(),
@@ -75,7 +76,7 @@ public class ConnInstanceRepoExtImpl implements
ConnInstanceRepoExt {
"SELECT e FROM " + JPAConnInstance.class.getSimpleName() + "
e", ConnInstance.class);
return query.getResultList().stream().filter(connInstance ->
authRealms.stream().
- anyMatch(realm ->
connInstance.getAdminRealm().getFullPath().startsWith(realm))).
+ anyMatch(realm ->
RealmUtils.subtree(connInstance.getAdminRealm().getFullPath(), realm))).
toList();
}
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/ExternalResourceRepoExtImpl.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/ExternalResourceRepoExtImpl.java
index c8553fed17..099e184600 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/ExternalResourceRepoExtImpl.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/ExternalResourceRepoExtImpl.java
@@ -38,6 +38,7 @@ import
org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
import org.apache.syncope.core.persistence.api.entity.policy.Policy;
import org.apache.syncope.core.persistence.api.entity.policy.PropagationPolicy;
import org.apache.syncope.core.persistence.api.entity.policy.PushPolicy;
+import org.apache.syncope.core.persistence.api.utils.RealmUtils;
import org.apache.syncope.core.persistence.jpa.entity.JPAExternalResource;
import org.apache.syncope.core.spring.security.AuthContextUtils;
import
org.apache.syncope.core.spring.security.DelegatedAdministrationException;
@@ -84,7 +85,7 @@ public class ExternalResourceRepoExtImpl implements
ExternalResourceRepoExt {
Set<String> authRealms =
AuthContextUtils.getAuthorizations().get(IdMEntitlement.RESOURCE_READ);
if (authRealms == null || authRealms.isEmpty()
|| authRealms.stream().noneMatch(realm ->
resource.getConnector() != null
- &&
resource.getConnector().getAdminRealm().getFullPath().startsWith(realm))) {
+ &&
RealmUtils.subtree(resource.getConnector().getAdminRealm().getFullPath(),
realm))) {
throw new DelegatedAdministrationException(
resource.getConnector().getAdminRealm().getFullPath(),
@@ -132,7 +133,7 @@ public class ExternalResourceRepoExtImpl implements
ExternalResourceRepoExt {
return query.getResultList().stream().filter(resource ->
authRealms.stream().
anyMatch(realm -> resource.getConnector() != null
- &&
resource.getConnector().getAdminRealm().getFullPath().startsWith(realm))).
+ &&
RealmUtils.subtree(resource.getConnector().getAdminRealm().getFullPath(),
realm))).
toList();
}
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepoExtImpl.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepoExtImpl.java
index 4e810a2b1a..ba53327d3f 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepoExtImpl.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepoExtImpl.java
@@ -103,7 +103,7 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group> implements Group
// 1. check if group is in Realm (or descendants) for which
AuthContextUtils.getUsername() owns entitlement
if (!authorized) {
- authorized = authRealms.stream().anyMatch(realm::startsWith);
+ authorized =
RealmUtils.SubtreePredicate.of(authRealms).test(realm);
}
if (!authorized) {
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/UserRepoExtImpl.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/UserRepoExtImpl.java
index 62621ed493..3c0fa93ebe 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/UserRepoExtImpl.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/UserRepoExtImpl.java
@@ -233,7 +233,7 @@ public class UserRepoExtImpl extends
AbstractAnyRepoExt<User> implements UserRep
// 2. check if user is in Realm (or descendants) for which
AuthContextUtils.getUsername() owns entitlement
if (!authorized) {
- authorized = authRealms.stream().anyMatch(realm::startsWith);
+ authorized =
RealmUtils.SubtreePredicate.of(authRealms).test(realm);
}
if (!authorized) {
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAnySearchDAO.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAnySearchDAO.java
index 39c976238c..2842f82944 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAnySearchDAO.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAnySearchDAO.java
@@ -215,7 +215,7 @@ public class Neo4jAnySearchDAO extends AbstractAnySearchDAO
{
stream().map(Realm::getKey).toList());
}));
} else {
- if (adminRealms.stream().anyMatch(r ->
r.startsWith(base.getFullPath()))) {
+ if
(RealmUtils.SubtreePredicate.of(adminRealms).test(base.getFullPath())) {
realmKeys.add(base.getKey());
}
}
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyObjectRepoExtImpl.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyObjectRepoExtImpl.java
index 6f9409c423..a9c76e6568 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyObjectRepoExtImpl.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyObjectRepoExtImpl.java
@@ -158,7 +158,7 @@ public class AnyObjectRepoExtImpl extends
AbstractAnyRepoExt<AnyObject, Neo4jAny
// 2. check if anyObject is in Realm (or descendants) for which
AuthContextUtils.getUsername() owns entitlement
if (!authorized) {
- authorized = authRealms.stream().anyMatch(realm::startsWith);
+ authorized =
RealmUtils.SubtreePredicate.of(authRealms).test(realm);
}
if (!authorized) {
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/ConnInstanceRepoExtImpl.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/ConnInstanceRepoExtImpl.java
index 80784d2d8e..cde58eddd7 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/ConnInstanceRepoExtImpl.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/ConnInstanceRepoExtImpl.java
@@ -24,12 +24,14 @@ import org.apache.syncope.common.lib.types.IdMEntitlement;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.entity.ConnInstance;
import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+import org.apache.syncope.core.persistence.api.utils.RealmUtils;
import org.apache.syncope.core.persistence.neo4j.entity.Neo4jConnInstance;
import org.apache.syncope.core.persistence.neo4j.spring.NodeValidator;
import org.apache.syncope.core.spring.security.AuthContextUtils;
import
org.apache.syncope.core.spring.security.DelegatedAdministrationException;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
public class ConnInstanceRepoExtImpl implements ConnInstanceRepoExt {
@@ -58,9 +60,8 @@ public class ConnInstanceRepoExtImpl implements
ConnInstanceRepoExt {
}
Set<String> authRealms =
AuthContextUtils.getAuthorizations().get(IdMEntitlement.CONNECTOR_READ);
- if (authRealms == null || authRealms.isEmpty()
- || authRealms.stream().noneMatch(
- realm ->
connInstance.getAdminRealm().getFullPath().startsWith(realm))) {
+ if (CollectionUtils.isEmpty(authRealms)
+ ||
!RealmUtils.SubtreePredicate.of(authRealms).test(connInstance.getAdminRealm().getFullPath()))
{
throw new DelegatedAdministrationException(
connInstance.getAdminRealm().getFullPath(),
@@ -79,7 +80,7 @@ public class ConnInstanceRepoExtImpl implements
ConnInstanceRepoExt {
}
return
neo4jTemplate.findAll(Neo4jConnInstance.class).stream().filter(connInstance ->
authRealms.stream().
- anyMatch(realm ->
connInstance.getAdminRealm().getFullPath().startsWith(realm))).
+ anyMatch(realm ->
RealmUtils.subtree(connInstance.getAdminRealm().getFullPath(), realm))).
toList();
}
@@ -95,7 +96,7 @@ public class ConnInstanceRepoExtImpl implements
ConnInstanceRepoExt {
public void deleteById(final String key) {
neo4jTemplate.findById(key,
Neo4jConnInstance.class).ifPresent(connInstance -> {
connInstance.getResources().stream().
-
map(ExternalResource::getKey).toList().forEach(resourceDAO::deleteById);
+
map(ExternalResource::getKey).toList().forEach(resourceDAO::deleteById);
neo4jTemplate.deleteById(key, Neo4jConnInstance.class);
});
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/ExternalResourceRepoExtImpl.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/ExternalResourceRepoExtImpl.java
index a0115498e8..a54c1fffbd 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/ExternalResourceRepoExtImpl.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/ExternalResourceRepoExtImpl.java
@@ -39,6 +39,7 @@ import
org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
import org.apache.syncope.core.persistence.api.entity.policy.Policy;
import org.apache.syncope.core.persistence.api.entity.policy.PropagationPolicy;
import org.apache.syncope.core.persistence.api.entity.policy.PushPolicy;
+import org.apache.syncope.core.persistence.api.utils.RealmUtils;
import org.apache.syncope.core.persistence.neo4j.dao.AbstractDAO;
import org.apache.syncope.core.persistence.neo4j.entity.EntityCacheKey;
import org.apache.syncope.core.persistence.neo4j.entity.Neo4jConnInstance;
@@ -112,7 +113,7 @@ public class ExternalResourceRepoExtImpl extends
AbstractDAO implements External
Set<String> authRealms =
AuthContextUtils.getAuthorizations().get(IdMEntitlement.RESOURCE_READ);
if (authRealms == null || authRealms.isEmpty()
|| authRealms.stream().noneMatch(realm ->
resource.getConnector() != null
- &&
resource.getConnector().getAdminRealm().getFullPath().startsWith(realm))) {
+ &&
RealmUtils.subtree(resource.getConnector().getAdminRealm().getFullPath(),
realm))) {
throw new DelegatedAdministrationException(
resource.getConnector().getAdminRealm().getFullPath(),
@@ -196,7 +197,7 @@ public class ExternalResourceRepoExtImpl extends
AbstractDAO implements External
cache);
return all.stream().filter(resource -> authRealms.stream().
anyMatch(realm -> resource.getConnector() != null
- &&
resource.getConnector().getAdminRealm().getFullPath().startsWith(realm))).
+ &&
RealmUtils.subtree(resource.getConnector().getAdminRealm().getFullPath(),
realm))).
toList();
}
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepoExtImpl.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepoExtImpl.java
index 1cc08e6ade..1af911e9c2 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepoExtImpl.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepoExtImpl.java
@@ -148,7 +148,7 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group, Neo4jGroup> impl
// 1. check if group is in Realm (or descendants) for which
AuthContextUtils.getUsername() owns entitlement
if (!authorized) {
- authorized = authRealms.stream().anyMatch(realm::startsWith);
+ authorized =
RealmUtils.SubtreePredicate.of(authRealms).test(realm);
}
if (!authorized) {
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/UserRepoExtImpl.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/UserRepoExtImpl.java
index c14af7caad..12874546eb 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/UserRepoExtImpl.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/UserRepoExtImpl.java
@@ -259,7 +259,7 @@ public class UserRepoExtImpl extends
AbstractAnyRepoExt<User, Neo4jUser> impleme
// 2. check if user is in Realm (or descendants) for which
AuthContextUtils.getUsername() owns entitlement
if (!authorized) {
- authorized = authRealms.stream().anyMatch(realm::startsWith);
+ authorized =
RealmUtils.SubtreePredicate.of(authRealms).test(realm);
}
if (!authorized) {
diff --git
a/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchAnySearchDAO.java
b/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchAnySearchDAO.java
index 986176cc8b..1288133f31 100644
---
a/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchAnySearchDAO.java
+++
b/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchAnySearchDAO.java
@@ -149,7 +149,7 @@ public class ElasticsearchAnySearchDAO extends
AbstractAnySearchDAO {
build()));
}));
} else {
- if (adminRealms.stream().anyMatch(r ->
r.startsWith(base.getFullPath()))) {
+ if
(RealmUtils.SubtreePredicate.of(adminRealms).test(base.getFullPath())) {
queries.add(new Query.Builder().term(QueryBuilders.term().
field("realm").value(base.getKey()).caseInsensitive(false).build()).
build());
diff --git
a/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchAnySearchDAO.java
b/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchAnySearchDAO.java
index d27fb819f1..ea30d7a6c4 100644
---
a/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchAnySearchDAO.java
+++
b/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchAnySearchDAO.java
@@ -148,7 +148,7 @@ public class OpenSearchAnySearchDAO extends
AbstractAnySearchDAO {
build()));
}));
} else {
- if (adminRealms.stream().anyMatch(r ->
r.startsWith(base.getFullPath()))) {
+ if
(RealmUtils.SubtreePredicate.of(adminRealms).test(base.getFullPath())) {
queries.add(new Query.Builder().term(QueryBuilders.term().
field("realm").value(FieldValue.of(base.getKey())).caseInsensitive(false).build()).
build());