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 19bc681  [SYNCOPE-1608] Allowing MembershipCond to bear group name 
pattern
19bc681 is described below

commit 19bc68120cd3ec31809b4f69f0b7f12890dfbbc8
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Mon Jan 11 09:07:36 2021 +0100

    [SYNCOPE-1608] Allowing MembershipCond to bear group name pattern
---
 .../syncope/core/persistence/api/dao/GroupDAO.java |  2 +
 .../persistence/jpa/dao/AbstractAnySearchDAO.java  | 19 +++++----
 .../core/persistence/jpa/dao/JPAAnySearchDAO.java  | 12 ++++--
 .../core/persistence/jpa/dao/JPAGroupDAO.java      | 11 ++++++
 .../core/persistence/jpa/inner/AnySearchTest.java  | 31 ++++++++++-----
 .../jpa/dao/ElasticsearchAnySearchDAO.java         | 12 ++++--
 .../org/apache/syncope/fit/core/SearchITCase.java  | 46 +++++++++++++---------
 .../workingwithapachesyncope/restfulservices.adoc  |  6 +++
 8 files changed, 95 insertions(+), 44 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 0cb6738..b862dc0 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
@@ -37,6 +37,8 @@ public interface GroupDAO extends AnyDAO<Group> {
 
     Group findByName(String name);
 
+    List<String> findKeysByNamePattern(String pattern);
+
     List<Group> findOwnedByUser(String userKey);
 
     List<Group> findOwnedByGroup(String groupKey);
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
index ea9c5ed..479efe4 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
@@ -59,7 +59,6 @@ import 
org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 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.jpa.entity.JPAPlainSchema;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -236,20 +235,20 @@ public abstract class AbstractAnySearchDAO extends 
AbstractDAO<Any<?>> implement
         return Triple.of(schema, attrValue, computed);
     }
 
-    protected String check(final MembershipCond cond) {
-        String groupKey;
+    protected List<String> check(final MembershipCond cond) {
         if (SyncopeConstants.UUID_PATTERN.matcher(cond.getGroup()).matches()) {
-            groupKey = cond.getGroup();
-        } else {
-            Group group = groupDAO.findByName(cond.getGroup());
-            groupKey = 
Optional.ofNullable(group).map(Entity::getKey).orElse(null);
+            return List.of(cond.getGroup());
         }
-        if (groupKey == null) {
-            LOG.error("Could not find group for '" + cond.getGroup() + '\'');
+
+        List<String> matching = cond.getGroup().indexOf('%') == -1
+                ? 
Optional.ofNullable(groupDAO.findKey(cond.getGroup())).map(List::of).orElseGet(()
 -> List.of())
+                : groupDAO.findKeysByNamePattern(cond.getGroup());
+        if (matching.isEmpty()) {
+            LOG.error("Could not find group(s) for '" + cond.getGroup() + 
'\'');
             throw new IllegalArgumentException();
         }
 
-        return groupKey;
+        return matching;
     }
 
     protected String check(final RelationshipCond cond) {
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
index f539f7c..0ed8893 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
@@ -646,13 +646,17 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO 
{
             final List<Object> parameters,
             final SearchSupport svs) {
 
-        String groupKey;
+        List<String> groupKeys;
         try {
-            groupKey = check(cond);
+            groupKeys = check(cond);
         } catch (IllegalArgumentException e) {
             return EMPTY_QUERY;
         }
 
+        String where = groupKeys.stream().
+                map(key -> "group_id=?" + setParameter(parameters, key)).
+                collect(Collectors.joining(" OR "));
+
         StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM 
").
                 append(svs.field().name).append(" WHERE (");
 
@@ -664,7 +668,7 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
 
         query.append("SELECT DISTINCT any_id FROM ").
                 append(svs.membership().name).append(" WHERE ").
-                append("group_id=?").append(setParameter(parameters, 
groupKey)).
+                append(where).
                 append(") ");
 
         if (not) {
@@ -675,7 +679,7 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
 
         query.append("SELECT DISTINCT any_id FROM ").
                 append(svs.dyngroupmembership().name).append(" WHERE ").
-                append("group_id=?").append(setParameter(parameters, 
groupKey)).
+                append(where).
                 append("))");
 
         return query.toString();
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index 19d0901..e6fe9d1 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -166,6 +166,17 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> 
implements GroupDAO {
         return result;
     }
 
+    @Override
+    public List<String> findKeysByNamePattern(final String pattern) {
+        Query query = entityManager().createNativeQuery(
+                "SELECT id FROM " + JPAGroup.TABLE + " WHERE LOWER(name) LIKE 
LOWER(?1)");
+        query.setParameter(1, pattern);
+
+        @SuppressWarnings("unchecked")
+        List<Object> raw = query.getResultList();
+        return raw.stream().map(Object::toString).collect(Collectors.toList());
+    }
+
     @Transactional(readOnly = true)
     @Override
     public List<Group> findOwnedByUser(final String userKey) {
diff --git 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
index abf21e1..e37984c 100644
--- 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
+++ 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnySearchTest.java
@@ -29,6 +29,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.time.DateUtils;
+import java.util.stream.Stream;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
@@ -239,18 +240,30 @@ public class AnySearchTest extends AbstractTest {
     @Test
     public void searchByGroup() {
         MembershipCond groupCond = new MembershipCond();
-        groupCond.setGroup("root");
+        groupCond.setGroup("child");
 
-        List<User> users = searchDAO.search(SearchCond.getLeaf(groupCond), 
AnyTypeKind.USER);
-        assertNotNull(users);
-        assertEquals(2, users.size());
+        List<User> matchingChild = 
searchDAO.search(SearchCond.getLeaf(groupCond), AnyTypeKind.USER);
+        assertNotNull(matchingChild);
+        assertTrue(matchingChild.stream().anyMatch(user -> 
"verdi".equals(user.getUsername())));
 
-        groupCond = new MembershipCond();
-        groupCond.setGroup("secretary");
+        groupCond.setGroup("otherchild");
 
-        users = searchDAO.search(SearchCond.getNotLeaf(groupCond), 
AnyTypeKind.USER);
-        assertNotNull(users);
-        assertEquals(5, users.size());
+        List<User> matchingOtherChild = 
searchDAO.search(SearchCond.getLeaf(groupCond), AnyTypeKind.USER);
+        assertNotNull(matchingOtherChild);
+        assertTrue(matchingOtherChild.stream().anyMatch(user -> 
"rossini".equals(user.getUsername())));
+
+        Set<String> union = Stream.concat(
+                matchingChild.stream().map(User::getUsername),
+                matchingOtherChild.stream().map(User::getUsername)).
+                collect(Collectors.toSet());
+
+        groupCond.setGroup("%child");
+
+        List<User> matchingStar = 
searchDAO.search(SearchCond.getLeaf(groupCond), AnyTypeKind.USER);
+        assertNotNull(matchingStar);
+        assertTrue(matchingStar.stream().anyMatch(user -> 
"verdi".equals(user.getUsername())));
+        assertTrue(matchingStar.stream().anyMatch(user -> 
"rossini".equals(user.getUsername())));
+        assertEquals(union, 
matchingStar.stream().map(User::getUsername).collect(Collectors.toSet()));
     }
 
     @Test
diff --git 
a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
 
b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
index 92cb77a..15674ad 100644
--- 
a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
+++ 
b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
@@ -349,14 +349,20 @@ public class ElasticsearchAnySearchDAO extends 
AbstractAnySearchDAO {
     }
 
     private QueryBuilder getQueryBuilder(final MembershipCond cond) {
-        String groupKey;
+        List<String> groupKeys;
         try {
-            groupKey = check(cond);
+            groupKeys = check(cond);
         } catch (IllegalArgumentException e) {
             return EMPTY_QUERY_BUILDER;
         }
 
-        return QueryBuilders.termQuery("memberships", groupKey);
+        if (groupKeys.size() == 1) {
+            return QueryBuilders.termQuery("memberships", groupKeys.get(0));
+        }
+
+        DisMaxQueryBuilder builder = QueryBuilders.disMaxQuery();
+        groupKeys.forEach(key -> 
builder.add(QueryBuilders.termQuery("memberships", key)));
+        return builder;
     }
 
     private QueryBuilder getQueryBuilder(final AssignableCond cond) {
diff --git 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
index 8b20425..77384fd 100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
@@ -30,6 +30,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import javax.ws.rs.core.Response;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.syncope.client.lib.SyncopeClient;
@@ -95,24 +96,21 @@ public class SearchITCase extends AbstractITCase {
                                 
is("username").equalToIgnoreCase("RoSsINI").and("key").lessThan(2).query()).build());
         assertNotNull(matchingUsers);
         assertEquals(1, matchingUsers.getResult().size());
-        assertEquals("rossini", 
matchingUsers.getResult().iterator().next().getUsername());
-        assertEquals("1417acbe-cbf6-4277-9372-e75e04f97000", 
matchingUsers.getResult().iterator().next().getKey());
+        assertEquals("rossini", 
matchingUsers.getResult().get(0).getUsername());
 
         matchingUsers = userService.search(
                 new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                         fiql("fullname=~*oSsINi").page(1).size(2).build());
         assertNotNull(matchingUsers);
         assertEquals(1, matchingUsers.getResult().size());
-        assertEquals("rossini", 
matchingUsers.getResult().iterator().next().getUsername());
-        assertEquals("1417acbe-cbf6-4277-9372-e75e04f97000", 
matchingUsers.getResult().iterator().next().getKey());
+        assertEquals("rossini", 
matchingUsers.getResult().get(0).getUsername());
 
         matchingUsers = userService.search(
                 new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                         
fiql("fullname=~*ino*rossini*").page(1).size(2).build());
         assertNotNull(matchingUsers);
         assertEquals(1, matchingUsers.getResult().size());
-        assertEquals("rossini", 
matchingUsers.getResult().iterator().next().getUsername());
-        assertEquals("1417acbe-cbf6-4277-9372-e75e04f97000", 
matchingUsers.getResult().iterator().next().getKey());
+        assertEquals("rossini", 
matchingUsers.getResult().get(0).getUsername());
     }
 
     @Test
@@ -123,8 +121,7 @@ public class SearchITCase extends AbstractITCase {
                                 
is("username").equalTo("rossini").and("key").lessThan(2).query()).build());
         assertNotNull(matchingUsers);
         assertEquals(1, matchingUsers.getResult().size());
-        assertEquals("rossini", 
matchingUsers.getResult().iterator().next().getUsername());
-        assertEquals("1417acbe-cbf6-4277-9372-e75e04f97000", 
matchingUsers.getResult().iterator().next().getKey());
+        assertEquals("rossini", 
matchingUsers.getResult().get(0).getUsername());
     }
 
     @Test
@@ -141,15 +138,30 @@ public class SearchITCase extends AbstractITCase {
 
     @Test
     public void searchByGroup() {
-        PagedResult<UserTO> matchingUsers = userService.search(
+        PagedResult<UserTO> matchingChild = userService.search(
                 new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
-                        
fiql(SyncopeClient.getUserSearchConditionBuilder().inGroups("root").query()).
+                        
fiql(SyncopeClient.getUserSearchConditionBuilder().inGroups("child").query()).
                         build());
-        assertNotNull(matchingUsers);
-        assertFalse(matchingUsers.getResult().isEmpty());
+        assertTrue(matchingChild.getResult().stream().anyMatch(user -> 
"verdi".equals(user.getUsername())));
 
-        assertTrue(matchingUsers.getResult().stream().
-                anyMatch(user -> 
"1417acbe-cbf6-4277-9372-e75e04f97000".equals(user.getKey())));
+        PagedResult<UserTO> matchingOtherChild = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+                        
fiql(SyncopeClient.getUserSearchConditionBuilder().inGroups("otherchild").query()).
+                        build());
+        assertTrue(matchingOtherChild.getResult().stream().anyMatch(user -> 
"rossini".equals(user.getUsername())));
+
+        Set<String> union = Stream.concat(
+                matchingChild.getResult().stream().map(UserTO::getUsername),
+                
matchingOtherChild.getResult().stream().map(UserTO::getUsername)).
+                collect(Collectors.toSet());
+
+        PagedResult<UserTO> matchingStar = userService.search(
+                new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+                        
fiql(SyncopeClient.getUserSearchConditionBuilder().inGroups("*child").query()).
+                        build());
+        assertTrue(matchingStar.getResult().stream().anyMatch(user -> 
"verdi".equals(user.getUsername())));
+        assertTrue(matchingStar.getResult().stream().anyMatch(user -> 
"rossini".equals(user.getUsername())));
+        assertEquals(union, 
matchingStar.getResult().stream().map(UserTO::getUsername).collect(Collectors.toSet()));
     }
 
     @Test
@@ -194,8 +206,7 @@ public class SearchITCase extends AbstractITCase {
         assertNotNull(matchingUsers);
         assertFalse(matchingUsers.getResult().isEmpty());
 
-        assertTrue(matchingUsers.getResult().stream().
-                anyMatch(user -> 
"1417acbe-cbf6-4277-9372-e75e04f97000".equals(user.getKey())));
+        assertTrue(matchingUsers.getResult().stream().anyMatch(user -> 
"rossini".equals(user.getUsername())));
     }
 
     @Test
@@ -207,8 +218,7 @@ public class SearchITCase extends AbstractITCase {
         assertNotNull(matchingUsers);
         assertFalse(matchingUsers.getResult().isEmpty());
 
-        assertTrue(matchingUsers.getResult().stream().
-                anyMatch(user -> 
"1417acbe-cbf6-4277-9372-e75e04f97000".equals(user.getKey())));
+        assertTrue(matchingUsers.getResult().stream().anyMatch(user -> 
"rossini".equals(user.getUsername())));
     }
 
     @Test
diff --git 
a/src/main/asciidoc/reference-guide/workingwithapachesyncope/restfulservices.adoc
 
b/src/main/asciidoc/reference-guide/workingwithapachesyncope/restfulservices.adoc
index 0fd3c5d..a70fecf 100644
--- 
a/src/main/asciidoc/reference-guide/workingwithapachesyncope/restfulservices.adoc
+++ 
b/src/main/asciidoc/reference-guide/workingwithapachesyncope/restfulservices.adoc
@@ -450,6 +450,12 @@ $resources==resource-ldap
 $groups==root
 ----
 ====
+.Wildcard group membership match (only for Users and Any Objects)
+====
+----
+$groups==*child
+----
+====
 
 .Role membership match (only for Users)
 ====

Reply via email to