Skip to content

Commit 4f5a8cb

Browse files
ozimakovilgrosso
authored andcommitted
[SYNCOPE-1981] Search audit events by who (#1438)
1 parent e250090 commit 4f5a8cb

9 files changed

Lines changed: 160 additions & 6 deletions

File tree

‎common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
package org.apache.syncope.common.rest.api.beans;
2020

2121
import io.swagger.v3.oas.annotations.Parameter;
22+
import io.swagger.v3.oas.annotations.media.ArraySchema;
2223
import io.swagger.v3.oas.annotations.media.Schema;
2324
import jakarta.ws.rs.QueryParam;
25+
import java.util.HashSet;
26+
import java.util.Set;
2427
import org.apache.syncope.common.lib.types.OpEvent;
2528
import org.apache.syncope.common.rest.api.service.JAXRSService;
2629

@@ -40,6 +43,11 @@ public Builder entityKey(final String entityKey) {
4043
return this;
4144
}
4245

46+
public Builder who(final String who) {
47+
getInstance().getWho().add(who);
48+
return this;
49+
}
50+
4351
public Builder type(final OpEvent.CategoryType type) {
4452
getInstance().setType(type);
4553
return this;
@@ -68,6 +76,8 @@ public Builder outcome(final OpEvent.Outcome outcome) {
6876

6977
private String entityKey;
7078

79+
private Set<String> who = new HashSet<>();
80+
7181
private OpEvent.CategoryType type;
7282

7383
private String category;
@@ -89,6 +99,18 @@ public void setEntityKey(final String entityKey) {
8999
this.entityKey = entityKey;
90100
}
91101

102+
@Parameter(name = "who", description = "audit event author(s) (username) to match; "
103+
+ "may be repeated to match any of the given values", array =
104+
@ArraySchema(schema = @Schema(implementation = String.class)))
105+
public Set<String> getWho() {
106+
return who;
107+
}
108+
109+
@QueryParam("who")
110+
public void setWho(final Set<String> who) {
111+
this.who = who;
112+
}
113+
92114
@Parameter(name = "type", description = "audit type to match", schema =
93115
@Schema(implementation = OpEvent.CategoryType.class))
94116
public OpEvent.CategoryType getType() {

‎core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ public List<OpEvent> events() {
275275
@Transactional(readOnly = true)
276276
public Page<AuditEventTO> search(
277277
final String entityKey,
278+
final Set<String> who,
278279
final OpEvent.CategoryType type,
279280
final String category,
280281
final String subcategory,
@@ -284,10 +285,10 @@ public Page<AuditEventTO> search(
284285
final OffsetDateTime after,
285286
final Pageable pageable) {
286287

287-
long count = auditEventDAO.count(entityKey, type, category, subcategory, op, result, before, after);
288+
long count = auditEventDAO.count(entityKey, who, type, category, subcategory, op, result, before, after);
288289

289290
List<AuditEventTO> matching = auditEventDAO.search(
290-
entityKey, type, category, subcategory, op, result, before, after, pageable);
291+
entityKey, who, type, category, subcategory, op, result, before, after, pageable);
291292

292293
return new SyncopePage<>(matching, pageable, count);
293294
}

‎core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public List<OpEvent> events() {
7070
public PagedResult<AuditEventTO> search(final AuditQuery auditQuery) {
7171
Page<AuditEventTO> result = logic.search(
7272
auditQuery.getEntityKey(),
73+
auditQuery.getWho(),
7374
auditQuery.getType(),
7475
auditQuery.getCategory(),
7576
auditQuery.getSubcategory(),

‎core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditEventDAO.java‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.time.OffsetDateTime;
2222
import java.util.List;
23+
import java.util.Set;
2324
import org.apache.syncope.common.lib.to.AuditEventTO;
2425
import org.apache.syncope.common.lib.types.OpEvent;
2526
import org.apache.syncope.core.persistence.api.entity.AuditEvent;
@@ -31,6 +32,7 @@ public interface AuditEventDAO {
3132

3233
long count(
3334
String entityKey,
35+
Set<String> who,
3436
OpEvent.CategoryType type,
3537
String category,
3638
String subcategory,
@@ -54,6 +56,7 @@ default AuditEventTO toAuditEventTO(final AuditEvent auditEvent) {
5456

5557
List<AuditEventTO> search(
5658
String entityKey,
59+
Set<String> who,
5760
OpEvent.CategoryType type,
5861
String category,
5962
String subcategory,

‎core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditEventDAO.java‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.ArrayList;
2525
import java.util.List;
2626
import java.util.Objects;
27+
import java.util.Set;
2728
import java.util.stream.Collectors;
2829
import org.apache.syncope.common.lib.to.AuditEventTO;
2930
import org.apache.syncope.common.lib.types.OpEvent;
@@ -34,6 +35,7 @@
3435
import org.springframework.data.domain.Pageable;
3536
import org.springframework.data.domain.Sort;
3637
import org.springframework.transaction.annotation.Transactional;
38+
import org.springframework.util.CollectionUtils;
3739

3840
public class JPAAuditEventDAO extends AbstractAuditEventDAO implements AuditEventDAO {
3941

@@ -61,6 +63,17 @@ protected AuditEventCriteriaBuilder entityKey(final String entityKey) {
6163
return this;
6264
}
6365

66+
public AuditEventCriteriaBuilder who(final Set<String> who, final List<Object> parameters) {
67+
if (!CollectionUtils.isEmpty(who)) {
68+
query.append(andIfNeeded()).append("who IN (").
69+
append(who.stream().
70+
map(value -> "?" + setParameter(parameters, value)).
71+
collect(Collectors.joining(", "))).
72+
append(")");
73+
}
74+
return this;
75+
}
76+
6477
public AuditEventCriteriaBuilder opEvent(
6578
final OpEvent.CategoryType type,
6679
final String category,
@@ -127,6 +140,7 @@ protected void fillWithParameters(final Query query, final List<Object> paramete
127140
@Override
128141
public long count(
129142
final String entityKey,
143+
final Set<String> who,
130144
final OpEvent.CategoryType type,
131145
final String category,
132146
final String subcategory,
@@ -139,6 +153,7 @@ public long count(
139153
String queryString = "SELECT COUNT(0)"
140154
+ " FROM " + JPAAuditEvent.TABLE
141155
+ " WHERE" + criteriaBuilder(entityKey).
156+
who(who, parameters).
142157
opEvent(type, category, subcategory, op, outcome).
143158
before(before, parameters).
144159
after(after, parameters).
@@ -153,6 +168,7 @@ public long count(
153168
@Override
154169
public List<AuditEventTO> search(
155170
final String entityKey,
171+
final Set<String> who,
156172
final OpEvent.CategoryType type,
157173
final String category,
158174
final String subcategory,
@@ -166,6 +182,7 @@ public List<AuditEventTO> search(
166182
String queryString = "SELECT id"
167183
+ " FROM " + JPAAuditEvent.TABLE
168184
+ " WHERE" + criteriaBuilder(entityKey).
185+
who(who, parameters).
169186
opEvent(type, category, subcategory, op, outcome).
170187
before(before, parameters).
171188
after(after, parameters).

‎core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAuditEventDAO.java‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.List;
2424
import java.util.Map;
2525
import java.util.Optional;
26+
import java.util.Set;
2627
import java.util.stream.Collectors;
2728
import org.apache.syncope.common.lib.to.AuditEventTO;
2829
import org.apache.syncope.common.lib.types.OpEvent;
@@ -36,6 +37,7 @@
3637
import org.springframework.data.neo4j.core.Neo4jClient;
3738
import org.springframework.data.neo4j.core.Neo4jTemplate;
3839
import org.springframework.transaction.annotation.Transactional;
40+
import org.springframework.util.CollectionUtils;
3941

4042
public class Neo4jAuditEventDAO extends AbstractAuditEventDAO implements AuditEventDAO {
4143

@@ -58,6 +60,14 @@ protected AuditEventCriteriaBuilder entityKey(final String entityKey) {
5860
return this;
5961
}
6062

63+
public AuditEventCriteriaBuilder who(final Set<String> who, final Map<String, Object> parameters) {
64+
if (!CollectionUtils.isEmpty(who)) {
65+
parameters.put("who", List.copyOf(who));
66+
query.append(andIfNeeded()).append("n.who IN $who");
67+
}
68+
return this;
69+
}
70+
6171
public AuditEventCriteriaBuilder opEvent(
6272
final OpEvent.CategoryType type,
6373
final String category,
@@ -125,6 +135,7 @@ protected AuditEventCriteriaBuilder criteriaBuilder(final String entityKey) {
125135
@Override
126136
public long count(
127137
final String entityKey,
138+
final Set<String> who,
128139
final OpEvent.CategoryType type,
129140
final String category,
130141
final String subcategory,
@@ -136,6 +147,7 @@ public long count(
136147
Map<String, Object> parameters = new HashMap<>();
137148
String query = "MATCH (n:" + Neo4jAuditEvent.NODE + ") "
138149
+ " WHERE " + criteriaBuilder(entityKey).
150+
who(who, parameters).
139151
opEvent(type, category, subcategory, op, outcome).
140152
before(before, parameters).
141153
after(after, parameters).
@@ -148,6 +160,7 @@ public long count(
148160
@Override
149161
public List<AuditEventTO> search(
150162
final String entityKey,
163+
final Set<String> who,
151164
final OpEvent.CategoryType type,
152165
final String category,
153166
final String subcategory,
@@ -161,6 +174,7 @@ public List<AuditEventTO> search(
161174

162175
StringBuilder query = new StringBuilder("MATCH (n:" + Neo4jAuditEvent.NODE + ") "
163176
+ "WHERE " + criteriaBuilder(entityKey).
177+
who(who, parameters).
164178
opEvent(type, category, subcategory, op, outcome).
165179
before(before, parameters).
166180
after(after, parameters).

‎ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchAuditEventDAO.java‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.util.ArrayList;
3838
import java.util.List;
3939
import java.util.Objects;
40+
import java.util.Set;
4041
import java.util.stream.Stream;
4142
import org.apache.syncope.common.lib.to.AuditEventTO;
4243
import org.apache.syncope.common.lib.types.OpEvent;
@@ -84,6 +85,7 @@ public AuditEvent save(final AuditEvent auditEvent) {
8485

8586
protected Query getQuery(
8687
final String entityKey,
88+
final Set<String> who,
8789
final OpEvent.CategoryType type,
8890
final String category,
8991
final String subcategory,
@@ -102,6 +104,14 @@ protected Query getQuery(
102104
query("\"key\":\"" + entityKey + "\"").build()).build());
103105
}
104106

107+
if (!CollectionUtils.isEmpty(who)) {
108+
List<Query> whoQueries = who.stream().map(value -> new Query.Builder().
109+
term(QueryBuilders.term().field("who").value(value).build()).build()).
110+
toList();
111+
queries.add(new Query.Builder().
112+
bool(QueryBuilders.bool().should(whoQueries).minimumShouldMatch("1").build()).build());
113+
}
114+
105115
queries.add(new Query.Builder().regexp(QueryBuilders.regexp().
106116
field("opEvent").
107117
value(OpEvent.toString(type, category, subcategory, op, outcome).
@@ -130,6 +140,7 @@ protected Query getQuery(
130140
@Override
131141
public long count(
132142
final String entityKey,
143+
final Set<String> who,
133144
final OpEvent.CategoryType type,
134145
final String category,
135146
final String subcategory,
@@ -140,7 +151,7 @@ public long count(
140151

141152
CountRequest request = new CountRequest.Builder().
142153
index(ElasticsearchUtils.getAuditIndex(AuthContextUtils.getDomain())).
143-
query(getQuery(entityKey, type, category, subcategory, op, outcome, before, after)).
154+
query(getQuery(entityKey, who, type, category, subcategory, op, outcome, before, after)).
144155
build();
145156
LOG.debug("Count request: {}", request);
146157

@@ -164,6 +175,7 @@ protected List<SortOptions> sortBuilders(final Stream<Sort.Order> orderBy) {
164175
@Override
165176
public List<AuditEventTO> search(
166177
final String entityKey,
178+
final Set<String> who,
167179
final OpEvent.CategoryType type,
168180
final String category,
169181
final String subcategory,
@@ -176,7 +188,7 @@ public List<AuditEventTO> search(
176188
SearchRequest request = new SearchRequest.Builder().
177189
index(ElasticsearchUtils.getAuditIndex(AuthContextUtils.getDomain())).
178190
searchType(SearchType.QueryThenFetch).
179-
query(getQuery(entityKey, type, category, subcategory, op, outcome, before, after)).
191+
query(getQuery(entityKey, who, type, category, subcategory, op, outcome, before, after)).
180192
from(pageable.isUnpaged() ? 0 : pageable.getPageSize() * pageable.getPageNumber()).
181193
size(pageable.isUnpaged() ? indexMaxResultWindow : pageable.getPageSize()).
182194
sort(sortBuilders(pageable.getSort().get())).

‎ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchAuditEventDAO.java‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.ArrayList;
2525
import java.util.List;
2626
import java.util.Objects;
27+
import java.util.Set;
2728
import java.util.stream.Stream;
2829
import org.apache.syncope.common.lib.to.AuditEventTO;
2930
import org.apache.syncope.common.lib.types.OpEvent;
@@ -83,6 +84,7 @@ public AuditEvent save(final AuditEvent auditEvent) {
8384

8485
protected Query getQuery(
8586
final String entityKey,
87+
final Set<String> who,
8688
final OpEvent.CategoryType type,
8789
final String category,
8890
final String subcategory,
@@ -101,6 +103,14 @@ protected Query getQuery(
101103
query("\"key\":\"" + entityKey + "\"").build()).build());
102104
}
103105

106+
if (!CollectionUtils.isEmpty(who)) {
107+
List<Query> whoQueries = who.stream().map(value -> new Query.Builder().
108+
term(QueryBuilders.term().field("who").value(v -> v.stringValue(value)).build()).build()).
109+
toList();
110+
queries.add(new Query.Builder().
111+
bool(QueryBuilders.bool().should(whoQueries).minimumShouldMatch("1").build()).build());
112+
}
113+
104114
queries.add(new Query.Builder().regexp(QueryBuilders.regexp().
105115
field("opEvent").
106116
value(OpEvent.toString(type, category, subcategory, op, outcome).
@@ -129,6 +139,7 @@ protected Query getQuery(
129139
@Override
130140
public long count(
131141
final String entityKey,
142+
final Set<String> who,
132143
final OpEvent.CategoryType type,
133144
final String category,
134145
final String subcategory,
@@ -139,7 +150,7 @@ public long count(
139150

140151
CountRequest request = new CountRequest.Builder().
141152
index(OpenSearchUtils.getAuditIndex(AuthContextUtils.getDomain())).
142-
query(getQuery(entityKey, type, category, subcategory, op, outcome, before, after)).
153+
query(getQuery(entityKey, who, type, category, subcategory, op, outcome, before, after)).
143154
build();
144155
LOG.debug("Count request: {}", request);
145156

@@ -163,6 +174,7 @@ protected List<SortOptions> sortBuilders(final Stream<Sort.Order> orderBy) {
163174
@Override
164175
public List<AuditEventTO> search(
165176
final String entityKey,
177+
final Set<String> who,
166178
final OpEvent.CategoryType type,
167179
final String category,
168180
final String subcategory,
@@ -175,7 +187,7 @@ public List<AuditEventTO> search(
175187
SearchRequest request = new SearchRequest.Builder().
176188
index(OpenSearchUtils.getAuditIndex(AuthContextUtils.getDomain())).
177189
searchType(SearchType.QueryThenFetch).
178-
query(getQuery(entityKey, type, category, subcategory, op, outcome, before, after)).
190+
query(getQuery(entityKey, who, type, category, subcategory, op, outcome, before, after)).
179191
from(pageable.isUnpaged() ? 0 : pageable.getPageSize() * pageable.getPageNumber()).
180192
size(pageable.isUnpaged() ? indexMaxResultWindow : pageable.getPageSize()).
181193
sort(sortBuilders(pageable.getSort().get())).

0 commit comments

Comments
 (0)