You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2019/10/09 13:49:55 UTC

[syncope] branch master updated (4cef608 -> 52062c4)

This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git.


    from 4cef608  NOJIRA: fix compile issue after merge with master
     new e0c2fd9  [SYNCOPE-1501] Connector Objects can now be filtered via FIQL
     new 52062c4  [SYNCOPE-1465] White noise

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../client/console/rest/ResourceRestClient.java    |   6 +-
 .../apache/syncope/client/lib/SyncopeClient.java   |  10 +
 .../common/rest/api/service/ResourceService.java   |  15 +-
 .../search/AbstractFiqlSearchConditionBuilder.java |   1 -
 .../AnyObjectFiqlSearchConditionBuilder.java       |   1 -
 .../ConnObjectTOFiqlSearchConditionBuilder.java    |  80 ++++++
 .../search/GroupFiqlSearchConditionBuilder.java    |   1 -
 ...jectTOListQuery.java => ConnObjectTOQuery.java} |  33 ++-
 .../apache/syncope/core/logic/ResourceLogic.java   | 133 +++++-----
 .../core/rest/cxf/service/ResourceServiceImpl.java |  49 +++-
 .../org/apache/syncope/core/logic/GroupLogic.java  |   7 +-
 .../org/apache/syncope/core/logic/RealmLogic.java  |  12 +-
 .../org/apache/syncope/core/logic/ReportLogic.java |  19 +-
 .../org/apache/syncope/core/logic/TaskLogic.java   |   6 +-
 ...archCondConverter.java => FilterConverter.java} |  20 +-
 .../core/persistence/api/search/FilterVisitor.java | 166 ++++++++++++
 .../persistence/api/search/SearchCondVisitor.java  |  26 +-
 .../api/search/FilterConverterTest.java            | 289 +++++++++++++++++++++
 .../pushpull/DefaultUserPullResultHandler.java     |   3 +-
 .../syncope/core/logic/UserRequestLogic.java       |   3 +-
 .../syncope/core/logic/UserWorkflowTaskLogic.java  |   3 +-
 .../syncope/fit/core/LinkedAccountITCase.java      |  34 +--
 .../org/apache/syncope/fit/core/ReportITCase.java  |  19 +-
 .../syncope/fit/core/ReportTemplateITCase.java     |  18 +-
 .../apache/syncope/fit/core/ResourceITCase.java    |  58 -----
 .../org/apache/syncope/fit/core/SearchITCase.java  | 122 ++++++++-
 26 files changed, 877 insertions(+), 257 deletions(-)
 create mode 100644 common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/ConnObjectTOFiqlSearchConditionBuilder.java
 rename common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/{ConnObjectTOListQuery.java => ConnObjectTOQuery.java} (79%)
 copy core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/{SearchCondConverter.java => FilterConverter.java} (75%)
 create mode 100644 core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/FilterVisitor.java
 create mode 100644 core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/FilterConverterTest.java


[syncope] 01/02: [SYNCOPE-1501] Connector Objects can now be filtered via FIQL

Posted by il...@apache.org.
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

commit e0c2fd972523fe2d34f5ce1e98db23c2f63989f5
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Wed Oct 9 14:33:54 2019 +0200

    [SYNCOPE-1501] Connector Objects can now be filtered via FIQL
---
 .../client/console/rest/ResourceRestClient.java    |   6 +-
 .../apache/syncope/client/lib/SyncopeClient.java   |  10 +
 .../common/rest/api/service/ResourceService.java   |  15 +-
 .../search/AbstractFiqlSearchConditionBuilder.java |   1 -
 .../AnyObjectFiqlSearchConditionBuilder.java       |   1 -
 .../ConnObjectTOFiqlSearchConditionBuilder.java    |  80 ++++++
 .../search/GroupFiqlSearchConditionBuilder.java    |   1 -
 ...jectTOListQuery.java => ConnObjectTOQuery.java} |  33 ++-
 .../apache/syncope/core/logic/ResourceLogic.java   | 133 +++++-----
 .../core/rest/cxf/service/ResourceServiceImpl.java |  49 +++-
 .../persistence/api/search/FilterConverter.java    |  64 +++++
 .../core/persistence/api/search/FilterVisitor.java | 166 ++++++++++++
 .../persistence/api/search/SearchCondVisitor.java  |  26 +-
 .../api/search/FilterConverterTest.java            | 289 +++++++++++++++++++++
 .../syncope/fit/core/LinkedAccountITCase.java      |  34 +--
 .../apache/syncope/fit/core/ResourceITCase.java    |  58 -----
 .../org/apache/syncope/fit/core/SearchITCase.java  | 122 ++++++++-
 17 files changed, 907 insertions(+), 181 deletions(-)

diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java
index 71dfd5c..ff5e201 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java
@@ -26,7 +26,7 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.PagedConnObjectTOResult;
 import org.apache.syncope.common.lib.to.ResourceTO;
-import org.apache.syncope.common.rest.api.beans.ConnObjectTOListQuery;
+import org.apache.syncope.common.rest.api.beans.ConnObjectTOQuery;
 import org.apache.syncope.common.rest.api.service.ResourceService;
 import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
 
@@ -62,7 +62,7 @@ public class ResourceRestClient extends BaseRestClient {
         final String pagedResultCookie,
         final SortParam<String> sort) {
 
-        ConnObjectTOListQuery.Builder builder = new ConnObjectTOListQuery.Builder().
+        ConnObjectTOQuery.Builder builder = new ConnObjectTOQuery.Builder().
                 pagedResultsCookie(pagedResultCookie).
                 size(size).
                 orderBy(toOrderBy(sort));
@@ -72,7 +72,7 @@ public class ResourceRestClient extends BaseRestClient {
 
         PagedConnObjectTOResult list;
         try {
-            list = getService(ResourceService.class).listConnObjects(resource, anyTypeKey, builder.build());
+            list = getService(ResourceService.class).searchConnObjects(resource, anyTypeKey, builder.build());
             result.addAll(list.getResult());
             nextPageResultCookie = list.getPagedResultsCookie();
         } catch (Exception e) {
diff --git a/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java b/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java
index d5e6362..2979c9b 100644
--- a/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java
+++ b/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java
@@ -42,6 +42,7 @@ import org.apache.cxf.transport.http.HTTPConduit;
 import org.apache.cxf.transport.http.URLConnectionHTTPConduit;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.search.AnyObjectFiqlSearchConditionBuilder;
+import org.apache.syncope.common.lib.search.ConnObjectTOFiqlSearchConditionBuilder;
 import org.apache.syncope.common.lib.search.OrderByClauseBuilder;
 import org.apache.syncope.common.lib.search.GroupFiqlSearchConditionBuilder;
 import org.apache.syncope.common.lib.search.UserFiqlSearchConditionBuilder;
@@ -188,6 +189,15 @@ public class SyncopeClient {
     }
 
     /**
+     * Returns a new instance of {@link ConnObjectTOFiqlSearchConditionBuilder}, for assisted building of FIQL queries.
+     *
+     * @return default instance of {@link ConnObjectTOFiqlSearchConditionBuilder}
+     */
+    public static ConnObjectTOFiqlSearchConditionBuilder getConnObjectTOFiqlSearchConditionBuilder() {
+        return new ConnObjectTOFiqlSearchConditionBuilder();
+    }
+
+    /**
      * Returns a new instance of {@link OrderByClauseBuilder}, for assisted building of {@code orderby} clauses.
      *
      * @return default instance of {@link OrderByClauseBuilder}
diff --git a/common/idm/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ResourceService.java b/common/idm/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ResourceService.java
index 27b7813..cca2ac0 100644
--- a/common/idm/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ResourceService.java
+++ b/common/idm/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ResourceService.java
@@ -45,7 +45,7 @@ import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.PagedConnObjectTOResult;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.common.rest.api.beans.ConnObjectTOListQuery;
+import org.apache.syncope.common.rest.api.beans.ConnObjectTOQuery;
 
 /**
  * REST operations for external resources.
@@ -62,16 +62,17 @@ public interface ResourceService extends JAXRSService {
      *
      * @param key name of resource to read connector object from
      * @param anyTypeKey any object type
-     * @param anyKey any object key
+     * @param value if value looks like a UUID then it is interpreted as user, group or any object key, otherwise
+     * as key value on the resource
      * @return connector object from the external resource, for the given type and key
      */
     @GET
-    @Path("{key}/{anyTypeKey}/{anyKey}")
+    @Path("{key}/{anyTypeKey}/{value}")
     @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     ConnObjectTO readConnObject(
             @NotNull @PathParam("key") String key,
             @NotNull @PathParam("anyTypeKey") String anyTypeKey,
-            @NotNull @PathParam("anyKey") String anyKey);
+            @NotNull @PathParam("value") String value);
 
     /**
      * Returns a paged list of connector objects from external resource, for the given type, matching
@@ -79,16 +80,16 @@ public interface ResourceService extends JAXRSService {
      *
      * @param key name of resource to read connector object from
      * @param anyTypeKey any object type
-     * @param listQuery query conditions
+     * @param connObjectTOQuery query conditions
      * @return connector objects from the external resource, for the given type
      */
     @GET
     @Path("{key}/{anyTypeKey}")
     @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
-    PagedConnObjectTOResult listConnObjects(
+    PagedConnObjectTOResult searchConnObjects(
             @NotNull @PathParam("key") String key,
             @NotNull @PathParam("anyTypeKey") String anyTypeKey,
-            @BeanParam ConnObjectTOListQuery listQuery);
+            @BeanParam ConnObjectTOQuery connObjectTOQuery);
 
     /**
      * Returns the resource with matching name.
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/AbstractFiqlSearchConditionBuilder.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/AbstractFiqlSearchConditionBuilder.java
index 18fee59..5f8aa43 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/AbstractFiqlSearchConditionBuilder.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/AbstractFiqlSearchConditionBuilder.java
@@ -146,6 +146,5 @@ public abstract class AbstractFiqlSearchConditionBuilder extends FiqlSearchCondi
             this.result = SpecialAttr.DYNREALMS.toString();
             return condition(FiqlParser.NEQ, dynRealm, (Object[]) moreDynRealms);
         }
-
     }
 }
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/AnyObjectFiqlSearchConditionBuilder.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/AnyObjectFiqlSearchConditionBuilder.java
index 9276015..b497c7b 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/AnyObjectFiqlSearchConditionBuilder.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/AnyObjectFiqlSearchConditionBuilder.java
@@ -162,6 +162,5 @@ public class AnyObjectFiqlSearchConditionBuilder extends AbstractFiqlSearchCondi
             this.result = SpecialAttr.ASSIGNABLE.toString();
             return condition(FiqlParser.EQ, SpecialAttr.NULL);
         }
-
     }
 }
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/ConnObjectTOFiqlSearchConditionBuilder.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/ConnObjectTOFiqlSearchConditionBuilder.java
new file mode 100644
index 0000000..d028a71
--- /dev/null
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/ConnObjectTOFiqlSearchConditionBuilder.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.search;
+
+import java.util.Map;
+import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
+
+/**
+ * Extends {@link AbstractFiqlSearchConditionBuilder} by providing some additional facilities for searching
+ * connector objects.
+ */
+public class ConnObjectTOFiqlSearchConditionBuilder extends AbstractFiqlSearchConditionBuilder {
+
+    private static final long serialVersionUID = 4983742159694010935L;
+
+    @Override
+    protected Builder newBuilderInstance() {
+        return new Builder(properties);
+    }
+
+    @Override
+    public SyncopeProperty is(final String property) {
+        return newBuilderInstance().is(property);
+    }
+
+    protected class Builder extends AbstractFiqlSearchConditionBuilder.Builder
+            implements SyncopeProperty, CompleteCondition {
+
+        public Builder(final Map<String, String> properties) {
+            super(properties);
+        }
+
+        public Builder(final Builder parent) {
+            super(parent);
+        }
+
+        @Override
+        public SyncopeProperty is(final String property) {
+            Builder b = new Builder(this);
+            b.result = property;
+            return b;
+        }
+
+        @Override
+        public CompleteCondition inDynRealms(final String dynRealm, final String... moreDynRealms) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public CompleteCondition notInDynRealms(final String dynRealm, final String... moreDynRealms) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public CompleteCondition hasResources(final String resource, final String... moreResources) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public CompleteCondition hasNotResources(final String resource, final String... moreResources) {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java
index 232ba6b..1a875c9 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/search/GroupFiqlSearchConditionBuilder.java
@@ -93,6 +93,5 @@ public class GroupFiqlSearchConditionBuilder extends AbstractFiqlSearchCondition
             this.result = SpecialAttr.MEMBER.toString();
             return condition(FiqlParser.NEQ, member, (Object[]) moreMembers);
         }
-
     }
 }
diff --git a/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/ConnObjectTOListQuery.java b/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/ConnObjectTOQuery.java
similarity index 79%
rename from common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/ConnObjectTOListQuery.java
rename to common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/ConnObjectTOQuery.java
index 9c8d172..db874ce 100644
--- a/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/ConnObjectTOListQuery.java
+++ b/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/ConnObjectTOQuery.java
@@ -19,15 +19,13 @@
 package org.apache.syncope.common.rest.api.beans;
 
 import java.io.Serializable;
-import java.util.Optional;
-
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
 import javax.ws.rs.DefaultValue;
 import javax.ws.rs.QueryParam;
 import org.apache.syncope.common.rest.api.service.JAXRSService;
 
-public class ConnObjectTOListQuery implements Serializable {
+public class ConnObjectTOQuery implements Serializable {
 
     private static final long serialVersionUID = -371488230250055359L;
 
@@ -35,7 +33,7 @@ public class ConnObjectTOListQuery implements Serializable {
 
     public static class Builder {
 
-        private final ConnObjectTOListQuery instance = new ConnObjectTOListQuery();
+        private final ConnObjectTOQuery instance = new ConnObjectTOQuery();
 
         public Builder size(final Integer size) {
             instance.setSize(size);
@@ -52,10 +50,14 @@ public class ConnObjectTOListQuery implements Serializable {
             return this;
         }
 
-        public ConnObjectTOListQuery build() {
-            return instance;
+        public Builder fiql(final String fiql) {
+            instance.setFiql(fiql);
+            return this;
         }
 
+        public ConnObjectTOQuery build() {
+            return instance;
+        }
     }
 
     private Integer size;
@@ -64,10 +66,14 @@ public class ConnObjectTOListQuery implements Serializable {
 
     private String orderBy;
 
+    private String fiql;
+
     public Integer getSize() {
-        return Optional.ofNullable(size).map(integer -> integer > MAX_SIZE
-            ? MAX_SIZE
-            : integer).orElse(25);
+        return size == null
+                ? 25
+                : size > MAX_SIZE
+                        ? MAX_SIZE
+                        : size;
     }
 
     @Min(1)
@@ -95,4 +101,13 @@ public class ConnObjectTOListQuery implements Serializable {
     public void setOrderBy(final String orderBy) {
         this.orderBy = orderBy;
     }
+
+    public String getFiql() {
+        return fiql;
+    }
+
+    @QueryParam(JAXRSService.PARAM_FIQL)
+    public void setFiql(final String fiql) {
+        this.fiql = fiql;
+    }
 }
diff --git a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index 704cbe8..9dd0c93 100644
--- a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -27,37 +27,32 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.tuple.ImmutableTriple;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.commons.lang3.tuple.Triple;
 import org.apache.syncope.common.lib.collections.IteratorChain;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.IdMEntitlement;
 import org.apache.syncope.core.persistence.api.dao.DuplicateException;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
-import org.apache.syncope.core.persistence.api.dao.GroupDAO;
-import org.apache.syncope.core.persistence.api.dao.UserDAO;
-import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.provisioning.api.Connector;
 import org.apache.syncope.core.provisioning.api.ConnectorFactory;
 import org.apache.syncope.core.provisioning.api.data.ResourceDataBinder;
 import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
-import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.ConnInstance;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.provisioning.api.MappingManager;
 import org.apache.syncope.core.provisioning.api.data.ConnInstanceDataBinder;
@@ -74,6 +69,7 @@ import org.identityconnectors.framework.common.objects.ObjectClass;
 import org.identityconnectors.framework.common.objects.OperationOptions;
 import org.identityconnectors.framework.common.objects.SearchResult;
 import org.identityconnectors.framework.common.objects.Uid;
+import org.identityconnectors.framework.common.objects.filter.Filter;
 import org.identityconnectors.framework.spi.SearchResultsHandler;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -90,18 +86,9 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     private AnyTypeDAO anyTypeDAO;
 
     @Autowired
-    private AnyObjectDAO anyObjectDAO;
-
-    @Autowired
     private ConnInstanceDAO connInstanceDAO;
 
     @Autowired
-    private UserDAO userDAO;
-
-    @Autowired
-    private GroupDAO groupDAO;
-
-    @Autowired
     private VirSchemaDAO virSchemaDAO;
 
     @Autowired
@@ -116,6 +103,9 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     @Autowired
     private ConnectorFactory connFactory;
 
+    @Autowired
+    private AnyUtilsFactory anyUtilsFactory;
+
     protected static void securityChecks(final Set<String> effectiveRealms, final String realm, final String key) {
         boolean authorized = effectiveRealms.stream().anyMatch(realm::startsWith);
         if (!authorized) {
@@ -277,69 +267,57 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
         return resourceDAO.findAll().stream().map(binder::getResourceTO).collect(Collectors.toList());
     }
 
-    private Triple<ExternalResource, AnyType, Provision> connObjectInit(
+    private Pair<AnyType, Provision> connObjectInit(
             final String resourceKey, final String anyTypeKey) {
 
         ExternalResource resource = resourceDAO.authFind(resourceKey);
         if (resource == null) {
             throw new NotFoundException("Resource '" + resourceKey + '\'');
         }
+
         AnyType anyType = anyTypeDAO.find(anyTypeKey);
         if (anyType == null) {
             throw new NotFoundException("AnyType '" + anyTypeKey + '\'');
         }
-        Optional<? extends Provision> provision = resource.getProvision(anyType);
-        if (provision.isEmpty()) {
-            throw new NotFoundException("Provision on resource '" + resourceKey + "' for type '" + anyTypeKey + '\'');
-        }
 
-        return ImmutableTriple.of(resource, anyType, provision.get());
-    }
+        Provision provision = resource.getProvision(anyType).
+                orElseThrow(() -> new NotFoundException(
+                "Provision on resource '" + resourceKey + "' for type '" + anyTypeKey + "'"));
 
-    @PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_GET_CONNOBJECT + "')")
-    @Transactional(readOnly = true)
-    public ConnObjectTO readConnObject(final String key, final String anyTypeKey, final String anyKey) {
-        Triple<ExternalResource, AnyType, Provision> init = connObjectInit(key, anyTypeKey);
+        return Pair.of(anyType, provision);
+    }
 
-        // 1. find any
-        Any<?> any = init.getMiddle().getKind() == AnyTypeKind.USER
-                ? userDAO.find(anyKey)
-                : init.getMiddle().getKind() == AnyTypeKind.ANY_OBJECT
-                ? anyObjectDAO.find(anyKey)
-                : groupDAO.find(anyKey);
-        if (any == null) {
-            throw new NotFoundException(init.getMiddle() + " " + anyKey);
-        }
+    private ConnObjectTO readConnObject(
+            final Provision provision,
+            final String connObjectKeyValue) {
 
-        // 2. build connObjectKeyItem
-        MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(init.getRight()).
+        // 0. build connObjectKeyItem
+        MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision).
                 orElseThrow(() -> new NotFoundException(
-                "ConnObjectKey mapping for " + init.getMiddle() + ' ' + anyKey + " on resource '" + key + '\''));
-        String connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, init.getRight()).
-                orElseThrow(() -> new NotFoundException(
-                "ConnObjectKey value for " + init.getMiddle() + ' ' + anyKey + " on resource '" + key + '\''));
+                "ConnObjectKey mapping for " + provision.getAnyType().getKey()
+                + " on resource '" + provision.getResource().getKey() + "'"));
 
-        // 3. determine attributes to query
-        Set<MappingItem> linkinMappingItems = virSchemaDAO.findByProvision(init.getRight()).stream().
-                map(VirSchema::asLinkingMappingItem).collect(Collectors.toSet());
+        // 1. determine attributes to query
+        Set<MappingItem> linkinMappingItems = virSchemaDAO.findByProvision(provision).stream().
+                map(virSchema -> virSchema.asLinkingMappingItem()).collect(Collectors.toSet());
         Iterator<MappingItem> mapItems = new IteratorChain<>(
-                init.getRight().getMapping().getItems().iterator(),
+                provision.getMapping().getItems().iterator(),
                 linkinMappingItems.iterator());
 
-        // 4. read from the underlying connector
-        Connector connector = connFactory.getConnector(init.getLeft());
+        // 2. read from the underlying connector
+        Connector connector = connFactory.getConnector(provision.getResource());
         ConnectorObject connectorObject = connector.getObject(
-                init.getRight().getObjectClass(),
+                provision.getObjectClass(),
                 AttributeBuilder.build(connObjectKeyItem.getExtAttrName(), connObjectKeyValue),
-                init.getRight().isIgnoreCaseMatch(),
+                provision.isIgnoreCaseMatch(),
                 MappingUtils.buildOperationOptions(mapItems));
         if (connectorObject == null) {
             throw new NotFoundException(
-                    "Object " + connObjectKeyValue + " with class " + init.getRight().getObjectClass()
-                    + " not found on resource " + key);
+                    "Object " + connObjectKeyValue + " with class " + provision.getObjectClass()
+                    + " not found on resource " + provision.getResource().getKey());
         }
 
-        // 5. build result
+        // 3. build result
         Set<Attribute> attributes = connectorObject.getAttributes();
         if (AttributeUtil.find(Uid.NAME, attributes) == null) {
             attributes.add(connectorObject.getUid());
@@ -351,10 +329,49 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
         return ConnObjectUtils.getConnObjectTO(connectorObject);
     }
 
+    @PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_GET_CONNOBJECT + "')")
+    @Transactional(readOnly = true)
+    public ConnObjectTO readConnObjectByAnyKey(
+            final String key,
+            final String anyTypeKey,
+            final String anyKey) {
+
+        Pair<AnyType, Provision> init = connObjectInit(key, anyTypeKey);
+
+        // 1. find any
+        Any<?> any = anyUtilsFactory.getInstance(init.getLeft().getKind()).dao().authFind(anyKey);
+        if (any == null) {
+            throw new NotFoundException(init.getLeft() + " " + anyKey);
+        }
+
+        // 2. find connObjectKeyValue
+        String connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, init.getRight()).
+                orElseThrow(() -> new NotFoundException(
+                "ConnObjectKey value for " + init.getLeft() + " " + anyKey + " on resource '" + key + "'"));
+
+        return readConnObject(init.getRight(), connObjectKeyValue);
+    }
+
+    @PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_GET_CONNOBJECT + "')")
+    @Transactional(readOnly = true)
+    public ConnObjectTO readConnObjectByConnObjectKey(
+            final String key,
+            final String anyTypeKey,
+            final String connObjectKeyValue) {
+
+        Pair<AnyType, Provision> init = connObjectInit(key, anyTypeKey);
+        return readConnObject(init.getRight(), connObjectKeyValue);
+    }
+
     @PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_LIST_CONNOBJECT + "')")
     @Transactional(readOnly = true)
-    public Pair<SearchResult, List<ConnObjectTO>> listConnObjects(final String key, final String anyTypeKey,
-            final int size, final String pagedResultsCookie, final List<OrderByClause> orderBy) {
+    public Pair<SearchResult, List<ConnObjectTO>> searchConnObjects(
+            final Filter filter,
+            final String key,
+            final String anyTypeKey,
+            final int size,
+            final String pagedResultsCookie,
+            final List<OrderByClause> orderBy) {
 
         ExternalResource resource;
         ObjectClass objectClass;
@@ -372,8 +389,8 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
             options = MappingUtils.buildOperationOptions(
                     MappingUtils.getPropagationItems(resource.getOrgUnit().getItems()).iterator());
         } else {
-            Triple<ExternalResource, AnyType, Provision> init = connObjectInit(key, anyTypeKey);
-            resource = init.getLeft();
+            Pair<AnyType, Provision> init = connObjectInit(key, anyTypeKey);
+            resource = init.getRight().getResource();
             objectClass = init.getRight().getObjectClass();
             init.getRight().getMapping().getItems();
 
@@ -387,7 +404,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
 
         List<ConnObjectTO> connObjects = new ArrayList<>();
         SearchResult searchResult = connFactory.getConnector(resource).
-                search(objectClass, null, new SearchResultsHandler() {
+                search(objectClass, filter, new SearchResultsHandler() {
 
                     private int count;
 
diff --git a/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java b/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
index 2076fbb..ea255de 100644
--- a/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
+++ b/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
@@ -25,15 +25,23 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.commons.lang3.tuple.Pair;
+import org.apache.cxf.jaxrs.ext.search.SearchBean;
+import org.apache.cxf.jaxrs.ext.search.SearchCondition;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.PagedConnObjectTOResult;
 import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.common.rest.api.beans.ConnObjectTOListQuery;
+import org.apache.syncope.common.rest.api.beans.ConnObjectTOQuery;
 import org.apache.syncope.common.rest.api.service.ResourceService;
 import org.apache.syncope.core.logic.ResourceLogic;
+import org.apache.syncope.core.persistence.api.search.FilterVisitor;
 import org.identityconnectors.framework.common.objects.SearchResult;
+import org.identityconnectors.framework.common.objects.filter.Filter;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -83,16 +91,41 @@ public class ResourceServiceImpl extends AbstractServiceImpl implements Resource
     }
 
     @Override
-    public ConnObjectTO readConnObject(final String key, final String anyTypeKey, final String anyKey) {
-        return logic.readConnObject(key, anyTypeKey, anyKey);
+    public ConnObjectTO readConnObject(final String key, final String anyTypeKey, final String value) {
+        return SyncopeConstants.UUID_PATTERN.matcher(value).matches()
+                ? logic.readConnObjectByAnyKey(key, anyTypeKey, value)
+                : logic.readConnObjectByConnObjectKey(key, anyTypeKey, value);
     }
 
     @Override
-    public PagedConnObjectTOResult listConnObjects(
-            final String key, final String anyTypeKey, final ConnObjectTOListQuery listQuery) {
+    public PagedConnObjectTOResult searchConnObjects(
+            final String key, final String anyTypeKey, final ConnObjectTOQuery query) {
+
+        Filter filter = null;
+        if (StringUtils.isNotBlank(query.getFiql())) {
+            try {
+                FilterVisitor visitor = new FilterVisitor();
+                SearchCondition<SearchBean> sc = searchContext.getCondition(query.getFiql(), SearchBean.class);
+                sc.accept(visitor);
+
+                filter = visitor.getQuery();
+            } catch (Exception e) {
+                LOG.error("Invalid FIQL expression: {}", query.getFiql(), e);
+
+                SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSearchExpression);
+                sce.getElements().add(query.getFiql());
+                sce.getElements().add(ExceptionUtils.getRootCauseMessage(e));
+                throw sce;
+            }
+        }
 
-        Pair<SearchResult, List<ConnObjectTO>> list = logic.listConnObjects(key, anyTypeKey,
-                listQuery.getSize(), listQuery.getPagedResultsCookie(), getOrderByClauses(listQuery.getOrderBy()));
+        Pair<SearchResult, List<ConnObjectTO>> list = logic.searchConnObjects(
+                filter,
+                key,
+                anyTypeKey,
+                query.getSize(),
+                query.getPagedResultsCookie(),
+                getOrderByClauses(query.getOrderBy()));
 
         PagedConnObjectTOResult result = new PagedConnObjectTOResult();
         if (list.getLeft() != null) {
@@ -111,7 +144,7 @@ public class ResourceServiceImpl extends AbstractServiceImpl implements Resource
         if (StringUtils.isNotBlank(result.getPagedResultsCookie())) {
             result.setNext(builder.
                     replaceQueryParam(PARAM_CONNID_PAGED_RESULTS_COOKIE, result.getPagedResultsCookie()).
-                    replaceQueryParam(PARAM_SIZE, listQuery.getSize()).
+                    replaceQueryParam(PARAM_SIZE, query.getSize()).
                     build());
         }
 
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/FilterConverter.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/FilterConverter.java
new file mode 100644
index 0000000..b57c854
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/FilterConverter.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.search;
+
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.cxf.jaxrs.ext.search.SearchBean;
+import org.apache.cxf.jaxrs.ext.search.SearchCondition;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.search.AbstractFiqlSearchConditionBuilder;
+import org.apache.syncope.common.lib.search.SyncopeFiqlParser;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.identityconnectors.framework.common.objects.filter.Filter;
+
+/**
+ * Converts FIQL expressions to ConnId's {@link Filter}.
+ */
+public final class FilterConverter {
+
+    /**
+     * Parses a FIQL expression into ConnId's {@link Filter}, using {@link SyncopeFiqlParser}.
+     *
+     * @param fiql FIQL string
+     * @return {@link Filter} instance for given FIQL expression
+     */
+    public static Filter convert(final String fiql) {
+        SyncopeFiqlParser<SearchBean> parser = new SyncopeFiqlParser<>(
+                SearchBean.class, AbstractFiqlSearchConditionBuilder.CONTEXTUAL_PROPERTIES);
+
+        try {
+            FilterVisitor visitor = new FilterVisitor();
+            SearchCondition<SearchBean> sc = parser.parse(URLDecoder.decode(fiql, StandardCharsets.UTF_8));
+            sc.accept(visitor);
+
+            return visitor.getQuery();
+        } catch (Exception e) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSearchExpression);
+            sce.getElements().add(fiql);
+            sce.getElements().add(ExceptionUtils.getRootCauseMessage(e));
+            throw sce;
+        }
+    }
+
+    private FilterConverter() {
+        // empty constructor for static utility class        
+    }
+}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/FilterVisitor.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/FilterVisitor.java
new file mode 100644
index 0000000..8a159d4
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/FilterVisitor.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.search;
+
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import org.apache.cxf.jaxrs.ext.search.ConditionType;
+import org.apache.cxf.jaxrs.ext.search.SearchBean;
+import org.apache.cxf.jaxrs.ext.search.SearchCondition;
+import org.apache.cxf.jaxrs.ext.search.SearchUtils;
+import org.apache.cxf.jaxrs.ext.search.visitor.AbstractSearchConditionVisitor;
+import org.apache.syncope.common.lib.search.SpecialAttr;
+import org.apache.syncope.common.lib.search.SyncopeFiqlParser;
+import org.apache.syncope.common.lib.search.SyncopeFiqlSearchCondition;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.AttributeBuilder;
+import org.identityconnectors.framework.common.objects.filter.Filter;
+import org.identityconnectors.framework.common.objects.filter.FilterBuilder;
+
+public class FilterVisitor extends AbstractSearchConditionVisitor<SearchBean, Filter> {
+
+    private Filter filter;
+
+    public FilterVisitor() {
+        super(null);
+    }
+
+    private Filter visitPrimitive(final SearchCondition<SearchBean> sc) {
+        String name = getRealPropertyName(sc.getStatement().getProperty());
+        Optional<SpecialAttr> specialAttrName = SpecialAttr.fromString(name);
+
+        String value = SearchUtils.toSqlWildcardString(
+                URLDecoder.decode(sc.getStatement().getValue().toString(), StandardCharsets.UTF_8), false).
+                replaceAll("\\\\_", "_");
+        Optional<SpecialAttr> specialAttrValue = SpecialAttr.fromString(value);
+
+        ConditionType ct = sc.getConditionType();
+        if (sc instanceof SyncopeFiqlSearchCondition && sc.getConditionType() == ConditionType.CUSTOM) {
+            SyncopeFiqlSearchCondition<SearchBean> sfsc = (SyncopeFiqlSearchCondition<SearchBean>) sc;
+            switch (sfsc.getOperator()) {
+                case SyncopeFiqlParser.IEQ:
+                    ct = ConditionType.EQUALS;
+                    break;
+
+                case SyncopeFiqlParser.NIEQ:
+                    ct = ConditionType.NOT_EQUALS;
+                    break;
+
+                default:
+                    throw new IllegalArgumentException(
+                            String.format("Condition type %s is not supported", sfsc.getOperator()));
+            }
+        }
+
+        Attribute attr = AttributeBuilder.build(name, value);
+
+        Filter leaf;
+        switch (ct) {
+            case EQUALS:
+            case NOT_EQUALS:
+                if (!specialAttrName.isPresent()) {
+                    if (specialAttrValue.isPresent() && specialAttrValue.get() == SpecialAttr.NULL) {
+                        leaf = FilterBuilder.equalTo(AttributeBuilder.build(name));
+                    } else if (value.indexOf('%') == -1) {
+                        leaf = sc.getConditionType() == ConditionType.CUSTOM
+                                ? FilterBuilder.equalsIgnoreCase(attr)
+                                : FilterBuilder.equalTo(attr);
+                    } else if (sc.getConditionType() != ConditionType.CUSTOM && value.startsWith("%")) {
+                        leaf = FilterBuilder.endsWith(
+                                AttributeBuilder.build(name, value.substring(1)));
+                    } else if (sc.getConditionType() != ConditionType.CUSTOM && value.endsWith("%")) {
+                        leaf = FilterBuilder.startsWith(
+                                AttributeBuilder.build(name, value.substring(0, value.length() - 1)));
+                    } else {
+                        throw new IllegalArgumentException(
+                                String.format("Unsupported search value %s", value));
+                    }
+                } else {
+                    throw new IllegalArgumentException(
+                            String.format("Special attr name %s is not supported", specialAttrName));
+                }
+                if (ct == ConditionType.NOT_EQUALS) {
+                    leaf = FilterBuilder.not(leaf);
+                }
+                break;
+
+            case GREATER_OR_EQUALS:
+                leaf = FilterBuilder.greaterThanOrEqualTo(attr);
+                break;
+
+            case GREATER_THAN:
+                leaf = FilterBuilder.greaterThan(attr);
+                break;
+
+            case LESS_OR_EQUALS:
+                leaf = FilterBuilder.lessThanOrEqualTo(attr);
+                break;
+
+            case LESS_THAN:
+                leaf = FilterBuilder.lessThan(attr);
+                break;
+
+            default:
+                throw new IllegalArgumentException(String.format("Condition type %s is not supported", ct.name()));
+        }
+
+        return leaf;
+    }
+
+    private Filter visitCompount(final SearchCondition<SearchBean> sc) {
+        List<Filter> searchConds = new ArrayList<>();
+        sc.getSearchConditions().forEach(searchCond -> {
+            searchConds.add(searchCond.getStatement() == null
+                    ? visitCompount(searchCond)
+                    : visitPrimitive(searchCond));
+        });
+
+        Filter compound;
+        switch (sc.getConditionType()) {
+            case AND:
+                compound = FilterBuilder.and(searchConds);
+                break;
+
+            case OR:
+                compound = FilterBuilder.or(searchConds);
+                break;
+
+            default:
+                throw new IllegalArgumentException(
+                        String.format("Condition type %s is not supported", sc.getConditionType().name()));
+        }
+
+        return compound;
+    }
+
+    @Override
+    public void visit(final SearchCondition<SearchBean> sc) {
+        filter = sc.getStatement() == null
+                ? visitCompount(sc)
+                : visitPrimitive(sc);
+    }
+
+    @Override
+    public Filter getQuery() {
+        return filter;
+    }
+}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java
index 7a1a9d4..616a195 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/search/SearchCondVisitor.java
@@ -98,13 +98,18 @@ public class SearchCondVisitor extends AbstractSearchConditionVisitor<SearchBean
         ConditionType ct = sc.getConditionType();
         if (sc instanceof SyncopeFiqlSearchCondition && sc.getConditionType() == ConditionType.CUSTOM) {
             SyncopeFiqlSearchCondition<SearchBean> sfsc = (SyncopeFiqlSearchCondition<SearchBean>) sc;
-            if (SyncopeFiqlParser.IEQ.equals(sfsc.getOperator())) {
-                ct = ConditionType.EQUALS;
-            } else if (SyncopeFiqlParser.NIEQ.equals(sfsc.getOperator())) {
-                ct = ConditionType.NOT_EQUALS;
-            } else {
-                throw new IllegalArgumentException(
-                        String.format("Condition type %s is not supported", sfsc.getOperator()));
+            switch (sfsc.getOperator()) {
+                case SyncopeFiqlParser.IEQ:
+                    ct = ConditionType.EQUALS;
+                    break;
+
+                case SyncopeFiqlParser.NIEQ:
+                    ct = ConditionType.NOT_EQUALS;
+                    break;
+
+                default:
+                    throw new IllegalArgumentException(
+                            String.format("Condition type %s is not supported", sfsc.getOperator()));
             }
         }
 
@@ -252,9 +257,9 @@ public class SearchCondVisitor extends AbstractSearchConditionVisitor<SearchBean
 
     private SearchCond visitCompount(final SearchCondition<SearchBean> sc) {
         List<SearchCond> searchConds = new ArrayList<>();
-        sc.getSearchConditions().forEach(searchCondition -> searchConds.add(searchCondition.getStatement() == null
-                ? visitCompount(searchCondition)
-                : visitPrimitive(searchCondition)));
+        sc.getSearchConditions().forEach(searchCond -> searchConds.add(searchCond.getStatement() == null
+                ? visitCompount(searchCond)
+                : visitPrimitive(searchCond)));
 
         SearchCond compound;
         switch (sc.getConditionType()) {
@@ -285,5 +290,4 @@ public class SearchCondVisitor extends AbstractSearchConditionVisitor<SearchBean
     public SearchCond getQuery() {
         return searchCond;
     }
-
 }
diff --git a/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/FilterConverterTest.java b/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/FilterConverterTest.java
new file mode 100644
index 0000000..40c9b69
--- /dev/null
+++ b/core/persistence-api/src/test/java/org/apache/syncope/core/persistence/api/search/FilterConverterTest.java
@@ -0,0 +1,289 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.search;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.List;
+import java.util.ListIterator;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.search.SpecialAttr;
+import org.apache.syncope.common.lib.search.ConnObjectTOFiqlSearchConditionBuilder;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.identityconnectors.framework.common.objects.AttributeBuilder;
+import org.identityconnectors.framework.common.objects.filter.AndFilter;
+import org.identityconnectors.framework.common.objects.filter.Filter;
+import org.identityconnectors.framework.common.objects.filter.FilterBuilder;
+import org.identityconnectors.framework.common.objects.filter.NotFilter;
+import org.identityconnectors.framework.common.objects.filter.OrFilter;
+import org.junit.jupiter.api.Test;
+
+public class FilterConverterTest {
+
+    private boolean equals(final Filter filter1, final Filter filter2) {
+        return EqualsBuilder.reflectionEquals(filter1, filter2);
+    }
+
+    private boolean equals(final List<Filter> filters1, final List<Filter> filters2) {
+        ListIterator<Filter> e1 = filters1.listIterator();
+        ListIterator<Filter> e2 = filters2.listIterator();
+        while (e1.hasNext() && e2.hasNext()) {
+            Filter o1 = e1.next();
+            Filter o2 = e2.next();
+            if (!equals(o1, o2)) {
+                return false;
+            }
+        }
+        return !(e1.hasNext() || e2.hasNext());
+    }
+
+    @Test
+    public void eq() {
+        String fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("username").equalTo("rossini").query();
+        assertEquals("username==rossini", fiql);
+
+        Filter filter = FilterBuilder.equalTo(AttributeBuilder.build("username", "rossini"));
+
+        assertTrue(equals(filter, FilterConverter.convert(fiql)));
+    }
+
+    @Test
+    public void ieq() {
+        String fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("username").equalToIgnoreCase("rossini").query();
+        assertEquals("username=~rossini", fiql);
+
+        Filter filter = FilterBuilder.equalsIgnoreCase(AttributeBuilder.build("username", "rossini"));
+
+        assertTrue(equals(filter, FilterConverter.convert(fiql)));
+    }
+
+    @Test
+    public void nieq() {
+        String fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("username").notEqualTolIgnoreCase("rossini").
+                query();
+        assertEquals("username!~rossini", fiql);
+
+        Filter filter = FilterBuilder.not(
+                FilterBuilder.equalsIgnoreCase(AttributeBuilder.build("username", "rossini")));
+        assertTrue(filter instanceof NotFilter);
+
+        Filter converted = FilterConverter.convert(fiql);
+        assertTrue(converted instanceof NotFilter);
+
+        assertTrue(equals(
+                ((NotFilter) filter).getFilter(), ((NotFilter) converted).getFilter()));
+    }
+
+    @Test
+    public void like() {
+        String fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("username").equalTo("ros*").query();
+        assertEquals("username==ros*", fiql);
+
+        Filter filter = FilterBuilder.startsWith(AttributeBuilder.build("username", "ros"));
+
+        assertTrue(equals(filter, FilterConverter.convert(fiql)));
+
+        fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("username").equalTo("*ini").query();
+        assertEquals("username==*ini", fiql);
+
+        filter = FilterBuilder.endsWith(AttributeBuilder.build("username", "ini"));
+
+        assertTrue(equals(filter, FilterConverter.convert(fiql)));
+
+        fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("username").equalTo("r*ini").query();
+        assertEquals("username==r*ini", fiql);
+
+        try {
+            FilterConverter.convert(fiql);
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.InvalidSearchExpression, e.getType());
+        }
+    }
+
+    @Test
+    public void ilike() {
+        String fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("username").equalToIgnoreCase("ros*").query();
+        assertEquals("username=~ros*", fiql);
+
+        try {
+            FilterConverter.convert(fiql);
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.InvalidSearchExpression, e.getType());
+        }
+    }
+
+    @Test
+    public void nilike() {
+        String fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("username").notEqualTolIgnoreCase("ros*").query();
+        assertEquals("username!~ros*", fiql);
+
+        try {
+            FilterConverter.convert(fiql);
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.InvalidSearchExpression, e.getType());
+        }
+    }
+
+    @Test
+    public void isNull() {
+        String fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("loginDate").nullValue().query();
+        assertEquals("loginDate==" + SpecialAttr.NULL, fiql);
+
+        Filter filter = FilterBuilder.equalTo(AttributeBuilder.build("loginDate"));
+
+        assertTrue(equals(filter, FilterConverter.convert(fiql)));
+    }
+
+    @Test
+    public void isNotNull() {
+        String fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("loginDate").notNullValue().query();
+        assertEquals("loginDate!=" + SpecialAttr.NULL, fiql);
+
+        Filter filter = FilterBuilder.not(FilterBuilder.equalTo(AttributeBuilder.build("loginDate")));
+        assertTrue(filter instanceof NotFilter);
+
+        Filter converted = FilterConverter.convert(fiql);
+        assertTrue(converted instanceof NotFilter);
+
+        assertTrue(equals(
+                ((NotFilter) filter).getFilter(), ((NotFilter) converted).getFilter()));
+    }
+
+    @Test
+    public void inDynRealms() {
+        try {
+            new ConnObjectTOFiqlSearchConditionBuilder().inDynRealms("realm").query();
+            fail();
+        } catch (UnsupportedOperationException e) {
+            assertNotNull(e);
+        }
+
+        try {
+            FilterConverter.convert(SpecialAttr.DYNREALMS + "==realm");
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.InvalidSearchExpression, e.getType());
+        }
+    }
+
+    @Test
+    public void notInDynRealms() {
+        try {
+            new ConnObjectTOFiqlSearchConditionBuilder().notInDynRealms("realm").query();
+            fail();
+        } catch (UnsupportedOperationException e) {
+            assertNotNull(e);
+        }
+
+        try {
+            FilterConverter.convert(SpecialAttr.DYNREALMS + "!=realm");
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.InvalidSearchExpression, e.getType());
+        }
+    }
+
+    @Test
+    public void hasResources() {
+        try {
+            new ConnObjectTOFiqlSearchConditionBuilder().hasResources("resource").query();
+            fail();
+        } catch (UnsupportedOperationException e) {
+            assertNotNull(e);
+        }
+
+        try {
+            FilterConverter.convert(SpecialAttr.RESOURCES + "==resource");
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.InvalidSearchExpression, e.getType());
+        }
+    }
+
+    @Test
+    public void hasNotResources() {
+        try {
+            new ConnObjectTOFiqlSearchConditionBuilder().hasNotResources("resource").query();
+            fail();
+        } catch (UnsupportedOperationException e) {
+            assertNotNull(e);
+        }
+
+        try {
+            FilterConverter.convert(SpecialAttr.RESOURCES + "!=resource");
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.InvalidSearchExpression, e.getType());
+        }
+    }
+
+    @Test
+    public void and() {
+        String fiql = new ConnObjectTOFiqlSearchConditionBuilder().
+                is("fullname").equalTo("ro*").and("fullname").equalTo("*i").query();
+        assertEquals("fullname==ro*;fullname==*i", fiql);
+
+        Filter filter1 = FilterBuilder.startsWith(AttributeBuilder.build("fullname", "ro"));
+        Filter filter2 = FilterBuilder.endsWith(AttributeBuilder.build("fullname", "i"));
+
+        Filter filter = FilterBuilder.and(filter1, filter2);
+        assertTrue(filter instanceof AndFilter);
+
+        Filter converted = FilterConverter.convert(fiql);
+        assertTrue(converted instanceof AndFilter);
+
+        assertTrue(equals(
+                (List<Filter>) ((AndFilter) filter).getFilters(), (List<Filter>) ((AndFilter) converted).getFilters()));
+    }
+
+    @Test
+    public void or() {
+        String fiql = new ConnObjectTOFiqlSearchConditionBuilder().
+                is("fullname").equalTo("ro*").or("fullname").equalTo("*i").query();
+        assertEquals("fullname==ro*,fullname==*i", fiql);
+
+        Filter filter1 = FilterBuilder.startsWith(AttributeBuilder.build("fullname", "ro"));
+        Filter filter2 = FilterBuilder.endsWith(AttributeBuilder.build("fullname", "i"));
+
+        Filter filter = FilterBuilder.or(filter1, filter2);
+        assertTrue(filter instanceof OrFilter);
+
+        Filter converted = FilterConverter.convert(fiql);
+        assertTrue(converted instanceof OrFilter);
+
+        assertTrue(equals(
+                (List<Filter>) ((OrFilter) filter).getFilters(), (List<Filter>) ((OrFilter) converted).getFilters()));
+    }
+
+    @Test
+    public void issueSYNCOPE1223() {
+        String fiql = new ConnObjectTOFiqlSearchConditionBuilder().is("ctype").equalTo("ou=sample%252Co=isp").query();
+
+        Filter filter = FilterBuilder.equalTo(AttributeBuilder.build("ctype", "ou=sample,o=isp"));
+
+        assertTrue(equals(filter, FilterConverter.convert(fiql)));
+    }
+}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LinkedAccountITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LinkedAccountITCase.java
index f02f5cd..a04a07f 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LinkedAccountITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LinkedAccountITCase.java
@@ -30,8 +30,6 @@ import java.util.List;
 import java.util.Optional;
 import java.util.UUID;
 import javax.naming.NamingException;
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapContext;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -44,6 +42,7 @@ import org.apache.cxf.jaxrs.client.WebClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.policy.PullPolicyTO;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.ExecTO;
 import org.apache.syncope.common.lib.to.ImplementationTO;
 import org.apache.syncope.common.lib.to.LinkedAccountTO;
@@ -102,15 +101,11 @@ public class LinkedAccountITCase extends AbstractITCase {
         assertEquals(ResourceOperation.CREATE, tasks.getResult().get(0).getOperation());
         assertEquals(ExecStatus.SUCCESS.name(), tasks.getResult().get(0).getLatestExecStatus());
 
-        LdapContext ldapObj = (LdapContext) getLdapRemoteObject(
-                RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, connObjectKeyValue);
+        ConnObjectTO ldapObj = resourceService.readConnObject(
+                RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), connObjectKeyValue);
         assertNotNull(ldapObj);
-
-        Attributes ldapAttrs = ldapObj.getAttributes("");
-        assertEquals(
-                user.getPlainAttr("email").get().getValues().get(0),
-                ldapAttrs.get("mail").getAll().next().toString());
-        assertEquals("LINKED_SURNAME", ldapAttrs.get("sn").getAll().next().toString());
+        assertEquals(user.getPlainAttr("email").get().getValues(), ldapObj.getAttr("mail").get().getValues());
+        assertEquals("LINKED_SURNAME", ldapObj.getAttr("sn").get().getValues().get(0));
 
         // 3. remove linked account from user
         UserUR userUR = new UserUR();
@@ -125,12 +120,11 @@ public class LinkedAccountITCase extends AbstractITCase {
         assertEquals(1, user.getLinkedAccounts().size());
 
         // 4 verify that account was updated on resource
-        ldapObj = (LdapContext) getLdapRemoteObject(RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, connObjectKeyValue);
+        ldapObj = resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), connObjectKeyValue);
         assertNotNull(ldapObj);
 
-        ldapAttrs = ldapObj.getAttributes("");
-        assertEquals("UPDATED_EMAIL@syncope.apache.org", ldapAttrs.get("mail").getAll().next().toString());
-        assertEquals("UPDATED_SURNAME", ldapAttrs.get("sn").getAll().next().toString());
+        assertTrue(ldapObj.getAttr("mail").get().getValues().contains("UPDATED_EMAIL@syncope.apache.org"));
+        assertEquals("UPDATED_SURNAME", ldapObj.getAttr("sn").get().getValues().get(0));
 
         // 5. remove linked account from user
         userUR = new UserUR();
@@ -196,15 +190,11 @@ public class LinkedAccountITCase extends AbstractITCase {
         assertEquals(ResourceOperation.CREATE, tasks.getResult().get(0).getOperation());
         assertEquals(ExecStatus.SUCCESS.name(), tasks.getResult().get(0).getLatestExecStatus());
 
-        LdapContext ldapObj = (LdapContext) getLdapRemoteObject(
-                RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, connObjectKeyValue);
+        ConnObjectTO ldapObj = resourceService.readConnObject(
+                RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), connObjectKeyValue);
         assertNotNull(ldapObj);
-
-        Attributes ldapAttrs = ldapObj.getAttributes("");
-        assertEquals(
-                user.getPlainAttr("email").get().getValues().get(0),
-                ldapAttrs.get("mail").getAll().next().toString());
-        assertEquals("LINKED_SURNAME", ldapAttrs.get("sn").getAll().next().toString());
+        assertEquals(user.getPlainAttr("email").get().getValues(), ldapObj.getAttr("mail").get().getValues());
+        assertEquals("LINKED_SURNAME", ldapObj.getAttr("sn").get().getValues().get(0));
     }
 
     @Test
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
index 74e8473..d1d8826 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
@@ -27,26 +27,19 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
-import java.util.stream.Collectors;
 import javax.ws.rs.core.Response;
 import org.apache.commons.lang3.SerializationUtils;
-import org.apache.syncope.client.console.commons.ConnIdSpecialName;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.request.AnyObjectCR;
-import org.apache.syncope.common.lib.request.GroupCR;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
-import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.to.MappingTO;
 import org.apache.syncope.common.lib.to.OrgUnitTO;
-import org.apache.syncope.common.lib.to.PagedConnObjectTOResult;
 import org.apache.syncope.common.lib.to.ProvisionTO;
 import org.apache.syncope.common.lib.to.ResourceHistoryConfTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
@@ -58,7 +51,6 @@ import org.apache.syncope.common.lib.types.EntityViolationType;
 import org.apache.syncope.common.lib.types.IdMImplementationType;
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.common.lib.types.TraceLevel;
-import org.apache.syncope.common.rest.api.beans.ConnObjectTOListQuery;
 import org.apache.syncope.common.rest.api.service.ResourceService;
 import org.identityconnectors.framework.common.objects.ObjectClass;
 import org.apache.syncope.fit.AbstractITCase;
@@ -518,56 +510,6 @@ public class ResourceITCase extends AbstractITCase {
     }
 
     @Test
-    public void listConnObjects() {
-        List<String> groupKeys = new ArrayList<>();
-        for (int i = 0; i < 10; i++) {
-            GroupCR groupCR = GroupITCase.getSample("group");
-            groupCR.getResources().add(RESOURCE_NAME_LDAP);
-            GroupTO group = createGroup(groupCR).getEntity();
-            groupKeys.add(group.getKey());
-        }
-
-        int totalRead = 0;
-        Set<String> read = new HashSet<>();
-        try {
-            ConnObjectTOListQuery.Builder builder = new ConnObjectTOListQuery.Builder().size(10);
-            PagedConnObjectTOResult list;
-            do {
-                list = null;
-
-                boolean succeeded = false;
-                // needed because ApacheDS seems to randomly fail when searching with cookie
-                for (int i = 0; i < 5 && !succeeded; i++) {
-                    try {
-                        list = resourceService.listConnObjects(
-                                RESOURCE_NAME_LDAP,
-                                AnyTypeKind.GROUP.name(),
-                                builder.build());
-                        succeeded = true;
-                    } catch (SyncopeClientException e) {
-                        assertEquals(ClientExceptionType.ConnectorException, e.getType());
-                    }
-                }
-                assertNotNull(list);
-
-                totalRead += list.getResult().size();
-                read.addAll(list.getResult().stream().
-                        map(input -> input.getAttr(ConnIdSpecialName.NAME).get().getValues().get(0)).
-                        collect(Collectors.toList()));
-
-                if (list.getPagedResultsCookie() != null) {
-                    builder.pagedResultsCookie(list.getPagedResultsCookie());
-                }
-            } while (list.getPagedResultsCookie() != null);
-
-            assertEquals(totalRead, read.size());
-            assertTrue(totalRead >= 10);
-        } finally {
-            groupKeys.forEach(key -> groupService.delete(key));
-        }
-    }
-
-    @Test
     public void history() {
         List<ResourceHistoryConfTO> history = resourceHistoryService.list(RESOURCE_NAME_LDAP);
         assertNotNull(history);
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 35b298d..347e0b7 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
@@ -25,8 +25,14 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 import javax.ws.rs.core.Response;
 import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.syncope.client.console.commons.ConnIdSpecialName;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
@@ -39,18 +45,22 @@ import org.apache.syncope.common.lib.request.UserUR;
 import org.apache.syncope.common.lib.request.AttrPatch;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTypeTO;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.PagedConnObjectTOResult;
 import org.apache.syncope.common.lib.to.RoleTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.rest.api.beans.AnyQuery;
+import org.apache.syncope.common.rest.api.beans.ConnObjectTOQuery;
 import org.apache.syncope.common.rest.api.service.RoleService;
 import org.apache.syncope.fit.AbstractITCase;
 import org.apache.syncope.fit.ElasticsearchDetector;
 import org.junit.jupiter.api.Assertions;
+import org.identityconnectors.framework.common.objects.Name;
 import org.junit.jupiter.api.Test;
 
 public class SearchITCase extends AbstractITCase {
@@ -75,7 +85,8 @@ public class SearchITCase extends AbstractITCase {
         assertNotNull(matchingUsers);
         assertFalse(matchingUsers.getResult().isEmpty());
 
-        assertEquals(2, matchingUsers.getResult().stream().filter(user -> "74cd8ece-715a-44a4-a736-e17b46c4e7e6".equals(user.getKey())
+        assertEquals(2, matchingUsers.getResult().stream().filter(user -> "74cd8ece-715a-44a4-a736-e17b46c4e7e6".equals(
+                user.getKey())
                 || "b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee".equals(user.getKey())).count());
     }
 
@@ -445,6 +456,113 @@ public class SearchITCase extends AbstractITCase {
     }
 
     @Test
+    public void searchConnObjectsBrowsePagedResult() {
+        List<String> groupKeys = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            GroupCR groupCR = GroupITCase.getSample("group");
+            groupCR.getResources().add(RESOURCE_NAME_LDAP);
+            GroupTO group = createGroup(groupCR).getEntity();
+            groupKeys.add(group.getKey());
+        }
+
+        int totalRead = 0;
+        Set<String> read = new HashSet<>();
+        try {
+            // 1. first search with no filters
+            ConnObjectTOQuery.Builder builder = new ConnObjectTOQuery.Builder().size(10);
+            PagedConnObjectTOResult matches;
+            do {
+                matches = null;
+
+                boolean succeeded = false;
+                // needed because ApacheDS seems to randomly fail when searching with cookie
+                for (int i = 0; i < 5 && !succeeded; i++) {
+                    try {
+                        matches = resourceService.searchConnObjects(
+                                RESOURCE_NAME_LDAP,
+                                AnyTypeKind.GROUP.name(),
+                                builder.build());
+                        succeeded = true;
+                    } catch (SyncopeClientException e) {
+                        assertEquals(ClientExceptionType.ConnectorException, e.getType());
+                    }
+                }
+                assertNotNull(matches);
+
+                totalRead += matches.getResult().size();
+                read.addAll(matches.getResult().stream().
+                        map(input -> input.getAttr(ConnIdSpecialName.NAME).get().getValues().get(0)).
+                        collect(Collectors.toList()));
+
+                if (matches.getPagedResultsCookie() != null) {
+                    builder.pagedResultsCookie(matches.getPagedResultsCookie());
+                }
+            } while (matches.getPagedResultsCookie() != null);
+
+            assertEquals(totalRead, read.size());
+            assertTrue(totalRead >= 10);
+        } finally {
+            groupKeys.forEach(key -> {
+                groupService.delete(key);
+            });
+        }
+    }
+
+    @Test
+    public void searchConnObjectsWithFilter() {
+        ConnObjectTO user = resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), "pullFromLDAP");
+        assertNotNull(user);
+
+        PagedConnObjectTOResult matches = resourceService.searchConnObjects(
+                RESOURCE_NAME_LDAP,
+                AnyTypeKind.USER.name(),
+                new ConnObjectTOQuery.Builder().size(100).fiql(
+                        SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
+                                is("givenName").equalTo("pullFromLDAP").query()).build());
+        assertTrue(matches.getResult().contains(user));
+
+        matches = resourceService.searchConnObjects(
+                RESOURCE_NAME_LDAP,
+                AnyTypeKind.USER.name(),
+                new ConnObjectTOQuery.Builder().size(100).fiql(
+                        SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
+                                is("mail").equalTo("pullFromLDAP*").query()).build());
+        assertTrue(matches.getResult().contains(user));
+
+        matches = resourceService.searchConnObjects(
+                RESOURCE_NAME_LDAP,
+                AnyTypeKind.USER.name(),
+                new ConnObjectTOQuery.Builder().size(100).fiql(
+                        SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
+                                is("mail").equalTo("*@syncope.apache.org").query()).build());
+        assertTrue(matches.getResult().contains(user));
+
+        matches = resourceService.searchConnObjects(
+                RESOURCE_NAME_LDAP,
+                AnyTypeKind.USER.name(),
+                new ConnObjectTOQuery.Builder().size(100).fiql(
+                        SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
+                                is("givenName").equalToIgnoreCase("pullfromldap").query()).build());
+        assertTrue(matches.getResult().contains(user));
+
+        matches = resourceService.searchConnObjects(
+                RESOURCE_NAME_LDAP,
+                AnyTypeKind.USER.name(),
+                new ConnObjectTOQuery.Builder().size(100).fiql(
+                        SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
+                                is(Name.NAME).equalTo("uid=pullFromLDAP%252Cou=people%252Co=isp").query()).build());
+        assertTrue(matches.getResult().contains(user));
+
+        matches = resourceService.searchConnObjects(
+                RESOURCE_NAME_LDAP,
+                AnyTypeKind.USER.name(),
+                new ConnObjectTOQuery.Builder().size(100).fiql(
+                        SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
+                                is("givenName").notEqualTo("pullFromLDAP").query()).build());
+        assertFalse(matches.getResult().contains(user));
+    }
+
+    @Test
     public void issueSYNCOPE768() {
         int usersWithNullable = userService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
                 fiql(SyncopeClient.getUserSearchConditionBuilder().is("ctype").nullValue().query()).build()).
@@ -534,7 +652,7 @@ public class SearchITCase extends AbstractITCase {
         req.getPlainAttrs().add(new AttrPatch.Builder(attr("ctype", "ou=sample,o=isp")).build());
         userService.update(req);
 
-	if (ElasticsearchDetector.isElasticSearchEnabled(syncopeService)) {
+        if (ElasticsearchDetector.isElasticSearchEnabled(syncopeService)) {
             try {
                 Thread.sleep(2000);
             } catch (InterruptedException ex) {


[syncope] 02/02: [SYNCOPE-1465] White noise

Posted by il...@apache.org.
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

commit 52062c462fffa5a440bc75952d9ec832f44914f0
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Wed Oct 9 15:49:44 2019 +0200

    [SYNCOPE-1465] White noise
---
 .../org/apache/syncope/core/logic/GroupLogic.java     |  7 +++----
 .../org/apache/syncope/core/logic/RealmLogic.java     | 12 ++++++------
 .../org/apache/syncope/core/logic/ReportLogic.java    | 19 +++++++------------
 .../java/org/apache/syncope/core/logic/TaskLogic.java |  6 ++----
 .../java/pushpull/DefaultUserPullResultHandler.java   |  3 +--
 .../apache/syncope/core/logic/UserRequestLogic.java   |  3 +--
 .../syncope/core/logic/UserWorkflowTaskLogic.java     |  3 +--
 .../org/apache/syncope/fit/core/ReportITCase.java     | 19 +++----------------
 .../apache/syncope/fit/core/ReportTemplateITCase.java | 18 ++----------------
 9 files changed, 26 insertions(+), 64 deletions(-)

diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
index a3875fc..f563347 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
@@ -161,11 +161,11 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupCR, GroupUR> {
 
         int count = searchDAO.count(
                 RealmUtils.getEffective(SyncopeConstants.FULL_ADMIN_REALMS, realm),
-            Optional.ofNullable(searchCond).orElseGet(() -> groupDAO.getAllMatchingCond()), AnyTypeKind.GROUP);
+                Optional.ofNullable(searchCond).orElseGet(() -> groupDAO.getAllMatchingCond()), AnyTypeKind.GROUP);
 
         List<Group> matching = searchDAO.search(
                 RealmUtils.getEffective(SyncopeConstants.FULL_ADMIN_REALMS, realm),
-            Optional.ofNullable(searchCond).orElseGet(() -> groupDAO.getAllMatchingCond()),
+                Optional.ofNullable(searchCond).orElseGet(() -> groupDAO.getAllMatchingCond()),
                 page, size, orderBy, AnyTypeKind.GROUP);
         List<GroupTO> result = matching.stream().
                 map(group -> binder.getGroupTO(group, details)).collect(Collectors.toList());
@@ -410,12 +410,11 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupCR, GroupUR> {
         task = taskDAO.save(task);
 
         try {
-            String executor = AuthContextUtils.getUsername();
             Map<String, Object> jobDataMap = jobManager.register(
                     task,
                     null,
                     confParamOps.get(AuthContextUtils.getDomain(), "tasks.interruptMaxRetries", 1L, Long.class),
-                    executor);
+                    AuthContextUtils.getUsername());
 
             jobDataMap.put(TaskJob.DRY_RUN_JOBDETAIL_KEY, false);
             jobDataMap.put(GroupMemberProvisionTaskJobDelegate.GROUP_KEY_JOBDETAIL_KEY, key);
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
index b3d5585..580ac15 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
@@ -117,11 +117,11 @@ public class RealmLogic extends AbstractTransactionalLogic<RealmTO> {
         }
 
         Realm realm = realmDAO.save(binder.create(parent, realmTO));
-        String executor = AuthContextUtils.getUsername();
         PropagationByResource<String> propByRes = new PropagationByResource<>();
         propByRes.addAll(ResourceOperation.CREATE, realm.getResourceKeys());
         List<PropagationTaskInfo> taskInfos = propagationManager.createTasks(realm, propByRes, null);
-        PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, false, executor);
+        PropagationReporter propagationReporter =
+                taskExecutor.execute(taskInfos, false, AuthContextUtils.getUsername());
 
         ProvisioningResult<RealmTO> result = new ProvisioningResult<>();
         result.setEntity(binder.getRealmTO(realm, true));
@@ -138,12 +138,12 @@ public class RealmLogic extends AbstractTransactionalLogic<RealmTO> {
 
             throw new NotFoundException(realmTO.getFullPath());
         }
-        String executor = AuthContextUtils.getUsername();
         PropagationByResource<String> propByRes = binder.update(realm, realmTO);
         realm = realmDAO.save(realm);
 
         List<PropagationTaskInfo> taskInfos = propagationManager.createTasks(realm, propByRes, null);
-        PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, false, executor);
+        PropagationReporter propagationReporter =
+                taskExecutor.execute(taskInfos, false, AuthContextUtils.getUsername());
 
         ProvisioningResult<RealmTO> result = new ProvisioningResult<>();
         result.setEntity(binder.getRealmTO(realm, true));
@@ -180,11 +180,11 @@ public class RealmLogic extends AbstractTransactionalLogic<RealmTO> {
             containedAnys.getElements().add(anyObjects + " anyObject(s)");
             throw containedAnys;
         }
-        String executor = AuthContextUtils.getUsername();
         PropagationByResource<String> propByRes = new PropagationByResource<>();
         propByRes.addAll(ResourceOperation.DELETE, realm.getResourceKeys());
         List<PropagationTaskInfo> taskInfos = propagationManager.createTasks(realm, propByRes, null);
-        PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, false, executor);
+        PropagationReporter propagationReporter =
+                taskExecutor.execute(taskInfos, false, AuthContextUtils.getUsername());
 
         ProvisioningResult<RealmTO> result = new ProvisioningResult<>();
         result.setEntity(binder.getRealmTO(realm, true));
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java
index e471af2..bf5b987 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java
@@ -75,7 +75,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.Assert;
 
 @Component
 public class ReportLogic extends AbstractExecutableLogic<ReportTO> {
@@ -100,14 +99,12 @@ public class ReportLogic extends AbstractExecutableLogic<ReportTO> {
         Report report = entityFactory.newEntity(Report.class);
         binder.getReport(report, reportTO);
         report = reportDAO.save(report);
-        String executor = AuthContextUtils.getUsername();
-        Assert.notNull(executor, "executor cannot be null when creating report");
         try {
             jobManager.register(
                     report,
                     null,
                     confParamOps.get(AuthContextUtils.getDomain(), "tasks.interruptMaxRetries", 1L, Long.class),
-                    executor);
+                    AuthContextUtils.getUsername());
         } catch (Exception e) {
             LOG.error("While registering quartz job for report " + report.getKey(), e);
 
@@ -128,13 +125,12 @@ public class ReportLogic extends AbstractExecutableLogic<ReportTO> {
 
         binder.getReport(report, reportTO);
         report = reportDAO.save(report);
-        String executor = AuthContextUtils.getUsername();
         try {
             jobManager.register(
                     report,
                     null,
                     confParamOps.get(AuthContextUtils.getDomain(), "tasks.interruptMaxRetries", 1L, Long.class),
-                    executor);
+                    AuthContextUtils.getUsername());
         } catch (Exception e) {
             LOG.error("While registering quartz job for report " + report.getKey(), e);
 
@@ -175,14 +171,13 @@ public class ReportLogic extends AbstractExecutableLogic<ReportTO> {
             sce.getElements().add("Report " + key + " is not active");
             throw sce;
         }
-        String executor = AuthContextUtils.getUsername();
-        Assert.notNull(executor, "executor cannot be null when executing report");
+
         try {
             jobManager.register(
                     report,
                     startAt,
                     confParamOps.get(AuthContextUtils.getDomain(), "tasks.interruptMaxRetries", 1L, Long.class),
-                    executor);
+                    AuthContextUtils.getUsername());
 
             scheduler.getScheduler().triggerJob(JobNamer.getJobKey(report));
         } catch (Exception e) {
@@ -200,7 +195,7 @@ public class ReportLogic extends AbstractExecutableLogic<ReportTO> {
         result.setStart(new Date());
         result.setStatus(ReportExecStatus.STARTED.name());
         result.setMessage("Job fired; waiting for results...");
-        result.setExecutor(executor);
+        result.setExecutor(AuthContextUtils.getUsername());
         return result;
     }
 
@@ -222,7 +217,7 @@ public class ReportLogic extends AbstractExecutableLogic<ReportTO> {
 
     @PreAuthorize("hasRole('" + IdRepoEntitlement.REPORT_READ + "')")
     public static void exportExecutionResult(final OutputStream os, final ReportExec reportExec,
-                                             final ReportExecExportFormat format) {
+            final ReportExecExportFormat format) {
 
         // streaming SAX handler from a compressed byte array stream
         try (ByteArrayInputStream bais = new ByteArrayInputStream(reportExec.getExecResult());
@@ -379,7 +374,7 @@ public class ReportLogic extends AbstractExecutableLogic<ReportTO> {
 
         Report report = reportDAO.find(key);
         return Optional.ofNullable(report)
-            .map(report1 -> Triple.of(JobType.REPORT, key, binder.buildRefDesc(report1))).orElse(null);
+                .map(report1 -> Triple.of(JobType.REPORT, key, binder.buildRefDesc(report1))).orElse(null);
     }
 
     @PreAuthorize("hasRole('" + IdRepoEntitlement.REPORT_LIST + "')")
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
index 96fba5d..7dec93d 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
@@ -110,7 +110,6 @@ public class TaskLogic extends AbstractExecutableLogic<TaskTO> {
             sce.getElements().add("Found " + type + ", expected " + taskUtils.getType());
             throw sce;
         }
-        String executor = AuthContextUtils.getUsername();
         SchedTask task = binder.createSchedTask(taskTO, taskUtils);
         task = taskDAO.save(task);
 
@@ -119,7 +118,7 @@ public class TaskLogic extends AbstractExecutableLogic<TaskTO> {
                     task,
                     task.getStartAt(),
                     confParamOps.get(AuthContextUtils.getDomain(), "tasks.interruptMaxRetries", 1L, Long.class),
-                    executor);
+                    AuthContextUtils.getUsername());
         } catch (Exception e) {
             LOG.error("While registering quartz job for task " + task.getKey(), e);
 
@@ -147,13 +146,12 @@ public class TaskLogic extends AbstractExecutableLogic<TaskTO> {
 
         binder.updateSchedTask(task, taskTO, taskUtils);
         task = taskDAO.save(task);
-        String executor = AuthContextUtils.getUsername();
         try {
             jobManager.register(
                     task,
                     task.getStartAt(),
                     confParamOps.get(AuthContextUtils.getDomain(), "tasks.interruptMaxRetries", 1L, Long.class),
-                    executor);
+                    AuthContextUtils.getUsername());
         } catch (Exception e) {
             LOG.error("While registering quartz job for task " + task.getKey(), e);
 
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPullResultHandler.java
index a344a3f..20ec326 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPullResultHandler.java
@@ -253,7 +253,6 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
                 propByLinkedAccount.add(
                         ResourceOperation.DELETE,
                         Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue()));
-                String executor = AuthContextUtils.getUsername();
                 taskExecutor.execute(propagationManager.getDeleteTasks(
                         AnyTypeKind.USER,
                         account.getOwner().getKey(),
@@ -261,7 +260,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
                         propByLinkedAccount,
                         null),
                         false,
-                        executor);
+                        AuthContextUtils.getUsername());
 
                 for (PullActions action : profile.getActions()) {
                     action.after(profile, delta, before, report);
diff --git a/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserRequestLogic.java b/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserRequestLogic.java
index 2df4c59..a0b4a3a 100644
--- a/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserRequestLogic.java
+++ b/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserRequestLogic.java
@@ -184,7 +184,6 @@ public class UserRequestLogic extends AbstractTransactionalLogic<EntityTO> {
         }
 
         UserWorkflowResult<UserUR> wfResult = userRequestHandler.submitForm(form);
-        String executor = AuthContextUtils.getUsername();
         // propByRes can be made empty by the workflow definition if no propagation should occur 
         // (for example, with rejected users)
         if (wfResult.getPropByRes() != null && !wfResult.getPropByRes().isEmpty()) {
@@ -195,7 +194,7 @@ public class UserRequestLogic extends AbstractTransactionalLogic<EntityTO> {
                             wfResult.getPropByLinkedAccount(),
                             wfResult.getPerformedTasks()));
 
-            taskExecutor.execute(taskInfos, false, executor);
+            taskExecutor.execute(taskInfos, false, AuthContextUtils.getUsername());
         }
 
         UserTO userTO;
diff --git a/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowTaskLogic.java b/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowTaskLogic.java
index 0de8c70..343d21d 100644
--- a/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowTaskLogic.java
+++ b/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowTaskLogic.java
@@ -80,8 +80,7 @@ public class UserWorkflowTaskLogic extends AbstractTransactionalLogic<EntityTO>
                         updated.getPropByRes(),
                         updated.getPropByLinkedAccount(),
                         updated.getPerformedTasks()));
-        String executor = AuthContextUtils.getUsername();
-        taskExecutor.execute(taskInfos, false, executor);
+        taskExecutor.execute(taskInfos, false, AuthContextUtils.getUsername());
 
         return binder.getUserTO(updated.getResult());
     }
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReportITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReportITCase.java
index d458347..f0cc43d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReportITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReportITCase.java
@@ -54,25 +54,12 @@ import org.apache.syncope.common.rest.api.batch.BatchResponseItem;
 import org.apache.syncope.common.rest.api.beans.ExecDeleteQuery;
 import org.apache.syncope.common.rest.api.beans.ExecuteQuery;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
-import org.apache.syncope.core.spring.security.SyncopeAuthenticationDetails;
 import org.apache.syncope.fit.AbstractITCase;
 import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.User;
 
 public class ReportITCase extends AbstractITCase {
 
-    @BeforeAll
-    public static void setup() {
-        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
-            new User("admin", "FAKE_PASSWORD", List.of()), "FAKE_PASSWORD", List.of());
-        auth.setDetails(new SyncopeAuthenticationDetails("Master"));
-        SecurityContextHolder.getContext().setAuthentication(auth);
-    }
-    
     protected static String execReport(final String reportKey) {
         ReportTO reportTO = reportService.read(reportKey);
         assertNotNull(reportTO);
@@ -83,7 +70,7 @@ public class ReportITCase extends AbstractITCase {
         ExecTO exec = reportService.execute(query);
         assertNotNull(exec);
         assertNotNull(exec.getExecutor());
-        
+
         int i = 0;
         int maxit = 50;
 
@@ -98,7 +85,7 @@ public class ReportITCase extends AbstractITCase {
 
             assertNotNull(reportTO);
             assertNotNull(reportTO.getExecutions());
-            
+
             i++;
         } while (preExecSize == reportTO.getExecutions().size() && i < maxit);
         if (i == maxit) {
@@ -370,7 +357,7 @@ public class ReportITCase extends AbstractITCase {
         reportTO.setTemplate("sample");
         reportTO = createReport(reportTO);
         assertNotNull(reportTO);
-        
+
         ExecTO execution = reportService.execute(new ExecuteQuery.Builder().key(reportTO.getKey()).build());
         assertNotNull(execution);
 
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReportTemplateITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReportTemplateITCase.java
index 535b84f..773c2d6 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReportTemplateITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReportTemplateITCase.java
@@ -36,23 +36,11 @@ import org.apache.syncope.common.lib.to.ReportTemplateTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.ReportExecExportFormat;
 import org.apache.syncope.common.lib.types.ReportTemplateFormat;
-import org.apache.syncope.core.spring.security.SyncopeAuthenticationDetails;
 import org.apache.syncope.fit.AbstractITCase;
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.User;
 
 public class ReportTemplateITCase extends AbstractITCase {
-    @BeforeAll
-    public static void setup() {
-        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
-            new User("admin", "FAKE_PASSWORD", List.of()), "FAKE_PASSWORD", List.of());
-        auth.setDetails(new SyncopeAuthenticationDetails("Master"));
-        SecurityContextHolder.getContext().setAuthentication(auth);
-    }
-    
+
     @Test
     public void read() {
         ReportTemplateTO reportTemplateTO = reportTemplateService.read("sample");
@@ -64,9 +52,7 @@ public class ReportTemplateITCase extends AbstractITCase {
         List<ReportTemplateTO> reportTemplateTOs = reportTemplateService.list();
         assertNotNull(reportTemplateTOs);
         assertFalse(reportTemplateTOs.isEmpty());
-        for (ReportTemplateTO instance : reportTemplateTOs) {
-            assertNotNull(instance);
-        }
+        reportTemplateTOs.forEach(instance -> assertNotNull(instance));
     }
 
     @Test