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 30f872f9a4 [SYNCOPE-1830] Supporting membership attributes query with
Neo4j (#870)
30f872f9a4 is described below
commit 30f872f9a4bd8b5d2b655a26eb7900d8c1deb54d
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Wed Oct 23 12:51:21 2024 +0200
[SYNCOPE-1830] Supporting membership attributes query with Neo4j (#870)
---
.../client/console/panels/AnyDirectoryPanel.java | 4 +-
.../org/apache/syncope/core/logic/UserLogic.java | 2 +-
.../jpa/dao/repo/AbstractAnyRepoExt.java | 2 +-
.../jpa/dao/repo/AnyObjectRepoExtImpl.java | 2 +-
.../persistence/jpa/dao/repo/UserRepoExtImpl.java | 4 +-
.../core/persistence/jpa/outer/AnySearchTest.java | 39 ++++++
.../core/persistence/jpa/outer/GroupTest.java | 4 +-
.../core/persistence/neo4j/dao/AbstractDAO.java | 2 +-
.../persistence/neo4j/dao/Neo4jAnySearchDAO.java | 118 +++++++++++++++--
.../persistence/neo4j/dao/Neo4jAuditEventDAO.java | 2 +-
.../neo4j/dao/repo/AbstractAnyRepoExt.java | 12 +-
.../persistence/neo4j/dao/repo/AnyRepoExt.java | 13 ++
.../neo4j/dao/repo/AnyTypeClassRepoExtImpl.java | 5 +-
.../neo4j/dao/repo/GroupRepoExtImpl.java | 2 +-
.../neo4j/entity/AbstractGroupableRelatable.java | 2 +-
.../persistence/neo4j/inner/AnySearchTest.java | 2 +
.../persistence/neo4j/outer/AnySearchTest.java | 57 ++++++++
.../src/test/resources/domains/MasterContent.xml | 7 +-
.../provisioning/java/DefaultMappingManager.java | 3 +-
.../java/data/AbstractAnyDataBinder.java | 4 +-
.../java/data/ResourceDataBinderImpl.java | 2 +-
.../propagation/DefaultPropagationManager.java | 2 +-
.../LDAPMembershipPropagationActions.java | 2 +-
.../provisioning/java/pushpull/InboundMatcher.java | 3 +-
.../java/pushpull/SinglePullJobDelegate.java | 2 +-
.../java/pushpull/SinglePushJobDelegate.java | 2 +-
.../pushpull/stream/StreamPullJobDelegate.java | 2 +-
.../pushpull/stream/StreamPushJobDelegate.java | 2 +-
.../provisioning/java/utils/ConnObjectUtils.java | 2 +-
.../java/AbstractAnyObjectWorkflowAdapter.java | 2 +-
.../workflow/java/AbstractUserWorkflowAdapter.java | 2 +-
.../elasticsearch/client/ElasticsearchUtils.java | 14 +-
.../dao/ElasticsearchRealmSearchDAO.java | 6 +-
.../syncope/core/logic/oidc/OIDCUserManager.java | 3 +-
.../ext/opensearch/client/OpenSearchUtils.java | 14 +-
.../opensearch/dao/OpenSearchRealmSearchDAO.java | 6 +-
.../core/logic/saml2/SAML2SP4UIUserManager.java | 3 +-
.../org/apache/syncope/fit/core/SearchITCase.java | 145 +++++++++++++--------
pom.xml | 4 +-
.../wa/starter/mapping/DefaultAuthMapper.java | 3 +-
40 files changed, 367 insertions(+), 140 deletions(-)
diff --git
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
index 50f5d63890..6026563e9b 100644
---
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
+++
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
@@ -188,13 +188,13 @@ public abstract class AnyDirectoryPanel<A extends AnyTO,
E extends AbstractAnyRe
PreferenceManager.getList(DisplayAttributesModalPanel.getPrefPlainAttributeView(type)).stream().
map(a -> plainSchemas.stream().filter(p ->
p.getKey().equals(a)).findFirst()).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
forEach(s -> prefcolumns.add(new AttrColumn<>(
s.getKey(),
s.getLabel(SyncopeConsoleSession.get().getLocale()), SchemaType.PLAIN)));
PreferenceManager.getList(DisplayAttributesModalPanel.getPrefDerivedAttributeView(type)).stream().
map(a -> derSchemas.stream().filter(p ->
p.getKey().equals(a)).findFirst()).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
forEach(s -> prefcolumns.add(new AttrColumn<>(
s.getKey(),
s.getLabel(SyncopeConsoleSession.get().getLocale()), SchemaType.DERIVED)));
diff --git
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
index fe4b06cb73..44d2aedf3f 100644
---
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
+++
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
@@ -398,7 +398,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO,
UserCR, UserUR> {
orElseThrow(() -> new NotFoundException("Realm " +
query.getRealm()));
}
Set<ExternalResource> resources = query.getResources().stream().
-
map(resourceDAO::findById).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet());
+
map(resourceDAO::findById).flatMap(Optional::stream).collect(Collectors.toSet());
if (realm == null && resources.isEmpty()) {
sce.getElements().add("Nothing to check");
throw sce;
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AbstractAnyRepoExt.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AbstractAnyRepoExt.java
index b84e8cb7b2..2786163b67 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AbstractAnyRepoExt.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AbstractAnyRepoExt.java
@@ -228,7 +228,7 @@ public abstract class AbstractAnyRepoExt<A extends Any<?>>
implements AnyRepoExt
List<Object> result = query.getResultList();
return result.stream().
map(dynRealm -> dynRealmDAO.findById(dynRealm.toString())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
map(DynRealm::getKey).
distinct().
toList();
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AnyObjectRepoExtImpl.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AnyObjectRepoExtImpl.java
index fb919cd819..6bff4c4e72 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AnyObjectRepoExtImpl.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/AnyObjectRepoExtImpl.java
@@ -232,7 +232,7 @@ public class AnyObjectRepoExtImpl extends
AbstractAnyRepoExt<AnyObject> implemen
List<Object> result = query.getResultList();
return result.stream().
map(groupKey -> groupDAO.findById(groupKey.toString())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
distinct().
collect(Collectors.toList());
}
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 3903f3551d..20d04067b3 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
@@ -234,7 +234,7 @@ public class UserRepoExtImpl extends
AbstractAnyRepoExt<User> implements UserRep
List<Object> result = query.getResultList();
return result.stream().
map(roleKey -> roleDAO.findById(roleKey.toString())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
distinct().
collect(Collectors.toList());
}
@@ -250,7 +250,7 @@ public class UserRepoExtImpl extends
AbstractAnyRepoExt<User> implements UserRep
List<Object> result = query.getResultList();
return result.stream().
map(groupKey -> groupDAO.findById(groupKey.toString())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
distinct().
collect(Collectors.toList());
}
diff --git
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java
index 36cbc8e30f..0f0c6ca389 100644
---
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java
+++
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java
@@ -32,6 +32,7 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import
org.apache.syncope.core.persistence.api.attrvalue.PlainAttrValidationManager;
+import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
@@ -44,6 +45,9 @@ import
org.apache.syncope.core.persistence.api.dao.search.AttrCond;
import org.apache.syncope.core.persistence.api.dao.search.RoleCond;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
import org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.user.UMembership;
@@ -66,6 +70,9 @@ public class AnySearchTest extends AbstractTest {
@Autowired
private GroupDAO groupDAO;
+ @Autowired
+ private AnyObjectDAO anyObjectDAO;
+
@Autowired
private AnySearchDAO searchDAO;
@@ -148,6 +155,38 @@ public class AnySearchTest extends AbstractTest {
assertEquals(rossini.getKey(), users.get(0).getKey());
}
+ @Test
+ public void searchByMembershipAttribute() {
+ AttrCond attrCond = new AttrCond(AttrCond.Type.EQ);
+ attrCond.setSchema("ctype");
+ attrCond.setExpression("otherchildctype");
+ SearchCond cond = SearchCond.getLeaf(attrCond);
+
+ List<AnyObject> results = searchDAO.search(cond,
AnyTypeKind.ANY_OBJECT);
+ assertTrue(results.isEmpty());
+
+ // add any object membership and its plain attribute
+ AnyObject anyObject =
anyObjectDAO.findById("8559d14d-58c2-46eb-a2d4-a7d35161e8f8").orElseThrow();
+ AMembership memb = entityFactory.newEntity(AMembership.class);
+ memb.setLeftEnd(anyObject);
+ memb.setRightEnd(groupDAO.findByName("otherchild").orElseThrow());
+ anyObject.add(memb);
+ anyObject = anyObjectDAO.save(anyObject);
+
+ APlainAttr attr = entityFactory.newEntity(APlainAttr.class);
+ attr.setSchema(plainSchemaDAO.findById("ctype").orElseThrow());
+ attr.add(validator, "otherchildctype",
anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT));
+ attr.setOwner(anyObject);
+ attr.setMembership(anyObject.getMemberships().get(0));
+ anyObject.add(attr);
+ anyObjectDAO.save(anyObject);
+
+ results = searchDAO.search(cond, AnyTypeKind.ANY_OBJECT);
+ assertEquals(1, results.size());
+
+ assertTrue(results.stream().anyMatch(a ->
"8559d14d-58c2-46eb-a2d4-a7d35161e8f8".equals(a.getKey())));
+ }
+
@Test
public void issueSYNCOPE95() {
groupDAO.findAll().forEach(group ->
groupDAO.deleteById(group.getKey()));
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 b18c27c427..8bd268a6ab 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
@@ -240,7 +240,7 @@ public class GroupTest extends AbstractTest {
List<Object> result = query.getResultList();
return result.stream().
map(groupKey -> groupDAO.findById(groupKey.toString())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
distinct().
collect(Collectors.toList());
}
@@ -332,7 +332,7 @@ public class GroupTest extends AbstractTest {
List<Object> result = query.getResultList();
return result.stream().
map(groupKey -> groupDAO.findById(groupKey.toString())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
distinct().
collect(Collectors.toList());
}
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/AbstractDAO.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/AbstractDAO.java
index 082d235927..255abf7ab3 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/AbstractDAO.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/AbstractDAO.java
@@ -112,7 +112,7 @@ public abstract class AbstractDAO {
return result.stream().
map(found -> findById(found.get(property).toString(),
domainType, cache)).
- filter(Optional::isPresent).map(Optional::get).map(n -> (E)
n).toList();
+ flatMap(Optional::stream).map(n -> (E) n).toList();
}
protected void cascadeDelete(
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAnySearchDAO.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAnySearchDAO.java
index a3cba3abe9..0fd7c73516 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAnySearchDAO.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAnySearchDAO.java
@@ -100,7 +100,11 @@ public class Neo4jAnySearchDAO extends
AbstractAnySearchDAO {
}
- protected static record QueryInfo(TextStringBuilder query, Set<String>
fields, Set<PlainSchema> plainSchemas) {
+ protected static record QueryInfo(
+ TextStringBuilder query,
+ Set<String> fields,
+ Set<PlainSchema> plainSchemas,
+ List<Pair<String, PlainSchema>> membershipAttrConds) {
}
@@ -754,6 +758,7 @@ public class Neo4jAnySearchDAO extends AbstractAnySearchDAO
{
TextStringBuilder query = new TextStringBuilder();
Set<String> involvedFields = new HashSet<>();
Set<PlainSchema> involvedPlainSchemas = new HashSet<>();
+ List<Pair<String, PlainSchema>> membershipAttrConds = new
ArrayList<>();
switch (cond.getType()) {
case LEAF, NOT_LEAF -> {
@@ -804,6 +809,13 @@ public class Neo4jAnySearchDAO extends
AbstractAnySearchDAO {
Pair<String, PlainSchema> attrCondResult =
getQuery(kind, leaf, not, parameters);
query.append(attrCondResult.getLeft());
involvedPlainSchemas.add(attrCondResult.getRight());
+ if (kind != AnyTypeKind.GROUP
+ && !not
+ && leaf.getType() != AttrCond.Type.ISNULL
+ && leaf.getType() !=
AttrCond.Type.ISNOTNULL) {
+
+ membershipAttrConds.add(attrCondResult);
+ }
}));
// allow for additional search conditions
@@ -813,10 +825,12 @@ public class Neo4jAnySearchDAO extends
AbstractAnySearchDAO {
QueryInfo leftAndInfo = getQuery(kind, cond.getLeft(),
parameters);
involvedFields.addAll(leftAndInfo.fields());
involvedPlainSchemas.addAll(leftAndInfo.plainSchemas());
+ membershipAttrConds.addAll(leftAndInfo.membershipAttrConds());
QueryInfo rigthAndInfo = getQuery(kind, cond.getRight(),
parameters);
involvedFields.addAll(rigthAndInfo.fields());
involvedPlainSchemas.addAll(rigthAndInfo.plainSchemas());
+ membershipAttrConds.addAll(rigthAndInfo.membershipAttrConds());
queryOp(query, "AND", leftAndInfo, rigthAndInfo);
}
@@ -825,10 +839,12 @@ public class Neo4jAnySearchDAO extends
AbstractAnySearchDAO {
QueryInfo leftOrInfo = getQuery(kind, cond.getLeft(),
parameters);
involvedFields.addAll(leftOrInfo.fields());
involvedPlainSchemas.addAll(leftOrInfo.plainSchemas());
+ membershipAttrConds.addAll(leftOrInfo.membershipAttrConds());
QueryInfo rigthOrInfo = getQuery(kind, cond.getRight(),
parameters);
involvedFields.addAll(rigthOrInfo.fields());
involvedPlainSchemas.addAll(rigthOrInfo.plainSchemas());
+ membershipAttrConds.addAll(rigthOrInfo.membershipAttrConds());
queryOp(query, "OR", leftOrInfo, rigthOrInfo);
}
@@ -837,7 +853,7 @@ public class Neo4jAnySearchDAO extends AbstractAnySearchDAO
{
}
}
- return new QueryInfo(query, involvedFields, involvedPlainSchemas);
+ return new QueryInfo(query, involvedFields, involvedPlainSchemas,
membershipAttrConds);
}
protected void wrapQuery(
@@ -846,8 +862,6 @@ public class Neo4jAnySearchDAO extends AbstractAnySearchDAO
{
final AnyTypeKind kind,
final String adminRealmsFilter) {
- TextStringBuilder query = queryInfo.query();
-
TextStringBuilder match = new TextStringBuilder("MATCH
(n:").append(AnyRepoExt.node(kind)).append(") ").
append("WITH n.id AS id");
@@ -864,7 +878,7 @@ public class Neo4jAnySearchDAO extends AbstractAnySearchDAO
{
Stream.concat(
queryInfo.plainSchemas().stream(),
orderBy.stream().map(clause ->
plainSchemaDAO.findById(clause.getProperty())).
-
filter(Optional::isPresent).map(Optional::get)).distinct().forEach(schema -> {
+ flatMap(Optional::stream)).distinct().forEach(schema
-> {
match.append(", apoc.convert.getJsonProperty(n,
'plainAttrs.").append(schema.getKey());
if (schema.isUniqueConstraint()) {
@@ -875,6 +889,8 @@ public class Neo4jAnySearchDAO extends AbstractAnySearchDAO
{
match.append(" AS ").append(schema.getKey());
});
+ TextStringBuilder query = queryInfo.query();
+
// take realms into account
if (query.startsWith("MATCH (n)")) {
query.replaceFirst("MATCH (n)", match + " WHERE (EXISTS { MATCH
(n)");
@@ -886,6 +902,75 @@ public class Neo4jAnySearchDAO extends
AbstractAnySearchDAO {
query.append(") AND EXISTS { ").append(adminRealmsFilter).append(" }
");
}
+ protected void membershipAttrConds(
+ final TextStringBuilder query,
+ final QueryInfo queryInfo,
+ final List<String> orderBy,
+ final AnyTypeKind kind) {
+
+ if (kind == AnyTypeKind.GROUP) {
+ return;
+ }
+ if (queryInfo.membershipAttrConds().isEmpty()) {
+ return;
+ }
+
+ Set<String> orderByItems = orderBy.stream().
+ map(clause -> StringUtils.substringBefore(clause, " ")).
+ collect(Collectors.toSet());
+
+ AnyUtils anyUtils = anyUtilsFactory.getInstance(kind);
+ Set<String> fields = Stream.concat(
+ queryInfo.fields().stream().filter(f -> !"id".equals(f)),
+ orderByItems.stream().filter(item -> !"id".equals(item) &&
anyUtils.getField(item).isPresent())).
+ collect(Collectors.toSet());
+
+ Set<PlainSchema> plainSchemas = Stream.concat(
+ queryInfo.membershipAttrConds().stream().map(Pair::getRight),
+ orderByItems.stream().map(item ->
plainSchemaDAO.findById(item)).flatMap(Optional::stream)).
+ collect(Collectors.toSet());
+
+ // call
+ query.insert(0, "CALL () { ");
+
+ // return
+ TextStringBuilder returnStmt = new TextStringBuilder("RETURN id");
+
+ fields.forEach(f -> returnStmt.append(", ").append(f));
+
+ plainSchemas.forEach(schema -> returnStmt.append(",
").append(schema.getKey()));
+
+ query.append(returnStmt);
+
+ // union
+ query.append(" UNION ").
+ append("MATCH (n:").append(AnyRepoExt.membNode(kind)).
+ append(")-[]-(m:").append(AnyRepoExt.node(kind) + ") ").
+ append("WITH m.id AS id ");
+
+ fields.forEach(f -> query.append(", m.").append(f).append(" AS
").append(f));
+
+ plainSchemas.forEach(schema -> {
+ query.append(", apoc.convert.getJsonProperty(n,
'plainAttrs.").append(schema.getKey());
+ if (schema.isUniqueConstraint()) {
+ query.append("', '$.uniqueValue')");
+ } else {
+ query.append("', '$.values')");
+ }
+ query.append(" AS ").append(schema.getKey());
+ });
+
+ query.append(" WHERE ");
+
+ query.append(queryInfo.membershipAttrConds().stream().
+ map(mac -> "(EXISTS { " + mac.getLeft() + "} )").
+ collect(Collectors.joining(" AND ")));
+
+ query.append(" AND EXISTS { (m)-[]-(r:Realm) WHERE r.id IN $param0 }
").
+ append(returnStmt).
+ append(" } ");
+ }
+
@Override
protected long doCount(
final Realm base,
@@ -906,15 +991,18 @@ public class Neo4jAnySearchDAO extends
AbstractAnySearchDAO {
wrapQuery(queryInfo, Streamable.empty(), kind, filter.filter());
TextStringBuilder query = queryInfo.query();
- // 3. prepare the count query
+ // 3. include membership plain attr queries
+ membershipAttrConds(query, queryInfo, List.of(), kind);
+
+ // 4. prepare the count query
query.append("RETURN COUNT(id)");
return neo4jTemplate.count(query.toString(), parameters);
}
- protected String parseOrderBy(
+ protected List<String> parseOrderBy(
final AnyTypeKind kind,
- final Stream<Sort.Order> orderBy) {
+ final Streamable<Sort.Order> orderBy) {
AnyUtils anyUtils = anyUtilsFactory.getInstance(kind);
@@ -946,7 +1034,7 @@ public class Neo4jAnySearchDAO extends
AbstractAnySearchDAO {
}
});
- return clauses.stream().collect(Collectors.joining(", "));
+ return clauses;
}
@Override
@@ -970,9 +1058,15 @@ public class Neo4jAnySearchDAO extends
AbstractAnySearchDAO {
wrapQuery(queryInfo, pageable.getSort(), kind, filter.filter());
TextStringBuilder query = queryInfo.query();
- // 3. prepare the search query
+ List<String> orderBy = parseOrderBy(kind, pageable.getSort());
+ String orderByStmt =
orderBy.stream().collect(Collectors.joining(", "));
+
+ // 3. include membership plain attr queries
+ membershipAttrConds(query, queryInfo, orderBy, kind);
+
+ // 4. prepare the search query
query.append("RETURN id ").
- append("ORDER BY ").append(parseOrderBy(kind,
pageable.getSort().get()));
+ append("ORDER BY ").append(orderByStmt);
if (pageable.isPaged()) {
query.append(" SKIP ").append(pageable.getPageSize() *
pageable.getPageNumber()).
@@ -981,7 +1075,7 @@ public class Neo4jAnySearchDAO extends
AbstractAnySearchDAO {
LOG.debug("Query with auth and order by statements: {},
parameters: {}", query, parameters);
- // 4. Prepare the result (avoiding duplicates)
+ // 5. Prepare the result (avoiding duplicates)
return
buildResult(neo4jClient.query(query.toString()).bindAll(parameters).fetch().all().stream().
map(found -> found.get("id")).toList(), kind);
} catch (SyncopeClientException e) {
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAuditEventDAO.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAuditEventDAO.java
index 038886e6fd..8c8d9f2b4f 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAuditEventDAO.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAuditEventDAO.java
@@ -183,6 +183,6 @@ public class Neo4jAuditEventDAO implements AuditEventDAO {
return neo4jClient.query(query.toString()).
bindAll(parameters).fetch().all().stream().
map(found -> neo4jTemplate.findById(found.get("n.id"),
Neo4jAuditEvent.class)).
-
filter(Optional::isPresent).map(Optional::get).map(this::toAuditEventTO).toList();
+ flatMap(Optional::stream).map(this::toAuditEventTO).toList();
}
}
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AbstractAnyRepoExt.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AbstractAnyRepoExt.java
index c342094a1c..8857f06f90 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AbstractAnyRepoExt.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AbstractAnyRepoExt.java
@@ -364,17 +364,17 @@ public abstract class AbstractAnyRepoExt<A extends
Any<?>, N extends AbstractAny
if (reference.equals(PlainSchema.class)) {
atc.getPlainSchemas().stream().
map(schema ->
plainSchemaDAO.findById(schema.getKey())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
forEach(schema -> result.getForSelf().add((S) schema));
} else if (reference.equals(DerSchema.class)) {
atc.getDerSchemas().stream().
map(schema -> derSchemaDAO.findById(schema.getKey())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
forEach(schema -> result.getForSelf().add((S) schema));
} else if (reference.equals(VirSchema.class)) {
atc.getVirSchemas().stream().
map(schema -> virSchemaDAO.findById(schema.getKey())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
forEach(schema -> result.getForSelf().add((S) schema));
}
});
@@ -419,17 +419,17 @@ public abstract class AbstractAnyRepoExt<A extends
Any<?>, N extends AbstractAny
if (reference.equals(PlainSchema.class)) {
atc.getPlainSchemas().stream().
map(schema ->
plainSchemaDAO.findById(schema.getKey())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
forEach(schema ->
result.getForMemberships().get(entry.getKey()).add((S) schema));
} else if (reference.equals(DerSchema.class)) {
atc.getDerSchemas().stream().
map(schema -> derSchemaDAO.findById(schema.getKey())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
forEach(schema ->
result.getForMemberships().get(entry.getKey()).add((S) schema));
} else if (reference.equals(VirSchema.class)) {
atc.getVirSchemas().stream().
map(schema -> virSchemaDAO.findById(schema.getKey())).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
forEach(schema ->
result.getForMemberships().get(entry.getKey()).add((S) schema));
}
}));
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyRepoExt.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyRepoExt.java
index 2d10177deb..8aa602c186 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyRepoExt.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyRepoExt.java
@@ -31,8 +31,10 @@ import
org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
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.Schema;
+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;
public interface AnyRepoExt<A extends Any<?>> {
@@ -60,6 +62,17 @@ public interface AnyRepoExt<A extends Any<?>> {
};
}
+ static String membNode(final AnyTypeKind anyTypeKind) {
+ return switch (anyTypeKind) {
+ case USER ->
+ Neo4jUMembership.NODE;
+ case ANY_OBJECT ->
+ Neo4jAMembership.NODE;
+ default ->
+ "";
+ };
+ }
+
List<A> findByKeys(List<String> keys);
Optional<OffsetDateTime> findLastChange(String key);
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyTypeClassRepoExtImpl.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyTypeClassRepoExtImpl.java
index b2c432fb46..8669192b97 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyTypeClassRepoExtImpl.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/AnyTypeClassRepoExtImpl.java
@@ -186,17 +186,16 @@ public class AnyTypeClassRepoExtImpl extends AbstractDAO
implements AnyTypeClass
typeExt.getAuxClasses().remove(anyTypeClass);
if (typeExt.getAuxClasses().isEmpty()) {
+
groupCache.remove(EntityCacheKey.of(typeExt.getGroup().getKey()));
+
typeExt.getGroup().getTypeExtensions().remove(typeExt);
typeExt.setGroup(null);
-
-
groupCache.remove(EntityCacheKey.of(typeExt.getGroup().getKey()));
}
}
resourceDAO.findAll().stream().filter(resource ->
resource.getProvisions().stream().
anyMatch(provision ->
provision.getAuxClasses().contains(anyTypeClass.getKey()))).
forEach(resource -> {
-
resource.getProvisions().stream().
filter(provision ->
provision.getAuxClasses().contains(anyTypeClass.getKey())).
forEach(provision ->
provision.getAuxClasses().remove(anyTypeClass.getKey()));
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 f0a969591b..2c1a4789a1 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
@@ -227,7 +227,7 @@ public class GroupRepoExtImpl extends
AbstractAnyRepoExt<Group, Neo4jGroup> impl
return owned.stream().
map(id -> neo4jTemplate.findById(id, Neo4jGroup.class)).
-
filter(Optional::isPresent).map(Optional::get).map(Group.class::cast).toList();
+ flatMap(Optional::stream).map(Group.class::cast).toList();
}
@Override
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/AbstractGroupableRelatable.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/AbstractGroupableRelatable.java
index d2e428f334..10c3d04353 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/AbstractGroupableRelatable.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/AbstractGroupableRelatable.java
@@ -76,7 +76,7 @@ public abstract class AbstractGroupableRelatable<
public Collection<? extends P> getPlainAttrs(final String plainSchema) {
return
Stream.concat(getPlainAttr(plainSchema).map(Stream::of).orElse(Stream.empty()),
memberships().stream().map(m -> m.getPlainAttr(plainSchema)).
- filter(Optional::isPresent).map(Optional::get)).
+ flatMap(Optional::stream)).
toList();
}
diff --git
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/inner/AnySearchTest.java
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/inner/AnySearchTest.java
index 6efb2836f2..735d54cf33 100644
---
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/inner/AnySearchTest.java
+++
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/inner/AnySearchTest.java
@@ -615,6 +615,8 @@ public class AnySearchTest extends AbstractTest {
List<Sort.Order> orderByClauses = new ArrayList<>();
orderByClauses.add(new Sort.Order(Sort.Direction.DESC, "username"));
orderByClauses.add(new Sort.Order(Sort.Direction.ASC, "fullname"));
+ orderByClauses.add(new Sort.Order(Sort.Direction.ASC, "status"));
+ orderByClauses.add(new Sort.Order(Sort.Direction.DESC, "firstname"));
List<User> users = searchDAO.search(searchCondition, orderByClauses,
AnyTypeKind.USER);
assertEquals(
diff --git
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/AnySearchTest.java
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/AnySearchTest.java
index 7861038fd8..94fbff1e75 100644
---
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/AnySearchTest.java
+++
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/AnySearchTest.java
@@ -32,6 +32,7 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import
org.apache.syncope.core.persistence.api.attrvalue.PlainAttrValidationManager;
+import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
@@ -40,10 +41,14 @@ import
org.apache.syncope.core.persistence.api.dao.RealmSearchDAO;
import org.apache.syncope.core.persistence.api.dao.RoleDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
+import org.apache.syncope.core.persistence.api.dao.search.AnyTypeCond;
import org.apache.syncope.core.persistence.api.dao.search.AttrCond;
import org.apache.syncope.core.persistence.api.dao.search.RoleCond;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
import org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.user.UMembership;
@@ -66,6 +71,9 @@ public class AnySearchTest extends AbstractTest {
@Autowired
private GroupDAO groupDAO;
+ @Autowired
+ private AnyObjectDAO anyObjectDAO;
+
@Autowired
private AnySearchDAO searchDAO;
@@ -144,6 +152,55 @@ public class AnySearchTest extends AbstractTest {
assertEquals(rossini.getKey(), users.get(0).getKey());
}
+ @Test
+ public void searchByMembershipAttribute() {
+ AnyTypeCond typeCond = new AnyTypeCond();
+ typeCond.setAnyTypeKey("PRINTER");
+
+ AttrCond attrCond = new AttrCond(AttrCond.Type.EQ);
+ attrCond.setSchema("ctype");
+ attrCond.setExpression("otherchildctype");
+ SearchCond cond = SearchCond.getAnd(SearchCond.getLeaf(typeCond),
SearchCond.getLeaf(attrCond));
+
+ long count = searchDAO.count(
+
realmSearchDAO.findByFullPath(SyncopeConstants.ROOT_REALM).orElseThrow(),
+ true,
+ SyncopeConstants.FULL_ADMIN_REALMS,
+ cond,
+ AnyTypeKind.ANY_OBJECT);
+ assertEquals(0, count);
+ List<AnyObject> results = searchDAO.search(cond,
AnyTypeKind.ANY_OBJECT);
+ assertTrue(results.isEmpty());
+
+ // add any object membership and its plain attribute
+ AnyObject anyObject =
anyObjectDAO.findById("8559d14d-58c2-46eb-a2d4-a7d35161e8f8").orElseThrow();
+ AMembership memb = entityFactory.newEntity(AMembership.class);
+ memb.setLeftEnd(anyObject);
+ memb.setRightEnd(groupDAO.findByName("otherchild").orElseThrow());
+ anyObject.add(memb);
+ anyObject = anyObjectDAO.save(anyObject);
+
+ APlainAttr attr = entityFactory.newEntity(APlainAttr.class);
+ attr.setSchema(plainSchemaDAO.findById("ctype").orElseThrow());
+ attr.add(validator, "otherchildctype",
anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT));
+ attr.setOwner(anyObject);
+ attr.setMembership(anyObject.getMemberships().get(0));
+ anyObject.add(attr);
+ anyObjectDAO.save(anyObject);
+
+ count = searchDAO.count(
+
realmSearchDAO.findByFullPath(SyncopeConstants.ROOT_REALM).orElseThrow(),
+ true,
+ SyncopeConstants.FULL_ADMIN_REALMS,
+ cond,
+ AnyTypeKind.ANY_OBJECT);
+ assertEquals(1, count);
+ results = searchDAO.search(cond, AnyTypeKind.ANY_OBJECT);
+ assertEquals(1, results.size());
+
+ assertTrue(results.stream().anyMatch(a ->
"8559d14d-58c2-46eb-a2d4-a7d35161e8f8".equals(a.getKey())));
+ }
+
@Test
public void issueSYNCOPE95() {
groupDAO.findAll().forEach(group ->
groupDAO.deleteById(group.getKey()));
diff --git
a/core/persistence-neo4j/src/test/resources/domains/MasterContent.xml
b/core/persistence-neo4j/src/test/resources/domains/MasterContent.xml
index 233e9f3d25..5944661a80 100644
--- a/core/persistence-neo4j/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-neo4j/src/test/resources/domains/MasterContent.xml
@@ -384,9 +384,10 @@ under the License.
creator="admin" lastModifier="admin"
creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20
11:00:00"/>
<SyncopeGroup_Realm left="f779c0d4-633b-4be5-8f57-32eb478a3ca5"
right="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"/>
- <TypeExtension id="88a71478-30aa-4ee0-8b2b-6cb32e7ba264"
- group_id="f779c0d4-633b-4be5-8f57-32eb478a3ca5"
anyType_id="PRINTER"/>
- <TypeExtension_AnyTypeClass
typeExtension_id="88a71478-30aa-4ee0-8b2b-6cb32e7ba264"
anyTypeClass_id="other"/>
+ <TypeExtension id="88a71478-30aa-4ee0-8b2b-6cb32e7ba264"/>
+ <TypeExtension_SyncopeGroup left="88a71478-30aa-4ee0-8b2b-6cb32e7ba264"
right="f779c0d4-633b-4be5-8f57-32eb478a3ca5"/>
+ <TypeExtension_AnyType left="88a71478-30aa-4ee0-8b2b-6cb32e7ba264"
right="PRINTER"/>
+ <TypeExtension_AnyTypeClass left="88a71478-30aa-4ee0-8b2b-6cb32e7ba264"
right="other"/>
<SyncopeGroup id="0cbcabd2-4410-4b6b-8f05-a052b451d18f"
name="groupForWorkflowApproval"
creator="admin" lastModifier="admin"
creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20
11:00:00"/>
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultMappingManager.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultMappingManager.java
index d884aab5fa..98bcc0b614 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultMappingManager.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultMappingManager.java
@@ -171,8 +171,7 @@ public class DefaultMappingManager implements
MappingManager {
protected List<Implementation> getTransformers(final Item item) {
return item.getTransformers().stream().
map(implementationDAO::findById).
- filter(Optional::isPresent).
- map(Optional::get).
+ flatMap(Optional::stream).
collect(Collectors.toList());
}
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index 1ec1c99871..0ab69d0162 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -246,7 +246,7 @@ abstract class AbstractAnyDataBinder {
Map<String, ConnObject> onResources = new HashMap<>();
-
resources.stream().map(resourceDAO::findById).filter(Optional::isPresent).map(Optional::get).
+
resources.stream().map(resourceDAO::findById).flatMap(Optional::stream).
forEach(resource ->
resource.getProvisionByAnyType(any.getType().getKey()).
ifPresent(provision ->
MappingUtils.getConnObjectKeyItem(provision).ifPresent(keyItem -> {
@@ -617,7 +617,7 @@ abstract class AbstractAnyDataBinder {
any.getAuxClasses().clear();
anyCR.getAuxClasses().stream().
map(className -> anyTypeClassDAO.findById(className)).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
forEach(auxClass -> {
if (auxClass == null) {
LOG.debug("Invalid " +
AnyTypeClass.class.getSimpleName() + " {}, ignoring...", auxClass);
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index 66cb3af462..e240615bca 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -205,7 +205,7 @@ public class ResourceDataBinderImpl implements
ResourceDataBinder {
Stream.concat(
anyType.getClasses().stream(),
provision.getAuxClasses().stream().map(anyTypeClassDAO::findById).
-
filter(Optional::isPresent).map(Optional::get)).forEach(anyTypeClass -> {
+
flatMap(Optional::stream)).forEach(anyTypeClass -> {
allowedSchemas.getPlainSchemas().addAll(anyTypeClass.getPlainSchemas().stream().
map(PlainSchema::getKey).toList());
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java
index bca2d34c1f..f7aae75b0f 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java
@@ -638,7 +638,7 @@ public class DefaultPropagationManager implements
PropagationManager {
anyUtilsFactory.getInstance(kind).dao().findAllResourceKeys(key).stream().
map(resourceDAO::findById).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
filter(resource ->
!excludedResources.contains(resource.getKey())
&&
resource.getProvisionByAnyType(any.getType().getKey()).isPresent()
&& resource.getPropagationPolicy() != null &&
resource.getPropagationPolicy().isUpdateDelta()).
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java
index fda71b05d9..c2de716df7 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java
@@ -122,7 +122,7 @@ public class LDAPMembershipPropagationActions implements
PropagationActions {
// for each user group assigned to the resource of this task,
compute and add the group's
// connector object link
userDAO.findAllGroupKeys(user).stream().
-
map(groupDAO::findById).filter(Optional::isPresent).map(Optional::get).
+ map(groupDAO::findById).flatMap(Optional::stream).
filter(group ->
group.getResources().contains(taskInfo.getResource())).
forEach(group -> {
String groupConnObjectLink =
evaluateGroupConnObjectLink(
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/InboundMatcher.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/InboundMatcher.java
index d774d6cebb..690332d0c0 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/InboundMatcher.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/InboundMatcher.java
@@ -223,8 +223,7 @@ public class InboundMatcher {
protected List<Implementation> getTransformers(final Item item) {
return item.getTransformers().stream().
map(implementationDAO::findById).
- filter(Optional::isPresent).
- map(Optional::get).
+ flatMap(Optional::stream).
collect(Collectors.toList());
}
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
index a0e5cc69f1..229648f656 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
@@ -111,7 +111,7 @@ public class SinglePullJobDelegate extends PullJobDelegate
implements SyncopeSin
profile.setDryRun(false);
profile.setConflictResolutionAction(ConflictResolutionAction.FIRSTMATCH);
profile.getActions().addAll(getPullActions(pullTaskTO.getActions().stream().
-
map(implementationDAO::findById).filter(Optional::isPresent).map(Optional::get).
+ map(implementationDAO::findById).flatMap(Optional::stream).
toList()));
profile.setExecutor(executor);
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
index 12fba70677..a24cede99e 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
@@ -72,7 +72,7 @@ public class SinglePushJobDelegate extends PushJobDelegate
implements SyncopeSin
profile = new ProvisioningProfile<>(connector, task);
profile.setExecutor(executor);
profile.getActions().addAll(getPushActions(pushTaskTO.getActions().stream().
-
map(implementationDAO::findById).filter(Optional::isPresent).map(Optional::get).
+ map(implementationDAO::findById).flatMap(Optional::stream).
toList()));
profile.setConflictResolutionAction(ConflictResolutionAction.FIRSTMATCH);
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPullJobDelegate.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPullJobDelegate.java
index 6e280a7337..fcc875f7df 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPullJobDelegate.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPullJobDelegate.java
@@ -186,7 +186,7 @@ public class StreamPullJobDelegate extends PullJobDelegate
implements SyncopeStr
profile.setDryRun(false);
profile.setConflictResolutionAction(conflictResolutionAction);
profile.getActions().addAll(getPullActions(pullTaskTO.getActions().stream().
-
map(implementationDAO::findById).filter(Optional::isPresent).map(Optional::get).
+ map(implementationDAO::findById).flatMap(Optional::stream).
toList()));
profile.setExecutor(executor);
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPushJobDelegate.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPushJobDelegate.java
index dfd95b72ab..7b6b760f35 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPushJobDelegate.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPushJobDelegate.java
@@ -141,7 +141,7 @@ public class StreamPushJobDelegate extends PushJobDelegate
implements SyncopeStr
profile = new ProvisioningProfile<>(connector, task);
profile.setExecutor(executor);
profile.getActions().addAll(getPushActions(pushTaskTO.getActions().stream().
-
map(implementationDAO::findById).filter(Optional::isPresent).map(Optional::get).
+ map(implementationDAO::findById).flatMap(Optional::stream).
toList()));
profile.setConflictResolutionAction(ConflictResolutionAction.FIRSTMATCH);
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
index b8ca9fd36c..d180a325d7 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
@@ -202,7 +202,7 @@ public class ConnObjectUtils {
// add resource policies
userCR.getResources().stream().
map(resourceDAO::findById).
- filter(Optional::isPresent).map(Optional::get).
+ flatMap(Optional::stream).
filter(r -> r.getPasswordPolicy() != null).
forEach(r -> passwordPolicies.add(r.getPasswordPolicy()));
diff --git
a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractAnyObjectWorkflowAdapter.java
b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractAnyObjectWorkflowAdapter.java
index c19a2898fe..00b645e90c 100644
---
a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractAnyObjectWorkflowAdapter.java
+++
b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractAnyObjectWorkflowAdapter.java
@@ -111,7 +111,7 @@ public abstract class AbstractAnyObjectWorkflowAdapter
// finally publish events for all groups affected by this operation,
via membership
result.getResult().getMemberships().stream().map(MembershipUR::getGroup).distinct().
-
map(groupDAO::findById).filter(Optional::isPresent).map(Optional::get).
+ map(groupDAO::findById).flatMap(Optional::stream).
forEach(group -> publisher.publishEvent(new
EntityLifecycleEvent<>(
this, SyncDeltaType.UPDATE, group,
AuthContextUtils.getDomain())));
diff --git
a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
index b1f6966962..3c8228ef26 100644
---
a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
+++
b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
@@ -345,7 +345,7 @@ public abstract class AbstractUserWorkflowAdapter extends
AbstractWorkflowAdapte
// finally publish events for all groups affected by this operation,
via membership
result.getResult().getLeft().getMemberships().stream().map(MembershipUR::getGroup).distinct().
-
map(groupDAO::findById).filter(Optional::isPresent).map(Optional::get).
+ map(groupDAO::findById).flatMap(Optional::stream).
forEach(group -> publisher.publishEvent(new
EntityLifecycleEvent<>(
this, SyncDeltaType.UPDATE, group,
AuthContextUtils.getDomain())));
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 621f0723ac..0f9658f078 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
@@ -36,14 +36,11 @@ import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
import org.apache.syncope.core.persistence.api.entity.AuditEvent;
-import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
-import org.apache.syncope.core.persistence.api.entity.Membership;
import org.apache.syncope.core.persistence.api.entity.PlainAttr;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.Privilege;
import org.apache.syncope.core.persistence.api.entity.Realm;
-import org.apache.syncope.core.persistence.api.entity.Relationship;
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;
@@ -208,11 +205,10 @@ public class ElasticsearchUtils {
// add also flattened membership attributes
if (any instanceof GroupableRelatable) {
- GroupableRelatable<? extends Any, ? extends Membership, ? extends
GroupablePlainAttr, ? extends Any, ?
- extends Relationship> entity =
GroupableRelatable.class.cast(any);
- entity.getMemberships().forEach(m ->
entity.getPlainAttrs(m).forEach(mAttr -> {
- List<Object> values =
mAttr.getValues().stream().map(PlainAttrValue::getValue)
- .collect(Collectors.toList());
+ GroupableRelatable<?, ?, ?, ?, ?> groupable =
GroupableRelatable.class.cast(any);
+ groupable.getMemberships().forEach(m ->
groupable.getPlainAttrs(m).forEach(mAttr -> {
+ List<Object> values = mAttr.getValues().stream().
+
map(PlainAttrValue::getValue).collect(Collectors.toList());
Optional.ofNullable(mAttr.getUniqueValue()).ifPresent(v ->
values.add(v.getValue()));
@@ -226,7 +222,7 @@ public class ElasticsearchUtils {
}
}));
}
-
+
return builder;
}
diff --git
a/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchRealmSearchDAO.java
b/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchRealmSearchDAO.java
index 2155d6dc67..2208ad5c6a 100644
---
a/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchRealmSearchDAO.java
+++
b/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchRealmSearchDAO.java
@@ -127,7 +127,7 @@ public class ElasticsearchRealmSearchDAO implements
RealmSearchDAO {
new Query.Builder().term(QueryBuilders.term().
field("name").value(name).build()).build());
return result.stream().map(realmDAO::findById).
-
filter(Optional::isPresent).map(Optional::get).map(Realm.class::cast).toList();
+ flatMap(Optional::stream).map(Realm.class::cast).toList();
}
@Override
@@ -136,7 +136,7 @@ public class ElasticsearchRealmSearchDAO implements
RealmSearchDAO {
new Query.Builder().term(QueryBuilders.term().
field("parent_id").value(realm.getKey()).build()).build());
return result.stream().map(realmDAO::findById).
-
filter(Optional::isPresent).map(Optional::get).map(Realm.class::cast).toList();
+ flatMap(Optional::stream).map(Realm.class::cast).toList();
}
protected Query buildDescendantQuery(final String base, final String
keyword) {
@@ -209,7 +209,7 @@ public class ElasticsearchRealmSearchDAO implements
RealmSearchDAO {
}
return result.stream().map(realmDAO::findById).
-
filter(Optional::isPresent).map(Optional::get).map(Realm.class::cast).toList();
+ flatMap(Optional::stream).map(Realm.class::cast).toList();
}
@Override
diff --git
a/ext/oidcc4ui/logic/src/main/java/org/apache/syncope/core/logic/oidc/OIDCUserManager.java
b/ext/oidcc4ui/logic/src/main/java/org/apache/syncope/core/logic/oidc/OIDCUserManager.java
index 8e689dce91..3b98bf5bd5 100644
---
a/ext/oidcc4ui/logic/src/main/java/org/apache/syncope/core/logic/oidc/OIDCUserManager.java
+++
b/ext/oidcc4ui/logic/src/main/java/org/apache/syncope/core/logic/oidc/OIDCUserManager.java
@@ -130,8 +130,7 @@ public class OIDCUserManager {
protected List<Implementation> getTransformers(final Item item) {
return item.getTransformers().stream().
map(implementationDAO::findById).
- filter(Optional::isPresent).
- map(Optional::get).
+ flatMap(Optional::stream).
collect(Collectors.toList());
}
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 6ef66d10ae..367b648110 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
@@ -36,14 +36,11 @@ import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
import org.apache.syncope.core.persistence.api.entity.AuditEvent;
-import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
-import org.apache.syncope.core.persistence.api.entity.Membership;
import org.apache.syncope.core.persistence.api.entity.PlainAttr;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.Privilege;
import org.apache.syncope.core.persistence.api.entity.Realm;
-import org.apache.syncope.core.persistence.api.entity.Relationship;
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;
@@ -208,11 +205,10 @@ public class OpenSearchUtils {
// add also flattened membership attributes
if (any instanceof GroupableRelatable) {
- GroupableRelatable<? extends Any, ? extends Membership, ? extends
GroupablePlainAttr, ? extends Any, ?
- extends Relationship> entity =
GroupableRelatable.class.cast(any);
- entity.getMemberships().forEach(m ->
entity.getPlainAttrs(m).forEach(mAttr -> {
- List<Object> values =
mAttr.getValues().stream().map(PlainAttrValue::getValue)
- .collect(Collectors.toList());
+ GroupableRelatable<?, ?, ?, ?, ?> groupable =
GroupableRelatable.class.cast(any);
+ groupable.getMemberships().forEach(m ->
groupable.getPlainAttrs(m).forEach(mAttr -> {
+ List<Object> values = mAttr.getValues().stream().
+
map(PlainAttrValue::getValue).collect(Collectors.toList());
Optional.ofNullable(mAttr.getUniqueValue()).ifPresent(v ->
values.add(v.getValue()));
@@ -226,7 +222,7 @@ public class OpenSearchUtils {
}
}));
}
-
+
return builder;
}
diff --git
a/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchRealmSearchDAO.java
b/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchRealmSearchDAO.java
index 5cd31034a1..d882119faa 100644
---
a/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchRealmSearchDAO.java
+++
b/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchRealmSearchDAO.java
@@ -127,7 +127,7 @@ public class OpenSearchRealmSearchDAO implements
RealmSearchDAO {
new Query.Builder().term(QueryBuilders.term().
field("name").value(FieldValue.of(name)).build()).build());
return result.stream().map(realmDAO::findById).
-
filter(Optional::isPresent).map(Optional::get).map(Realm.class::cast).toList();
+ flatMap(Optional::stream).map(Realm.class::cast).toList();
}
@Override
@@ -136,7 +136,7 @@ public class OpenSearchRealmSearchDAO implements
RealmSearchDAO {
new Query.Builder().term(QueryBuilders.term().
field("parent_id").value(FieldValue.of(realm.getKey())).build()).build());
return result.stream().map(realmDAO::findById).
-
filter(Optional::isPresent).map(Optional::get).map(Realm.class::cast).toList();
+ flatMap(Optional::stream).map(Realm.class::cast).toList();
}
protected Query buildDescendantQuery(final String base, final String
keyword) {
@@ -209,7 +209,7 @@ public class OpenSearchRealmSearchDAO implements
RealmSearchDAO {
}
return result.stream().map(realmDAO::findById).
-
filter(Optional::isPresent).map(Optional::get).map(Realm.class::cast).toList();
+ flatMap(Optional::stream).map(Realm.class::cast).toList();
}
@Override
diff --git
a/ext/saml2sp4ui/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2SP4UIUserManager.java
b/ext/saml2sp4ui/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2SP4UIUserManager.java
index 45274ecb0c..1b1c121d90 100644
---
a/ext/saml2sp4ui/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2SP4UIUserManager.java
+++
b/ext/saml2sp4ui/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2SP4UIUserManager.java
@@ -142,8 +142,7 @@ public class SAML2SP4UIUserManager {
protected List<Implementation> getTransformers(final Item item) {
return item.getTransformers().stream().
map(implementationDAO::findById).
- filter(Optional::isPresent).
- map(Optional::get).
+ flatMap(Optional::stream).
collect(Collectors.toList());
}
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 4609efbf09..ec9247e9d6 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
@@ -18,7 +18,6 @@
*/
package org.apache.syncope.fit.core;
-import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
@@ -354,7 +353,7 @@ public class SearchITCase extends AbstractITCase {
PagedResult<UserTO> issueSYNCOPE1321 = USER_SERVICE.search(new
AnyQuery.Builder().
realm(SyncopeConstants.ROOT_REALM).
fiql(SyncopeClient.getUserSearchConditionBuilder().
-
is("lastLoginDate").lexicalNotBefore("2016-03-02T15:21:22%2B0300").
+
is("lastChangeDate").lexicalNotBefore("2010-03-02T15:21:22%2B0300").
and("username").equalTo("bellini").query()).
build());
assertEquals(users, issueSYNCOPE1321);
@@ -623,6 +622,95 @@ public class SearchITCase extends AbstractITCase {
assertTrue(users > 0);
}
+ @Test
+ public void userByMembershipAttribute() {
+ // create type extension for the 'employee' group, if not present
+ GroupTO employee = GROUP_SERVICE.read("employee");
+ if (employee.getTypeExtension(AnyTypeKind.USER.name()).isEmpty()) {
+ TypeExtensionTO typeExtensionTO = new TypeExtensionTO();
+ typeExtensionTO.setAnyType(AnyTypeKind.USER.name());
+ typeExtensionTO.getAuxClasses().add("other");
+ updateGroup(new
GroupUR.Builder(employee.getKey()).typeExtension(typeExtensionTO).build());
+ }
+
+ if (IS_EXT_SEARCH_ENABLED) {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ // ignore
+ }
+ }
+
+ PagedResult<UserTO> matching = USER_SERVICE.search(
+ new
AnyQuery.Builder().fiql(SyncopeClient.getUserSearchConditionBuilder().
+
is("ctype").equalTo("additionalctype").query()).build());
+ assertEquals(0, matching.getTotalCount());
+ matching = USER_SERVICE.search(
+ new
AnyQuery.Builder().fiql(SyncopeClient.getUserSearchConditionBuilder().
+ is("ctype").equalTo("myownctype").query()).build());
+ assertEquals(0, matching.getTotalCount());
+
+ // add user membership and its plain attribute
+ updateUser(new UserUR.Builder(USER_SERVICE.read("puccini").getKey())
+ .plainAttr(attrAddReplacePatch("ctype", "myownctype"))
+ .membership(new
MembershipUR.Builder(GROUP_SERVICE.read("additional").getKey()).
+ plainAttrs(attr("ctype", "additionalctype")).build())
+ .membership(new MembershipUR.Builder(employee.getKey())
+ .plainAttrs(attr("ctype",
"additionalemployeectype")).build())
+ .build());
+
+ if (IS_EXT_SEARCH_ENABLED) {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ // ignore
+ }
+ }
+
+ matching = USER_SERVICE.search(
+ new
AnyQuery.Builder().fiql(SyncopeClient.getUserSearchConditionBuilder().
+
is("ctype").equalTo("additionalctype").query()).build());
+ assertEquals(1, matching.getTotalCount());
+ assertTrue(matching.getResult().stream().anyMatch(u ->
"puccini".equals(u.getUsername())));
+
+ // check also that search on user plain attribute (not in membership)
works
+ matching = USER_SERVICE.search(
+ new
AnyQuery.Builder().fiql(SyncopeClient.getUserSearchConditionBuilder().
+ is("ctype").equalTo("myownctype").query()).build());
+ assertEquals(1, matching.getTotalCount());
+ assertTrue(matching.getResult().stream().anyMatch(u ->
"puccini".equals(u.getUsername())));
+ }
+
+ @Test
+ public void anyObjectByMembershipAttribute() {
+ PagedResult<AnyObjectTO> matching = ANY_OBJECT_SERVICE.search(
+ new
AnyQuery.Builder().fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER)
+
.is("ctype").equalTo("otherchildctype").query()).build());
+ assertEquals(0, matching.getTotalCount());
+
+ // add any object membership and its plain attribute
+ updateAnyObject(new
AnyObjectUR.Builder("8559d14d-58c2-46eb-a2d4-a7d35161e8f8").
+ membership(new
MembershipUR.Builder(GROUP_SERVICE.read("otherchild").getKey()).
+ plainAttrs(attr("ctype", "otherchildctype")).
+ build()).build());
+
+ if (IS_EXT_SEARCH_ENABLED) {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ // ignore
+ }
+ }
+
+ matching = ANY_OBJECT_SERVICE.search(
+ new
AnyQuery.Builder().fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER)
+
.is("ctype").equalTo("otherchildctype").query()).build());
+ assertEquals(1, matching.getTotalCount());
+
+ assertTrue(matching.getResult().stream().
+ anyMatch(a ->
"8559d14d-58c2-46eb-a2d4-a7d35161e8f8".equals(a.getKey())));
+ }
+
@Test
public void issueSYNCOPE768() {
long usersWithNullable = USER_SERVICE.search(new
AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
@@ -1060,57 +1148,4 @@ public class SearchITCase extends AbstractITCase {
deleteUser("user test 182");
}
}
-
- @Test
- void userByMembershipAttribute() {
- // search user by membership attribute
- UserTO puccini = USER_SERVICE.read("puccini");
- GroupTO additional = GROUP_SERVICE.read("additional");
- GroupTO employee = GROUP_SERVICE.read("employee");
- TypeExtensionTO typeExtensionTO = new TypeExtensionTO();
- typeExtensionTO.setAnyType(AnyTypeKind.USER.name());
- typeExtensionTO.getAuxClasses().add("other");
- updateGroup(new
GroupUR.Builder(employee.getKey()).typeExtension(typeExtensionTO).build());
- // add a membership and its plain attribute
- updateUser(new UserUR.Builder(puccini.getKey())
- .plainAttr(attrAddReplacePatch("ctype", "myownctype"))
- .memberships(
- new
MembershipUR.Builder(additional.getKey()).plainAttrs(attr("ctype",
"additionalctype"))
- .build(), new MembershipUR.Builder(employee.getKey())
- .plainAttrs(attr("ctype",
"additionalemployeectype"))
- .build()).build());
- await().until(() -> USER_SERVICE.search(new
AnyQuery.Builder().page(1).size(10)
-
.fiql(SyncopeClient.getUserSearchConditionBuilder().is("ctype").equalTo("additionalctype").query())
- .build()).getTotalCount() == 1);
- assertTrue(USER_SERVICE.search(new AnyQuery.Builder().page(1).size(10)
-
.fiql(SyncopeClient.getUserSearchConditionBuilder().is("ctype").equalTo("additionalctype").query())
- .build()).getResult().stream().anyMatch(u ->
"puccini".equals(u.getUsername())));
- assertTrue(USER_SERVICE.search(new AnyQuery.Builder().page(1).size(10)
-
.fiql(SyncopeClient.getUserSearchConditionBuilder().is("ctype").equalTo("additionalemployeectype")
- .query()).build()).getResult().stream().anyMatch(u ->
"puccini".equals(u.getUsername())));
- // check also that search on user plain attribute (not in membership)
works
- assertTrue(USER_SERVICE.search(new AnyQuery.Builder().page(1).size(10)
-
.fiql(SyncopeClient.getUserSearchConditionBuilder().is("ctype").equalTo("myownctype").query())
- .build()).getResult().stream().anyMatch(u ->
"puccini".equals(u.getUsername())));
- }
-
- @Test
- void anyObjectByMembershipAttribute() {
- // search user by membership attribute
- AnyObjectTO canonMf =
ANY_OBJECT_SERVICE.read("8559d14d-58c2-46eb-a2d4-a7d35161e8f8");
- GroupTO otherchild = GROUP_SERVICE.read("otherchild");
- // add a membership and its plain attribute
- updateAnyObject(new AnyObjectUR.Builder(canonMf.getKey()).memberships(
- new
MembershipUR.Builder(otherchild.getKey()).plainAttrs(attr("ctype",
"otherchildctype"))
- .build()).build());
- await().until(() -> ANY_OBJECT_SERVICE.search(new
AnyQuery.Builder().page(1).size(10)
-
.fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).is("ctype").equalTo("otherchildctype")
- .query()).build()).getTotalCount() == 1);
- assertTrue(ANY_OBJECT_SERVICE.search(new
AnyQuery.Builder().page(1).size(10)
-
.fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).is("ctype").equalTo(
- "otherchildctype")
- .query()).build()).getResult().stream()
- .anyMatch(u ->
"8559d14d-58c2-46eb-a2d4-a7d35161e8f8".equals(u.getKey())));
- }
-
}
diff --git a/pom.xml b/pom.xml
index 085cb4584c..3b8c158bbd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -495,7 +495,7 @@ under the License.
<cargo.deployable.ping.timeout>60000</cargo.deployable.ping.timeout>
<tomcat.version>10.1.31</tomcat.version>
- <wildfly.version>33.0.2.Final</wildfly.version>
+ <wildfly.version>34.0.0.Final</wildfly.version>
<payara.version>6.2024.10</payara.version>
<jakarta.faces.version>4.1.1</jakarta.faces.version>
@@ -503,7 +503,7 @@ under the License.
<docker.mysql.version>9.0</docker.mysql.version>
<docker.mariadb.version>11</docker.mariadb.version>
<docker.oracle.version>23-slim-faststart</docker.oracle.version>
- <docker.neo4j.version>5.23.0</docker.neo4j.version>
+ <docker.neo4j.version>5.24.2</docker.neo4j.version>
<jdbc.postgresql.version>42.7.4</jdbc.postgresql.version>
<jdbc.mysql.version>9.1.0</jdbc.mysql.version>
diff --git
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java
index f35e642654..3f925e9373 100644
---
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java
+++
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java
@@ -99,8 +99,7 @@ public class DefaultAuthMapper implements AuthMapper {
if (!mfaAuthHandlers.isEmpty()) {
Set<String> fns = mfaAuthHandlers.stream().
map(handler -> authModules.stream().filter(am ->
handler.equals(am.getKey())).findFirst()).
- filter(Optional::isPresent).
- map(Optional::get).
+ flatMap(Optional::stream).
filter(am -> am.getConf() instanceof MFAAuthModuleConf).
map(am -> ((MFAAuthModuleConf)
am.getConf()).getFriendlyName()).
collect(Collectors.toSet());