You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by mm...@apache.org on 2019/11/28 08:48:36 UTC
[syncope] branch 2_1_X updated: SYNCOPE-1511: Enhance audit queries
with additional params (#140)
This is an automated email from the ASF dual-hosted git repository.
mmoayyed pushed a commit to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/2_1_X by this push:
new e4fb0ed SYNCOPE-1511: Enhance audit queries with additional params (#140)
e4fb0ed is described below
commit e4fb0ed33744207f90b7cc0126c58ca7984112df
Author: Misagh Moayyed <mm...@gmail.com>
AuthorDate: Thu Nov 28 12:48:28 2019 +0400
SYNCOPE-1511: Enhance audit queries with additional params (#140)
* improve audit query to allow for events and results as query params
* clean up new test
* clean up formatting
* clean up formatting
* apply suggestions after review
* add null filter
---
.../syncope/common/rest/api/beans/AuditQuery.java | 49 +++++++++++++++
.../org/apache/syncope/core/logic/AuditLogic.java | 9 ++-
.../syncope/core/persistence/api/dao/AuditDAO.java | 6 +-
.../core/persistence/jpa/dao/JPAAuditDAO.java | 72 +++++++++++++++++-----
.../java/data/AuditDataBinderImpl.java | 8 ++-
.../core/rest/cxf/service/AuditServiceImpl.java | 6 +-
.../org/apache/syncope/fit/core/AuditITCase.java | 44 ++++++++++---
7 files changed, 160 insertions(+), 34 deletions(-)
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java
index d8152de..cb05bb9 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java
@@ -18,13 +18,20 @@
*/
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 +42,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 +71,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 String result) {
+ getInstance().getResults().add(AuditElements.Result.valueOf(result.toUpperCase()));
+ 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/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java
index eec44cb..29d081c 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java
@@ -23,6 +23,7 @@ import java.util.List;
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.AuditElements;
import org.apache.syncope.common.lib.types.StandardEntitlement;
import org.apache.syncope.core.persistence.api.dao.AuditDAO;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
@@ -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().
+ List<AuditEntry> matching = auditDAO.findByEntityKey(key, page, size, results, events, orderByClauses);
+ List<AuditEntryTO> finalResults = matching.stream().
map(audit -> binder.returnAuditTO(binder.getAuditTO(audit))).
collect(Collectors.toList());
- return Pair.of(count, results);
+ return Pair.of(count, finalResults);
}
@Override
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 ccf52e9..f76e9e8 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
@@ -18,13 +18,7 @@
*/
package org.apache.syncope.core.persistence.jpa.dao;
-import javax.sql.DataSource;
-import java.sql.Timestamp;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
+import org.apache.syncope.common.lib.types.AuditElements;
import org.apache.syncope.core.persistence.api.DomainsHolder;
import org.apache.syncope.core.persistence.api.dao.AuditDAO;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
@@ -38,6 +32,15 @@ import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
+import javax.sql.DataSource;
+
+import java.sql.Timestamp;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
@Transactional(rollbackFor = Throwable.class)
@Repository
public class JPAAuditDAO extends AbstractDAO<AbstractEntity> implements AuditDAO {
@@ -51,17 +54,23 @@ public class JPAAuditDAO extends AbstractDAO<AbstractEntity> implements AuditDAO
@Override
public List<AuditEntry> findByEntityKey(
- final String key,
- final int page,
- final int itemsPerPage,
- final List<OrderByClause> orderByClauses) {
-
+ 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()).
- collect(Collectors.joining(","));
+ map(orderBy -> orderBy.getField() + ' ' + orderBy.getDirection().name()).
+ collect(Collectors.joining(","));
}
JdbcTemplate template = getJdbcTemplate();
template.setMaxRows(itemsPerPage);
@@ -100,4 +109,37 @@ 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-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..5acbe34 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,6 +19,7 @@
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;
@@ -51,9 +52,10 @@ public class AuditDataBinderImpl implements AuditDataBinder {
}
if (auditEntry.getInput() != null) {
- auditTO.getInputs().addAll(Arrays.stream(auditEntry.getInput()).
- map(input -> ToStringBuilder.reflectionToString(input, ToStringStyle.JSON_STYLE)).
- collect(Collectors.toList()));
+ auditTO.getInputs().addAll(Arrays.stream(auditEntry.getInput())
+ .filter(Objects::nonNull)
+ .map(input -> ToStringBuilder.reflectionToString(input, ToStringStyle.JSON_STYLE))
+ .collect(Collectors.toList()));
}
if (auditEntry.getOutput() != null) {
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java
index df1c978..67126f7 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java
+++ b/core/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/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 59cc115..1421773 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
@@ -18,22 +18,23 @@
*/
package org.apache.syncope.fit.core;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.fail;
-
import java.util.Collections;
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.ProvisioningResult;
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;
+import static org.junit.jupiter.api.Assertions.*;
+
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 = Collections.emptyList();
do {
@@ -42,13 +43,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 +59,28 @@ public class AuditITCase extends AbstractITCase {
UserTO userTO = createUser(UserITCase.getUniqueSampleTO("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.getUniqueSampleTO("audit-2@syncope.org")).getEntity();
+ assertNotNull(userTO.getKey());
+
+ AuditQuery query = new AuditQuery.Builder()
+ .key(userTO.getKey())
+ .orderBy("event_date desc")
+ .page(1)
+ .size(1)
+ .events(Collections.singletonList("create"))
+ .results(Collections.singletonList(AuditElements.Result.SUCCESS))
+ .build();
+ AuditEntryTO entry = query(query, 50);
assertEquals(userTO.getKey(), entry.getKey());
userService.delete(userTO.getKey());
}
@@ -69,7 +90,10 @@ public class AuditITCase extends AbstractITCase {
GroupTO groupTO = createGroup(GroupITCase.getBasicSampleTO("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());
}