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/11/28 09:31:52 UTC

[syncope] branch master updated: SYNCOPE-1511: Enhance audit queries with additional params

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 33e3629  SYNCOPE-1511: Enhance audit queries with additional params
33e3629 is described below

commit 33e36297fe1ad7447a868d6f457fdca5231e6b4a
Author: Misagh Moayyed <mm...@gmail.com>
AuthorDate: Thu Nov 28 12:48:28 2019 +0400

    SYNCOPE-1511: Enhance audit queries with additional params
---
 .../syncope/common/rest/api/beans/AuditQuery.java  | 51 ++++++++++++++++++++++
 .../org/apache/syncope/core/logic/AuditLogic.java  | 11 +++--
 .../core/rest/cxf/service/AuditServiceImpl.java    |  6 ++-
 .../syncope/core/persistence/api/dao/AuditDAO.java |  6 ++-
 .../core/persistence/jpa/dao/JPAAuditDAO.java      | 44 ++++++++++++++++++-
 .../core/provisioning/api/AuditEntryImpl.java      | 16 +++----
 .../provisioning/api/data/AuditDataBinder.java     |  3 +-
 .../provisioning/java/DefaultAuditManager.java     | 30 ++++++-------
 .../java/data/AuditDataBinderImpl.java             | 16 +++----
 .../java/job/report/AuditReportlet.java            | 11 ++---
 .../org/apache/syncope/fit/core/AuditITCase.java   | 37 +++++++++++++---
 11 files changed, 173 insertions(+), 58 deletions(-)

diff --git a/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java b/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java
index d8152de..d5dcd1a 100644
--- a/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java
+++ b/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java
@@ -18,14 +18,23 @@
  */
 package org.apache.syncope.common.rest.api.beans;
 
+import org.apache.syncope.common.lib.types.AuditElements;
+
 import javax.ws.rs.QueryParam;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class AuditQuery extends AbstractQuery {
 
     private static final long serialVersionUID = -2863334226169614417L;
 
     private String key;
 
+    private final List<AuditElements.Result> results = new ArrayList<>();
+
+    private final List<String> events = new ArrayList<>();
+
     public String getKey() {
         return key;
     }
@@ -35,6 +44,28 @@ public class AuditQuery extends AbstractQuery {
         this.key = key;
     }
 
+    public List<AuditElements.Result> getResults() {
+        return results;
+    }
+
+    @QueryParam("results")
+    public void setResults(final List<AuditElements.Result> results) {
+        if (results != null) {
+            this.results.addAll(results);
+        }
+    }
+
+    public List<String> getEvents() {
+        return events;
+    }
+
+    @QueryParam("events")
+    public void setEvents(final List<String> events) {
+        if (events != null) {
+            this.events.addAll(events);
+        }
+    }
+
     public static class Builder extends AbstractQuery.Builder<AuditQuery, Builder> {
 
         public Builder key(final String keyword) {
@@ -42,6 +73,26 @@ public class AuditQuery extends AbstractQuery {
             return this;
         }
 
+        public Builder results(final List<AuditElements.Result> results) {
+            getInstance().setResults(results);
+            return this;
+        }
+
+        public Builder result(final AuditElements.Result result) {
+            getInstance().getResults().add(result);
+            return this;
+        }
+
+        public Builder events(final List<String> events) {
+            getInstance().setEvents(events);
+            return this;
+        }
+
+        public Builder event(final String event) {
+            getInstance().getEvents().add(event);
+            return this;
+        }
+
         @Override
         protected AuditQuery newInstance() {
             return new AuditQuery();
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java
index 6fd482d..f730de2 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java
@@ -24,6 +24,7 @@ import java.util.stream.Collectors;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.to.AuditEntryTO;
 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
+import org.apache.syncope.common.lib.types.AuditElements;
 import org.apache.syncope.core.persistence.api.dao.AuditDAO;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.AuditEntry;
@@ -48,14 +49,16 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditEntryTO> {
             final String key,
             final int page,
             final int size,
+            final List<AuditElements.Result> results,
+            final List<String> events,
             final List<OrderByClause> orderByClauses) {
 
         Integer count = auditDAO.count(key);
-        List<AuditEntry> matching = auditDAO.findByEntityKey(key, page, size, orderByClauses);
-        List<AuditEntryTO> results = matching.stream().
-                map(audit -> binder.returnAuditTO(binder.getAuditTO(audit))).
+        List<AuditEntry> matching = auditDAO.findByEntityKey(key, page, size, results, events, orderByClauses);
+        List<AuditEntryTO> searchResults = matching.stream().
+                map(binder::getAuditTO).
                 collect(Collectors.toList());
-        return Pair.of(count, results);
+        return Pair.of(count, searchResults);
     }
 
     @Override
diff --git a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java
index df1c978..67126f7 100644
--- a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java
+++ b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.core.rest.cxf.service;
 
-import java.util.List;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.to.AuditEntryTO;
 import org.apache.syncope.common.lib.to.PagedResult;
@@ -28,6 +27,8 @@ import org.apache.syncope.core.logic.AuditLogic;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+
 @Service
 public class AuditServiceImpl extends AbstractServiceImpl implements AuditService {
 
@@ -40,8 +41,9 @@ public class AuditServiceImpl extends AbstractServiceImpl implements AuditServic
                 auditQuery.getKey(),
                 auditQuery.getPage(),
                 auditQuery.getSize(),
+                auditQuery.getResults(),
+                auditQuery.getEvents(),
                 getOrderByClauses(auditQuery.getOrderBy()));
-
         return buildPagedResult(result.getRight(), auditQuery.getPage(), auditQuery.getSize(), result.getLeft());
     }
 }
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditDAO.java
index 0d1692d..3f1994c 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditDAO.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.persistence.api.dao;
 
 import java.util.List;
 
+import org.apache.syncope.common.lib.types.AuditElements;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.AuditEntry;
 
@@ -27,7 +28,10 @@ public interface AuditDAO {
 
     String TABLE_NAME = "SYNCOPEAUDIT";
 
-    List<AuditEntry> findByEntityKey(String key, int page, int size, List<OrderByClause> orderByClauses);
+    List<AuditEntry> findByEntityKey(String key, int page, int size,
+                                     List<AuditElements.Result> results,
+                                     List<String> events,
+                                     List<OrderByClause> orderByClauses);
 
     Integer count(String key);
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditDAO.java
index 5f56392..1fd173c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditDAO.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 import org.apache.syncope.core.persistence.api.DomainHolder;
+import org.apache.syncope.common.lib.types.AuditElements;
 import org.apache.syncope.core.persistence.api.dao.AuditDAO;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.AuditEntry;
@@ -54,10 +55,17 @@ public class JPAAuditDAO extends AbstractDAO<AbstractEntity> implements AuditDAO
             final String key,
             final int page,
             final int itemsPerPage,
+            final List<AuditElements.Result> results,
+            final List<String> events,
             final List<OrderByClause> orderByClauses) {
 
         try {
-            String queryString = "SELECT * FROM " + AuditDAO.TABLE_NAME + buildWhereClauseForEntityKey(key);
+            String query = new MessageCriteriaBuilder().
+                    results(results).
+                    events(events).
+                    key(key).
+                    build();
+            String queryString = "SELECT * FROM " + TABLE_NAME + " WHERE " + query;
             if (!orderByClauses.isEmpty()) {
                 queryString += " ORDER BY " + orderByClauses.stream().
                         map(orderBy -> orderBy.getField() + ' ' + orderBy.getDirection().name()).
@@ -100,4 +108,38 @@ public class JPAAuditDAO extends AbstractDAO<AbstractEntity> implements AuditDAO
         }
         return new JdbcTemplate(datasource);
     }
+
+    private static class MessageCriteriaBuilder {
+
+        private final StringBuilder query = new StringBuilder(" 1=1 ");
+
+        public MessageCriteriaBuilder key(final String key) {
+            query.append(" AND MESSAGE LIKE '%\"key\":\"").append(key).append("\"%' ");
+            return this;
+        }
+
+        public MessageCriteriaBuilder results(final List<AuditElements.Result> results) {
+            buildCriteriaFor(results.stream().map(Enum::name).collect(Collectors.toList()), "result");
+            return this;
+        }
+
+        private void buildCriteriaFor(final List<String> items, final String field) {
+            if (!items.isEmpty()) {
+                query.append(" AND ( ");
+                query.append(items.stream().map(res -> "MESSAGE LIKE '%\"" + field + "\":\"" + res + "\"%'").
+                        collect(Collectors.joining(" OR ")));
+                query.append(" )");
+            }
+        }
+
+        public MessageCriteriaBuilder events(final List<String> events) {
+            buildCriteriaFor(events, "event");
+            return this;
+        }
+
+        public String build() {
+            query.trimToSize();
+            return query.toString();
+        }
+    }
 }
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AuditEntryImpl.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AuditEntryImpl.java
index e64a911..2d6d118 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AuditEntryImpl.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AuditEntryImpl.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.provisioning.api;
 
+import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import org.apache.commons.lang3.ArrayUtils;
@@ -28,8 +29,6 @@ import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AuditLoggerName;
 import org.apache.syncope.core.persistence.api.entity.AuditEntry;
 
-import java.util.Date;
-
 public class AuditEntryImpl implements AuditEntry {
 
     private static final long serialVersionUID = -2299082316063743582L;
@@ -51,14 +50,14 @@ public class AuditEntryImpl implements AuditEntry {
     private Date date;
 
     private String key;
-    
+
     @JsonCreator
     public AuditEntryImpl(
-        @JsonProperty("who") final String who,
-        @JsonProperty("logger") final AuditLoggerName logger,
-        @JsonProperty("before") final Object before,
-        @JsonProperty("output") final Object output,
-        @JsonProperty("input") final Object[] input) {
+            @JsonProperty("who") final String who,
+            @JsonProperty("logger") final AuditLoggerName logger,
+            @JsonProperty("before") final Object before,
+            @JsonProperty("output") final Object output,
+            @JsonProperty("input") final Object[] input) {
 
         super();
 
@@ -160,6 +159,7 @@ public class AuditEntryImpl implements AuditEntry {
     }
 
     public static final class Builder {
+
         private String who;
 
         private AuditLoggerName logger;
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AuditDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AuditDataBinder.java
index 81e3241..2f79388 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AuditDataBinder.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AuditDataBinder.java
@@ -22,7 +22,6 @@ import org.apache.syncope.common.lib.to.AuditEntryTO;
 import org.apache.syncope.core.persistence.api.entity.AuditEntry;
 
 public interface AuditDataBinder {
-    AuditEntryTO getAuditTO(AuditEntry application);
 
-    AuditEntryTO returnAuditTO(AuditEntryTO user);
+    AuditEntryTO getAuditTO(AuditEntry auditEntry);
 }
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java
index 0f9e169..d5b9df6 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java
@@ -49,10 +49,10 @@ public class DefaultAuditManager implements AuditManager {
             final String subcategory,
             final String event) {
 
-        AuditEntry auditEntry = AuditEntryImpl.builder()
-            .who(who)
-            .logger(new AuditLoggerName(type, category, subcategory, event, Result.SUCCESS))
-            .build();
+        AuditEntry auditEntry = AuditEntryImpl.builder().
+                who(who).
+                logger(new AuditLoggerName(type, category, subcategory, event, Result.SUCCESS)).
+                build();
         org.apache.syncope.core.persistence.api.entity.Logger syncopeLogger =
                 loggerDAO.find(auditEntry.getLogger().toLoggerName());
         boolean auditRequested = syncopeLogger != null && syncopeLogger.getLevel() == LoggerLevel.DEBUG;
@@ -62,9 +62,9 @@ public class DefaultAuditManager implements AuditManager {
         }
 
         auditEntry = AuditEntryImpl.builder()
-            .who(who)
-            .logger(new AuditLoggerName(type, category, subcategory, event, Result.FAILURE))
-            .build();
+                .who(who)
+                .logger(new AuditLoggerName(type, category, subcategory, event, Result.FAILURE))
+                .build();
         syncopeLogger = loggerDAO.find(auditEntry.getLogger().toLoggerName());
         auditRequested = syncopeLogger != null && syncopeLogger.getLevel() == LoggerLevel.DEBUG;
 
@@ -104,14 +104,14 @@ public class DefaultAuditManager implements AuditManager {
             throwable = (Throwable) output;
         }
 
-        AuditEntry auditEntry = AuditEntryImpl.builder()
-            .who(who)
-            .logger(new AuditLoggerName(type, category, subcategory, event, condition))
-            .before(before)
-            .output(throwable == null ? output : throwable.getMessage())
-            .input(input)
-            .build();
-        
+        AuditEntry auditEntry = AuditEntryImpl.builder().
+                who(who).
+                logger(new AuditLoggerName(type, category, subcategory, event, condition)).
+                before(before).
+                output(throwable == null ? output : throwable.getMessage()).
+                input(input).
+                build();
+
         org.apache.syncope.core.persistence.api.entity.Logger syncopeLogger =
                 loggerDAO.find(auditEntry.getLogger().toLoggerName());
         if (syncopeLogger != null && syncopeLogger.getLevel() == LoggerLevel.DEBUG) {
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java
index 6a34094..8d74e11 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java
@@ -19,12 +19,12 @@
 package org.apache.syncope.core.provisioning.java.data;
 
 import java.util.Arrays;
+import java.util.Objects;
 import java.util.stream.Collectors;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.syncope.common.lib.to.AuditEntryTO;
 import org.apache.syncope.core.persistence.api.entity.AuditEntry;
 import org.apache.syncope.core.provisioning.api.data.AuditDataBinder;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 import org.springframework.stereotype.Component;
 
 @Component
@@ -47,24 +47,20 @@ public class AuditDataBinderImpl implements AuditDataBinder {
         }
 
         if (auditEntry.getBefore() != null) {
-            auditTO.setBefore(ToStringBuilder.reflectionToString(auditEntry.getBefore(), ToStringStyle.JSON_STYLE));
+            auditTO.setBefore(POJOHelper.serialize(auditEntry.getBefore()));
         }
 
         if (auditEntry.getInput() != null) {
             auditTO.getInputs().addAll(Arrays.stream(auditEntry.getInput()).
-                    map(input -> ToStringBuilder.reflectionToString(input, ToStringStyle.JSON_STYLE)).
+                    filter(Objects::nonNull).
+                    map(POJOHelper::serialize).
                     collect(Collectors.toList()));
         }
 
         if (auditEntry.getOutput() != null) {
-            auditTO.setOutput(ToStringBuilder.reflectionToString(auditEntry.getOutput(), ToStringStyle.JSON_STYLE));
+            auditTO.setOutput(POJOHelper.serialize(auditEntry.getOutput()));
         }
 
         return auditTO;
     }
-
-    @Override
-    public AuditEntryTO returnAuditTO(final AuditEntryTO auditEntryTO) {
-        return auditEntryTO;
-    }
 }
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AuditReportlet.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AuditReportlet.java
index 894d3e1..4529a0a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AuditReportlet.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AuditReportlet.java
@@ -23,8 +23,6 @@ import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
 import javax.sql.DataSource;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.syncope.common.lib.report.AuditReportletConf;
 import org.apache.syncope.common.lib.report.ReportletConf;
 import org.apache.syncope.core.persistence.api.DomainHolder;
@@ -89,8 +87,7 @@ public class AuditReportlet extends AbstractReportlet {
             handler.endElement("", "", "logger");
 
             if (auditEntry.getBefore() != null) {
-                char[] before = ToStringBuilder.reflectionToString(
-                        auditEntry.getBefore(), ToStringStyle.JSON_STYLE).toCharArray();
+                char[] before = POJOHelper.serialize(auditEntry.getBefore()).toCharArray();
                 handler.startElement("", "", "before", null);
                 handler.characters(before, 0, before.length);
                 handler.endElement("", "", "before");
@@ -99,8 +96,7 @@ public class AuditReportlet extends AbstractReportlet {
             if (auditEntry.getInput() != null) {
                 handler.startElement("", "", "inputs", null);
                 for (Object inputObj : auditEntry.getInput()) {
-                    char[] input = ToStringBuilder.reflectionToString(
-                            inputObj, ToStringStyle.JSON_STYLE).toCharArray();
+                    char[] input = POJOHelper.serialize(inputObj).toCharArray();
                     handler.startElement("", "", "input", null);
                     handler.characters(input, 0, input.length);
                     handler.endElement("", "", "input");
@@ -109,8 +105,7 @@ public class AuditReportlet extends AbstractReportlet {
             }
 
             if (auditEntry.getOutput() != null) {
-                char[] output = ToStringBuilder.reflectionToString(
-                        auditEntry.getOutput(), ToStringStyle.JSON_STYLE).toCharArray();
+                char[] output = POJOHelper.serialize(auditEntry.getOutput()).toCharArray();
                 handler.startElement("", "", "output", null);
                 handler.characters(output, 0, output.length);
                 handler.endElement("", "", "output");
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java
index 2bedab7..d8fc20a 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java
@@ -25,15 +25,15 @@ import static org.junit.jupiter.api.Assertions.fail;
 import java.util.List;
 import org.apache.syncope.common.lib.to.AuditEntryTO;
 import org.apache.syncope.common.lib.to.GroupTO;
-import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AuditElements;
 import org.apache.syncope.common.rest.api.beans.AuditQuery;
 import org.apache.syncope.fit.AbstractITCase;
 import org.junit.jupiter.api.Test;
 
 public class AuditITCase extends AbstractITCase {
 
-    private AuditEntryTO query(final String key, final int maxWaitSeconds) {
+    private AuditEntryTO query(final AuditQuery query, final int maxWaitSeconds) {
         int i = 0;
         List<AuditEntryTO> results = List.of();
         do {
@@ -42,13 +42,12 @@ public class AuditITCase extends AbstractITCase {
             } catch (InterruptedException e) {
             }
 
-            results = auditService.search(new AuditQuery.Builder().
-                    key(key).orderBy("event_date desc").page(1).size(1).build()).getResult();
+            results = auditService.search(query).getResult();
 
             i++;
         } while (results.isEmpty() && i < maxWaitSeconds);
         if (results.isEmpty()) {
-            fail("Timeout when executing query for key " + key);
+            fail("Timeout when executing query for key " + query.getKey());
         }
 
         return results.get(0);
@@ -59,7 +58,28 @@ public class AuditITCase extends AbstractITCase {
         UserTO userTO = createUser(UserITCase.getUniqueSample("audit@syncope.org")).getEntity();
         assertNotNull(userTO.getKey());
 
-        AuditEntryTO entry = query(userTO.getKey(), 50);
+        AuditQuery query = new AuditQuery.Builder().
+                key(userTO.getKey()).orderBy("event_date desc").
+                page(1).size(1).build();
+        AuditEntryTO entry = query(query, 50);
+        assertEquals(userTO.getKey(), entry.getKey());
+        userService.delete(userTO.getKey());
+    }
+
+    @Test
+    public void findByUserAndByEventAndByResults() {
+        UserTO userTO = createUser(UserITCase.getUniqueSample("audit-2@syncope.org")).getEntity();
+        assertNotNull(userTO.getKey());
+
+        AuditQuery query = new AuditQuery.Builder().
+                key(userTO.getKey()).
+                orderBy("event_date desc").
+                page(1).
+                size(1).
+                event("create").
+                result(AuditElements.Result.SUCCESS).
+                build();
+        AuditEntryTO entry = query(query, 50);
         assertEquals(userTO.getKey(), entry.getKey());
         userService.delete(userTO.getKey());
     }
@@ -69,7 +89,10 @@ public class AuditITCase extends AbstractITCase {
         GroupTO groupTO = createGroup(GroupITCase.getBasicSample("AuditGroup")).getEntity();
         assertNotNull(groupTO.getKey());
 
-        AuditEntryTO entry = query(groupTO.getKey(), 50);
+        AuditQuery query = new AuditQuery.Builder().
+                key(groupTO.getKey()).orderBy("event_date desc").
+                page(1).size(1).build();
+        AuditEntryTO entry = query(query, 50);
         assertEquals(groupTO.getKey(), entry.getKey());
         groupService.delete(groupTO.getKey());
     }