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 32cf119474 [SYNCOPE-1999] Fixing managed users / groups / any objects
find operations (#1557)
32cf119474 is described below
commit 32cf1194742fbb51158de57c3841cd80eb14c2c8
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Fri Sep 25 08:23:22 2026 +0200
[SYNCOPE-1999] Fixing managed users / groups / any objects find operations
(#1557)
---
.../syncope/core/persistence/api/dao/GroupDAO.java | 78 ++++--
.../syncope/core/persistence/api/dao/UserDAO.java | 49 ++++
.../core/persistence/jpa/dao/repo/GroupRepo.java | 16 --
.../persistence/jpa/dao/repo/GroupRepoExt.java | 26 +-
.../persistence/jpa/dao/repo/GroupRepoExtImpl.java | 198 ++++++++++-----
.../persistence/jpa/dao/repo/UserRepoExtImpl.java | 63 +++--
.../core/persistence/jpa/outer/GroupTest.java | 28 ---
.../core/persistence/jpa/outer/ManagerTest.java | 270 +++++++++++++++++++++
.../core/persistence/neo4j/dao/repo/GroupRepo.java | 46 ----
.../persistence/neo4j/dao/repo/GroupRepoExt.java | 26 +-
.../neo4j/dao/repo/GroupRepoExtImpl.java | 238 ++++++++++++------
.../neo4j/dao/repo/UserRepoExtImpl.java | 127 ++++++----
.../core/persistence/neo4j/outer/GroupTest.java | 27 ---
.../core/persistence/neo4j/outer/ManagerTest.java | 259 ++++++++++++++++++++
.../syncope/core/starter/SelfKeymasterContext.java | 2 +-
.../core/spring/security/AuthDataAccessor.java | 55 +++--
pom.xml | 54 ++---
17 files changed, 1164 insertions(+), 398 deletions(-)
diff --git
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/GroupDAO.java
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/GroupDAO.java
index c92aa39317..19a6b8a0d5 100644
---
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/GroupDAO.java
+++
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/GroupDAO.java
@@ -38,9 +38,13 @@ public interface GroupDAO extends AnyDAO<Group> {
Optional<? extends Group> findByName(String name);
+ List<String> findKeysByNamePattern(String pattern);
+
@Override
Collection<String> findAllResourceKeys(String key);
+ Map<String, Long> countByRealm();
+
/**
* Checks if the calling user is authorized to access the Group matching
the provided key, under the given
* realm.
@@ -51,33 +55,73 @@ public interface GroupDAO extends AnyDAO<Group> {
*/
void securityChecks(Set<String> authRealms, String key, String realm);
- boolean isManager(String key);
-
- List<User> findManagedUsers(String key);
-
- List<Group> findManagedGroups(String key);
-
- List<AnyObject> findManagedAnyObjects(String key);
-
- Map<String, Long> countByRealm();
+ long countUMembers(String groupKey);
- List<String> findKeysByNamePattern(String pattern);
+ List<String> findUMembers(String groupKey);
- List<AMembership> findAMemberships(Group group);
+ boolean existsUMembership(String userKey, String groupKey);
List<UMembership> findUMemberships(Group group, Pageable pageable);
- List<String> findAMembers(String groupKey);
+ long countAMembers(String groupKey);
- List<String> findUMembers(String groupKey);
+ List<String> findAMembers(String groupKey);
boolean existsAMembership(String anyObjectKey, String groupKey);
- boolean existsUMembership(String userKey, String groupKey);
+ List<AMembership> findAMemberships(Group group);
- long countAMembers(String groupKey);
+ List<GroupTypeExtension> findTypeExtensions(AnyTypeClass anyTypeClass);
- long countUMembers(String groupKey);
+ boolean isManager(String key);
- List<GroupTypeExtension> findTypeExtensions(AnyTypeClass anyTypeClass);
+ /**
+ * Returns all users managed by the group for the given key.
+ *
+ * Given:
+ * * group G1 for the provided key
+ * * group G2, with user member U
+ *
+ * then we have 2 cases where U is managed by G1:
+ *
+ * (a) U has gManager set to G1
+ * (b) G2 has gManager set to G1
+ *
+ * @param key manager key
+ * @return users managed by the group for the given key
+ */
+ List<User> findManagedUsers(String key);
+
+ /**
+ * Returns all groups managed by the group for the given key.
+ *
+ * Given:
+ * * group G1 for the provided key
+ * * group G2
+ *
+ * then we have 1 case where G2 is managed by G1:
+ *
+ * (a) G2 has gManager set to G1
+ *
+ * @param key manager key
+ * @return groups managed by the group for the given key
+ */
+ List<Group> findManagedGroups(String key);
+
+ /**
+ * Returns all any objects managed by the group for the given key.
+ *
+ * Given:
+ * * group G1 for the provided key
+ * * group G2, with any object member O
+ *
+ * then we have 2 cases where O is managed by G1:
+ *
+ * (a) O has gManager set to G1
+ * (b) G2 has gManager set to G1
+ *
+ * @param key manager key
+ * @return any objects managed by the group for the given key
+ */
+ List<AnyObject> findManagedAnyObjects(String key);
}
diff --git
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
index 38adb15061..742976fc1a 100644
---
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
+++
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
@@ -51,10 +51,59 @@ public interface UserDAO extends AnyDAO<User> {
boolean isManager(String key);
+ /**
+ * Returns all users managed by the user for the given key.
+ *
+ * Given:
+ * * user U1 for the provided key, member of group G1
+ * * user U2, member of group G2
+ *
+ * then we have 4 cases where U2 is managed by U1:
+ *
+ * (a) U2 has uManager set to U1
+ * (b) G2 has uManager set to U1
+ * (c) U2 has gManager set to G1
+ * (d) G2 has gManager set to G1
+ *
+ * @param key manager key
+ * @return users managed by the user for the given key
+ */
List<User> findManagedUsers(String key);
+ /**
+ * Returns all groups managed by the user for the given key.
+ *
+ * Given:
+ * * user U1 for the provided key, member of group G1
+ * * group G2
+ *
+ * then we have 2 cases where G2 is managed by U1:
+ *
+ * (a) G2 has uManager set to U1
+ * (b) G2 has gManager set to G1
+ *
+ * @param key manager key
+ * @return groups managed by the user for the given key
+ */
List<Group> findManagedGroups(String key);
+ /**
+ * Returns all any objects managed by the user for the given key.
+ *
+ * Given:
+ * * user U for the provided key, member of group G1
+ * * any object O, member of group G2
+ *
+ * then we have 4 cases where O is managed by U:
+ *
+ * (a) O has uManager set to U
+ * (b) G2 has uManager set to U
+ * (c) O has gManager set to G1
+ * (d) G2 has gManager set to G1
+ *
+ * @param key manager key
+ * @return any objects managed by the user for the given key
+ */
List<AnyObject> findManagedAnyObjects(String key);
Map<String, Long> countByRealm();
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepo.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepo.java
index d992d45aa0..a49692428e 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepo.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepo.java
@@ -41,20 +41,4 @@ public interface GroupRepo
@Query("SELECT e FROM #{#entityName} e WHERE e.id IN (:keys)")
@Override
List<Group> findByKeys(@Param("keys") List<String> keys);
-
- @Query("SELECT DISTINCT e.leftEnd.id FROM JPAAMembership e WHERE
e.rightEnd.id = :groupKey")
- @Override
- List<String> findAMembers(@Param("groupKey") String groupKey);
-
- @Query("SELECT DISTINCT e.leftEnd.id FROM JPAUMembership e WHERE
e.rightEnd.id = :groupKey")
- @Override
- List<String> findUMembers(@Param("groupKey") String groupKey);
-
- @Query("SELECT COUNT(DISTINCT e.leftEnd.id) FROM JPAAMembership e WHERE
e.rightEnd.id = :groupKey")
- @Override
- long countAMembers(@Param("groupKey") String groupKey);
-
- @Query("SELECT COUNT(DISTINCT e.leftEnd.id) FROM JPAUMembership e WHERE
e.rightEnd.id = :groupKey")
- @Override
- long countUMembers(@Param("groupKey") String groupKey);
}
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepoExt.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepoExt.java
index 2a4cd46d99..e161420c32 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepoExt.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/GroupRepoExt.java
@@ -32,28 +32,36 @@ import org.springframework.data.domain.Pageable;
public interface GroupRepoExt extends AnyRepoExt<Group> {
+ Map<String, Long> countByRealm();
+
void securityChecks(Set<String> authRealms, String key, String realm);
- boolean isManager(String key);
+ long countUMembers(String groupKey);
- List<User> findManagedUsers(String key);
+ List<String> findUMembers(String groupKey);
- List<Group> findManagedGroups(String key);
+ boolean existsUMembership(String userKey, String groupKey);
- List<AnyObject> findManagedAnyObjects(String key);
+ List<UMembership> findUMemberships(Group group, Pageable pageable);
- Map<String, Long> countByRealm();
+ long countAMembers(String groupKey);
- boolean existsAMembership(String anyObjectKey, String groupKey);
+ List<String> findAMembers(String groupKey);
- boolean existsUMembership(String userKey, String groupKey);
+ boolean existsAMembership(String anyObjectKey, String groupKey);
List<AMembership> findAMemberships(Group group);
- List<UMembership> findUMemberships(Group group, Pageable pageable);
-
List<GroupTypeExtension> findTypeExtensions(AnyTypeClass anyTypeClass);
+ boolean isManager(String key);
+
+ List<User> findManagedUsers(String key);
+
+ List<Group> findManagedGroups(String key);
+
+ List<AnyObject> findManagedAnyObjects(String key);
+
@Override
<S extends Group> S save(S group);
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 ba53327d3f..8ccbbcf749 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
@@ -21,12 +21,15 @@ package org.apache.syncope.core.persistence.jpa.dao.repo;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.persistence.TypedQuery;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
@@ -88,6 +91,25 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group> implements Group
this.anyObjectDAO = anyObjectDAO;
}
+ @Override
+ public Collection<String> findAllResourceKeys(final String key) {
+ return findById(key).map(Any::getResources).
+ orElseGet(List::of).
+ stream().map(ExternalResource::getKey).toList();
+ }
+
+ @Override
+ public Map<String, Long> countByRealm() {
+ Query query = entityManager.createQuery(
+ "SELECT e.realm, COUNT(e) FROM " +
anyUtils.anyClass().getSimpleName() + " e GROUP BY e.realm");
+
+ @SuppressWarnings("unchecked")
+ List<Object[]> results = query.getResultList();
+ return results.stream().collect(Collectors.toMap(
+ result -> ((Realm) result[0]).getFullPath(),
+ result -> ((Number) result[1]).longValue()));
+ }
+
@Transactional(readOnly = true)
@Override
public void securityChecks(
@@ -120,86 +142,77 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group> implements Group
}
@Override
- public boolean isManager(final String key) {
- Query user = entityManager.createNativeQuery(
- "SELECT COUNT(*) FROM " + JPAUser.TABLE + " WHERE
gManager_id=?");
- user.setParameter(1, key);
-
- Query group = entityManager.createNativeQuery(
- "SELECT COUNT(*) FROM " + JPAGroup.TABLE + " WHERE
gManager_id=?");
- group.setParameter(1, key);
-
- Query anyObject = entityManager.createNativeQuery(
- "SELECT COUNT(*) FROM " + JPAAnyObject.TABLE + " WHERE
gManager_id=?");
- anyObject.setParameter(1, key);
+ public long countUMembers(final String groupKey) {
+ Query query = entityManager.createNativeQuery(
+ "SELECT COUNT(DISTINCT user_id) FROM " + JPAUMembership.TABLE
+ " WHERE group_id=?");
+ query.setParameter(1, groupKey);
- return ((Number) user.getSingleResult()).longValue()
- + ((Number) group.getSingleResult()).longValue()
- + ((Number) anyObject.getSingleResult()).longValue() > 0;
+ return ((Number) query.getSingleResult()).longValue();
}
@Override
- public List<User> findManagedUsers(final String key) {
- TypedQuery<User> query = entityManager.createQuery(
- "SELECT e FROM " + JPAUser.class.getSimpleName() + " e WHERE
e.gManager.id=:key", User.class);
- query.setParameter("key", key);
- return query.getResultList();
+ public List<String> findUMembers(final String groupKey) {
+ Query query = entityManager.createNativeQuery(
+ "SELECT DISTINCT user_id FROM " + JPAUMembership.TABLE + "
WHERE group_id=?");
+ query.setParameter(1, groupKey);
+
+ @SuppressWarnings("unchecked")
+ List<Object> result = query.getResultList();
+ return result.stream().map(String.class::cast).toList();
}
@Override
- public List<Group> findManagedGroups(final String key) {
- TypedQuery<Group> query = entityManager.createQuery(
- "SELECT e FROM " + JPAGroup.class.getSimpleName() + " e WHERE
e.gManager.id=:key", Group.class);
- query.setParameter("key", key);
- return query.getResultList();
+ public boolean existsUMembership(final String userKey, final String
groupKey) {
+ Query query = entityManager.createNativeQuery(
+ "SELECT COUNT(*) FROM " + JPAUMembership.TABLE + " WHERE
group_id=? AND user_id=?");
+ query.setParameter(1, groupKey);
+ query.setParameter(2, userKey);
+
+ return ((Number) query.getSingleResult()).longValue() > 0;
}
@Override
- public List<AnyObject> findManagedAnyObjects(final String key) {
- TypedQuery<AnyObject> query = entityManager.createQuery(
- "SELECT e FROM " + JPAAnyObject.class.getSimpleName() + " e
WHERE e.gManager.id=:key", AnyObject.class);
- query.setParameter("key", key);
+ public List<UMembership> findUMemberships(final Group group, final
Pageable pageable) {
+ TypedQuery<UMembership> query = entityManager.createQuery(
+ "SELECT e FROM " + JPAUMembership.class.getSimpleName()
+ + " e WHERE e.rightEnd=:group ORDER BY e.leftEnd",
+ UMembership.class);
+ query.setParameter("group", group);
+ if (pageable.isPaged()) {
+ query.setFirstResult(pageable.getPageSize() *
pageable.getPageNumber());
+ query.setMaxResults(pageable.getPageSize());
+ }
+
return query.getResultList();
}
@Override
- public Map<String, Long> countByRealm() {
- Query query = entityManager.createQuery(
- "SELECT e.realm, COUNT(e) FROM " +
anyUtils.anyClass().getSimpleName() + " e GROUP BY e.realm");
+ public long countAMembers(final String groupKey) {
+ Query query = entityManager.createNativeQuery(
+ "SELECT COUNT(DISTINCT anyObject_id) FROM " +
JPAAMembership.TABLE + " WHERE group_id=?");
+ query.setParameter(1, groupKey);
- @SuppressWarnings("unchecked")
- List<Object[]> results = query.getResultList();
- return results.stream().collect(Collectors.toMap(
- result -> ((Realm) result[0]).getFullPath(),
- result -> ((Number) result[1]).longValue()));
- }
+ return ((Number) query.getSingleResult()).longValue();
- @Transactional(readOnly = true)
- @Override
- public Collection<String> findAllResourceKeys(final String key) {
- return findById(key).map(Any::getResources).
- orElseGet(List::of).
- stream().map(ExternalResource::getKey).toList();
}
- @Transactional(readOnly = true)
@Override
- public boolean existsAMembership(final String anyObjectKey, final String
groupKey) {
+ public List<String> findAMembers(final String groupKey) {
Query query = entityManager.createNativeQuery(
- "SELECT COUNT(*) FROM " + JPAAMembership.TABLE + " WHERE
group_id=? AND anyobject_it=?");
+ "SELECT DISTINCT anyObject_id FROM " + JPAAMembership.TABLE +
" WHERE group_id=?");
query.setParameter(1, groupKey);
- query.setParameter(2, anyObjectKey);
- return ((Number) query.getSingleResult()).longValue() > 0;
+ @SuppressWarnings("unchecked")
+ List<Object> result = query.getResultList();
+ return result.stream().map(String.class::cast).toList();
}
- @Transactional(readOnly = true)
@Override
- public boolean existsUMembership(final String userKey, final String
groupKey) {
+ public boolean existsAMembership(final String anyObjectKey, final String
groupKey) {
Query query = entityManager.createNativeQuery(
- "SELECT COUNT(*) FROM " + JPAUMembership.TABLE + " WHERE
group_id=? AND user_id=?");
+ "SELECT COUNT(*) FROM " + JPAAMembership.TABLE + " WHERE
group_id=? AND anyobject_it=?");
query.setParameter(1, groupKey);
- query.setParameter(2, userKey);
+ query.setParameter(2, anyObjectKey);
return ((Number) query.getSingleResult()).longValue() > 0;
}
@@ -215,18 +228,75 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group> implements Group
}
@Override
- public List<UMembership> findUMemberships(final Group group, final
Pageable pageable) {
- TypedQuery<UMembership> query = entityManager.createQuery(
- "SELECT e FROM " + JPAUMembership.class.getSimpleName()
- + " e WHERE e.rightEnd=:group ORDER BY e.leftEnd",
- UMembership.class);
- query.setParameter("group", group);
- if (pageable.isPaged()) {
- query.setFirstResult(pageable.getPageSize() *
pageable.getPageNumber());
- query.setMaxResults(pageable.getPageSize());
- }
+ public boolean isManager(final String key) {
+ Query user = entityManager.createNativeQuery(
+ "SELECT COUNT(*) FROM " + JPAUser.TABLE + " WHERE
gManager_id=?");
+ user.setParameter(1, key);
- return query.getResultList();
+ Query group = entityManager.createNativeQuery(
+ "SELECT COUNT(*) FROM " + JPAGroup.TABLE + " WHERE
gManager_id=?");
+ group.setParameter(1, key);
+
+ Query anyObject = entityManager.createNativeQuery(
+ "SELECT COUNT(*) FROM " + JPAAnyObject.TABLE + " WHERE
gManager_id=?");
+ anyObject.setParameter(1, key);
+
+ return ((Number) user.getSingleResult()).longValue()
+ + ((Number) group.getSingleResult()).longValue()
+ + ((Number) anyObject.getSingleResult()).longValue() > 0;
+ }
+
+ @Override
+ public List<User> findManagedUsers(final String key) {
+ List<User> result = new ArrayList<>();
+
+ // (a) see GroupDAO#findManagedUsers
+ TypedQuery<User> query = entityManager.createQuery(
+ "SELECT e FROM " + JPAUser.class.getSimpleName() + " e WHERE
e.gManager.id=:key", User.class);
+ query.setParameter("key", key);
+ result.addAll(query.getResultList());
+
+ // (b) see GroupDAO#findManagedUsers
+ findManagedGroupKeys(key).forEach(group -> findUMembers(group).
+ forEach(m -> userDAO.findById(m).ifPresent(result::add)));
+
+ return result.stream().distinct().toList();
+ }
+
+ protected Stream<String> findManagedGroupKeys(final String key) {
+ Query query = entityManager.createNativeQuery(
+ "SELECT DISTINCT id FROM " + JPAGroup.TABLE + " WHERE
gManager_id=?");
+ query.setParameter(1, key);
+
+ @SuppressWarnings("unchecked")
+ List<Object> result = query.getResultList();
+ return result.stream().map(String.class::cast);
+ }
+
+ @Override
+ public List<Group> findManagedGroups(final String key) {
+ return findManagedGroupKeys(key).
+ map(group ->
Optional.ofNullable(entityManager.find(JPAGroup.class, group))).
+ flatMap(Optional::stream).
+ map(Group.class::cast).
+ toList();
+ }
+
+ @Override
+ public List<AnyObject> findManagedAnyObjects(final String key) {
+ List<AnyObject> result = new ArrayList<>();
+
+ // (a) see GroupDAO#findManagedAnyObjects
+ TypedQuery<AnyObject> query = entityManager.createQuery(
+ "SELECT e FROM " + JPAAnyObject.class.getSimpleName() + " e
WHERE e.gManager.id=:key", AnyObject.class);
+ query.setParameter("key", key);
+ result.addAll(query.getResultList());
+
+ // (b) see GroupDAO#findManagedUsers
+ findManagedGroupKeys(key).forEach(group -> findAMembers(group).
+ forEach(m -> anyObjectDAO.findById(m).ifPresent(result::add)));
+
+ return result.stream().distinct().toList();
}
@Override
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 3c0fa93ebe..3c4e0405bb 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
@@ -30,6 +30,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.syncope.core.persistence.api.dao.AccessTokenDAO;
@@ -47,6 +48,7 @@ import
org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.user.UMembership;
import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.persistence.api.utils.RealmUtils;
+import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAMembership;
import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAnyObject;
import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
import org.apache.syncope.core.persistence.jpa.entity.user.JPALinkedAccount;
@@ -112,74 +114,85 @@ public class UserRepoExtImpl extends
AbstractAnyRepoExt<User> implements UserRep
return ((Number) user.getSingleResult()).longValue()
+ ((Number) group.getSingleResult()).longValue()
+ ((Number) anyObject.getSingleResult()).longValue() > 0;
+
+ }
+
+ protected Stream<String> findUMembershipGroups(final String key) {
+ Query query = entityManager.createNativeQuery(
+ "SELECT DISTINCT group_id FROM " + JPAUMembership.TABLE + "
WHERE user_id=?");
+ query.setParameter(1, key);
+
+ @SuppressWarnings("unchecked")
+ List<Object> groups = query.getResultList();
+ return groups.stream().map(String.class::cast);
}
@Override
public List<User> findManagedUsers(final String key) {
List<User> result = new ArrayList<>();
- // 1. users having uManager set to the requested user
+ // (a) see UserDAO#findManagedUsers
TypedQuery<User> users = entityManager.createQuery(
"SELECT e FROM " + JPAUser.class.getSimpleName() + " e WHERE
e.uManager.id=:key", User.class);
users.setParameter("key", key);
result.addAll(users.getResultList());
- // 2. user members of groups having uManager set to the requested user
+ // (b) see UserDAO#findManagedUsers
findManagedGroupKeys(key).forEach(group ->
groupDAO.findUMembers(group).
- forEach(member ->
Optional.ofNullable(entityManager.find(JPAUser.class, member)).
- ifPresent(result::add)));
+ forEach(m ->
Optional.ofNullable(entityManager.find(JPAUser.class,
m)).ifPresent(result::add)));
- // 3. users managed by groups the requested user is member of
- Query query = entityManager.createNativeQuery(
- "SELECT DISTINCT group_id FROM " + JPAUMembership.TABLE + "
WHERE user_id=?");
- query.setParameter(1, key);
- @SuppressWarnings("unchecked")
- List<Object> groups = query.getResultList();
- groups.stream().map(String.class::cast).forEach(group ->
result.addAll(groupDAO.findManagedUsers(group)));
+ // (c) see UserDAO#findManagedUsers
+ // (d) see UserDAO#findManagedUsers
+ findUMembershipGroups(key).forEach(group ->
result.addAll(groupDAO.findManagedUsers(group)));
return result.stream().distinct().toList();
}
- protected List<String> findManagedGroupKeys(final String key) {
+ protected Stream<String> findManagedGroupKeys(final String key) {
Query query = entityManager.createNativeQuery(
"SELECT DISTINCT id FROM " + JPAGroup.TABLE + " WHERE
uManager_id=?");
query.setParameter(1, key);
@SuppressWarnings("unchecked")
List<Object> result = query.getResultList();
- return result.stream().map(String.class::cast).toList();
+ return result.stream().map(String.class::cast);
}
@Override
public List<Group> findManagedGroups(final String key) {
- return findManagedGroupKeys(key).stream().
- map(group ->
Optional.ofNullable(entityManager.find(JPAGroup.class, group))).
- flatMap(Optional::stream).
- map(Group.class::cast).
- toList();
+ List<Group> result = new ArrayList<>();
+
+ // (a) see UserDAO#findManagedGroups
+ findManagedGroupKeys(key).forEach(group ->
groupDAO.findById(group).ifPresent(result::add));
+
+ // (b) see UserDAO#findManagedGroups
+ findUMembershipGroups(key).forEach(g ->
result.addAll(groupDAO.findManagedGroups(g)));
+
+ return result.stream().distinct().toList();
}
@Override
public List<AnyObject> findManagedAnyObjects(final String key) {
List<AnyObject> result = new ArrayList<>();
- // 1. anyObjects having uManager set to the requested user
+ // (a) see UserDAO#findManagedAnyObjects
TypedQuery<AnyObject> anyObjects = entityManager.createQuery(
"SELECT e FROM " + JPAAnyObject.class.getSimpleName() + " e
WHERE e.uManager.id=:key", AnyObject.class);
anyObjects.setParameter("key", key);
result.addAll(anyObjects.getResultList());
- // 2. anyObject members of groups having uManager set to the requested
user
- findManagedGroupKeys(key).forEach(group ->
groupDAO.findUMembers(group).
- forEach(member ->
Optional.ofNullable(entityManager.find(JPAAnyObject.class, member)).
- ifPresent(result::add)));
+ // (b) see UserDAO#findManagedAnyObjects
+ findManagedGroupKeys(key).forEach(group ->
groupDAO.findAMembers(group).
+ forEach(m ->
Optional.ofNullable(entityManager.find(JPAAnyObject.class,
m)).ifPresent(result::add)));
- // 3. anyObject managed by groups the requested user is member of
Query query = entityManager.createNativeQuery(
- "SELECT DISTINCT group_id FROM " + JPAUMembership.TABLE + "
WHERE user_id=?");
+ "SELECT DISTINCT group_id FROM " + JPAAMembership.TABLE + "
WHERE anyObject_id=?");
query.setParameter(1, key);
@SuppressWarnings("unchecked")
List<Object> groups = query.getResultList();
+
+ // (c) see UserDAO#findManagedAnyObjects
+ // (d) see UserDAO#findManagedAnyObjects
groups.stream().map(String.class::cast).forEach(group ->
result.addAll(groupDAO.findManagedAnyObjects(group)));
return result.stream().distinct().toList();
diff --git
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
index 6a5f487700..cb92e78d98 100644
---
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
+++
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
@@ -143,34 +143,6 @@ public class GroupTest extends AbstractTest {
});
}
- @Test
- public void findByUManager() {
- Group group =
groupDAO.findById("ebf97068-aa4b-4a85-9f01-680e8c4cf227").orElseThrow();
-
- User user =
userDAO.findById("823074dc-d280-436d-a7dd-07399fae48ec").orElseThrow();
-
- assertEquals(user, group.getuManager());
-
- List<Group> managed = userDAO.findManagedGroups(user.getKey());
- assertFalse(managed.isEmpty());
- assertEquals(1, managed.size());
- assertTrue(managed.contains(group));
- }
-
- @Test
- public void findByGManager() {
- Group root = groupDAO.findByName("root").orElseThrow();
- Group group = entityFactory.newEntity(Group.class);
- group.setRealm(realmDAO.getRoot());
- group.setName("error");
- group.setgManager(root);
- group = groupDAO.save(group);
- entityManager.flush();
-
- List<Group> managed = groupDAO.findManagedGroups(root.getKey());
- assertEquals(List.of(group), managed);
- }
-
@Test
public void create() {
Group group = entityFactory.newEntity(Group.class);
diff --git
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ManagerTest.java
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ManagerTest.java
new file mode 100644
index 0000000000..f1a856bfda
--- /dev/null
+++
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ManagerTest.java
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.outer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.transaction.annotation.Transactional;
+
+@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
+@Transactional
+class ManagerTest extends AbstractTest {
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @Autowired
+ private GroupDAO groupDAO;
+
+ @Autowired
+ private RealmDAO realmDAO;
+
+ /**
+ * (a) U2 has uManager set to U1
+ */
+ @Test
+ void findUManagedUsersA() {
+ User vivaldi = userDAO.findByUsername("vivaldi").orElseThrow();
+ assertNull(vivaldi.getgManager());
+ assertNull(vivaldi.getuManager());
+
+ User rossini = userDAO.findByUsername("rossini").orElseThrow();
+ assertFalse(userDAO.isManager(rossini.getKey()));
+
+ vivaldi.setuManager(rossini);
+ vivaldi = userDAO.save(vivaldi);
+ entityManager.flush();
+ assertEquals(rossini, vivaldi.getuManager());
+ assertTrue(userDAO.isManager(rossini.getKey()));
+
+ List<User> managed = userDAO.findManagedUsers(rossini.getKey());
+ assertEquals(List.of(vivaldi), managed);
+ }
+
+ /**
+ * (b) G2 has uManager set to U1
+ */
+ @Test
+ void findUManagedUsersB() {
+ Group artDirector = groupDAO.findByName("artDirector").orElseThrow();
+ assertNull(artDirector.getuManager());
+ assertNull(artDirector.getgManager());
+
+ User vivaldi = userDAO.findByUsername("vivaldi").orElseThrow();
+ assertFalse(userDAO.isManager(vivaldi.getKey()));
+
+ artDirector.setuManager(vivaldi);
+ artDirector = groupDAO.save(artDirector);
+ entityManager.flush();
+ assertEquals(vivaldi, artDirector.getuManager());
+ assertTrue(userDAO.isManager(vivaldi.getKey()));
+
+ User puccini = userDAO.findByUsername("puccini").orElseThrow();
+ assertNull(puccini.getgManager());
+ assertNull(puccini.getuManager());
+ assertTrue(puccini.getMembership(artDirector.getKey()).isPresent());
+
+ List<User> managed = userDAO.findManagedUsers(vivaldi.getKey());
+ assertEquals(List.of(puccini), managed);
+ }
+
+ /**
+ * (c) U2 has gManager set to G1
+ */
+ @Test
+ void findUManagedUsersC() {
+ Group managingDirector =
groupDAO.findByName("managingDirector").orElseThrow();
+ assertFalse(groupDAO.isManager(managingDirector.getKey()));
+
+ User bellini = userDAO.findByUsername("bellini").orElseThrow();
+
assertTrue(bellini.getMembership(managingDirector.getKey()).isPresent());
+ assertFalse(userDAO.isManager(bellini.getKey()));
+
+ User rossini = userDAO.findByUsername("rossini").orElseThrow();
+ assertNull(rossini.getgManager());
+ assertNull(rossini.getuManager());
+
+ rossini.setgManager(managingDirector);
+ rossini = userDAO.save(rossini);
+ entityManager.flush();
+ assertEquals(managingDirector, rossini.getgManager());
+ assertTrue(groupDAO.isManager(managingDirector.getKey()));
+
+ List<User> managed = userDAO.findManagedUsers(bellini.getKey());
+ assertEquals(List.of(rossini), managed);
+ }
+
+ /**
+ * (d) G2 has gManager set to G1
+ */
+ @Test
+ void findUManagedUsersD() {
+ Group managingDirector =
groupDAO.findByName("managingDirector").orElseThrow();
+ assertFalse(groupDAO.isManager(managingDirector.getKey()));
+
+ User bellini = userDAO.findByUsername("bellini").orElseThrow();
+
assertTrue(bellini.getMembership(managingDirector.getKey()).isPresent());
+ assertFalse(userDAO.isManager(bellini.getKey()));
+
+ Group otherchild = groupDAO.findByName("otherchild").orElseThrow();
+ assertNull(otherchild.getgManager());
+ assertNull(otherchild.getuManager());
+
+ User rossini = userDAO.findByUsername("rossini").orElseThrow();
+ assertTrue(rossini.getMembership(otherchild.getKey()).isPresent());
+ rossini.setuManager(null);
+ rossini.setgManager(null);
+ rossini = userDAO.save(rossini);
+ entityManager.flush();
+ assertNull(rossini.getgManager());
+ assertNull(rossini.getuManager());
+
+ otherchild.setgManager(managingDirector);
+ otherchild = groupDAO.save(otherchild);
+ entityManager.flush();
+ assertEquals(managingDirector, otherchild.getgManager());
+ assertTrue(groupDAO.isManager(managingDirector.getKey()));
+
+ List<User> managed = userDAO.findManagedUsers(bellini.getKey());
+ assertEquals(List.of(rossini), managed);
+ }
+
+ /**
+ * (a) G2 has uManager set to U1 - see UserDAO#findManagedGroups
+ */
+ @Test
+ void findUManagedGroupsA() {
+ Group director = groupDAO.findByName("director").orElseThrow();
+ User puccini = userDAO.findByUsername("puccini").orElseThrow();
+ assertEquals(puccini, director.getuManager());
+ assertTrue(userDAO.isManager(puccini.getKey()));
+
+ List<Group> managed = userDAO.findManagedGroups(puccini.getKey());
+ assertEquals(List.of(director), managed);
+ }
+
+ /**
+ * (b) G2 has gManager set to G1 - see UserDAO#findManagedGroups
+ */
+ @Test
+ void findUManagedGroupsB() {
+ Group managingDirector =
groupDAO.findByName("managingDirector").orElseThrow();
+ assertFalse(groupDAO.isManager(managingDirector.getKey()));
+
+ Group root = groupDAO.findByName("root").orElseThrow();
+ assertNull(root.getgManager());
+ assertNull(root.getuManager());
+
+ root.setgManager(managingDirector);
+ root = groupDAO.save(root);
+ entityManager.flush();
+ assertEquals(managingDirector, root.getgManager());
+ assertTrue(groupDAO.isManager(managingDirector.getKey()));
+
+ User bellini = userDAO.findByUsername("bellini").orElseThrow();
+
assertTrue(bellini.getMembership(managingDirector.getKey()).isPresent());
+
+ List<Group> managed = userDAO.findManagedGroups(bellini.getKey());
+ assertEquals(List.of(root), managed);
+ }
+
+ /**
+ * (a) U has gManager set to G1
+ */
+ @Test
+ void findGManagedUsersA() {
+ Group citizen = groupDAO.findByName("citizen").orElseThrow();
+ assertFalse(groupDAO.isManager(citizen.getKey()));
+
+ User verdi = userDAO.findByUsername("verdi").orElseThrow();
+ assertNull(verdi.getgManager());
+ assertNull(verdi.getuManager());
+
+ verdi.setgManager(citizen);
+ verdi = userDAO.save(verdi);
+ entityManager.flush();
+ assertEquals(citizen, verdi.getgManager());
+ assertTrue(groupDAO.isManager(citizen.getKey()));
+
+ List<User> managed = groupDAO.findManagedUsers(citizen.getKey());
+ assertEquals(List.of(verdi), managed);
+ }
+
+ /**
+ * (b) G2 has gManager set to G1
+ */
+ @Test
+ void findGManagedUsersB() {
+ Group managingDirector =
groupDAO.findByName("managingDirector").orElseThrow();
+ assertFalse(groupDAO.isManager(managingDirector.getKey()));
+
+ User bellini = userDAO.findByUsername("bellini").orElseThrow();
+
assertTrue(bellini.getMembership(managingDirector.getKey()).isPresent());
+
+ Group citizen = groupDAO.findByName("citizen").orElseThrow();
+ assertNull(citizen.getgManager());
+ assertNull(citizen.getuManager());
+
+ User verdi = userDAO.findByUsername("verdi").orElseThrow();
+ assertTrue(verdi.getMembership(citizen.getKey()).isPresent());
+
+ citizen.setgManager(managingDirector);
+ citizen = groupDAO.save(citizen);
+ entityManager.flush();
+ assertEquals(managingDirector, citizen.getgManager());
+ assertTrue(groupDAO.isManager(managingDirector.getKey()));
+
+ List<User> managed =
groupDAO.findManagedUsers(managingDirector.getKey());
+ assertEquals(List.of(verdi), managed);
+ }
+
+ /**
+ * (a) G2 has gManager set to G1 - see GroupDAO#findManagedGroups
+ */
+ @Test
+ void findGManagedGroups() {
+ Group root = groupDAO.findByName("root").orElseThrow();
+ assertFalse(groupDAO.isManager(root.getKey()));
+
+ Group group = entityFactory.newEntity(Group.class);
+ group.setRealm(realmDAO.getRoot());
+ group.setName("error");
+ group.setgManager(root);
+ group = groupDAO.save(group);
+ entityManager.flush();
+ assertEquals(root, group.getgManager());
+ assertTrue(groupDAO.isManager(root.getKey()));
+
+ List<Group> managed = groupDAO.findManagedGroups(root.getKey());
+ assertEquals(List.of(group), managed);
+ }
+}
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepo.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepo.java
index c6351fb358..4bcabe8dc1 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepo.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepo.java
@@ -21,11 +21,7 @@ package org.apache.syncope.core.persistence.neo4j.dao.repo;
import java.util.List;
import java.util.Optional;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
-import
org.apache.syncope.core.persistence.neo4j.entity.anyobject.Neo4jAMembership;
-import
org.apache.syncope.core.persistence.neo4j.entity.anyobject.Neo4jAnyObject;
import org.apache.syncope.core.persistence.neo4j.entity.group.Neo4jGroup;
-import org.apache.syncope.core.persistence.neo4j.entity.user.Neo4jUMembership;
-import org.apache.syncope.core.persistence.neo4j.entity.user.Neo4jUser;
import org.springframework.data.neo4j.repository.query.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
@@ -40,46 +36,4 @@ public interface GroupRepo
@Query("MATCH (n:" + Neo4jGroup.NODE + ") WHERE toLower(n.name) =~
$pattern RETURN n.id")
@Override
List<String> findKeysByNamePattern(@Param("pattern") String pattern);
-
- @Query("MATCH (a:" + Neo4jAnyObject.NODE + " {id: $anyObjectKey})-[]-"
- + "(n:" + Neo4jAMembership.NODE + ")-[]-"
- + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
- + "RETURN COUNT(n) > 0")
- @Override
- boolean existsAMembership(String anyObjectKey, String groupKey);
-
- @Query("MATCH (u:" + Neo4jUser.NODE + " {id: $userKey})-[]-"
- + "(n:" + Neo4jUMembership.NODE + ")-[]-"
- + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
- + "RETURN COUNT(n) > 0")
- @Override
- boolean existsUMembership(String userKey, String groupKey);
-
- @Query("MATCH (a:" + Neo4jAnyObject.NODE + ")-[]-"
- + "(n:" + Neo4jAMembership.NODE + ")-[]-"
- + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
- + "RETURN a.id")
- @Override
- List<String> findAMembers(@Param("groupKey") String groupKey);
-
- @Query("MATCH (u:" + Neo4jUser.NODE + ")-[]-"
- + "(n:" + Neo4jUMembership.NODE + ")-[]-"
- + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
- + "RETURN u.id")
- @Override
- List<String> findUMembers(@Param("groupKey") String groupKey);
-
- @Query("MATCH (a:" + Neo4jAnyObject.NODE + ")-[]-"
- + "(n:" + Neo4jAMembership.NODE + ")-[]-"
- + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
- + "RETURN COUNT(DISTINCT a)")
- @Override
- long countAMembers(@Param("groupKey") String groupKey);
-
- @Query("MATCH (u:" + Neo4jUser.NODE + ")-[]-"
- + "(n:" + Neo4jUMembership.NODE + ")-[]-"
- + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
- + "RETURN COUNT(DISTINCT u)")
- @Override
- long countUMembers(@Param("groupKey") String groupKey);
}
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepoExt.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepoExt.java
index 3adafe726f..7e3cfeae95 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepoExt.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/GroupRepoExt.java
@@ -34,24 +34,36 @@ public interface GroupRepoExt extends AnyRepoExt<Group> {
String CACHE = "groupCache";
+ Map<String, Long> countByRealm();
+
void securityChecks(Set<String> authRealms, String key, String realm);
- boolean isManager(String key);
+ long countUMembers(String groupKey);
- List<User> findManagedUsers(String key);
+ List<String> findUMembers(String groupKey);
- List<Group> findManagedGroups(String key);
+ boolean existsUMembership(String userKey, String groupKey);
- List<AnyObject> findManagedAnyObjects(String key);
+ List<UMembership> findUMemberships(Group group, Pageable pageable);
- Map<String, Long> countByRealm();
+ long countAMembers(String groupKey);
- List<AMembership> findAMemberships(Group group);
+ List<String> findAMembers(String groupKey);
- List<UMembership> findUMemberships(Group group, Pageable pageable);
+ boolean existsAMembership(String anyObjectKey, String groupKey);
+
+ List<AMembership> findAMemberships(Group group);
List<GroupTypeExtension> findTypeExtensions(AnyTypeClass anyTypeClass);
+ boolean isManager(String key);
+
+ List<User> findManagedUsers(String key);
+
+ List<Group> findManagedGroups(String key);
+
+ List<AnyObject> findManagedAnyObjects(String key);
+
@Override
<S extends Group> S save(S group);
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 f42f1573d0..50f0e5c145 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
@@ -19,6 +19,7 @@
package org.apache.syncope.core.persistence.neo4j.dao.repo;
import java.time.OffsetDateTime;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -26,6 +27,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.cache.Cache;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
@@ -127,12 +129,27 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group, Neo4jGroup> impl
return groupCache;
}
- @Transactional(readOnly = true)
@Override
public Optional<OffsetDateTime> findLastChange(final String key) {
return findLastChange(key, Neo4jGroup.NODE);
}
+ @Override
+ public Collection<String> findAllResourceKeys(final String key) {
+ return findById(key).map(Any::getResources).
+ orElseGet(List::of).
+ stream().map(ExternalResource::getKey).toList();
+ }
+
+ @Override
+ public Map<String, Long> countByRealm() {
+ Collection<Map<String, Object>> result = neo4jClient.query(
+ "MATCH (n:" + Neo4jGroup.NODE + ")-[]-(r:" + Neo4jRealm.NODE +
") "
+ + "RETURN r.fullPath AS realm, COUNT(n) AS
counted").fetch().all();
+
+ return result.stream().collect(Collectors.toMap(r ->
r.get("realm").toString(), r -> (Long) r.get("counted")));
+ }
+
@Transactional(readOnly = true)
@Override
public void securityChecks(
@@ -157,6 +174,94 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group, Neo4jGroup> impl
}
}
+ @Override
+ public long countUMembers(final String groupKey) {
+ return neo4jTemplate.count(
+ "MATCH (u:" + Neo4jUser.NODE + ")-[]-"
+ + "(n:" + Neo4jUMembership.NODE + ")-[]-"
+ + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
+ + "RETURN COUNT(DISTINCT u)",
+ Map.of("groupKey", groupKey));
+ }
+
+ @Override
+ public List<String> findUMembers(final String groupKey) {
+ Collection<Map<String, Object>> result = neo4jClient.query(
+ "MATCH (u:" + Neo4jUser.NODE + ")-[]-"
+ + "(n:" + Neo4jUMembership.NODE + ")-[]-"
+ + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
+ + "RETURN u.id").bindAll(Map.of("groupKey",
groupKey)).fetch().all();
+ return result.stream().map(found ->
found.get("u.id").toString()).toList();
+ }
+
+ @Override
+ public boolean existsUMembership(final String userKey, final String
groupKey) {
+ return neo4jTemplate.count(
+ "MATCH (u:" + Neo4jUser.NODE + " {id: $userKey})-[]-"
+ + "(n:" + Neo4jUMembership.NODE + ")-[]-"
+ + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
+ + "RETURN COUNT(n)",
+ Map.of("userKey", userKey, "groupKey", groupKey)) > 0;
+ }
+
+ @Override
+ public List<UMembership> findUMemberships(final Group group, final
Pageable pageable) {
+ String paged = "";
+ if (pageable.isPaged()) {
+ paged = " SKIP " + pageable.getPageSize() *
pageable.getPageNumber()
+ + " LIMIT " + pageable.getPageSize();
+ }
+ return toList(
+ neo4jClient.query(
+ "MATCH (n:" + Neo4jUMembership.NODE + ")-[]-(g:" +
Neo4jGroup.NODE + " {id: $id}) "
+ + "RETURN n.id" + paged)
+ .bindAll(Map.of("id", group.getKey())).fetch().all(),
+ "n.id",
+ Neo4jUMembership.class,
+ null);
+ }
+
+ @Override
+ public long countAMembers(final String groupKey) {
+ return neo4jTemplate.count(
+ "MATCH (a:" + Neo4jAnyObject.NODE + ")-[]-"
+ + "(n:" + Neo4jAMembership.NODE + ")-[]-"
+ + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
+ + "RETURN COUNT(DISTINCT a)",
+ Map.of("groupKey", groupKey));
+ }
+
+ @Override
+ public List<String> findAMembers(final String groupKey) {
+ Collection<Map<String, Object>> result = neo4jClient.query(
+ "MATCH (a:" + Neo4jAnyObject.NODE + ")-[]-"
+ + "(n:" + Neo4jAMembership.NODE + ")-[]-"
+ + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
+ + "RETURN a.id").bindAll(Map.of("groupKey",
groupKey)).fetch().all();
+ return result.stream().map(found ->
found.get("a.id").toString()).toList();
+ }
+
+ @Override
+ public boolean existsAMembership(final String anyObjectKey, final String
groupKey) {
+ return neo4jTemplate.count(
+ "MATCH (a:" + Neo4jAnyObject.NODE + " {id: $anyObjectKey})-[]-"
+ + "(n:" + Neo4jAMembership.NODE + ")-[]-"
+ + "(g:" + Neo4jGroup.NODE + " {id: $groupKey}) "
+ + "RETURN COUNT(n)",
+ Map.of("anyObjectKey", anyObjectKey, "groupKey", groupKey)) >
0;
+ }
+
+ @Override
+ public List<AMembership> findAMemberships(final Group group) {
+ return toList(
+ neo4jClient.query(
+ "MATCH (n:" + Neo4jAMembership.NODE + ")-[]-(g:" +
Neo4jGroup.NODE + " {id: $id}) "
+ + "RETURN n.id").bindAll(Map.of("id",
group.getKey())).fetch().all(),
+ "n.id",
+ Neo4jAMembership.class,
+ null);
+ }
+
@Override
protected void securityChecks(final Group group) {
Set<String> authRealms = AuthContextUtils.getAuthorizations().
@@ -167,90 +272,87 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group, Neo4jGroup> impl
@Override
public boolean isManager(final String key) {
- return !findManagedUsers(key).isEmpty()
- || !findManagedGroups(key).isEmpty()
- || !findManagedAnyObjects(key).isEmpty();
+ long users = neo4jTemplate.count(
+ "MATCH (n:" + Neo4jGroup.NODE + " {id: $key})-"
+ + "[:" + AbstractAny.GROUP_MANAGER_REL + "]-"
+ + "(p:" + Neo4jUser.NODE + ") "
+ + "RETURN COUNT(p.id)",
+ Map.of("key", key));
+
+ long groups = neo4jTemplate.count(
+ "MATCH (n:" + Neo4jGroup.NODE + " {id: $key})-"
+ + "[:" + AbstractAny.GROUP_MANAGER_REL + "]-"
+ + "(p:" + Neo4jGroup.NODE + ") "
+ + "RETURN COUNT(p.id)",
+ Map.of("key", key));
+
+ long anyObjects = neo4jTemplate.count(
+ "MATCH (n:" + Neo4jGroup.NODE + " {id: $key})-"
+ + "[:" + AbstractAny.GROUP_MANAGER_REL + "]-"
+ + "(p:" + Neo4jAnyObject.NODE + ") "
+ + "RETURN COUNT(p.id)",
+ Map.of("key", key));
+
+ return users + groups + anyObjects > 0;
}
@Override
public List<User> findManagedUsers(final String key) {
- return toList(neo4jClient.query(
+ List<User> result = new ArrayList<>();
+
+ // (a) see GroupDAO#findManagedUsers
+ result.addAll(toList(neo4jClient.query(
"MATCH (n:" + Neo4jGroup.NODE + " {id: $id})-"
+ "[:" + AbstractAny.GROUP_MANAGER_REL + "]-"
+ "(p:" + Neo4jUser.NODE + ") "
+ "RETURN p.id").bindAll(Map.of("id", key)).fetch().all(),
"p.id",
Neo4jUser.class,
- userCache);
+ userCache));
+
+ // (b) see GroupDAO#findManagedUsers
+ findManagedGroupKeys(key).forEach(group -> findUMembers(group).
+ forEach(m -> userDAO.findById(m).ifPresent(result::add)));
+
+ return result.stream().distinct().toList();
}
- @Override
- public List<Group> findManagedGroups(final String key) {
- return toList(neo4jClient.query(
+ protected Stream<String> findManagedGroupKeys(final String key) {
+ Collection<Map<String, Object>> result = neo4jClient.query(
"MATCH (n:" + Neo4jGroup.NODE + " {id: $id})-"
+ "[:" + AbstractAny.GROUP_MANAGER_REL + "]-"
+ "(p:" + Neo4jGroup.NODE + ") "
- + "RETURN p.id").bindAll(Map.of("id", key)).fetch().all(),
- "p.id",
- Neo4jGroup.class,
- groupCache);
+ + "RETURN p.id").bindAll(Map.of("id", key)).fetch().all();
+ return result.stream().map(found -> found.get("p.id").toString());
+ }
+
+ @Override
+ public List<Group> findManagedGroups(final String key) {
+ return findManagedGroupKeys(key).map(group -> findById(group,
Neo4jGroup.class, groupCache)).
+ flatMap(Optional::stream).
+ map(Group.class::cast).
+ toList();
}
@Override
public List<AnyObject> findManagedAnyObjects(final String key) {
- return toList(neo4jClient.query(
+ List<AnyObject> result = new ArrayList<>();
+
+ // (a) see GroupDAO#findManagedAnyObjects
+ result.addAll(toList(neo4jClient.query(
"MATCH (n:" + Neo4jGroup.NODE + " {id: $id})-"
+ "[:" + AbstractAny.GROUP_MANAGER_REL + "]-"
+ "(p:" + Neo4jGroup.NODE + ") "
+ "RETURN p.id").bindAll(Map.of("id", key)).fetch().all(),
"p.id",
Neo4jAnyObject.class,
- anyObjectCache);
- }
-
- @Override
- public Map<String, Long> countByRealm() {
- Collection<Map<String, Object>> result = neo4jClient.query(
- "MATCH (n:" + Neo4jGroup.NODE + ")-[]-(r:" + Neo4jRealm.NODE +
") "
- + "RETURN r.fullPath AS realm, COUNT(n) AS
counted").fetch().all();
-
- return result.stream().collect(Collectors.toMap(r ->
r.get("realm").toString(), r -> (Long) r.get("counted")));
- }
-
- @Transactional(readOnly = true)
- @Override
- public Collection<String> findAllResourceKeys(final String key) {
- return findById(key).map(Any::getResources).
- orElseGet(List::of).
- stream().map(ExternalResource::getKey).toList();
- }
+ anyObjectCache));
- @Override
- public List<AMembership> findAMemberships(final Group group) {
- return toList(
- neo4jClient.query(
- "MATCH (n:" + Neo4jAMembership.NODE + ")-[]-(g:" +
Neo4jGroup.NODE + " {id: $id}) "
- + "RETURN n.id").bindAll(Map.of("id",
group.getKey())).fetch().all(),
- "n.id",
- Neo4jAMembership.class,
- null);
- }
+ // (b) see GroupDAO#findManagedUsers
+ findManagedGroupKeys(key).forEach(group -> findAMembers(group).
+ forEach(m -> anyObjectDAO.findById(m).ifPresent(result::add)));
- @Override
- public List<UMembership> findUMemberships(final Group group, final
Pageable pageable) {
- String paged = "";
- if (pageable.isPaged()) {
- paged = " SKIP " + pageable.getPageSize() *
pageable.getPageNumber()
- + " LIMIT " + pageable.getPageSize();
- }
- return toList(
- neo4jClient.query(
- "MATCH (n:" + Neo4jUMembership.NODE + ")-[]-(g:" +
Neo4jGroup.NODE + " {id: $id}) "
- + "RETURN n.id" + paged)
- .bindAll(Map.of("id", group.getKey())).fetch().all(),
- "n.id",
- Neo4jUMembership.class,
- null);
+ return result.stream().distinct().toList();
}
@Override
@@ -262,18 +364,18 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group, Neo4jGroup> impl
neo4jTemplate.findById(group.getKey(),
Neo4jGroup.class).ifPresent(before -> {
before.getResources().stream().filter(resource ->
!group.getResources().contains(resource)).
forEach(resource -> deleteRelationship(
- Neo4jGroup.NODE,
- Neo4jExternalResource.NODE,
- group.getKey(),
- resource.getKey(),
- Neo4jGroup.GROUP_RESOURCE_REL));
+ Neo4jGroup.NODE,
+ Neo4jExternalResource.NODE,
+ group.getKey(),
+ resource.getKey(),
+ Neo4jGroup.GROUP_RESOURCE_REL));
before.getAuxClasses().stream().filter(auxClass ->
!group.getAuxClasses().contains(auxClass)).
forEach(auxClass -> deleteRelationship(
- Neo4jGroup.NODE,
- Neo4jAnyTypeClass.NODE,
- group.getKey(),
- auxClass.getKey(),
- Neo4jGroup.GROUP_AUX_CLASSES_REL));
+ Neo4jGroup.NODE,
+ Neo4jAnyTypeClass.NODE,
+ group.getKey(),
+ auxClass.getKey(),
+ Neo4jGroup.GROUP_AUX_CLASSES_REL));
if (before.getuManager() != null && group.getuManager() == null) {
deleteRelationship(
Neo4jGroup.NODE,
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 a2a1e41dd5..e497da8fbf 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
@@ -28,6 +28,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.cache.Cache;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
@@ -58,6 +59,7 @@ import
org.apache.syncope.core.persistence.neo4j.entity.Neo4jAnyTypeClass;
import org.apache.syncope.core.persistence.neo4j.entity.Neo4jExternalResource;
import org.apache.syncope.core.persistence.neo4j.entity.Neo4jRealm;
import org.apache.syncope.core.persistence.neo4j.entity.Neo4jRole;
+import
org.apache.syncope.core.persistence.neo4j.entity.anyobject.Neo4jAMembership;
import
org.apache.syncope.core.persistence.neo4j.entity.anyobject.Neo4jAnyObject;
import org.apache.syncope.core.persistence.neo4j.entity.group.Neo4jGroup;
import
org.apache.syncope.core.persistence.neo4j.entity.user.Neo4jLinkedAccount;
@@ -166,16 +168,44 @@ public class UserRepoExtImpl extends
AbstractAnyRepoExt<User, Neo4jUser> impleme
@Override
public boolean isManager(final String key) {
- return !findManagedUsers(key).isEmpty()
- || !findManagedGroups(key).isEmpty()
- || !findManagedAnyObjects(key).isEmpty();
+ long users = neo4jTemplate.count(
+ "MATCH (n:" + Neo4jUser.NODE + " {id: $key})-"
+ + "[:" + AbstractAny.USER_MANAGER_REL + "]-"
+ + "(p:" + Neo4jUser.NODE + ") "
+ + "RETURN COUNT(p.id)",
+ Map.of("key", key));
+
+ long groups = neo4jTemplate.count(
+ "MATCH (n:" + Neo4jUser.NODE + " {id: $key})-"
+ + "[:" + AbstractAny.USER_MANAGER_REL + "]-"
+ + "(p:" + Neo4jGroup.NODE + ") "
+ + "RETURN COUNT(p.id)",
+ Map.of("key", key));
+
+ long anyObjects = neo4jTemplate.count(
+ "MATCH (n:" + Neo4jUser.NODE + " {id: $key})-"
+ + "[:" + AbstractAny.USER_MANAGER_REL + "]-"
+ + "(p:" + Neo4jAnyObject.NODE + ") "
+ + "RETURN COUNT(p.id)",
+ Map.of("key", key));
+
+ return users + groups + anyObjects > 0;
+ }
+
+ protected Stream<String> findUMembershipGroups(final String key) {
+ Collection<Map<String, Object>> result = neo4jClient.query(
+ "MATCH (u:" + Neo4jUser.NODE + " {id: $key})-[]-"
+ + "(n:" + Neo4jUMembership.NODE + ")-[]-"
+ + "(g:" + Neo4jGroup.NODE + ") "
+ + "RETURN g.id").bindAll(Map.of("key", key)).fetch().all();
+ return result.stream().map(found -> found.get("g.id").toString());
}
@Override
public List<User> findManagedUsers(final String key) {
List<User> result = new ArrayList<>();
- // 1. users having uManager set to the requested user
+ // (a) see UserDAO#findManagedUsers
result.addAll(toList(neo4jClient.query(
"MATCH (n:" + Neo4jUser.NODE + " {id: $id})-"
+ "[:" + AbstractAny.USER_MANAGER_REL + "]-"
@@ -185,35 +215,44 @@ public class UserRepoExtImpl extends
AbstractAnyRepoExt<User, Neo4jUser> impleme
Neo4jUser.class,
userCache));
- // 2. user members of groups having uManager set to the requested user
- findManagedGroups(key).forEach(group ->
groupDAO.findUMembers(group.getKey()).
- forEach(member -> findById(member).
- ifPresent(result::add)));
+ // (b) see UserDAO#findManagedUsers
+ findManagedGroupKeys(key).forEach(group ->
groupDAO.findUMembers(group).
+ forEach(m -> findById(m).ifPresent(result::add)));
- // 3. users managed by groups the requested user is member of
- findById(key).ifPresent(user -> user.getMemberships().
- forEach(m ->
result.addAll(groupDAO.findManagedUsers(m.getRightEnd().getKey()))));
+ // (c) see UserDAO#findManagedUsers
+ // (d) see UserDAO#findManagedUsers
+ findUMembershipGroups(key).forEach(group ->
result.addAll(groupDAO.findManagedUsers(group)));
return result.stream().distinct().toList();
}
- @Override
- public List<Group> findManagedGroups(final String key) {
- return toList(neo4jClient.query(
+ protected Stream<String> findManagedGroupKeys(final String key) {
+ Collection<Map<String, Object>> result = neo4jClient.query(
"MATCH (n:" + Neo4jUser.NODE + " {id: $id})-"
+ "[:" + AbstractAny.USER_MANAGER_REL + "]-"
+ "(p:" + Neo4jGroup.NODE + ") "
- + "RETURN p.id").bindAll(Map.of("id", key)).fetch().all(),
- "p.id",
- Neo4jGroup.class,
- groupCache);
+ + "RETURN p.id").bindAll(Map.of("id", key)).fetch().all();
+ return result.stream().map(found -> found.get("p.id").toString());
+ }
+
+ @Override
+ public List<Group> findManagedGroups(final String key) {
+ List<Group> result = new ArrayList<>();
+
+ // (a) see UserDAO#findManagedGroups
+ findManagedGroupKeys(key).forEach(group ->
groupDAO.findById(group).ifPresent(result::add));
+
+ // (b) see UserDAO#findManagedGroups
+ findUMembershipGroups(key).forEach(g ->
result.addAll(groupDAO.findManagedGroups(g)));
+
+ return result.stream().distinct().toList();
}
@Override
public List<AnyObject> findManagedAnyObjects(final String key) {
List<AnyObject> result = new ArrayList<>();
- // 1. anyObjects having uManager set to the requested user
+ // (a) see UserDAO#findManagedAnyObjects
result.addAll(toList(neo4jClient.query(
"MATCH (n:" + Neo4jUser.NODE + " {id: $id})-"
+ "[:" + AbstractAny.USER_MANAGER_REL + "]-"
@@ -223,14 +262,20 @@ public class UserRepoExtImpl extends
AbstractAnyRepoExt<User, Neo4jUser> impleme
Neo4jAnyObject.class,
anyObjectCache));
- // 2. anyObject members of groups having uManager set to the requested
user
- findManagedGroups(key).forEach(group ->
groupDAO.findAMembers(group.getKey()).
- forEach(member -> findById(member, Neo4jAnyObject.class,
anyObjectCache).
- ifPresent(result::add)));
+ // (b) see UserDAO#findManagedAnyObjects
+ findManagedGroupKeys(key).forEach(group ->
groupDAO.findAMembers(group).
+ forEach(m -> findById(m, Neo4jAnyObject.class,
anyObjectCache).ifPresent(result::add)));
+
+ Collection<Map<String, Object>> membershipQueryResult =
neo4jClient.query(
+ "MATCH (u:" + Neo4jAnyObject.NODE + " {id: $key})-[]-"
+ + "(n:" + Neo4jAMembership.NODE + ")-[]-"
+ + "(g:" + Neo4jGroup.NODE + ") "
+ + "RETURN g.id").bindAll(Map.of("key", key)).fetch().all();
+ Stream<String> groups = membershipQueryResult.stream().map(found ->
found.get("g.id").toString());
- // 3. anyObject managed by groups the requested user is member of
- findById(key).ifPresent(user -> user.getMemberships().
- forEach(m ->
result.addAll(groupDAO.findManagedAnyObjects(m.getRightEnd().getKey()))));
+ // (c) see UserDAO#findManagedAnyObjects
+ // (d) see UserDAO#findManagedAnyObjects
+ groups.map(String.class::cast).forEach(group ->
result.addAll(groupDAO.findManagedAnyObjects(group)));
return result.stream().distinct().toList();
}
@@ -321,25 +366,25 @@ public class UserRepoExtImpl extends
AbstractAnyRepoExt<User, Neo4jUser> impleme
neo4jTemplate.findById(user.getKey(),
Neo4jUser.class).ifPresent(before -> {
before.getRoles().stream().filter(role ->
!user.getRoles().contains(role)).
forEach(role -> deleteRelationship(
- Neo4jUser.NODE,
- Neo4jRole.NODE,
- user.getKey(),
- role.getKey(),
- Neo4jUser.ROLE_MEMBERSHIP_REL));
+ Neo4jUser.NODE,
+ Neo4jRole.NODE,
+ user.getKey(),
+ role.getKey(),
+ Neo4jUser.ROLE_MEMBERSHIP_REL));
before.getResources().stream().filter(resource ->
!user.getResources().contains(resource)).
forEach(resource -> deleteRelationship(
- Neo4jUser.NODE,
- Neo4jExternalResource.NODE,
- user.getKey(),
- resource.getKey(),
- Neo4jUser.USER_RESOURCE_REL));
+ Neo4jUser.NODE,
+ Neo4jExternalResource.NODE,
+ user.getKey(),
+ resource.getKey(),
+ Neo4jUser.USER_RESOURCE_REL));
before.getAuxClasses().stream().filter(auxClass ->
!user.getAuxClasses().contains(auxClass)).
forEach(auxClass -> deleteRelationship(
- Neo4jUser.NODE,
- Neo4jAnyTypeClass.NODE,
- user.getKey(),
- auxClass.getKey(),
- Neo4jUser.USER_AUX_CLASSES_REL));
+ Neo4jUser.NODE,
+ Neo4jAnyTypeClass.NODE,
+ user.getKey(),
+ auxClass.getKey(),
+ Neo4jUser.USER_AUX_CLASSES_REL));
if (before.getuManager() != null && user.getuManager() == null) {
deleteRelationship(
Neo4jUser.NODE,
diff --git
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/GroupTest.java
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/GroupTest.java
index 7510fd30a9..1bb2e80edc 100644
---
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/GroupTest.java
+++
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/GroupTest.java
@@ -141,33 +141,6 @@ public class GroupTest extends AbstractTest {
});
}
- @Test
- public void findByUManager() {
- Group group =
groupDAO.findById("ebf97068-aa4b-4a85-9f01-680e8c4cf227").orElseThrow();
-
- User user =
userDAO.findById("823074dc-d280-436d-a7dd-07399fae48ec").orElseThrow();
-
- assertEquals(user, group.getuManager());
-
- List<Group> managed = userDAO.findManagedGroups(user.getKey());
- assertFalse(managed.isEmpty());
- assertEquals(1, managed.size());
- assertTrue(managed.contains(group));
- }
-
- @Test
- public void findByGManager() {
- Group root = groupDAO.findByName("root").orElseThrow();
- Group group = entityFactory.newEntity(Group.class);
- group.setRealm(realmDAO.getRoot());
- group.setName("error");
- group.setgManager(root);
- group = groupDAO.save(group);
-
- List<Group> managed = groupDAO.findManagedGroups(root.getKey());
- assertEquals(List.of(group), managed);
- }
-
@Test
public void create() {
Group group = entityFactory.newEntity(Group.class);
diff --git
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/ManagerTest.java
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/ManagerTest.java
new file mode 100644
index 0000000000..a85728aeb4
--- /dev/null
+++
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/ManagerTest.java
@@ -0,0 +1,259 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.neo4j.outer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.neo4j.AbstractTest;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+class ManagerTest extends AbstractTest {
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @Autowired
+ private GroupDAO groupDAO;
+
+ @Autowired
+ private RealmDAO realmDAO;
+
+ /**
+ * (a) U2 has uManager set to U1
+ */
+ @Test
+ void findUManagedUsersA() {
+ User vivaldi = userDAO.findByUsername("vivaldi").orElseThrow();
+ assertNull(vivaldi.getgManager());
+ assertNull(vivaldi.getuManager());
+
+ User rossini = userDAO.findByUsername("rossini").orElseThrow();
+ assertFalse(userDAO.isManager(rossini.getKey()));
+
+ vivaldi.setuManager(rossini);
+ vivaldi = userDAO.save(vivaldi);
+ assertEquals(rossini, vivaldi.getuManager());
+ assertTrue(userDAO.isManager(rossini.getKey()));
+
+ List<User> managed = userDAO.findManagedUsers(rossini.getKey());
+ assertEquals(List.of(vivaldi), managed);
+ }
+
+ /**
+ * (b) G2 has uManager set to U1
+ */
+ @Test
+ void findUManagedUsersB() {
+ Group artDirector = groupDAO.findByName("artDirector").orElseThrow();
+ assertNull(artDirector.getuManager());
+ assertNull(artDirector.getgManager());
+
+ User vivaldi = userDAO.findByUsername("vivaldi").orElseThrow();
+ assertFalse(userDAO.isManager(vivaldi.getKey()));
+
+ artDirector.setuManager(vivaldi);
+ artDirector = groupDAO.save(artDirector);
+ assertEquals(vivaldi, artDirector.getuManager());
+ assertTrue(userDAO.isManager(vivaldi.getKey()));
+
+ User puccini = userDAO.findByUsername("puccini").orElseThrow();
+ assertNull(puccini.getgManager());
+ assertNull(puccini.getuManager());
+ assertTrue(puccini.getMembership(artDirector.getKey()).isPresent());
+
+ List<User> managed = userDAO.findManagedUsers(vivaldi.getKey());
+ assertEquals(List.of(puccini), managed);
+ }
+
+ /**
+ * (c) U2 has gManager set to G1
+ */
+ @Test
+ void findUManagedUsersC() {
+ Group managingDirector =
groupDAO.findByName("managingDirector").orElseThrow();
+ assertFalse(groupDAO.isManager(managingDirector.getKey()));
+
+ User bellini = userDAO.findByUsername("bellini").orElseThrow();
+
assertTrue(bellini.getMembership(managingDirector.getKey()).isPresent());
+ assertFalse(userDAO.isManager(bellini.getKey()));
+
+ User rossini = userDAO.findByUsername("rossini").orElseThrow();
+ assertNull(rossini.getgManager());
+ assertNull(rossini.getuManager());
+
+ rossini.setgManager(managingDirector);
+ rossini = userDAO.save(rossini);
+ assertEquals(managingDirector, rossini.getgManager());
+ assertTrue(groupDAO.isManager(managingDirector.getKey()));
+
+ List<User> managed = userDAO.findManagedUsers(bellini.getKey());
+ assertEquals(List.of(rossini), managed);
+ }
+
+ /**
+ * (d) G2 has gManager set to G1
+ */
+ @Test
+ void findUManagedUsersD() {
+ Group managingDirector =
groupDAO.findByName("managingDirector").orElseThrow();
+ assertFalse(groupDAO.isManager(managingDirector.getKey()));
+
+ User bellini = userDAO.findByUsername("bellini").orElseThrow();
+
assertTrue(bellini.getMembership(managingDirector.getKey()).isPresent());
+ assertFalse(userDAO.isManager(bellini.getKey()));
+
+ Group otherchild = groupDAO.findByName("otherchild").orElseThrow();
+ assertNull(otherchild.getgManager());
+ assertNull(otherchild.getuManager());
+
+ User rossini = userDAO.findByUsername("rossini").orElseThrow();
+ assertTrue(rossini.getMembership(otherchild.getKey()).isPresent());
+ rossini.setuManager(null);
+ rossini.setgManager(null);
+ rossini = userDAO.save(rossini);
+ assertNull(rossini.getgManager());
+ assertNull(rossini.getuManager());
+
+ otherchild.setgManager(managingDirector);
+ otherchild = groupDAO.save(otherchild);
+ assertEquals(managingDirector, otherchild.getgManager());
+ assertTrue(groupDAO.isManager(managingDirector.getKey()));
+
+ List<User> managed = userDAO.findManagedUsers(bellini.getKey());
+ assertEquals(List.of(rossini), managed);
+ }
+
+ /**
+ * (a) G2 has uManager set to U1 - see UserDAO#findManagedGroups
+ */
+ @Test
+ void findUManagedGroupsA() {
+ Group director = groupDAO.findByName("director").orElseThrow();
+ User puccini = userDAO.findByUsername("puccini").orElseThrow();
+ assertEquals(puccini, director.getuManager());
+ assertTrue(userDAO.isManager(puccini.getKey()));
+
+ List<Group> managed = userDAO.findManagedGroups(puccini.getKey());
+ assertEquals(List.of(director), managed);
+ }
+
+ /**
+ * (b) G2 has gManager set to G1 - see UserDAO#findManagedGroups
+ */
+ @Test
+ void findUManagedGroupsB() {
+ Group managingDirector =
groupDAO.findByName("managingDirector").orElseThrow();
+ assertFalse(groupDAO.isManager(managingDirector.getKey()));
+
+ Group root = groupDAO.findByName("root").orElseThrow();
+ assertNull(root.getgManager());
+ assertNull(root.getuManager());
+
+ root.setgManager(managingDirector);
+ root = groupDAO.save(root);
+ assertEquals(managingDirector, root.getgManager());
+ assertTrue(groupDAO.isManager(managingDirector.getKey()));
+
+ User bellini = userDAO.findByUsername("bellini").orElseThrow();
+
assertTrue(bellini.getMembership(managingDirector.getKey()).isPresent());
+
+ List<Group> managed = userDAO.findManagedGroups(bellini.getKey());
+ assertEquals(List.of(root), managed);
+ }
+
+ /**
+ * (a) U has gManager set to G1
+ */
+ @Test
+ void findGManagedUsersA() {
+ Group citizen = groupDAO.findByName("citizen").orElseThrow();
+ assertFalse(groupDAO.isManager(citizen.getKey()));
+
+ User verdi = userDAO.findByUsername("verdi").orElseThrow();
+ assertNull(verdi.getgManager());
+ assertNull(verdi.getuManager());
+
+ verdi.setgManager(citizen);
+ verdi = userDAO.save(verdi);
+ assertEquals(citizen, verdi.getgManager());
+ assertTrue(groupDAO.isManager(citizen.getKey()));
+
+ List<User> managed = groupDAO.findManagedUsers(citizen.getKey());
+ assertEquals(List.of(verdi), managed);
+ }
+
+ /**
+ * (b) G2 has gManager set to G1
+ */
+ @Test
+ void findGManagedUsersB() {
+ Group managingDirector =
groupDAO.findByName("managingDirector").orElseThrow();
+ assertFalse(groupDAO.isManager(managingDirector.getKey()));
+
+ User bellini = userDAO.findByUsername("bellini").orElseThrow();
+
assertTrue(bellini.getMembership(managingDirector.getKey()).isPresent());
+
+ Group citizen = groupDAO.findByName("citizen").orElseThrow();
+ assertNull(citizen.getgManager());
+ assertNull(citizen.getuManager());
+
+ User verdi = userDAO.findByUsername("verdi").orElseThrow();
+ assertTrue(verdi.getMembership(citizen.getKey()).isPresent());
+
+ citizen.setgManager(managingDirector);
+ citizen = groupDAO.save(citizen);
+ assertEquals(managingDirector, citizen.getgManager());
+ assertTrue(groupDAO.isManager(managingDirector.getKey()));
+
+ List<User> managed =
groupDAO.findManagedUsers(managingDirector.getKey());
+ assertEquals(List.of(verdi), managed);
+ }
+
+ /**
+ * (a) G2 has gManager set to G1 - see GroupDAO#findManagedGroups
+ */
+ @Test
+ void findGManagedGroups() {
+ Group root = groupDAO.findByName("root").orElseThrow();
+ assertFalse(groupDAO.isManager(root.getKey()));
+
+ Group group = entityFactory.newEntity(Group.class);
+ group.setRealm(realmDAO.getRoot());
+ group.setName("error");
+ group.setgManager(root);
+ group = groupDAO.save(group);
+ assertEquals(root, group.getgManager());
+ assertTrue(groupDAO.isManager(root.getKey()));
+
+ List<Group> managed = groupDAO.findManagedGroups(root.getKey());
+ assertEquals(List.of(group), managed);
+ }
+}
diff --git
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
index 7e0f3e9c66..de35fb202a 100644
---
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
+++
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
@@ -205,7 +205,7 @@ public class SelfKeymasterContext {
openapiFeature.setUseContextBasedConfig(true);
openapiFeature.setTitle("Apache Syncope Self Keymaster");
openapiFeature.setVersion(version);
- openapiFeature.setDescription("Apache Syncope Self Keymaster" +
version);
+ openapiFeature.setDescription("Apache Syncope Self Keymaster " +
version);
openapiFeature.setContactName("The Apache Syncope community");
openapiFeature.setContactEmail("[email protected]");
openapiFeature.setContactUrl("https://syncope.apache.org");
diff --git
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
index b87d9e9d7e..2d5d907840 100644
---
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
+++
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
@@ -36,6 +36,7 @@ import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
import org.apache.syncope.common.keymaster.client.api.StandardConfParams;
@@ -570,34 +571,44 @@ public class AuthDataAccessor {
// Give role entitlements
userDAO.findAllRoles(user).forEach(role -> role.getEntitlements().
- forEach(e -> populateEntForRealms(entForRealms, e,
role.getRealms().stream().map(Realm::getFullPath).
- toList())));
+ forEach(e -> populateEntForRealms(
+ entForRealms, e,
role.getRealms().stream().map(Realm::getFullPath).toList())));
// Give manager entitlements
- if (userDAO.isManager(user.getKey())) {
+ MutableBoolean manager = new MutableBoolean(false);
+ userDAO.findManagedUsers(user.getKey()).forEach(managedUser -> {
+ USER_MANAGER_ENTITLEMENTS.forEach(e -> populateEntForRealms(
+ entForRealms, e, Set.of(new RealmUtils.ManagerRealm(
+ managedUser.getRealm().getFullPath(),
+ AnyTypeKind.USER,
+ managedUser.getKey()).output())));
+ manager.setTrue();
+ });
+
+ userDAO.findManagedGroups(user.getKey()).forEach(group -> {
+ GROUP_MANAGER_ENTITLEMENTS.forEach(e -> populateEntForRealms(
+ entForRealms, e, Set.of(new RealmUtils.ManagerRealm(
+ group.getRealm().getFullPath(),
+ AnyTypeKind.GROUP,
+ group.getKey()).output())));
+ manager.setTrue();
+ });
+
+ userDAO.findManagedAnyObjects(user.getKey()).forEach(anyObject -> {
+
ANYOBJECT_MANAGER_ENTITLEMENTS.apply(anyObject.getType().getKey()).forEach(e ->
populateEntForRealms(
+ entForRealms, e, Set.of(
+ new RealmUtils.ManagerRealm(
+ anyObject.getRealm().getFullPath(),
+ AnyTypeKind.ANY_OBJECT,
+ anyObject.getKey()).output())));
+ manager.setTrue();
+ });
+
+ if (manager.isTrue()) {
BASE_MANAGER_ENTITLEMENTS.forEach(e -> populateEntForRealms(
entForRealms, e, SyncopeConstants.FULL_ADMIN_REALMS));
}
- userDAO.findManagedUsers(user.getKey()).forEach(managedUser ->
USER_MANAGER_ENTITLEMENTS.
- forEach(e -> populateEntForRealms(entForRealms, e, Set.of(new
RealmUtils.ManagerRealm(
- managedUser.getRealm().getFullPath(),
- AnyTypeKind.USER,
- managedUser.getKey()).output()))));
-
- userDAO.findManagedGroups(user.getKey()).forEach(group ->
GROUP_MANAGER_ENTITLEMENTS.
- forEach(e -> populateEntForRealms(entForRealms, e, Set.of(new
RealmUtils.ManagerRealm(
- group.getRealm().getFullPath(),
- AnyTypeKind.GROUP,
- group.getKey()).output()))));
-
- userDAO.findManagedAnyObjects(user.getKey()).forEach(anyObject ->
ANYOBJECT_MANAGER_ENTITLEMENTS.
- apply(anyObject.getType().getKey()).forEach(e ->
populateEntForRealms(entForRealms, e, Set.of(
- new RealmUtils.ManagerRealm(
- anyObject.getRealm().getFullPath(),
- AnyTypeKind.ANY_OBJECT,
- anyObject.getKey()).output()))));
-
return buildAuthorities(entForRealms);
}
diff --git a/pom.xml b/pom.xml
index fdfd0aa3a0..36621e3cb1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2087,33 +2087,33 @@ under the License.
<groupId>org.apache.rat</groupId>
<artifactId>apache-rat-plugin</artifactId>
<configuration>
- <excludes>
- <exclude>**/nbactions.xml</exclude>
- <exclude>**/nb-configuration.xml</exclude>
- <exclude>**/META-INF/cxf/**</exclude>
- <exclude>**/META-INF/services/**</exclude>
- <exclude>**/META-INF/MANIFEST.MF</exclude>
- <exclude>**/*.csv</exclude>
- <exclude>**/archetype-resources/**</exclude>
- <exclude>**/adminlte*</exclude>
- <exclude>**/dataTables.bootstrap5.min.css</exclude>
- <exclude>**/goal.txt</exclude>
- <exclude>**/rat.txt</exclude>
- <exclude>**/build-copy-javadoc-files.xml</exclude>
- <exclude>**/maven-eclipse.xml</exclude>
- <exclude>**/*.iml</exclude>
- <exclude>**/*.log</exclude>
- <exclude>**/.externalToolBuilders/**</exclude>
- <exclude>.git/**</exclude>
- <exclude>.idea/**</exclude>
- <exclude>**/.settings/**</exclude>
- <exclude>**/.*</exclude>
- <exclude>**/*.lst</exclude>
- <exclude>**/*.json</exclude>
- <exclude>**/*font*awesome*</exclude>
- <exclude>**/banner.txt</exclude>
- <exclude>**/target/**</exclude>
- </excludes>
+ <inputExcludes>
+ <inputExclude>**/nbactions.xml</inputExclude>
+ <inputExclude>**/nb-configuration.xml</inputExclude>
+ <inputExclude>**/META-INF/cxf/**</inputExclude>
+ <inputExclude>**/META-INF/services/**</inputExclude>
+ <inputExclude>**/META-INF/MANIFEST.MF</inputExclude>
+ <inputExclude>**/*.csv</inputExclude>
+ <inputExclude>**/archetype-resources/**</inputExclude>
+ <inputExclude>**/adminlte*</inputExclude>
+ <inputExclude>**/dataTables.bootstrap5.min.css</inputExclude>
+ <inputExclude>**/goal.txt</inputExclude>
+ <inputExclude>**/rat.txt</inputExclude>
+ <inputExclude>**/build-copy-javadoc-files.xml</inputExclude>
+ <inputExclude>**/maven-eclipse.xml</inputExclude>
+ <inputExclude>**/*.iml</inputExclude>
+ <inputExclude>**/*.log</inputExclude>
+ <inputExclude>**/.externalToolBuilders/**</inputExclude>
+ <inputExclude>.git/**</inputExclude>
+ <inputExclude>.idea/**</inputExclude>
+ <inputExclude>**/.settings/**</inputExclude>
+ <inputExclude>**/.*</inputExclude>
+ <inputExclude>**/*.lst</inputExclude>
+ <inputExclude>**/*.json</inputExclude>
+ <inputExclude>**/*font*awesome*</inputExclude>
+ <inputExclude>**/banner.txt</inputExclude>
+ <inputExclude>**/target/**</inputExclude>
+ </inputExcludes>
</configuration>
<executions>
<execution>