This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new adb12ca7ad [SYNCOPE-1889] improve group search using SCIM extension
(#1127)
adb12ca7ad is described below
commit adb12ca7adbe395faa2e4e0b30d349116cbad74c
Author: Samuel Garofalo <[email protected]>
AuthorDate: Fri Jul 4 13:52:18 2025 +0200
[SYNCOPE-1889] improve group search using SCIM extension (#1127)
---
.../syncope/core/persistence/api/dao/GroupDAO.java | 3 +-
.../common/dao/AbstractAnyMatchDAO.java | 3 +-
.../persistence/jpa/dao/repo/GroupRepoExt.java | 3 +-
.../persistence/jpa/dao/repo/GroupRepoExtImpl.java | 12 ++++++--
.../core/persistence/jpa/outer/GroupTest.java | 3 +-
.../core/persistence/jpa/outer/UserTest.java | 6 ++--
.../persistence/neo4j/dao/repo/GroupRepoExt.java | 3 +-
.../neo4j/dao/repo/GroupRepoExtImpl.java | 13 +++++++--
.../core/persistence/neo4j/outer/GroupTest.java | 3 +-
.../core/persistence/neo4j/outer/UserTest.java | 6 ++--
.../java/data/GroupDataBinderImpl.java | 3 +-
.../java/pushpull/LDAPMembershipPullActions.java | 3 +-
.../pushpull/LDAPMembershipPullActionsTest.java | 5 +++-
.../elasticsearch/client/ElasticsearchUtils.java | 3 +-
.../flowable/support/SyncopeUserQueryImpl.java | 3 +-
.../ext/opensearch/client/OpenSearchUtils.java | 3 +-
.../apache/syncope/core/logic/SCIMDataBinder.java | 32 +++++++++++++---------
.../syncope/core/logic/SCIMLogicContext.java | 6 ++--
.../syncope/core/logic/SCIMDataBinderTest.java | 4 ++-
.../org/apache/syncope/fit/core/SCIMITCase.java | 32 ++++++++++++++++++++++
20 files changed, 111 insertions(+), 38 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 bae211073c..075afed7b0 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
@@ -31,6 +31,7 @@ import
org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
import org.apache.syncope.core.persistence.api.entity.user.UMembership;
import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.springframework.data.domain.Pageable;
public interface GroupDAO extends AnyDAO<Group> {
@@ -58,7 +59,7 @@ public interface GroupDAO extends AnyDAO<Group> {
List<AMembership> findAMemberships(Group group);
- List<UMembership> findUMemberships(Group group);
+ List<UMembership> findUMemberships(Group group, Pageable pageable);
List<String> findAMembers(String groupKey);
diff --git
a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/dao/AbstractAnyMatchDAO.java
b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/dao/AbstractAnyMatchDAO.java
index b511bc163c..eadd640bc1 100644
---
a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/dao/AbstractAnyMatchDAO.java
+++
b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/dao/AbstractAnyMatchDAO.java
@@ -67,6 +67,7 @@ import
org.apache.syncope.core.persistence.api.entity.user.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
+import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
public abstract class AbstractAnyMatchDAO implements AnyMatchDAO {
@@ -274,7 +275,7 @@ public abstract class AbstractAnyMatchDAO implements
AnyMatchDAO {
||
groupDAO.findADynMembers(group).contains(cond.getMember());
}
} else {
- found = groupDAO.findUMemberships(group).stream().
+ found = groupDAO.findUMemberships(group,
Pageable.unpaged()).stream().
anyMatch(memb ->
memb.getLeftEnd().getKey().equals(cond.getMember()))
||
groupDAO.findUDynMembers(group).contains(cond.getMember());
}
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 cc7004b39a..0ff0c94649 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
@@ -29,6 +29,7 @@ import
org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
import org.apache.syncope.core.persistence.api.entity.user.UMembership;
import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.springframework.data.domain.Pageable;
public interface GroupRepoExt extends AnyRepoExt<Group> {
@@ -48,7 +49,7 @@ public interface GroupRepoExt extends AnyRepoExt<Group> {
List<AMembership> findAMemberships(Group group);
- List<UMembership> findUMemberships(Group group);
+ List<UMembership> findUMemberships(Group group, Pageable pageable);
Group saveAndRefreshDynMemberships(Group 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 e06e96a078..427757ca23 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
@@ -69,6 +69,7 @@ import
org.apache.syncope.core.spring.security.DelegatedAdministrationException;
import org.identityconnectors.framework.common.objects.SyncDeltaType;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
public class GroupRepoExtImpl extends AbstractAnyRepoExt<Group> implements
GroupRepoExt {
@@ -214,11 +215,16 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group> implements Group
}
@Override
- public List<UMembership> findUMemberships(final Group group) {
+ 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",
+ "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();
}
@@ -308,7 +314,7 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group> implements Group
new EntityLifecycleEvent<>(this, SyncDeltaType.UPDATE,
leftEnd, AuthContextUtils.getDomain()));
});
- findUMemberships(group).forEach(membership -> {
+ findUMemberships(group, Pageable.unpaged()).forEach(membership -> {
User leftEnd = membership.getLeftEnd();
leftEnd.remove(membership);
membership.setRightEnd(null);
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 fbf58712d5..f41d052cbd 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
@@ -61,6 +61,7 @@ import
org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADynGroupMemb
import
org.apache.syncope.core.persistence.jpa.entity.user.JPAUDynGroupMembership;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.transaction.annotation.Transactional;
@@ -115,7 +116,7 @@ public class GroupTest extends AbstractTest {
@Test
public void uMemberships() {
List<UMembership> memberships = groupDAO.findUMemberships(
-
groupDAO.findById("37d15e4c-cdc1-460b-a591-8505c8133806").orElseThrow());
+
groupDAO.findById("37d15e4c-cdc1-460b-a591-8505c8133806").orElseThrow(),
Pageable.unpaged());
assertEquals(2, memberships.size());
assertTrue(memberships.stream().anyMatch(m ->
"3d5e91f6-305e-45f9-ad30-4897d3d43bd9".equals(m.getKey())));
assertTrue(memberships.stream().anyMatch(m ->
"d53f7657-2b22-4e10-a2cd-c3379a4d1a31".equals(m.getKey())));
diff --git
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
index cda04cc3ae..b4bb2186df 100644
---
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
+++
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
@@ -51,6 +51,7 @@ import org.apache.syncope.core.persistence.jpa.AbstractTest;
import org.apache.syncope.core.persistence.jpa.entity.user.JPALinkedAccount;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.transaction.annotation.Transactional;
@@ -91,7 +92,7 @@ public class UserTest extends AbstractTest {
@Test
public void delete() {
List<UMembership> memberships = groupDAO.findUMemberships(
- groupDAO.findByName("managingDirector").orElseThrow());
+ groupDAO.findByName("managingDirector").orElseThrow(),
Pageable.unpaged());
assertFalse(memberships.isEmpty());
userDAO.deleteById("c9b2dec2-00a7-4855-97c0-d854842b4b24");
@@ -101,7 +102,8 @@ public class UserTest extends AbstractTest {
assertTrue(userDAO.findByUsername("bellini").isEmpty());
assertTrue(plainSchemaDAO.findById("loginDate").isPresent());
- memberships =
groupDAO.findUMemberships(groupDAO.findByName("managingDirector").orElseThrow());
+ memberships = groupDAO.findUMemberships(
+ groupDAO.findByName("managingDirector").orElseThrow(),
Pageable.unpaged());
assertTrue(memberships.isEmpty());
}
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 8486469408..3aace7086e 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
@@ -29,6 +29,7 @@ import
org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
import org.apache.syncope.core.persistence.api.entity.user.UMembership;
import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.springframework.data.domain.Pageable;
public interface GroupRepoExt extends AnyRepoExt<Group> {
@@ -48,7 +49,7 @@ public interface GroupRepoExt extends AnyRepoExt<Group> {
List<AMembership> findAMemberships(Group group);
- List<UMembership> findUMemberships(Group group);
+ List<UMembership> findUMemberships(Group group, Pageable pageable);
Group saveAndRefreshDynMemberships(Group 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 4aa022737d..1d537d2816 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
@@ -80,6 +80,7 @@ import
org.apache.syncope.core.spring.security.DelegatedAdministrationException;
import org.identityconnectors.framework.common.objects.SyncDeltaType;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.transaction.annotation.Transactional;
@@ -260,11 +261,17 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group, Neo4jGroup> impl
}
@Override
- public List<UMembership> findUMemberships(final Group group) {
+ 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").bindAll(Map.of("id",
group.getKey())).fetch().all(),
+ + "RETURN n.id" + paged)
+ .bindAll(Map.of("id", group.getKey())).fetch().all(),
"n.id",
Neo4jUMembership.class,
null);
@@ -406,7 +413,7 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group, Neo4jGroup> impl
new EntityLifecycleEvent<>(this, SyncDeltaType.UPDATE,
leftEnd, AuthContextUtils.getDomain()));
});
- findUMemberships(group).forEach(membership -> {
+ findUMemberships(group, Pageable.unpaged()).forEach(membership -> {
User leftEnd = membership.getLeftEnd();
leftEnd.remove(membership);
membership.setRightEnd(null);
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 84d0772608..ef74532e6d 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
@@ -57,6 +57,7 @@ import
org.apache.syncope.core.persistence.neo4j.entity.anyobject.Neo4jADynGroup
import
org.apache.syncope.core.persistence.neo4j.entity.user.Neo4jUDynGroupMembership;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.transaction.annotation.Transactional;
@@ -113,7 +114,7 @@ public class GroupTest extends AbstractTest {
@Test
public void uMemberships() {
List<UMembership> memberships = groupDAO.findUMemberships(
-
groupDAO.findById("37d15e4c-cdc1-460b-a591-8505c8133806").orElseThrow());
+
groupDAO.findById("37d15e4c-cdc1-460b-a591-8505c8133806").orElseThrow(),
Pageable.unpaged());
assertEquals(2, memberships.size());
assertTrue(memberships.stream().anyMatch(m ->
"3d5e91f6-305e-45f9-ad30-4897d3d43bd9".equals(m.getKey())));
assertTrue(memberships.stream().anyMatch(m ->
"d53f7657-2b22-4e10-a2cd-c3379a4d1a31".equals(m.getKey())));
diff --git
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/UserTest.java
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/UserTest.java
index 3499d17a63..9f596eb402 100644
---
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/UserTest.java
+++
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/UserTest.java
@@ -49,6 +49,7 @@ import org.apache.syncope.core.persistence.neo4j.AbstractTest;
import
org.apache.syncope.core.persistence.neo4j.entity.user.Neo4jLinkedAccount;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.transaction.annotation.Transactional;
@@ -91,7 +92,7 @@ public class UserTest extends AbstractTest {
@Test
public void delete() {
List<UMembership> memberships = groupDAO.findUMemberships(
- groupDAO.findByName("managingDirector").orElseThrow());
+ groupDAO.findByName("managingDirector").orElseThrow(),
Pageable.unpaged());
assertFalse(memberships.isEmpty());
userDAO.deleteById("c9b2dec2-00a7-4855-97c0-d854842b4b24");
@@ -99,7 +100,8 @@ public class UserTest extends AbstractTest {
assertTrue(userDAO.findByUsername("bellini").isEmpty());
assertTrue(plainSchemaDAO.findById("loginDate").isPresent());
- memberships =
groupDAO.findUMemberships(groupDAO.findByName("managingDirector").orElseThrow());
+ memberships = groupDAO.findUMemberships(
+ groupDAO.findByName("managingDirector").orElseThrow(),
Pageable.unpaged());
assertTrue(memberships.isEmpty());
}
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
index e8c11d92ce..9ede39b550 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
@@ -75,6 +75,7 @@ import
org.apache.syncope.core.provisioning.api.MappingManager;
import org.apache.syncope.core.provisioning.api.PropagationByResource;
import org.apache.syncope.core.provisioning.api.data.GroupDataBinder;
import org.apache.syncope.core.provisioning.java.pushpull.OutboundMatcher;
+import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
@Transactional(rollbackFor = { Throwable.class })
@@ -580,7 +581,7 @@ public class GroupDataBinderImpl extends AnyDataBinder
implements GroupDataBinde
Map<String, PropagationByResource<String>> result = new HashMap<>();
- groupDAO.findUMemberships(group).
+ groupDAO.findUMemberships(group, Pageable.unpaged()).
forEach((membership) -> populateTransitiveResources(group,
membership.getLeftEnd(), result));
return result;
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
index 11d4c67d74..51edb543ee 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
@@ -52,6 +52,7 @@ import
org.identityconnectors.framework.common.objects.LiveSyncDelta;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@@ -129,7 +130,7 @@ public class LDAPMembershipPullActions implements
InboundActions {
}
groupDAO.findUMemberships(groupDAO.findById(entity.getKey()).
- orElseThrow(() -> new NotFoundException("Group " +
entity.getKey()))).
+ orElseThrow(() -> new NotFoundException("Group " +
entity.getKey())), Pageable.unpaged()).
forEach(uMembership -> {
Set<String> memb = membershipsBefore.computeIfAbsent(
uMembership.getLeftEnd().getKey(),
diff --git
a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java
b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java
index a5852e59a0..f7138cc600 100644
---
a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java
+++
b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java
@@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -68,6 +69,7 @@ import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
import org.springframework.test.util.ReflectionTestUtils;
public class LDAPMembershipPullActionsTest extends AbstractTest {
@@ -142,7 +144,8 @@ public class LDAPMembershipPullActionsTest extends
AbstractTest {
ReflectionTestUtils.setField(ldapMembershipPullActions,
"membershipsAfter", membershipsAfter);
lenient().when(groupDAO.findById(anyString())).thenAnswer(ic ->
Optional.of(mock(Group.class)));
-
lenient().when(groupDAO.findUMemberships(any(Group.class))).thenReturn(List.of(uMembership));
+ lenient().when(groupDAO.findUMemberships(any(Group.class),
eq(Pageable.unpaged())))
+ .thenReturn(List.of(uMembership));
ConnConfPropSchema connConfPropSchema = new ConnConfPropSchema();
connConfPropSchema.setName("testSchemaName");
diff --git
a/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java
b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java
index 5a95a11607..1f887cd7c8 100644
---
a/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java
+++
b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java
@@ -44,6 +44,7 @@ import org.apache.syncope.core.persistence.api.entity.Role;
import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
import org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
/**
@@ -146,7 +147,7 @@ public class ElasticsearchUtils {
Optional.ofNullable(group.getGroupOwner()).ifPresent(go ->
builder.put("groupOwner", go.getKey()));
Set<String> members = new HashSet<>();
- members.addAll(groupDAO.findUMemberships(group).stream().
+ members.addAll(groupDAO.findUMemberships(group,
Pageable.unpaged()).stream().
map(membership ->
membership.getLeftEnd().getKey()).toList());
members.addAll(groupDAO.findUDynMembers(group));
members.addAll(groupDAO.findAMemberships(group).stream().
diff --git
a/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/support/SyncopeUserQueryImpl.java
b/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/support/SyncopeUserQueryImpl.java
index 5868a97fc4..ecdf1425e6 100644
---
a/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/support/SyncopeUserQueryImpl.java
+++
b/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/support/SyncopeUserQueryImpl.java
@@ -27,6 +27,7 @@ import org.flowable.idm.engine.impl.UserQueryImpl;
import org.flowable.idm.engine.impl.persistence.entity.UserEntity;
import org.flowable.idm.engine.impl.persistence.entity.UserEntityImpl;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
public class SyncopeUserQueryImpl extends UserQueryImpl {
@@ -56,7 +57,7 @@ public class SyncopeUserQueryImpl extends UserQueryImpl {
} else if (groupId != null) {
groupDAO.findByName(groupId).map(group -> {
List<User> r = new ArrayList<>();
- groupDAO.findUMemberships(group).stream().map(m ->
fromSyncopeUser(m.getLeftEnd())).
+ groupDAO.findUMemberships(group,
Pageable.unpaged()).stream().map(m -> fromSyncopeUser(m.getLeftEnd())).
filter(user -> !r.contains(user)).
forEach(r::add);
return r;
diff --git
a/ext/opensearch/client-opensearch/src/main/java/org/apache/syncope/ext/opensearch/client/OpenSearchUtils.java
b/ext/opensearch/client-opensearch/src/main/java/org/apache/syncope/ext/opensearch/client/OpenSearchUtils.java
index afdb185449..b94ee902dc 100644
---
a/ext/opensearch/client-opensearch/src/main/java/org/apache/syncope/ext/opensearch/client/OpenSearchUtils.java
+++
b/ext/opensearch/client-opensearch/src/main/java/org/apache/syncope/ext/opensearch/client/OpenSearchUtils.java
@@ -44,6 +44,7 @@ import org.apache.syncope.core.persistence.api.entity.Role;
import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
import org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
/**
@@ -146,7 +147,7 @@ public class OpenSearchUtils {
Optional.ofNullable(group.getGroupOwner()).ifPresent(go ->
builder.put("groupOwner", go.getKey()));
Set<String> members = new HashSet<>();
- members.addAll(groupDAO.findUMemberships(group).stream().
+ members.addAll(groupDAO.findUMemberships(group,
Pageable.unpaged()).stream().
map(membership ->
membership.getLeftEnd().getKey()).toList());
members.addAll(groupDAO.findUDynMembers(group));
members.addAll(groupDAO.findAMemberships(group).stream().
diff --git
a/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMDataBinder.java
b/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMDataBinder.java
index e9292daa2b..389e6658d7 100644
---
a/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMDataBinder.java
+++
b/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMDataBinder.java
@@ -54,8 +54,11 @@ import org.apache.syncope.common.lib.types.PatchOperation;
import org.apache.syncope.common.lib.types.StatusRType;
import org.apache.syncope.core.logic.scim.SCIMConfManager;
import org.apache.syncope.core.persistence.api.dao.AnyDAO;
+import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
import org.apache.syncope.core.persistence.api.dao.search.MembershipCond;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.entity.user.UMembership;
import org.apache.syncope.core.provisioning.api.jexl.JexlUtils;
import org.apache.syncope.core.spring.security.AuthDataAccessor;
import org.apache.syncope.ext.scimv2.api.BadRequestException;
@@ -79,6 +82,7 @@ import org.apache.syncope.ext.scimv2.api.type.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
public class SCIMDataBinder {
@@ -123,14 +127,18 @@ public class SCIMDataBinder {
protected final AuthDataAccessor authDataAccessor;
+ protected final GroupDAO groupDAO;
+
public SCIMDataBinder(
final SCIMConfManager confManager,
final UserLogic userLogic,
- final AuthDataAccessor authDataAccessor) {
+ final AuthDataAccessor authDataAccessor,
+ final GroupDAO groupDAO) {
this.confManager = confManager;
this.userLogic = userLogic;
this.authDataAccessor = authDataAccessor;
+ this.groupDAO = groupDAO;
}
protected <E extends Enum<?>> void fill(
@@ -991,6 +999,7 @@ public class SCIMDataBinder {
return Pair.of(userUR, statusR);
}
+ @Transactional(readOnly = true)
public SCIMGroup toSCIMGroup(
final GroupTO groupTO,
final String location,
@@ -1029,18 +1038,15 @@ public class SCIMDataBinder {
long count = userLogic.search(
searchCond, PageRequest.of(0, 1),
SyncopeConstants.ROOT_REALM, true, false).getTotalElements();
- for (int page = 0; page <= (count / AnyDAO.DEFAULT_PAGE_SIZE);
page++) {
- List<UserTO> users = userLogic.search(
- searchCond,
- PageRequest.of(page, AnyDAO.DEFAULT_PAGE_SIZE),
- SyncopeConstants.ROOT_REALM,
- true,
- false).
- getContent();
- users.forEach(userTO -> group.getMembers().add(new Member(
- userTO.getKey(),
- StringUtils.substringBefore(location, "/Groups") +
"/Users/" + userTO.getKey(),
- userTO.getUsername())));
+ for (int page = 0; page <= (count / AnyDAO.DEFAULT_PAGE_SIZE) + 1;
page++) {
+ List<UMembership> users = groupDAO.findUMemberships(
+ groupDAO.findById(groupTO.getKey())
+ .orElseThrow(() -> new
NotFoundException("Group " + groupTO.getKey())),
+ PageRequest.of(page, AnyDAO.DEFAULT_PAGE_SIZE));
+ users.forEach(uMembership -> group.getMembers().add(new Member(
+ uMembership.getLeftEnd().getKey(),
+ StringUtils.substringBefore(location, "/Groups") +
"/Users/" + uMembership.getKey(),
+ uMembership.getLeftEnd().getUsername())));
}
}
diff --git
a/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMLogicContext.java
b/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMLogicContext.java
index 559146e273..968dd69dfc 100644
---
a/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMLogicContext.java
+++
b/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMLogicContext.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.logic;
import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
import org.apache.syncope.core.logic.init.SCIMLoader;
import org.apache.syncope.core.logic.scim.SCIMConfManager;
+import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.spring.security.AuthDataAccessor;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
@@ -46,9 +47,10 @@ public class SCIMLogicContext {
public SCIMDataBinder scimDataBinder(
final SCIMConfManager confManager,
final UserLogic userLogic,
- final AuthDataAccessor authDataAccessor) {
+ final AuthDataAccessor authDataAccessor,
+ final GroupDAO groupDAO) {
- return new SCIMDataBinder(confManager, userLogic, authDataAccessor);
+ return new SCIMDataBinder(confManager, userLogic, authDataAccessor,
groupDAO);
}
@ConditionalOnMissingBean
diff --git
a/ext/scimv2/logic/src/test/java/org/apache/syncope/core/logic/SCIMDataBinderTest.java
b/ext/scimv2/logic/src/test/java/org/apache/syncope/core/logic/SCIMDataBinderTest.java
index c3f378c147..d65e4b9d63 100644
---
a/ext/scimv2/logic/src/test/java/org/apache/syncope/core/logic/SCIMDataBinderTest.java
+++
b/ext/scimv2/logic/src/test/java/org/apache/syncope/core/logic/SCIMDataBinderTest.java
@@ -27,6 +27,7 @@ import java.util.stream.Stream;
import org.apache.syncope.common.lib.scim.SCIMConf;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.core.logic.scim.SCIMConfManager;
+import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.spring.security.AuthDataAccessor;
import org.apache.syncope.ext.scimv2.api.data.SCIMPatchOperation;
import org.apache.syncope.ext.scimv2.api.data.SCIMPatchPath;
@@ -50,7 +51,8 @@ class SCIMDataBinderTest {
when(scimConfManager.get()).thenReturn(new SCIMConf());
UserLogic userLogic = mock(UserLogic.class);
AuthDataAccessor authDataAccessor = mock(AuthDataAccessor.class);
- dataBinder = new SCIMDataBinder(scimConfManager, userLogic,
authDataAccessor);
+ GroupDAO groupDAO = mock(GroupDAO.class);
+ dataBinder = new SCIMDataBinder(scimConfManager, userLogic,
authDataAccessor, groupDAO);
}
@ParameterizedTest
diff --git
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SCIMITCase.java
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SCIMITCase.java
index 999b2c8dc3..6d8625db70 100644
---
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SCIMITCase.java
+++
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SCIMITCase.java
@@ -45,6 +45,7 @@ import java.util.List;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.request.GroupUR;
import org.apache.syncope.common.lib.request.StringPatchItem;
import org.apache.syncope.common.lib.request.UserUR;
@@ -63,6 +64,7 @@ import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.PatchOperation;
import org.apache.syncope.common.rest.api.Preference;
import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.beans.AnyQuery;
import org.apache.syncope.ext.scimv2.api.SCIMConstants;
import org.apache.syncope.ext.scimv2.api.data.Group;
import org.apache.syncope.ext.scimv2.api.data.ListResponse;
@@ -385,6 +387,36 @@ public class SCIMITCase extends AbstractITCase {
SCIMGroup additional = groups.getResources().getFirst();
assertEquals("additional", additional.getDisplayName());
+ List<UserTO> usersList = USER_SERVICE.search(new AnyQuery.Builder()
+ .realm(SyncopeConstants.ROOT_REALM)
+ .page(0)
+ .size(15)
+ .fiql("$groups==additional")
+ .build()).getResult();
+ assertEquals(usersList.size(), additional.getMembers().size());
+
+ // eq to get members
+ response = webClient().path("Groups").query("filter", "displayName eq
\"child\"").get();
+ assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
+ assertEquals(
+ SCIMConstants.APPLICATION_SCIM_JSON,
+
StringUtils.substringBefore(response.getHeaderString(HttpHeaders.CONTENT_TYPE),
";"));
+
+ groups = response.readEntity(new GenericType<>() {
+ });
+ assertNotNull(groups);
+ assertEquals(1, groups.getTotalResults());
+
+ SCIMGroup child = groups.getResources().getFirst();
+ assertEquals("child", child.getDisplayName());
+ usersList = USER_SERVICE.search(new AnyQuery.Builder()
+ .realm(SyncopeConstants.ROOT_REALM)
+ .page(0)
+ .size(15)
+ .fiql("$groups==child")
+ .build()).getResult();
+ assertEquals(usersList.size(), child.getMembers().size());
+ assertTrue(child.getMembers().stream().anyMatch(member ->
member.getDisplay().equals("verdi")));
// eq via POST
SCIMSearchRequest request = new SCIMSearchRequest("displayName eq
\"additional\"", null, null, null, null);