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)
====