From c4fe39257d0a1f4d6e3c31ca7ecdd878cb6fbc0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francesco=20Chicchiricc=C3=B2?= Date: Wed, 24 Jun 2026 11:25:28 +0200 Subject: [PATCH] Restricting orderby clauses for Audit Events search --- .../common/dao/AbstractAuditEventDAO.java | 37 +++++++++++++++++++ .../persistence/jpa/dao/JPAAuditEventDAO.java | 10 +++-- .../neo4j/dao/Neo4jAuditEventDAO.java | 13 +++---- .../persistence/neo4j/dao/Neo4jTaskDAO.java | 4 +- 4 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/dao/AbstractAuditEventDAO.java diff --git a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/dao/AbstractAuditEventDAO.java b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/dao/AbstractAuditEventDAO.java new file mode 100644 index 00000000000..a84dd746fc3 --- /dev/null +++ b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/dao/AbstractAuditEventDAO.java @@ -0,0 +1,37 @@ +/* + * 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.common.dao; + +import java.util.List; +import java.util.stream.Stream; +import org.apache.syncope.core.persistence.api.entity.AuditEvent; +import org.springframework.data.domain.Sort; +import org.springframework.util.ReflectionUtils; + +public abstract class AbstractAuditEventDAO { + + protected List filterOrderBy( + final Stream orderByClauses, + final Class clazz) { + + return orderByClauses. + filter(clause -> ReflectionUtils.findField(clazz, clause.getProperty().trim()) != null). + toList(); + } +} diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditEventDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditEventDAO.java index 180338ea1b6..4d9baa3cb7e 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditEventDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditEventDAO.java @@ -29,11 +29,13 @@ import org.apache.syncope.common.lib.types.OpEvent; import org.apache.syncope.core.persistence.api.dao.AuditEventDAO; import org.apache.syncope.core.persistence.api.entity.AuditEvent; +import org.apache.syncope.core.persistence.common.dao.AbstractAuditEventDAO; import org.apache.syncope.core.persistence.jpa.entity.JPAAuditEvent; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.transaction.annotation.Transactional; -public class JPAAuditEventDAO implements AuditEventDAO { +public class JPAAuditEventDAO extends AbstractAuditEventDAO implements AuditEventDAO { protected static class AuditEventCriteriaBuilder { @@ -168,8 +170,10 @@ public List search( before(before, parameters). after(after, parameters). build(); - if (!pageable.getSort().isEmpty()) { - queryString += " ORDER BY " + pageable.getSort().stream(). + + List orderBy = filterOrderBy(pageable.getSort().stream(), JPAAuditEvent.class); + if (!orderBy.isEmpty()) { + queryString += " ORDER BY " + orderBy.stream(). map(clause -> ("when".equals(clause.getProperty()) ? "event_date" : clause.getProperty()) + ' ' + clause.getDirection().name()). collect(Collectors.joining(",")); diff --git a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAuditEventDAO.java b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAuditEventDAO.java index 8c8d9f2b4fc..6cc3d0903c1 100644 --- a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAuditEventDAO.java +++ b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jAuditEventDAO.java @@ -28,18 +28,16 @@ import org.apache.syncope.common.lib.types.OpEvent; import org.apache.syncope.core.persistence.api.dao.AuditEventDAO; import org.apache.syncope.core.persistence.api.entity.AuditEvent; +import org.apache.syncope.core.persistence.common.dao.AbstractAuditEventDAO; import org.apache.syncope.core.persistence.neo4j.entity.Neo4jAuditEvent; import org.apache.syncope.core.persistence.neo4j.spring.NodeValidator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.data.neo4j.core.Neo4jClient; import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.transaction.annotation.Transactional; -public class Neo4jAuditEventDAO implements AuditEventDAO { - - protected static final Logger LOG = LoggerFactory.getLogger(AuditEventDAO.class); +public class Neo4jAuditEventDAO extends AbstractAuditEventDAO implements AuditEventDAO { protected static class AuditEventCriteriaBuilder { @@ -169,8 +167,9 @@ public List search( build() + " RETURN n.id"); - if (!pageable.getSort().isEmpty()) { - query.append(" ORDER BY ").append(pageable.getSort().stream(). + List orderBy = filterOrderBy(pageable.getSort().stream(), Neo4jAuditEvent.class); + if (!orderBy.isEmpty()) { + query.append(" ORDER BY ").append(orderBy.stream(). map(clause -> "n." + clause.getProperty() + ' ' + clause.getDirection().name()). collect(Collectors.joining(","))); } diff --git a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jTaskDAO.java b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jTaskDAO.java index 75576dd5c5e..28470fdbfab 100644 --- a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jTaskDAO.java +++ b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/Neo4jTaskDAO.java @@ -291,7 +291,7 @@ public > List findToExec(final TaskType type, final Pageabl query.append("(n)-[:").append(execRelationship(type)).append("]-() "); } - query.append("RETURN n.id ").append(toOrderByStatement(pageable.getSort().get())); + query.append("RETURN n.id ").append(toOrderByStatement(pageable.getSort().stream())); if (pageable.isPaged()) { query.append(" SKIP ").append(pageable.getPageSize() * pageable.getPageNumber()). @@ -463,7 +463,7 @@ public > List findAll( query.append(" WITH n "); - query.append(toOrderByStatement(pageable.getSort().get())); + query.append(toOrderByStatement(pageable.getSort().stream())); if (pageable.isPaged()) { query.append(" SKIP ").append(pageable.getPageSize() * pageable.getPageNumber()).