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 2022/11/03 12:05:51 UTC
[syncope] branch master updated: [SYNCOPE-1696] Adding support to manage Audit entries via Elasticsearch (#387)
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 f42ea0bb75 [SYNCOPE-1696] Adding support to manage Audit entries via Elasticsearch (#387)
f42ea0bb75 is described below
commit f42ea0bb756a82a39d42617a746f8f213b1f3ff8
Author: Francesco Chicchiriccò <il...@users.noreply.github.com>
AuthorDate: Thu Nov 3 13:05:46 2022 +0100
[SYNCOPE-1696] Adding support to manage Audit entries via Elasticsearch (#387)
---
.../syncope/common/lib/info/NumbersInfo.java | 20 +-
.../syncope/common/lib/info/PlatformInfo.java | 243 ---------------------
.../common/lib/types/ClientExceptionType.java | 1 -
.../core/logic/DummyImplementationLookup.java | 5 -
.../org/apache/syncope/core/logic/AuditLogic.java | 26 ++-
.../syncope/core/logic/IdRepoLogicContext.java | 48 +++-
.../apache/syncope/core/logic/LogicProperties.java | 35 ---
.../org/apache/syncope/core/logic/RealmLogic.java | 2 +-
.../syncope/core/logic/audit/AuditAppender.java | 2 -
.../core/logic/audit/DefaultAuditAppender.java | 8 +-
.../logic/audit/DefaultRewriteAuditAppender.java | 5 +-
.../core/logic/audit/JdbcAuditAppender.java | 52 ++---
.../syncope/core/logic/init/AuditLoader.java | 106 +++------
.../init/ClassPathScanImplementationLookup.java | 18 --
.../core/logic/DummyImplementationLookup.java | 5 -
.../core/rest/cxf/IdRepoRESTCXFContext.java | 3 +-
.../core/persistence/api/ImplementationLookup.java | 2 -
.../core/persistence/api/dao/AuditConfDAO.java | 4 +-
.../core/persistence/jpa/dao/JPAAuditConfDAO.java | 8 +-
.../persistence/jpa/DummyImplementationLookup.java | 5 -
.../provisioning/api/serialization/POJOHelper.java | 12 +
.../provisioning/java/DefaultAuditManager.java | 15 +-
.../AbstractPropagationTaskExecutor.java | 3 +-
.../pushpull/DefaultRealmPullResultHandler.java | 2 +-
.../java/DummyImplementationLookup.java | 5 -
.../spring/security/DummyImplementationLookup.java | 5 -
.../core/starter/SyncopeCoreApplication.java | 93 ++------
.../actuate/DefaultSyncopeCoreInfoContributor.java | 236 ++++----------------
core/starter/src/main/resources/core.properties | 6 -
.../client/ElasticsearchClientContext.java | 26 ++-
.../client/ElasticsearchIndexLoader.java} | 34 +--
.../client/ElasticsearchIndexManager.java | 158 +++++++++++---
.../client/ElasticsearchProperties.java | 86 ++++++++
.../elasticsearch/client/ElasticsearchUtils.java | 74 +++----
ext/elasticsearch/{ => logic}/pom.xml | 44 ++--
.../core/logic/audit/ElasticsearchAppender.java | 97 ++++++++
.../logic/audit/ElasticsearchAuditAppender.java | 52 +++++
.../logic/audit/ElasticsearchLogicContext.java | 62 ++++++
.../src/main/resources/META-INF/spring.factories | 3 +-
.../jpa/ElasticsearchPersistenceContext.java | 26 ++-
.../jpa/dao/ElasticsearchAnySearchDAO.java | 12 +-
.../jpa/dao/ElasticsearchAuditConfDAO.java | 182 +++++++++++++++
.../jpa/dao/ElasticsearchAnySearchDAOTest.java | 26 ++-
ext/elasticsearch/pom.xml | 1 +
.../java/job/ElasticsearchReindex.java | 31 ++-
fit/core-reference/pom.xml | 6 +
.../fit/core/reference/CoreReferenceContext.java | 12 +
.../fit/core/reference/ITImplementationLookup.java | 12 -
.../core/reference/SyslogRewriteAuditAppender.java | 25 ++-
.../fit/core/reference/TestFileAuditAppender.java | 39 ++--
.../reference/TestFileRewriteAuditAppender.java | 23 +-
.../main/resources/core-elasticsearch.properties | 7 +-
.../src/main/resources/core-embedded.properties | 3 +
.../org/apache/syncope/fit/AbstractITCase.java | 27 +++
.../org/apache/syncope/fit/AbstractUIITCase.java | 25 +++
.../apache/syncope/fit/ElasticsearchDetector.java | 32 ---
.../org/apache/syncope/fit/FlowableDetector.java | 32 ---
.../org/apache/syncope/fit/core/AuditITCase.java | 77 ++++---
.../syncope/fit/core/AuthenticationITCase.java | 8 +-
.../apache/syncope/fit/core/BpmnProcessITCase.java | 5 +-
.../apache/syncope/fit/core/DelegationITCase.java | 3 +-
.../apache/syncope/fit/core/DynRealmITCase.java | 7 +-
.../org/apache/syncope/fit/core/GroupITCase.java | 5 +-
.../apache/syncope/fit/core/KeymasterITCase.java | 3 +-
.../apache/syncope/fit/core/MembershipITCase.java | 3 +-
.../syncope/fit/core/MultitenancyITCase.java | 3 +-
.../apache/syncope/fit/core/PullTaskITCase.java | 10 +-
.../org/apache/syncope/fit/core/RealmITCase.java | 14 +-
.../org/apache/syncope/fit/core/SearchITCase.java | 13 +-
.../org/apache/syncope/fit/core/UserITCase.java | 7 +-
.../apache/syncope/fit/core/UserIssuesITCase.java | 3 +-
.../apache/syncope/fit/core/UserRequestITCase.java | 5 +-
.../apache/syncope/fit/core/UserSelfITCase.java | 26 +--
.../syncope/fit/enduser/AuthenticatedITCase.java | 3 +-
pom.xml | 10 +-
.../asciidoc/reference-guide/concepts/audit.adoc | 5 +-
.../reference-guide/concepts/extensions.adoc | 6 +-
.../reference-guide/usage/customization.adoc | 27 ++-
78 files changed, 1239 insertions(+), 1136 deletions(-)
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/info/NumbersInfo.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/info/NumbersInfo.java
index a2a087410b..49fd9e03a0 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/info/NumbersInfo.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/info/NumbersInfo.java
@@ -57,7 +57,7 @@ public class NumbersInfo implements BaseBean {
}
}
- public class TaskExecutorInfo {
+ public static class TaskExecutorInfo {
private int size;
@@ -158,9 +158,7 @@ public class NumbersInfo implements BaseBean {
private final Map<String, Boolean> confCompleteness = new HashMap<>();
- private final TaskExecutorInfo asyncConnectorExecutor = new TaskExecutorInfo();
-
- private final TaskExecutorInfo propagationTaskExecutor = new TaskExecutorInfo();
+ private final Map<String, TaskExecutorInfo> taskExecutorInfos = new HashMap<>();
public int getTotalUsers() {
return totalUsers;
@@ -250,12 +248,8 @@ public class NumbersInfo implements BaseBean {
return confCompleteness;
}
- public TaskExecutorInfo getAsyncConnectorExecutor() {
- return asyncConnectorExecutor;
- }
-
- public TaskExecutorInfo getPropagationTaskExecutor() {
- return propagationTaskExecutor;
+ public Map<String, TaskExecutorInfo> getTaskExecutorInfos() {
+ return taskExecutorInfos;
}
@Override
@@ -275,8 +269,7 @@ public class NumbersInfo implements BaseBean {
append(totalResources).
append(totalRoles).
append(confCompleteness).
- append(asyncConnectorExecutor).
- append(propagationTaskExecutor).
+ append(taskExecutorInfos).
build();
}
@@ -307,8 +300,7 @@ public class NumbersInfo implements BaseBean {
append(totalAny2, other.totalAny2).
append(any2ByRealm, other.any2ByRealm).
append(confCompleteness, other.confCompleteness).
- append(asyncConnectorExecutor, other.asyncConnectorExecutor).
- append(propagationTaskExecutor, other.propagationTaskExecutor).
+ append(taskExecutorInfos, other.taskExecutorInfos).
build();
}
}
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/info/PlatformInfo.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/info/PlatformInfo.java
index a58ee1d070..c81cd389e7 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/info/PlatformInfo.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/info/PlatformInfo.java
@@ -32,211 +32,6 @@ public class PlatformInfo implements BaseBean {
private static final long serialVersionUID = -7941853999417673827L;
- public static class ProvisioningInfo implements BaseBean {
-
- private static final long serialVersionUID = 533340357732839568L;
-
- private String propagationTaskExecutor;
-
- private String virAttrCache;
-
- private String anyObjectProvisioningManager;
-
- private String userProvisioningManager;
-
- private String groupProvisioningManager;
-
- private String notificationManager;
-
- private String auditManager;
-
- public String getPropagationTaskExecutor() {
- return propagationTaskExecutor;
- }
-
- public void setPropagationTaskExecutor(final String propagationTaskExecutor) {
- this.propagationTaskExecutor = propagationTaskExecutor;
- }
-
- public String getVirAttrCache() {
- return virAttrCache;
- }
-
- public void setVirAttrCache(final String virAttrCache) {
- this.virAttrCache = virAttrCache;
- }
-
- public String getAnyObjectProvisioningManager() {
- return anyObjectProvisioningManager;
- }
-
- public void setAnyObjectProvisioningManager(final String anyObjectProvisioningManager) {
- this.anyObjectProvisioningManager = anyObjectProvisioningManager;
- }
-
- public String getUserProvisioningManager() {
- return userProvisioningManager;
- }
-
- public void setUserProvisioningManager(final String userProvisioningManager) {
- this.userProvisioningManager = userProvisioningManager;
- }
-
- public String getGroupProvisioningManager() {
- return groupProvisioningManager;
- }
-
- public void setGroupProvisioningManager(final String groupProvisioningManager) {
- this.groupProvisioningManager = groupProvisioningManager;
- }
-
- public String getNotificationManager() {
- return notificationManager;
- }
-
- public void setNotificationManager(final String notificationManager) {
- this.notificationManager = notificationManager;
- }
-
- public String getAuditManager() {
- return auditManager;
- }
-
- public void setAuditManager(final String auditManager) {
- this.auditManager = auditManager;
- }
- }
-
- public static class WorkflowInfo implements BaseBean {
-
- private static final long serialVersionUID = 6736937721099195324L;
-
- private String anyObjectWorkflowAdapter;
-
- private String userWorkflowAdapter;
-
- private String groupWorkflowAdapter;
-
- public String getAnyObjectWorkflowAdapter() {
- return anyObjectWorkflowAdapter;
- }
-
- public void setAnyObjectWorkflowAdapter(final String anyObjectWorkflowAdapter) {
- this.anyObjectWorkflowAdapter = anyObjectWorkflowAdapter;
- }
-
- public String getUserWorkflowAdapter() {
- return userWorkflowAdapter;
- }
-
- public void setUserWorkflowAdapter(final String userWorkflowAdapter) {
- this.userWorkflowAdapter = userWorkflowAdapter;
- }
-
- public String getGroupWorkflowAdapter() {
- return groupWorkflowAdapter;
- }
-
- public void setGroupWorkflowAdapter(final String groupWorkflowAdapter) {
- this.groupWorkflowAdapter = groupWorkflowAdapter;
- }
- }
-
- public static class PersistenceInfo implements BaseBean {
-
- private static final long serialVersionUID = 2902980556801069487L;
-
- private String entityFactory;
-
- private String plainSchemaDAO;
-
- private String plainAttrDAO;
-
- private String plainAttrValueDAO;
-
- private String anySearchDAO;
-
- private String userDAO;
-
- private String groupDAO;
-
- private String anyObjectDAO;
-
- public String getEntityFactory() {
- return entityFactory;
- }
-
- public void setEntityFactory(final String entityFactory) {
- this.entityFactory = entityFactory;
- }
-
- public String getPlainSchemaDAO() {
- return plainSchemaDAO;
- }
-
- public void setPlainSchemaDAO(final String plainSchemaDAO) {
- this.plainSchemaDAO = plainSchemaDAO;
- }
-
- public String getPlainAttrDAO() {
- return plainAttrDAO;
- }
-
- public void setPlainAttrDAO(final String plainAttrDAO) {
- this.plainAttrDAO = plainAttrDAO;
- }
-
- public String getPlainAttrValueDAO() {
- return plainAttrValueDAO;
- }
-
- public void setPlainAttrValueDAO(final String plainAttrValueDAO) {
- this.plainAttrValueDAO = plainAttrValueDAO;
- }
-
- public String getAnySearchDAO() {
- return anySearchDAO;
- }
-
- public void setAnySearchDAO(final String anySearchDAO) {
- this.anySearchDAO = anySearchDAO;
- }
-
- public String getUserDAO() {
- return userDAO;
- }
-
- public void setUserDAO(final String userDAO) {
- this.userDAO = userDAO;
- }
-
- public String getGroupDAO() {
- return groupDAO;
- }
-
- public void setGroupDAO(final String groupDAO) {
- this.groupDAO = groupDAO;
- }
-
- public String getAnyObjectDAO() {
- return anyObjectDAO;
- }
-
- public void setAnyObjectDAO(final String anyObjectDAO) {
- this.anyObjectDAO = anyObjectDAO;
- }
- }
-
- private String keymasterConfParamOps;
-
- private String keymasterServiceOps;
-
- private final ProvisioningInfo provisioningInfo = new ProvisioningInfo();
-
- private final WorkflowInfo workflowInfo = new WorkflowInfo();
-
- private final PersistenceInfo persistenceInfo = new PersistenceInfo();
-
private boolean selfRegAllowed;
private boolean pwdResetAllowed;
@@ -245,8 +40,6 @@ public class PlatformInfo implements BaseBean {
private final Set<String> connIdLocations = new HashSet<>();
- private String passwordGenerator;
-
private final List<String> anyTypes = new ArrayList<>();
private final List<String> userClasses = new ArrayList<>();
@@ -261,26 +54,6 @@ public class PlatformInfo implements BaseBean {
private final Set<JavaImplInfo> javaImplInfos = new HashSet<>();
- public String getKeymasterConfParamOps() {
- return keymasterConfParamOps;
- }
-
- public String getKeymasterServiceOps() {
- return keymasterServiceOps;
- }
-
- public ProvisioningInfo getProvisioningInfo() {
- return provisioningInfo;
- }
-
- public WorkflowInfo getWorkflowInfo() {
- return workflowInfo;
- }
-
- public PersistenceInfo getPersistenceInfo() {
- return persistenceInfo;
- }
-
public boolean isSelfRegAllowed() {
return selfRegAllowed;
}
@@ -299,14 +72,6 @@ public class PlatformInfo implements BaseBean {
return connIdLocations;
}
- public String getPasswordGenerator() {
- return passwordGenerator;
- }
-
- public void setPasswordGenerator(final String passwordGenerator) {
- this.passwordGenerator = passwordGenerator;
- }
-
@JacksonXmlElementWrapper(localName = "anyTypes")
@JacksonXmlProperty(localName = "anyType")
public List<String> getAnyTypes() {
@@ -354,14 +119,6 @@ public class PlatformInfo implements BaseBean {
return javaImplInfos;
}
- public void setKeymasterConfParamOps(final String keymasterConfParamOps) {
- this.keymasterConfParamOps = keymasterConfParamOps;
- }
-
- public void setKeymasterServiceOps(final String keymasterServiceOps) {
- this.keymasterServiceOps = keymasterServiceOps;
- }
-
public void setSelfRegAllowed(final boolean selfRegAllowed) {
this.selfRegAllowed = selfRegAllowed;
}
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
index 555488be6f..3586e23cae 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
@@ -29,7 +29,6 @@ public enum ClientExceptionType {
DataIntegrityViolation(Response.Status.CONFLICT),
EntityExists(Response.Status.CONFLICT),
GenericPersistence(Response.Status.BAD_REQUEST),
- HasChildren(Response.Status.BAD_REQUEST),
InvalidAccessToken(Response.Status.INTERNAL_SERVER_ERROR),
InvalidPrivilege(Response.Status.BAD_REQUEST),
InvalidImplementation(Response.Status.BAD_REQUEST),
diff --git a/core/idm/logic/src/test/java/org/apache/syncope/core/logic/DummyImplementationLookup.java b/core/idm/logic/src/test/java/org/apache/syncope/core/logic/DummyImplementationLookup.java
index 7cf8a155f3..ec237ee3d1 100644
--- a/core/idm/logic/src/test/java/org/apache/syncope/core/logic/DummyImplementationLookup.java
+++ b/core/idm/logic/src/test/java/org/apache/syncope/core/logic/DummyImplementationLookup.java
@@ -82,9 +82,4 @@ public class DummyImplementationLookup implements ImplementationLookup {
return null;
}
-
- @Override
- public Set<Class<?>> getAuditAppenderClasses() {
- return Set.of();
- }
}
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 18d31d2664..38d054e81d 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
@@ -45,6 +45,7 @@ import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.core.logic.audit.AuditAppender;
import org.apache.syncope.core.logic.init.AuditLoader;
import org.apache.syncope.core.persistence.api.dao.AuditConfDAO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
@@ -57,6 +58,7 @@ import org.apache.syncope.core.provisioning.api.data.AuditDataBinder;
import org.apache.syncope.core.provisioning.java.pushpull.PullJobDelegate;
import org.apache.syncope.core.provisioning.java.pushpull.PushJobDelegate;
import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
@@ -72,8 +74,6 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditConfTO> {
protected static final List<EventCategory> EVENTS = new ArrayList<>();
- protected final AuditLoader auditLoader;
-
protected final AuditConfDAO auditConfDAO;
protected final ExternalResourceDAO resourceDAO;
@@ -84,20 +84,22 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditConfTO> {
protected final AuditManager auditManager;
+ protected final ApplicationContext ctx;
+
public AuditLogic(
- final AuditLoader auditLoader,
final AuditConfDAO auditConfDAO,
final ExternalResourceDAO resourceDAO,
final EntityFactory entityFactory,
final AuditDataBinder binder,
- final AuditManager auditManager) {
+ final AuditManager auditManager,
+ final ApplicationContext ctx) {
- this.auditLoader = auditLoader;
this.auditConfDAO = auditConfDAO;
this.resourceDAO = resourceDAO;
this.entityFactory = entityFactory;
this.binder = binder;
this.auditManager = auditManager;
+ this.ctx = ctx;
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.AUDIT_LIST + "')")
@@ -141,17 +143,17 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditConfTO> {
protected void setLevel(final String key, final Level level) {
String auditLoggerName = AuditLoggerName.getAuditEventLoggerName(AuthContextUtils.getDomain(), key);
- LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
- LoggerConfig logConf = ctx.getConfiguration().getLoggerConfig(auditLoggerName);
+ LoggerContext logCtx = (LoggerContext) LogManager.getContext(false);
+ LoggerConfig logConf = logCtx.getConfiguration().getLoggerConfig(auditLoggerName);
// SYNCOPE-1144 For each custom audit appender class add related appenders to log4j logger
- auditLoader.auditAppenders(AuthContextUtils.getDomain()).stream().
+ ctx.getBeansOfType(AuditAppender.class).values().stream().
filter(appender -> appender.getEvents().stream().
anyMatch(event -> key.equalsIgnoreCase(event.toAuditKey()))).
- forEach(auditAppender -> AuditLoader.addAppenderToContext(ctx, auditAppender, logConf));
+ forEach(auditAppender -> AuditLoader.addAppenderToLoggerContext(logCtx, auditAppender, logConf));
logConf.setLevel(level);
- ctx.updateLoggers();
+ logCtx.updateLoggers();
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.AUDIT_LIST + "') "
@@ -270,11 +272,11 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditConfTO> {
final String subcategory,
final List<String> events,
final AuditElements.Result result,
- final List<OrderByClause> orderByClauses) {
+ final List<OrderByClause> orderBy) {
int count = auditConfDAO.countEntries(entityKey, type, category, subcategory, events, result);
List<AuditEntry> matching = auditConfDAO.searchEntries(
- entityKey, page, size, type, category, subcategory, events, result, orderByClauses);
+ entityKey, page, size, type, category, subcategory, events, result, orderBy);
return Pair.of(count, matching);
}
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/IdRepoLogicContext.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/IdRepoLogicContext.java
index 9a4e62889a..d04964193a 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/IdRepoLogicContext.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/IdRepoLogicContext.java
@@ -18,13 +18,23 @@
*/
package org.apache.syncope.core.logic;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
+import org.apache.syncope.common.lib.types.AuditLoggerName;
+import org.apache.syncope.core.logic.audit.AuditAppender;
+import org.apache.syncope.core.logic.audit.JdbcAuditAppender;
import org.apache.syncope.core.logic.init.AuditAccessor;
import org.apache.syncope.core.logic.init.AuditLoader;
import org.apache.syncope.core.logic.init.ClassPathScanImplementationLookup;
import org.apache.syncope.core.logic.init.EntitlementAccessor;
import org.apache.syncope.core.logic.init.IdRepoEntitlementLoader;
import org.apache.syncope.core.logic.init.IdRepoImplementationTypeLoader;
+import org.apache.syncope.core.persistence.api.DomainHolder;
import org.apache.syncope.core.persistence.api.ImplementationLookup;
import org.apache.syncope.core.persistence.api.content.ContentExporter;
import org.apache.syncope.core.persistence.api.dao.AccessTokenDAO;
@@ -98,14 +108,13 @@ import org.apache.syncope.core.workflow.api.AnyObjectWorkflowAdapter;
import org.apache.syncope.core.workflow.api.GroupWorkflowAdapter;
import org.apache.syncope.core.workflow.api.UserWorkflowAdapter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
@EnableAspectJAutoProxy(proxyTargetClass = false)
-@EnableConfigurationProperties(LogicProperties.class)
@Configuration(proxyBeanMethods = false)
public class IdRepoLogicContext {
@@ -134,10 +143,29 @@ public class IdRepoLogicContext {
@Bean
public AuditLoader auditLoader(
final AuditAccessor auditAccessor,
- final ImplementationLookup implementationLookup,
- final LogicProperties logicProperties) {
+ final ApplicationContext ctx) {
- return new AuditLoader(auditAccessor, implementationLookup, logicProperties);
+ return new AuditLoader(auditAccessor, ctx);
+ }
+
+ @ConditionalOnMissingBean(name = "defaultAuditAppenders")
+ @Bean
+ public List<AuditAppender> defaultAuditAppenders(final DomainHolder domainHolder) {
+ List<AuditAppender> auditAppenders = new ArrayList<>();
+
+ LoggerContext logCtx = (LoggerContext) LogManager.getContext(false);
+ domainHolder.getDomains().forEach((domain, dataSource) -> {
+ AuditAppender appender = new JdbcAuditAppender(domain, dataSource);
+
+ LoggerConfig logConf = new LoggerConfig(AuditLoggerName.getAuditLoggerName(domain), null, false);
+ logConf.addAppender(appender.getTargetAppender(), Level.DEBUG, null);
+ logConf.setLevel(Level.DEBUG);
+ logCtx.getConfiguration().addLogger(logConf.getName(), logConf);
+
+ auditAppenders.add(appender);
+ });
+
+ return auditAppenders;
}
@ConditionalOnMissingBean
@@ -220,20 +248,20 @@ public class IdRepoLogicContext {
@ConditionalOnMissingBean
@Bean
public AuditLogic auditLogic(
- final AuditManager auditManager,
- final AuditLoader auditLoader,
final AuditConfDAO auditConfDAO,
final ExternalResourceDAO externalResourceDAO,
final EntityFactory entityFactory,
- final AuditDataBinder binder) {
+ final AuditDataBinder binder,
+ final AuditManager auditManager,
+ final ApplicationContext ctx) {
return new AuditLogic(
- auditLoader,
auditConfDAO,
externalResourceDAO,
entityFactory,
binder,
- auditManager);
+ auditManager,
+ ctx);
}
@ConditionalOnMissingBean
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/LogicProperties.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/LogicProperties.java
deleted file mode 100644
index 0b69910777..0000000000
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/LogicProperties.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.logic;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-@ConfigurationProperties("logic")
-public class LogicProperties {
-
- private boolean enableJDBCAuditAppender = true;
-
- public boolean isEnableJDBCAuditAppender() {
- return enableJDBCAuditAppender;
- }
-
- public void setEnableJDBCAuditAppender(final boolean enableJDBCAuditAppender) {
- this.enableJDBCAuditAppender = enableJDBCAuditAppender;
- }
-}
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 cce7a068fc..5c259913ee 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
@@ -222,7 +222,7 @@ public class RealmLogic extends AbstractTransactionalLogic<RealmTO> {
orElseThrow(() -> new NotFoundException("Realm " + fullPath));
if (!realmDAO.findChildren(realm).isEmpty()) {
- throw SyncopeClientException.build(ClientExceptionType.HasChildren);
+ throw SyncopeClientException.build(ClientExceptionType.RealmContains);
}
Set<String> adminRealms = Set.of(realm.getFullPath());
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/AuditAppender.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/AuditAppender.java
index d81daa668d..9a8d8122b0 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/AuditAppender.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/AuditAppender.java
@@ -32,8 +32,6 @@ import org.apache.syncope.common.lib.types.AuditLoggerName;
*/
public interface AuditAppender {
- void init(String domain);
-
default Set<AuditLoggerName> getEvents() {
return Set.of();
}
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/DefaultAuditAppender.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/DefaultAuditAppender.java
index a78f82f474..a18d7c7d30 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/DefaultAuditAppender.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/DefaultAuditAppender.java
@@ -29,18 +29,14 @@ import org.apache.logging.log4j.core.Appender;
*/
public abstract class DefaultAuditAppender implements AuditAppender {
- protected String domain;
+ protected final String domain;
protected Appender targetAppender;
- @Override
- public void init(final String domain) {
+ protected DefaultAuditAppender(final String domain) {
this.domain = domain;
- initTargetAppender();
}
- protected abstract void initTargetAppender();
-
@Override
public Appender getTargetAppender() {
return targetAppender;
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/DefaultRewriteAuditAppender.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/DefaultRewriteAuditAppender.java
index ed62206e94..008752226a 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/DefaultRewriteAuditAppender.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/DefaultRewriteAuditAppender.java
@@ -39,9 +39,8 @@ public abstract class DefaultRewriteAuditAppender extends DefaultAuditAppender {
protected RewriteAppender rewriteAppender;
- @Override
- public void init(final String domain) {
- super.init(domain);
+ public DefaultRewriteAuditAppender(final String domain) {
+ super(domain);
rewriteAppender = RewriteAppender.createAppender(
getTargetAppenderName() + "_rewrite",
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/JdbcAuditAppender.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/JdbcAuditAppender.java
index 2229699e69..4ecce56d9b 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/JdbcAuditAppender.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/audit/JdbcAuditAppender.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.logic.audit;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Timestamp;
+import java.util.Optional;
import javax.sql.DataSource;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
@@ -28,54 +29,49 @@ import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.db.ColumnMapping;
import org.apache.logging.log4j.core.appender.db.jdbc.AbstractConnectionSource;
import org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender;
-import org.apache.syncope.core.persistence.api.DomainHolder;
import org.apache.syncope.core.persistence.api.dao.AuditConfDAO;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceUtils;
public class JdbcAuditAppender extends DefaultAuditAppender {
- @Autowired
- protected DomainHolder domainHolder;
+ public JdbcAuditAppender(final String domain, final DataSource domainDataSource) {
+ super(domain);
- @Override
- protected void initTargetAppender() {
- LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+ LoggerContext logCtx = (LoggerContext) LogManager.getContext(false);
ColumnMapping[] columnMappings = {
ColumnMapping.newBuilder().
- setConfiguration(ctx.getConfiguration()).setName("EVENT_DATE").setType(Timestamp.class).build(),
+ setConfiguration(logCtx.getConfiguration()).setName("EVENT_DATE").setType(Timestamp.class).build(),
ColumnMapping.newBuilder().
- setConfiguration(ctx.getConfiguration()).setName("LOGGER_LEVEL").setPattern("%level").build(),
+ setConfiguration(logCtx.getConfiguration()).setName("LOGGER_LEVEL").setPattern("%level").build(),
ColumnMapping.newBuilder().
- setConfiguration(ctx.getConfiguration()).setName("LOGGER").setPattern("%logger").build(),
+ setConfiguration(logCtx.getConfiguration()).setName("LOGGER").setPattern("%logger").build(),
ColumnMapping.newBuilder().
- setConfiguration(ctx.getConfiguration()).
+ setConfiguration(logCtx.getConfiguration()).
setName(AuditConfDAO.AUDIT_ENTRY_MESSAGE_COLUMN).setPattern("%message").build(),
ColumnMapping.newBuilder().
- setConfiguration(ctx.getConfiguration()).setName("THROWABLE").setPattern("%ex{full}").build()
+ setConfiguration(logCtx.getConfiguration()).setName("THROWABLE").setPattern("%ex{full}").build()
};
- Appender appender = ctx.getConfiguration().getAppender("audit_for_" + domain);
- if (appender == null) {
- appender = JdbcAppender.newBuilder().
- setName("audit_for_" + domain).
- setIgnoreExceptions(false).
- setConnectionSource(new DataSourceConnectionSource(domain, domainHolder.getDomains().get(domain))).
- setBufferSize(0).
- setTableName(AuditConfDAO.AUDIT_ENTRY_TABLE).
- setColumnMappings(columnMappings).
- build();
- appender.start();
- ctx.getConfiguration().addAppender(appender);
- }
- targetAppender = appender;
+ targetAppender = Optional.ofNullable(logCtx.getConfiguration().<Appender>getAppender(getTargetAppenderName())).
+ orElseGet(() -> {
+ JdbcAppender a = JdbcAppender.newBuilder().
+ setName(getTargetAppenderName()).
+ setIgnoreExceptions(false).
+ setConnectionSource(new DataSourceConnectionSource(domain, domainDataSource)).
+ setBufferSize(0).
+ setTableName(AuditConfDAO.AUDIT_ENTRY_TABLE).
+ setColumnMappings(columnMappings).
+ build();
+ a.start();
+ logCtx.getConfiguration().addAppender(a);
+ return a;
+ });
}
@Override
public String getTargetAppenderName() {
- // not used
- return null;
+ return "audit_for_" + domain;
}
protected static class DataSourceConnectionSource extends AbstractConnectionSource {
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/AuditLoader.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/AuditLoader.java
index 09ac732c8f..f906c52ed8 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/AuditLoader.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/AuditLoader.java
@@ -18,9 +18,7 @@
*/
package org.apache.syncope.core.logic.init;
-import java.util.List;
import java.util.Optional;
-import java.util.stream.Collectors;
import javax.sql.DataSource;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
@@ -29,34 +27,43 @@ import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.rewrite.RewriteAppender;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.syncope.common.lib.types.AuditLoggerName;
-import org.apache.syncope.core.logic.LogicProperties;
import org.apache.syncope.core.logic.audit.AuditAppender;
-import org.apache.syncope.core.logic.audit.JdbcAuditAppender;
-import org.apache.syncope.core.persistence.api.ImplementationLookup;
import org.apache.syncope.core.persistence.api.SyncopeCoreLoader;
-import org.apache.syncope.core.spring.ApplicationContextProvider;
import org.apache.syncope.core.spring.security.AuthContextUtils;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.context.ApplicationContext;
public class AuditLoader implements SyncopeCoreLoader {
protected static final String ROOT_LOGGER = "ROOT";
- protected final AuditAccessor auditAccessor;
+ public static void addAppenderToLoggerContext(
+ final LoggerContext ctx,
+ final AuditAppender auditAppender,
+ final LoggerConfig eventLogConf) {
+
+ Appender targetAppender = ctx.getConfiguration().getAppender(auditAppender.getTargetAppenderName());
+ if (targetAppender == null) {
+ targetAppender = auditAppender.getTargetAppender();
+ }
+ targetAppender.start();
+ ctx.getConfiguration().addAppender(targetAppender);
- protected final ImplementationLookup implementationLookup;
+ Optional<RewriteAppender> rewriteAppender = auditAppender.getRewriteAppender();
+ if (rewriteAppender.isPresent()) {
+ rewriteAppender.get().start();
+ eventLogConf.addAppender(rewriteAppender.get(), Level.DEBUG, null);
+ } else {
+ eventLogConf.addAppender(targetAppender, Level.DEBUG, null);
+ }
+ }
- protected final LogicProperties props;
+ protected final AuditAccessor auditAccessor;
- public AuditLoader(
- final AuditAccessor auditAccessor,
- final ImplementationLookup implementationLookup,
- final LogicProperties props) {
+ protected final ApplicationContext ctx;
+ public AuditLoader(final AuditAccessor auditAccessor, final ApplicationContext ctx) {
this.auditAccessor = auditAccessor;
- this.implementationLookup = implementationLookup;
- this.props = props;
+ this.ctx = ctx;
}
@Override
@@ -66,77 +73,32 @@ public class AuditLoader implements SyncopeCoreLoader {
@Override
public void load(final String domain, final DataSource datasource) {
- LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
-
- if (props.isEnableJDBCAuditAppender()) {
- JdbcAuditAppender jdbcAuditAppender = (JdbcAuditAppender) ApplicationContextProvider.getBeanFactory().
- createBean(JdbcAuditAppender.class, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
- jdbcAuditAppender.init(domain);
-
- LoggerConfig logConf = new LoggerConfig(AuditLoggerName.getAuditLoggerName(domain), null, false);
- logConf.addAppender(jdbcAuditAppender.getTargetAppender(), Level.DEBUG, null);
- logConf.setLevel(Level.DEBUG);
- ctx.getConfiguration().addLogger(logConf.getName(), logConf);
- }
+ LoggerContext logCtx = (LoggerContext) LogManager.getContext(false);
// SYNCOPE-1144 For each custom audit appender class add related appenders to log4j logger
- auditAppenders(domain).forEach(auditAppender -> auditAppender.getEvents().stream().
+ ctx.getBeansOfType(AuditAppender.class).values().forEach(auditAppender -> auditAppender.getEvents().stream().
map(event -> AuditLoggerName.getAuditEventLoggerName(domain, event.toAuditKey())).
forEach(domainAuditLoggerName -> {
- LoggerConfig eventLogConf = ctx.getConfiguration().getLoggerConfig(domainAuditLoggerName);
+ LoggerConfig eventLogConf = logCtx.getConfiguration().getLoggerConfig(domainAuditLoggerName);
boolean isRootLogConf = LogManager.ROOT_LOGGER_NAME.equals(eventLogConf.getName());
+
if (isRootLogConf) {
eventLogConf = new LoggerConfig(domainAuditLoggerName, null, false);
}
- addAppenderToContext(ctx, auditAppender, eventLogConf);
+
+ addAppenderToLoggerContext(logCtx, auditAppender, eventLogConf);
eventLogConf.setLevel(Level.DEBUG);
+
if (isRootLogConf) {
- ctx.getConfiguration().addLogger(domainAuditLoggerName, eventLogConf);
+ logCtx.getConfiguration().addLogger(domainAuditLoggerName, eventLogConf);
}
}));
AuthContextUtils.callAsAdmin(domain, () -> {
- auditAccessor.synchronizeLoggingWithAudit(ctx);
+ auditAccessor.synchronizeLoggingWithAudit(logCtx);
return null;
});
- ctx.updateLoggers();
- }
-
- public List<AuditAppender> auditAppenders(final String domain) throws BeansException {
- return implementationLookup.getAuditAppenderClasses().stream().map(clazz -> {
- AuditAppender auditAppender;
- if (ApplicationContextProvider.getBeanFactory().containsSingleton(clazz.getName())) {
- auditAppender = (AuditAppender) ApplicationContextProvider.getBeanFactory().
- getSingleton(clazz.getName());
- } else {
- auditAppender = (AuditAppender) ApplicationContextProvider.getBeanFactory().
- createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
- ApplicationContextProvider.getBeanFactory().registerSingleton(clazz.getName(), auditAppender);
- auditAppender.init(domain);
- }
- return auditAppender;
- }).collect(Collectors.toList());
- }
-
- public static void addAppenderToContext(
- final LoggerContext ctx,
- final AuditAppender auditAppender,
- final LoggerConfig eventLogConf) {
-
- Appender targetAppender = ctx.getConfiguration().getAppender(auditAppender.getTargetAppenderName());
- if (targetAppender == null) {
- targetAppender = auditAppender.getTargetAppender();
- }
- targetAppender.start();
- ctx.getConfiguration().addAppender(targetAppender);
-
- Optional<RewriteAppender> rewriteAppender = auditAppender.getRewriteAppender();
- if (rewriteAppender.isPresent()) {
- rewriteAppender.get().start();
- eventLogConf.addAppender(rewriteAppender.get(), Level.DEBUG, null);
- } else {
- eventLogConf.addAppender(targetAppender, Level.DEBUG, null);
- }
+ logCtx.updateLoggers();
}
}
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
index b1aa633cf8..8036954740 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
@@ -35,8 +35,6 @@ import org.apache.syncope.common.lib.types.IdRepoImplementationType;
import org.apache.syncope.common.lib.types.ImplementationTypesHolder;
import org.apache.syncope.core.logic.api.Command;
import org.apache.syncope.core.logic.api.LogicActions;
-import org.apache.syncope.core.logic.audit.AuditAppender;
-import org.apache.syncope.core.logic.audit.JdbcAuditAppender;
import org.apache.syncope.core.persistence.api.ImplementationLookup;
import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValueValidator;
import org.apache.syncope.core.persistence.api.dao.AccountRule;
@@ -92,8 +90,6 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
private Map<Class<? extends PushCorrelationRuleConf>, Class<? extends PushCorrelationRule>> pushCRClasses;
- private Set<Class<?>> auditAppenderClasses;
-
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 1;
@@ -129,7 +125,6 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
passwordRuleClasses = new HashMap<>();
pullCRClasses = new HashMap<>();
pushCRClasses = new HashMap<>();
- auditAppenderClasses = new HashSet<>();
scanner.findCandidateComponents(getBasePackage()).forEach(bd -> {
try {
@@ -234,13 +229,6 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
classNames.get(IdRepoImplementationType.RECIPIENTS_PROVIDER).add(bd.getBeanClassName());
}
- if (AuditAppender.class.isAssignableFrom(clazz)
- && !JdbcAuditAppender.class.equals(clazz) && !isAbstractClazz) {
-
- classNames.get(IdRepoImplementationType.AUDIT_APPENDER).add(clazz.getName());
- auditAppenderClasses.add(clazz);
- }
-
if (ProvisionSorter.class.isAssignableFrom(clazz) && !isAbstractClazz) {
classNames.get(IdMImplementationType.PROVISION_SORTER).add(bd.getBeanClassName());
}
@@ -262,7 +250,6 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
passwordRuleClasses = Collections.unmodifiableMap(passwordRuleClasses);
pullCRClasses = Collections.unmodifiableMap(pullCRClasses);
pushCRClasses = Collections.unmodifiableMap(pushCRClasses);
- auditAppenderClasses = Collections.unmodifiableSet(auditAppenderClasses);
}
@Override
@@ -309,9 +296,4 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
return pushCRClasses.get(correlationRuleConfClass);
}
-
- @Override
- public Set<Class<?>> getAuditAppenderClasses() {
- return auditAppenderClasses;
- }
}
diff --git a/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/DummyImplementationLookup.java b/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/DummyImplementationLookup.java
index 28c68461c1..92acd2764d 100644
--- a/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/DummyImplementationLookup.java
+++ b/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/DummyImplementationLookup.java
@@ -88,9 +88,4 @@ public class DummyImplementationLookup implements ImplementationLookup {
return null;
}
-
- @Override
- public Set<Class<?>> getAuditAppenderClasses() {
- return Set.of();
- }
}
diff --git a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/IdRepoRESTCXFContext.java b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/IdRepoRESTCXFContext.java
index aebfacf737..ab01ca51ad 100644
--- a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/IdRepoRESTCXFContext.java
+++ b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/IdRepoRESTCXFContext.java
@@ -130,6 +130,7 @@ import org.apache.syncope.core.rest.cxf.service.SyncopeServiceImpl;
import org.apache.syncope.core.rest.cxf.service.TaskServiceImpl;
import org.apache.syncope.core.rest.cxf.service.UserSelfServiceImpl;
import org.apache.syncope.core.rest.cxf.service.UserServiceImpl;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
@@ -145,7 +146,6 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration(proxyBeanMethods = false)
public class IdRepoRESTCXFContext {
- @ConditionalOnMissingBean
@Bean
public ThreadPoolTaskExecutor batchExecutor(final RESTProperties props) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
@@ -480,6 +480,7 @@ public class IdRepoRESTCXFContext {
public SyncopeService syncopeService(
final Bus bus,
final SyncopeLogic syncopeLogic,
+ @Qualifier("batchExecutor")
final ThreadPoolTaskExecutor batchExecutor,
final BatchDAO batchDAO,
final EntityFactory entityFactory) {
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
index 0fea24cc55..fd94f32420 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
@@ -50,6 +50,4 @@ public interface ImplementationLookup extends SyncopeCoreLoader {
Class<? extends PushCorrelationRule> getPushCorrelationRuleClass(
Class<? extends PushCorrelationRuleConf> pushCorrelationRuleConfClass);
-
- Set<Class<?>> getAuditAppenderClasses();
}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditConfDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditConfDAO.java
index 96d215838e..4e060e5499 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditConfDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditConfDAO.java
@@ -49,11 +49,11 @@ public interface AuditConfDAO extends DAO<AuditConf> {
List<AuditEntry> searchEntries(
String entityKey,
int page,
- int size,
+ int itemsPerPage,
AuditElements.EventCategoryType type,
String category,
String subcategory,
List<String> events,
AuditElements.Result result,
- List<OrderByClause> orderByClauses);
+ List<OrderByClause> orderBy);
}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditConfDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditConfDAO.java
index 6384a3df73..2f68b4cf2d 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditConfDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditConfDAO.java
@@ -165,7 +165,7 @@ public class JPAAuditConfDAO extends AbstractDAO<AuditConf> implements AuditConf
final String subcategory,
final List<String> events,
final AuditElements.Result result,
- final List<OrderByClause> orderByClauses) {
+ final List<OrderByClause> orderBy) {
String queryString = "SELECT " + select()
+ " FROM " + AUDIT_ENTRY_TABLE
@@ -176,9 +176,9 @@ public class JPAAuditConfDAO extends AbstractDAO<AuditConf> implements AuditConf
result(result).
events(events).
build();
- if (!orderByClauses.isEmpty()) {
- queryString += " ORDER BY " + orderByClauses.stream().
- map(orderBy -> orderBy.getField() + ' ' + orderBy.getDirection().name()).
+ if (!orderBy.isEmpty()) {
+ queryString += " ORDER BY " + orderBy.stream().
+ map(clause -> clause.getField() + ' ' + clause.getDirection().name()).
collect(Collectors.joining(","));
}
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyImplementationLookup.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyImplementationLookup.java
index 9ccb135da8..9118e68517 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyImplementationLookup.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyImplementationLookup.java
@@ -86,9 +86,4 @@ public class DummyImplementationLookup implements ImplementationLookup {
return DefaultPushCorrelationRule.class;
}
-
- @Override
- public Set<Class<?>> getAuditAppenderClasses() {
- return Set.of();
- }
}
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/serialization/POJOHelper.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/serialization/POJOHelper.java
index 963ee27de5..3f019807e9 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/serialization/POJOHelper.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/serialization/POJOHelper.java
@@ -107,6 +107,18 @@ public final class POJOHelper {
return result;
}
+
+ public static <T extends Object> T convertValue(final Object value, final Class<T> reference) {
+ T result = null;
+
+ try {
+ result = MAPPER.convertValue(value, reference);
+ } catch (Exception e) {
+ LOG.error("During conversion", e);
+ }
+
+ return result;
+ }
private POJOHelper() {
}
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 e63bba1ba2..80c43b0931 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
@@ -20,6 +20,7 @@ package org.apache.syncope.core.provisioning.java;
import java.time.OffsetDateTime;
import java.util.Arrays;
+import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.syncope.common.lib.audit.AuditEntry;
@@ -139,12 +140,12 @@ public class DefaultAuditManager implements AuditManager {
AuditLoggerName auditLoggerName = new AuditLoggerName(type, category, subcategory, event, condition);
- AuditConf audit = auditConfDAO.find(auditLoggerName.toAuditKey());
- if (audit != null && audit.isActive()) {
- Throwable throwable = null;
- if (output instanceof Throwable) {
- throwable = (Throwable) output;
- }
+ Optional.ofNullable(auditConfDAO.find(auditLoggerName.toAuditKey())).
+ filter(AuditConf::isActive).ifPresent(audit -> {
+
+ Throwable throwable = output instanceof Throwable
+ ? (Throwable) output
+ : null;
AuditEntry auditEntry = new AuditEntry();
auditEntry.setWho(who);
@@ -176,6 +177,6 @@ public class DefaultAuditManager implements AuditManager {
logger.debug(serializedAuditEntry, throwable);
eventLogger.debug(serializedAuditEntry, throwable);
}
- }
+ });
}
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
index 96cebfa701..02b992f1c5 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
@@ -646,8 +646,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
action.after(taskInfo, exec, afterObj);
}
// SYNCOPE-1136
- String anyTypeKind = Optional.ofNullable(taskInfo.getAnyTypeKind()).
- map(Enum::name).orElse("realm");
+ String anyTypeKind = Optional.ofNullable(taskInfo.getAnyTypeKind()).map(Enum::name).orElse("realm");
String operation = taskInfo.getOperation().name().toLowerCase();
boolean notificationsAvailable = notificationManager.notificationsAvailable(
AuditElements.EventCategoryType.PROPAGATION, anyTypeKind, taskInfo.getResource().getKey(), operation);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java
index 815fd934ea..2352263384 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java
@@ -576,7 +576,7 @@ public class DefaultRealmPullResultHandler
try {
if (!realmDAO.findChildren(realm).isEmpty()) {
- throw SyncopeClientException.build(ClientExceptionType.HasChildren);
+ throw SyncopeClientException.build(ClientExceptionType.RealmContains);
}
Set<String> adminRealms = Set.of(realm.getFullPath());
diff --git a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyImplementationLookup.java b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyImplementationLookup.java
index 44e323a444..ec1f54d72a 100644
--- a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyImplementationLookup.java
+++ b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyImplementationLookup.java
@@ -86,9 +86,4 @@ public class DummyImplementationLookup implements ImplementationLookup {
return DefaultPushCorrelationRule.class;
}
-
- @Override
- public Set<Class<?>> getAuditAppenderClasses() {
- return Set.of();
- }
}
diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/security/DummyImplementationLookup.java b/core/spring/src/test/java/org/apache/syncope/core/spring/security/DummyImplementationLookup.java
index e997809352..019430e81e 100644
--- a/core/spring/src/test/java/org/apache/syncope/core/spring/security/DummyImplementationLookup.java
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/security/DummyImplementationLookup.java
@@ -82,9 +82,4 @@ public class DummyImplementationLookup implements ImplementationLookup {
return null;
}
-
- @Override
- public Set<Class<?>> getAuditAppenderClasses() {
- return Set.of();
- }
}
diff --git a/core/starter/src/main/java/org/apache/syncope/core/starter/SyncopeCoreApplication.java b/core/starter/src/main/java/org/apache/syncope/core/starter/SyncopeCoreApplication.java
index 8e9db02976..90aaa28943 100644
--- a/core/starter/src/main/java/org/apache/syncope/core/starter/SyncopeCoreApplication.java
+++ b/core/starter/src/main/java/org/apache/syncope/core/starter/SyncopeCoreApplication.java
@@ -21,50 +21,29 @@ package org.apache.syncope.core.starter;
import java.util.Map;
import org.apache.cxf.spring.boot.autoconfigure.openapi.OpenApiAutoConfiguration;
import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
-import org.apache.syncope.common.keymaster.client.api.ServiceOps;
import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStop;
import org.apache.syncope.common.lib.info.SystemInfo;
-import org.apache.syncope.core.logic.LogicProperties;
import org.apache.syncope.core.persistence.api.DomainHolder;
import org.apache.syncope.core.persistence.api.ImplementationLookup;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
-import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
import org.apache.syncope.core.persistence.api.dao.EntityCacheDAO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.NotificationDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
import org.apache.syncope.core.persistence.api.dao.RoleDAO;
import org.apache.syncope.core.persistence.api.dao.SecurityQuestionDAO;
import org.apache.syncope.core.persistence.api.dao.TaskDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
-import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.jpa.PersistenceProperties;
-import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager;
-import org.apache.syncope.core.provisioning.api.AuditManager;
import org.apache.syncope.core.provisioning.api.ConnIdBundleManager;
-import org.apache.syncope.core.provisioning.api.GroupProvisioningManager;
-import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
-import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
-import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
-import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
-import org.apache.syncope.core.provisioning.java.ProvisioningProperties;
-import org.apache.syncope.core.spring.security.PasswordGenerator;
-import org.apache.syncope.core.spring.security.SecurityProperties;
import org.apache.syncope.core.starter.actuate.DefaultSyncopeCoreInfoContributor;
import org.apache.syncope.core.starter.actuate.DomainsHealthIndicator;
import org.apache.syncope.core.starter.actuate.EntityCacheEndpoint;
import org.apache.syncope.core.starter.actuate.ExternalResourcesHealthIndicator;
import org.apache.syncope.core.starter.actuate.SyncopeCoreInfoContributor;
-import org.apache.syncope.core.workflow.api.AnyObjectWorkflowAdapter;
-import org.apache.syncope.core.workflow.api.GroupWorkflowAdapter;
-import org.apache.syncope.core.workflow.api.UserWorkflowAdapter;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.mail.MailHealthIndicator;
@@ -80,6 +59,7 @@ import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguratio
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.PayloadApplicationEvent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.EventListener;
@@ -134,85 +114,40 @@ public class SyncopeCoreApplication extends SpringBootServletInitializer {
@ConditionalOnMissingBean
@Bean
public SyncopeCoreInfoContributor syncopeCoreInfoContributor(
- final SecurityProperties securityProperties,
- final PersistenceProperties persistenceProperties,
- final ProvisioningProperties provisioningProperties,
- final LogicProperties logicProperties,
final AnyTypeDAO anyTypeDAO,
final AnyTypeClassDAO anyTypeClassDAO,
+ final ExternalResourceDAO resourceDAO,
final UserDAO userDAO,
final GroupDAO groupDAO,
final AnyObjectDAO anyObjectDAO,
- final ExternalResourceDAO resourceDAO,
- final ConfParamOps confParamOps,
- final ServiceOps serviceOps,
- final ConnIdBundleManager bundleManager,
- final PropagationTaskExecutor propagationTaskExecutor,
- final AnyObjectWorkflowAdapter awfAdapter,
- final UserWorkflowAdapter uwfAdapter,
- final GroupWorkflowAdapter gwfAdapter,
- final AnyObjectProvisioningManager aProvisioningManager,
- final UserProvisioningManager uProvisioningManager,
- final GroupProvisioningManager gProvisioningManager,
- final VirAttrCache virAttrCache,
- final NotificationManager notificationManager,
- final AuditManager auditManager,
- final PasswordGenerator passwordGenerator,
- final EntityFactory entityFactory,
- final PlainSchemaDAO plainSchemaDAO,
- final PlainAttrDAO plainAttrDAO,
- final PlainAttrValueDAO plainAttrValueDAO,
- final AnySearchDAO anySearchDAO,
- final ImplementationLookup implLookup,
+ final RoleDAO roleDAO,
final PolicyDAO policyDAO,
final NotificationDAO notificationDAO,
final TaskDAO taskDAO,
final VirSchemaDAO virSchemaDAO,
- final RoleDAO roleDAO,
final SecurityQuestionDAO securityQuestionDAO,
- @Qualifier("asyncConnectorFacadeExecutor")
- final ThreadPoolTaskExecutor asyncConnectorFacadeExecutor,
- @Qualifier("propagationTaskExecutorAsyncExecutor")
- final ThreadPoolTaskExecutor propagationTaskExecutorAsyncExecutor) {
+ final ConfParamOps confParamOps,
+ final ConnIdBundleManager bundleManager,
+ final ImplementationLookup implLookup,
+ final ApplicationContext ctx) {
- return new DefaultSyncopeCoreInfoContributor(securityProperties,
- persistenceProperties,
- provisioningProperties,
- logicProperties,
+ return new DefaultSyncopeCoreInfoContributor(
anyTypeDAO,
anyTypeClassDAO,
+ resourceDAO,
userDAO,
groupDAO,
anyObjectDAO,
- resourceDAO,
- confParamOps,
- serviceOps,
- bundleManager,
- propagationTaskExecutor,
- awfAdapter,
- uwfAdapter,
- gwfAdapter,
- aProvisioningManager,
- uProvisioningManager,
- gProvisioningManager,
- virAttrCache,
- notificationManager,
- auditManager,
- passwordGenerator,
- entityFactory,
- plainSchemaDAO,
- plainAttrDAO,
- plainAttrValueDAO,
- anySearchDAO,
- implLookup,
+ roleDAO,
policyDAO,
notificationDAO,
taskDAO,
virSchemaDAO,
- roleDAO,
securityQuestionDAO,
- asyncConnectorFacadeExecutor,
- propagationTaskExecutorAsyncExecutor);
+ confParamOps,
+ bundleManager,
+ implLookup,
+ ctx.getBeansOfType(ThreadPoolTaskExecutor.class));
}
@ConditionalOnMissingBean
diff --git a/core/starter/src/main/java/org/apache/syncope/core/starter/actuate/DefaultSyncopeCoreInfoContributor.java b/core/starter/src/main/java/org/apache/syncope/core/starter/actuate/DefaultSyncopeCoreInfoContributor.java
index 5c27b103e2..5b869e0183 100644
--- a/core/starter/src/main/java/org/apache/syncope/core/starter/actuate/DefaultSyncopeCoreInfoContributor.java
+++ b/core/starter/src/main/java/org/apache/syncope/core/starter/actuate/DefaultSyncopeCoreInfoContributor.java
@@ -31,7 +31,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
-import org.apache.syncope.common.keymaster.client.api.ServiceOps;
import org.apache.syncope.common.lib.info.JavaImplInfo;
import org.apache.syncope.common.lib.info.NumbersInfo;
import org.apache.syncope.common.lib.info.PlatformInfo;
@@ -39,18 +38,13 @@ import org.apache.syncope.common.lib.info.SystemInfo;
import org.apache.syncope.common.lib.types.EntitlementsHolder;
import org.apache.syncope.common.lib.types.ImplementationTypesHolder;
import org.apache.syncope.common.lib.types.TaskType;
-import org.apache.syncope.core.logic.LogicProperties;
import org.apache.syncope.core.persistence.api.ImplementationLookup;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
-import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.NotificationDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
import org.apache.syncope.core.persistence.api.dao.RoleDAO;
import org.apache.syncope.core.persistence.api.dao.SecurityQuestionDAO;
@@ -59,29 +53,13 @@ import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
import org.apache.syncope.core.persistence.api.entity.AnyType;
import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
-import org.apache.syncope.core.persistence.api.entity.EntityFactory;
import org.apache.syncope.core.persistence.api.entity.ExternalResource;
import org.apache.syncope.core.persistence.api.entity.policy.AccountPolicy;
import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
-import org.apache.syncope.core.persistence.jpa.PersistenceProperties;
-import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager;
-import org.apache.syncope.core.provisioning.api.AuditManager;
import org.apache.syncope.core.provisioning.api.ConnIdBundleManager;
-import org.apache.syncope.core.provisioning.api.GroupProvisioningManager;
-import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
-import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
-import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
-import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
-import org.apache.syncope.core.provisioning.java.ProvisioningProperties;
import org.apache.syncope.core.spring.security.AuthContextUtils;
-import org.apache.syncope.core.spring.security.PasswordGenerator;
-import org.apache.syncope.core.spring.security.SecurityProperties;
-import org.apache.syncope.core.workflow.api.AnyObjectWorkflowAdapter;
-import org.apache.syncope.core.workflow.api.GroupWorkflowAdapter;
-import org.apache.syncope.core.workflow.api.UserWorkflowAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.aop.support.AopUtils;
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.context.PayloadApplicationEvent;
@@ -105,30 +83,34 @@ public class DefaultSyncopeCoreInfoContributor implements SyncopeCoreInfoContrib
+ "queued tasks = ([0-9]+), "
+ "completed tasks = ([0-9]+).*");
- protected static void setTaskExecutorInfo(final String toString, final NumbersInfo.TaskExecutorInfo info) {
+ protected static NumbersInfo.TaskExecutorInfo getTaskExecutorInfo(final String toString) {
+ NumbersInfo.TaskExecutorInfo info = new NumbersInfo.TaskExecutorInfo();
+
Matcher matcher = THREADPOOLTASKEXECUTOR_PATTERN.matcher(toString);
if (matcher.matches() && matcher.groupCount() == 4) {
try {
- info.setSize(Integer.valueOf(matcher.group(1)));
+ info.setSize(Integer.parseInt(matcher.group(1)));
} catch (NumberFormatException e) {
LOG.error("While parsing thread pool size", e);
}
try {
- info.setActive(Integer.valueOf(matcher.group(2)));
+ info.setActive(Integer.parseInt(matcher.group(2)));
} catch (NumberFormatException e) {
LOG.error("While parsing active threads #", e);
}
try {
- info.setQueued(Integer.valueOf(matcher.group(3)));
+ info.setQueued(Integer.parseInt(matcher.group(3)));
} catch (NumberFormatException e) {
LOG.error("While parsing queued threads #", e);
}
try {
- info.setCompleted(Integer.valueOf(matcher.group(4)));
+ info.setCompleted(Integer.parseInt(matcher.group(4)));
} catch (NumberFormatException e) {
LOG.error("While parsing completed threads #", e);
}
}
+
+ return info;
}
protected static void initSystemInfo() {
@@ -155,160 +137,72 @@ public class DefaultSyncopeCoreInfoContributor implements SyncopeCoreInfoContrib
}
}
- private final SecurityProperties securityProperties;
-
- private final PersistenceProperties persistenceProperties;
-
- private final ProvisioningProperties provisioningProperties;
-
- private final LogicProperties logicProperties;
-
- private final AnyTypeDAO anyTypeDAO;
-
- private final AnyTypeClassDAO anyTypeClassDAO;
-
- private final UserDAO userDAO;
-
- private final GroupDAO groupDAO;
-
- private final AnyObjectDAO anyObjectDAO;
-
- private final ExternalResourceDAO resourceDAO;
-
- private final ConfParamOps confParamOps;
-
- private final ServiceOps serviceOps;
-
- private final ConnIdBundleManager bundleManager;
-
- private final PropagationTaskExecutor propagationTaskExecutor;
-
- private final AnyObjectWorkflowAdapter awfAdapter;
-
- private final UserWorkflowAdapter uwfAdapter;
-
- private final GroupWorkflowAdapter gwfAdapter;
-
- private final AnyObjectProvisioningManager aProvisioningManager;
-
- private final UserProvisioningManager uProvisioningManager;
-
- private final GroupProvisioningManager gProvisioningManager;
-
- private final VirAttrCache virAttrCache;
-
- private final NotificationManager notificationManager;
+ protected final AnyTypeDAO anyTypeDAO;
- private final AuditManager auditManager;
+ protected final AnyTypeClassDAO anyTypeClassDAO;
- private final PasswordGenerator passwordGenerator;
+ protected final ExternalResourceDAO resourceDAO;
- private final EntityFactory entityFactory;
+ protected final UserDAO userDAO;
- private final PlainSchemaDAO plainSchemaDAO;
+ protected final GroupDAO groupDAO;
- private final PlainAttrDAO plainAttrDAO;
+ protected final AnyObjectDAO anyObjectDAO;
- private final PlainAttrValueDAO plainAttrValueDAO;
+ protected final RoleDAO roleDAO;
- private final AnySearchDAO anySearchDAO;
+ protected final PolicyDAO policyDAO;
- private final ImplementationLookup implLookup;
+ protected final TaskDAO taskDAO;
- private final PolicyDAO policyDAO;
+ protected final VirSchemaDAO virSchemaDAO;
- private final NotificationDAO notificationDAO;
+ protected final SecurityQuestionDAO securityQuestionDAO;
- private final TaskDAO taskDAO;
+ protected final NotificationDAO notificationDAO;
- private final VirSchemaDAO virSchemaDAO;
+ protected final ConfParamOps confParamOps;
- private final RoleDAO roleDAO;
+ protected final ConnIdBundleManager bundleManager;
- private final SecurityQuestionDAO securityQuestionDAO;
+ protected final ImplementationLookup implLookup;
- private final ThreadPoolTaskExecutor asyncConnectorFacadeExecutor;
-
- private final ThreadPoolTaskExecutor propagationTaskExecutorAsyncExecutor;
+ protected final Map<String, ThreadPoolTaskExecutor> taskExecutors;
public DefaultSyncopeCoreInfoContributor(
- final SecurityProperties securityProperties,
- final PersistenceProperties persistenceProperties,
- final ProvisioningProperties provisioningProperties,
- final LogicProperties logicProperties,
final AnyTypeDAO anyTypeDAO,
final AnyTypeClassDAO anyTypeClassDAO,
+ final ExternalResourceDAO resourceDAO,
final UserDAO userDAO,
final GroupDAO groupDAO,
final AnyObjectDAO anyObjectDAO,
- final ExternalResourceDAO resourceDAO,
- final ConfParamOps confParamOps,
- final ServiceOps serviceOps,
- final ConnIdBundleManager bundleManager,
- final PropagationTaskExecutor propagationTaskExecutor,
- final AnyObjectWorkflowAdapter awfAdapter,
- final UserWorkflowAdapter uwfAdapter,
- final GroupWorkflowAdapter gwfAdapter,
- final AnyObjectProvisioningManager aProvisioningManager,
- final UserProvisioningManager uProvisioningManager,
- final GroupProvisioningManager gProvisioningManager,
- final VirAttrCache virAttrCache,
- final NotificationManager notificationManager,
- final AuditManager auditManager,
- final PasswordGenerator passwordGenerator,
- final EntityFactory entityFactory,
- final PlainSchemaDAO plainSchemaDAO,
- final PlainAttrDAO plainAttrDAO,
- final PlainAttrValueDAO plainAttrValueDAO,
- final AnySearchDAO anySearchDAO,
- final ImplementationLookup implLookup,
+ final RoleDAO roleDAO,
final PolicyDAO policyDAO,
final NotificationDAO notificationDAO,
final TaskDAO taskDAO,
final VirSchemaDAO virSchemaDAO,
- final RoleDAO roleDAO,
final SecurityQuestionDAO securityQuestionDAO,
- final ThreadPoolTaskExecutor asyncConnectorFacadeExecutor,
- final ThreadPoolTaskExecutor propagationTaskExecutorAsyncExecutor) {
+ final ConfParamOps confParamOps,
+ final ConnIdBundleManager bundleManager,
+ final ImplementationLookup implLookup,
+ final Map<String, ThreadPoolTaskExecutor> taskExecutors) {
- this.securityProperties = securityProperties;
- this.persistenceProperties = persistenceProperties;
- this.provisioningProperties = provisioningProperties;
- this.logicProperties = logicProperties;
this.anyTypeDAO = anyTypeDAO;
this.anyTypeClassDAO = anyTypeClassDAO;
+ this.resourceDAO = resourceDAO;
this.userDAO = userDAO;
this.groupDAO = groupDAO;
this.anyObjectDAO = anyObjectDAO;
- this.resourceDAO = resourceDAO;
- this.confParamOps = confParamOps;
- this.serviceOps = serviceOps;
- this.bundleManager = bundleManager;
- this.propagationTaskExecutor = propagationTaskExecutor;
- this.awfAdapter = awfAdapter;
- this.uwfAdapter = uwfAdapter;
- this.gwfAdapter = gwfAdapter;
- this.aProvisioningManager = aProvisioningManager;
- this.uProvisioningManager = uProvisioningManager;
- this.gProvisioningManager = gProvisioningManager;
- this.virAttrCache = virAttrCache;
- this.notificationManager = notificationManager;
- this.auditManager = auditManager;
- this.passwordGenerator = passwordGenerator;
- this.entityFactory = entityFactory;
- this.plainSchemaDAO = plainSchemaDAO;
- this.plainAttrDAO = plainAttrDAO;
- this.plainAttrValueDAO = plainAttrValueDAO;
- this.anySearchDAO = anySearchDAO;
- this.implLookup = implLookup;
+ this.roleDAO = roleDAO;
this.policyDAO = policyDAO;
this.notificationDAO = notificationDAO;
this.taskDAO = taskDAO;
this.virSchemaDAO = virSchemaDAO;
- this.roleDAO = roleDAO;
this.securityQuestionDAO = securityQuestionDAO;
- this.asyncConnectorFacadeExecutor = asyncConnectorFacadeExecutor;
- this.propagationTaskExecutorAsyncExecutor = propagationTaskExecutorAsyncExecutor;
+ this.confParamOps = confParamOps;
+ this.bundleManager = bundleManager;
+ this.implLookup = implLookup;
+ this.taskExecutors = taskExecutors;
}
protected boolean isSelfRegAllowed() {
@@ -327,53 +221,10 @@ public class DefaultSyncopeCoreInfoContributor implements SyncopeCoreInfoContrib
synchronized (this) {
if (PLATFORM_INFO == null) {
PLATFORM_INFO = new PlatformInfo();
- PLATFORM_INFO.setKeymasterConfParamOps(AopUtils.getTargetClass(confParamOps).getName());
- PLATFORM_INFO.setKeymasterServiceOps(AopUtils.getTargetClass(serviceOps).getName());
PLATFORM_INFO.getConnIdLocations().addAll(bundleManager.getLocations().stream().
map(URI::toASCIIString).collect(Collectors.toList()));
- PLATFORM_INFO.getWorkflowInfo().
- setAnyObjectWorkflowAdapter(AopUtils.getTargetClass(awfAdapter).getName());
- PLATFORM_INFO.getWorkflowInfo().
- setUserWorkflowAdapter(AopUtils.getTargetClass(uwfAdapter).getName());
- PLATFORM_INFO.getWorkflowInfo().
- setGroupWorkflowAdapter(AopUtils.getTargetClass(gwfAdapter).getName());
-
- PLATFORM_INFO.getProvisioningInfo().
- setAnyObjectProvisioningManager(AopUtils.getTargetClass(aProvisioningManager).getName());
- PLATFORM_INFO.getProvisioningInfo().
- setUserProvisioningManager(AopUtils.getTargetClass(uProvisioningManager).getName());
- PLATFORM_INFO.getProvisioningInfo().
- setGroupProvisioningManager(AopUtils.getTargetClass(gProvisioningManager).getName());
- PLATFORM_INFO.getProvisioningInfo().
- setPropagationTaskExecutor(AopUtils.getTargetClass(propagationTaskExecutor).getName());
- PLATFORM_INFO.getProvisioningInfo().
- setVirAttrCache(AopUtils.getTargetClass(virAttrCache).getName());
- PLATFORM_INFO.getProvisioningInfo().
- setNotificationManager(AopUtils.getTargetClass(notificationManager).getName());
- PLATFORM_INFO.getProvisioningInfo().
- setAuditManager(AopUtils.getTargetClass(auditManager).getName());
-
- PLATFORM_INFO.setPasswordGenerator(AopUtils.getTargetClass(passwordGenerator).getName());
-
- PLATFORM_INFO.getPersistenceInfo().
- setEntityFactory(AopUtils.getTargetClass(entityFactory).getName());
- PLATFORM_INFO.getPersistenceInfo().
- setPlainSchemaDAO(AopUtils.getTargetClass(plainSchemaDAO).getName());
- PLATFORM_INFO.getPersistenceInfo().
- setPlainAttrDAO(AopUtils.getTargetClass(plainAttrDAO).getName());
- PLATFORM_INFO.getPersistenceInfo().
- setPlainAttrValueDAO(AopUtils.getTargetClass(plainAttrValueDAO).getName());
- PLATFORM_INFO.getPersistenceInfo().
- setAnySearchDAO(AopUtils.getTargetClass(anySearchDAO).getName());
- PLATFORM_INFO.getPersistenceInfo().
- setUserDAO(AopUtils.getTargetClass(userDAO).getName());
- PLATFORM_INFO.getPersistenceInfo().
- setGroupDAO(AopUtils.getTargetClass(groupDAO).getName());
- PLATFORM_INFO.getPersistenceInfo().
- setAnyObjectDAO(AopUtils.getTargetClass(anyObjectDAO).getName());
-
ImplementationTypesHolder.getInstance().getValues().forEach((typeName, typeInterface) -> {
Set<String> classNames = implLookup.getClassNames(typeName);
if (classNames != null) {
@@ -467,12 +318,8 @@ public class DefaultSyncopeCoreInfoContributor implements SyncopeCoreInfoContrib
numbersInfo.getConfCompleteness().put(
NumbersInfo.ConfItem.ROLE.name(), numbersInfo.getTotalRoles() > 0);
- setTaskExecutorInfo(
- asyncConnectorFacadeExecutor.getThreadPoolExecutor().toString(),
- numbersInfo.getAsyncConnectorExecutor());
- setTaskExecutorInfo(
- propagationTaskExecutorAsyncExecutor.getThreadPoolExecutor().toString(),
- numbersInfo.getPropagationTaskExecutor());
+ taskExecutors.forEach((name, bean) -> numbersInfo.getTaskExecutorInfos().
+ put(name, getTaskExecutorInfo(bean.getThreadPoolExecutor().toString())));
return numbersInfo;
}
@@ -494,11 +341,6 @@ public class DefaultSyncopeCoreInfoContributor implements SyncopeCoreInfoContrib
buildSystem();
builder.withDetail("system", SYSTEM_INFO);
-
- builder.withDetail("securityProperties", securityProperties);
- builder.withDetail("persistenceProperties", persistenceProperties);
- builder.withDetail("provisioningProperties", provisioningProperties);
- builder.withDetail("logicProperties", logicProperties);
}
@Override
diff --git a/core/starter/src/main/resources/core.properties b/core/starter/src/main/resources/core.properties
index bee222e60d..19b4ffaa7c 100644
--- a/core/starter/src/main/resources/core.properties
+++ b/core/starter/src/main/resources/core.properties
@@ -109,12 +109,6 @@ security.digester.invertPositionOfPlainSaltInEncryptionResults=true
security.digester.invertPositionOfSaltInMessageBeforeDigesting=true
security.digester.useLenientSaltSizeCheck=true
-#########
-# Logic #
-#########
-
-logic.enableJDBCAuditAppender=true
-
#########
# Disable CGLib Proxies #
#########
diff --git a/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchClientContext.java b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchClientContext.java
index babd0d784e..1995c1bf82 100644
--- a/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchClientContext.java
+++ b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchClientContext.java
@@ -25,18 +25,20 @@ import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
+@EnableConfigurationProperties(ElasticsearchProperties.class)
@Configuration(proxyBeanMethods = false)
public class ElasticsearchClientContext {
@ConditionalOnMissingBean
@Bean
- public ElasticsearchClientFactoryBean elasticsearchClientFactoryBean() {
+ public ElasticsearchClientFactoryBean elasticsearchClientFactoryBean(final ElasticsearchProperties props) {
return new ElasticsearchClientFactoryBean(
- List.of(new HttpHost("localhost", 9200, "http")));
+ List.of(new HttpHost(props.getHostname(), props.getPort(), props.getScheme())));
}
@ConditionalOnMissingBean
@@ -46,20 +48,26 @@ public class ElasticsearchClientContext {
final @Lazy GroupDAO groupDAO,
final @Lazy AnyObjectDAO anyObjectDAO) {
- ElasticsearchUtils utils = new ElasticsearchUtils(userDAO, groupDAO, anyObjectDAO);
- utils.setIndexMaxResultWindow(10000);
- utils.setRetryOnConflict(5);
- utils.setNumberOfShards(1);
- utils.setNumberOfReplicas(1);
- return utils;
+ return new ElasticsearchUtils(userDAO, groupDAO, anyObjectDAO);
}
@ConditionalOnMissingBean
@Bean
public ElasticsearchIndexManager elasticsearchIndexManager(
+ final ElasticsearchProperties props,
final ElasticsearchClient client,
final ElasticsearchUtils elasticsearchUtils) {
- return new ElasticsearchIndexManager(client, elasticsearchUtils);
+ return new ElasticsearchIndexManager(
+ client,
+ elasticsearchUtils,
+ props.getNumberOfShards(),
+ props.getNumberOfReplicas());
+ }
+
+ @ConditionalOnMissingBean
+ @Bean
+ public ElasticsearchIndexLoader elasticsearchIndexLoader(final ElasticsearchIndexManager indexManager) {
+ return new ElasticsearchIndexLoader(indexManager);
}
}
diff --git a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/DomainIndexLoader.java b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchIndexLoader.java
similarity index 61%
rename from ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/DomainIndexLoader.java
rename to ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchIndexLoader.java
index b2595be40e..c3fe69d34d 100644
--- a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/DomainIndexLoader.java
+++ b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchIndexLoader.java
@@ -16,23 +16,22 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.core.persistence.jpa;
+package org.apache.syncope.ext.elasticsearch.client;
import javax.sql.DataSource;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.SyncopeCoreLoader;
-import org.apache.syncope.ext.elasticsearch.client.ElasticsearchIndexManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
-public class DomainIndexLoader implements SyncopeCoreLoader {
+public class ElasticsearchIndexLoader implements SyncopeCoreLoader {
- protected static final Logger LOG = LoggerFactory.getLogger(DomainIndexLoader.class);
+ protected static final Logger LOG = LoggerFactory.getLogger(ElasticsearchIndexLoader.class);
protected final ElasticsearchIndexManager indexManager;
- public DomainIndexLoader(final ElasticsearchIndexManager indexManager) {
+ public ElasticsearchIndexLoader(final ElasticsearchIndexManager indexManager) {
this.indexManager = indexManager;
}
@@ -44,20 +43,25 @@ public class DomainIndexLoader implements SyncopeCoreLoader {
@Override
public void load(final String domain, final DataSource datasource) {
try {
- if (!indexManager.existsIndex(domain, AnyTypeKind.USER)) {
- indexManager.createIndex(domain, AnyTypeKind.USER,
- indexManager.defaultSettings(), indexManager.defaultMapping());
+ if (!indexManager.existsAnyIndex(domain, AnyTypeKind.USER)) {
+ indexManager.createAnyIndex(domain, AnyTypeKind.USER,
+ indexManager.defaultSettings(), indexManager.defaultAnyMapping());
}
- if (!indexManager.existsIndex(domain, AnyTypeKind.GROUP)) {
- indexManager.createIndex(domain, AnyTypeKind.GROUP,
- indexManager.defaultSettings(), indexManager.defaultMapping());
+ if (!indexManager.existsAnyIndex(domain, AnyTypeKind.GROUP)) {
+ indexManager.createAnyIndex(domain, AnyTypeKind.GROUP,
+ indexManager.defaultSettings(), indexManager.defaultAnyMapping());
}
- if (!indexManager.existsIndex(domain, AnyTypeKind.ANY_OBJECT)) {
- indexManager.createIndex(domain, AnyTypeKind.ANY_OBJECT,
- indexManager.defaultSettings(), indexManager.defaultMapping());
+ if (!indexManager.existsAnyIndex(domain, AnyTypeKind.ANY_OBJECT)) {
+ indexManager.createAnyIndex(domain, AnyTypeKind.ANY_OBJECT,
+ indexManager.defaultSettings(), indexManager.defaultAnyMapping());
+ }
+
+ if (!indexManager.existsAuditIndex(domain)) {
+ indexManager.createAuditIndex(domain,
+ indexManager.defaultSettings(), indexManager.defaultAuditMapping());
}
} catch (Exception e) {
- LOG.error("While creating index for domain {}", domain, e);
+ LOG.error("While creating indexes for domain {}", domain, e);
}
}
}
diff --git a/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchIndexManager.java b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchIndexManager.java
index 8822a2ab91..1a9bc7ad98 100644
--- a/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchIndexManager.java
+++ b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchIndexManager.java
@@ -24,7 +24,9 @@ import co.elastic.clients.elasticsearch._types.analysis.CustomNormalizer;
import co.elastic.clients.elasticsearch._types.analysis.Normalizer;
import co.elastic.clients.elasticsearch._types.mapping.DynamicTemplate;
import co.elastic.clients.elasticsearch._types.mapping.KeywordProperty;
+import co.elastic.clients.elasticsearch._types.mapping.ObjectProperty;
import co.elastic.clients.elasticsearch._types.mapping.Property;
+import co.elastic.clients.elasticsearch._types.mapping.TextProperty;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch.core.DeleteRequest;
import co.elastic.clients.elasticsearch.core.DeleteResponse;
@@ -34,14 +36,17 @@ import co.elastic.clients.elasticsearch.indices.CreateIndexRequest;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.DeleteIndexRequest;
import co.elastic.clients.elasticsearch.indices.DeleteIndexResponse;
+import co.elastic.clients.elasticsearch.indices.ExistsRequest;
import co.elastic.clients.elasticsearch.indices.IndexSettings;
import co.elastic.clients.elasticsearch.indices.IndexSettingsAnalysis;
+import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.provisioning.api.event.AnyLifecycleEvent;
+import org.apache.syncope.core.spring.security.SecureRandomUtils;
import org.identityconnectors.framework.common.objects.SyncDeltaType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,18 +63,31 @@ public class ElasticsearchIndexManager {
protected final ElasticsearchUtils elasticsearchUtils;
+ protected final String numberOfShards;
+
+ protected final String numberOfReplicas;
+
public ElasticsearchIndexManager(
final ElasticsearchClient client,
- final ElasticsearchUtils elasticsearchUtils) {
+ final ElasticsearchUtils elasticsearchUtils,
+ final String numberOfShards,
+ final String numberOfReplicas) {
this.client = client;
this.elasticsearchUtils = elasticsearchUtils;
+ this.numberOfShards = numberOfShards;
+ this.numberOfReplicas = numberOfReplicas;
}
- public boolean existsIndex(final String domain, final AnyTypeKind kind) throws IOException {
- return client.indices().exists(
- new co.elastic.clients.elasticsearch.indices.ExistsRequest.Builder().
- index(ElasticsearchUtils.getContextDomainName(domain, kind)).build()).
+ public boolean existsAnyIndex(final String domain, final AnyTypeKind kind) throws IOException {
+ return client.indices().exists(new ExistsRequest.Builder().
+ index(ElasticsearchUtils.getAnyIndex(domain, kind)).build()).
+ value();
+ }
+
+ public boolean existsAuditIndex(final String domain) throws IOException {
+ return client.indices().exists(new ExistsRequest.Builder().
+ index(ElasticsearchUtils.getAuditIndex(domain)).build()).
value();
}
@@ -83,12 +101,12 @@ public class ElasticsearchIndexManager {
build()).
build()).
build()).
- numberOfShards(elasticsearchUtils.getNumberOfShards()).
- numberOfReplicas(elasticsearchUtils.getNumberOfReplicas()).
+ numberOfShards(numberOfShards).
+ numberOfReplicas(numberOfReplicas).
build();
}
- public TypeMapping defaultMapping() throws IOException {
+ public TypeMapping defaultAnyMapping() throws IOException {
return new TypeMapping.Builder().
dynamicTemplates(List.of(Map.of(
"strings",
@@ -101,7 +119,45 @@ public class ElasticsearchIndexManager {
build();
}
- protected CreateIndexResponse doCreateIndex(
+ public TypeMapping defaultAuditMapping() throws IOException {
+ return new TypeMapping.Builder().
+ dynamicTemplates(List.of(Map.of(
+ "strings",
+ new DynamicTemplate.Builder().
+ matchMappingType("string").
+ mapping(new Property.Builder().
+ keyword(new KeywordProperty.Builder().normalizer("string_lowercase").build()).
+ build()).
+ build()))).
+ properties(
+ "message",
+ new Property.Builder().object(new ObjectProperty.Builder().
+ properties(
+ "before",
+ new Property.Builder().
+ text(new TextProperty.Builder().analyzer("standard").build()).
+ build()).
+ properties(
+ "inputs",
+ new Property.Builder().
+ text(new TextProperty.Builder().analyzer("standard").build()).
+ build()).
+ properties(
+ "output",
+ new Property.Builder().
+ text(new TextProperty.Builder().analyzer("standard").build()).
+ build()).
+ properties(
+ "throwable",
+ new Property.Builder().
+ text(new TextProperty.Builder().analyzer("standard").build()).
+ build()).
+ build()).
+ build()).
+ build();
+ }
+
+ protected CreateIndexResponse doCreateAnyIndex(
final String domain,
final AnyTypeKind kind,
final IndexSettings settings,
@@ -109,13 +165,13 @@ public class ElasticsearchIndexManager {
return client.indices().create(
new CreateIndexRequest.Builder().
- index(ElasticsearchUtils.getContextDomainName(domain, kind)).
+ index(ElasticsearchUtils.getAnyIndex(domain, kind)).
settings(settings).
mappings(mappings).
build());
}
- public void createIndex(
+ public void createAnyIndex(
final String domain,
final AnyTypeKind kind,
final IndexSettings settings,
@@ -123,44 +179,79 @@ public class ElasticsearchIndexManager {
throws IOException {
try {
- CreateIndexResponse response = doCreateIndex(domain, kind, settings, mappings);
+ CreateIndexResponse response = doCreateAnyIndex(domain, kind, settings, mappings);
LOG.debug("Successfully created {} for {}: {}",
- ElasticsearchUtils.getContextDomainName(domain, kind), kind.name(), response);
+ ElasticsearchUtils.getAnyIndex(domain, kind), kind.name(), response);
} catch (ElasticsearchException e) {
LOG.debug("Could not create index {} because it already exists",
- ElasticsearchUtils.getContextDomainName(domain, kind), e);
+ ElasticsearchUtils.getAnyIndex(domain, kind), e);
- removeIndex(domain, kind);
- doCreateIndex(domain, kind, settings, mappings);
+ removeAnyIndex(domain, kind);
+ doCreateAnyIndex(domain, kind, settings, mappings);
}
}
- public void removeIndex(final String domain, final AnyTypeKind kind) throws IOException {
+ public void removeAnyIndex(final String domain, final AnyTypeKind kind) throws IOException {
DeleteIndexResponse response = client.indices().delete(
- new DeleteIndexRequest.Builder().index(ElasticsearchUtils.getContextDomainName(domain, kind)).build());
- LOG.debug("Successfully removed {}: {}",
- ElasticsearchUtils.getContextDomainName(domain, kind), response);
+ new DeleteIndexRequest.Builder().index(ElasticsearchUtils.getAnyIndex(domain, kind)).build());
+ LOG.debug("Successfully removed {}: {}", ElasticsearchUtils.getAnyIndex(domain, kind), response);
+ }
+
+ protected CreateIndexResponse doCreateAuditIndex(
+ final String domain,
+ final IndexSettings settings,
+ final TypeMapping mappings) throws IOException {
+
+ return client.indices().create(
+ new CreateIndexRequest.Builder().
+ index(ElasticsearchUtils.getAuditIndex(domain)).
+ settings(settings).
+ mappings(mappings).
+ build());
+ }
+
+ public void createAuditIndex(
+ final String domain,
+ final IndexSettings settings,
+ final TypeMapping mappings)
+ throws IOException {
+
+ try {
+ CreateIndexResponse response = doCreateAuditIndex(domain, settings, mappings);
+
+ LOG.debug("Successfully created audit index {}: {}",
+ ElasticsearchUtils.getAuditIndex(domain), response);
+ } catch (ElasticsearchException e) {
+ LOG.debug("Could not create audit index {} because it already exists",
+ ElasticsearchUtils.getAuditIndex(domain), e);
+
+ removeAuditIndex(domain);
+ doCreateAuditIndex(domain, settings, mappings);
+ }
+ }
+
+ public void removeAuditIndex(final String domain) throws IOException {
+ DeleteIndexResponse response = client.indices().delete(
+ new DeleteIndexRequest.Builder().index(ElasticsearchUtils.getAuditIndex(domain)).build());
+ LOG.debug("Successfully removed {}: {}", ElasticsearchUtils.getAuditIndex(domain), response);
}
@TransactionalEventListener
- public void after(final AnyLifecycleEvent<Any<?>> event) throws IOException {
+ public void any(final AnyLifecycleEvent<Any<?>> event) throws IOException {
LOG.debug("About to {} index for {}", event.getType().name(), event.getAny());
if (event.getType() == SyncDeltaType.DELETE) {
DeleteRequest request = new DeleteRequest.Builder().index(
- ElasticsearchUtils.getContextDomainName(event.getDomain(), event.getAny().getType().getKind())).
+ ElasticsearchUtils.getAnyIndex(event.getDomain(), event.getAny().getType().getKind())).
id(event.getAny().getKey()).
build();
DeleteResponse response = client.delete(request);
LOG.debug("Index successfully deleted for {}[{}]: {}",
event.getAny().getType().getKind(), event.getAny().getKey(), response);
} else {
- String index = ElasticsearchUtils.getContextDomainName(
- event.getDomain(), event.getAny().getType().getKind());
-
IndexRequest<Map<String, Object>> request = new IndexRequest.Builder<Map<String, Object>>().
- index(index).
+ index(ElasticsearchUtils.getAnyIndex(event.getDomain(), event.getAny().getType().getKind())).
id(event.getAny().getKey()).
document(elasticsearchUtils.document(event.getAny(), event.getDomain())).
build();
@@ -168,4 +259,19 @@ public class ElasticsearchIndexManager {
LOG.debug("Index successfully created or updated for {}: {}", event.getAny(), response);
}
}
+
+ public void audit(final String domain, final long instant, final JsonNode message)
+ throws IOException {
+
+ LOG.debug("About to audit");
+
+ IndexRequest<Map<String, Object>> request = new IndexRequest.Builder<Map<String, Object>>().
+ index(ElasticsearchUtils.getAuditIndex(domain)).
+ id(SecureRandomUtils.generateRandomUUID().toString()).
+ document(elasticsearchUtils.document(instant, message, domain)).
+ build();
+ IndexResponse response = client.index(request);
+
+ LOG.debug("Audit successfully created: {}", response);
+ }
}
diff --git a/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchProperties.java b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchProperties.java
new file mode 100644
index 0000000000..4a86dca700
--- /dev/null
+++ b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchProperties.java
@@ -0,0 +1,86 @@
+/*
+ * 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.ext.elasticsearch.client;
+
+import org.apache.http.HttpHost;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties("elasticsearch")
+public class ElasticsearchProperties {
+
+ private String hostname = "localhost";
+
+ private int port = 9200;
+
+ private String scheme = HttpHost.DEFAULT_SCHEME_NAME;
+
+ private int indexMaxResultWindow = 10000;
+
+ private String numberOfShards = "1";
+
+ private String numberOfReplicas = "1";
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(final String hostname) {
+ this.hostname = hostname;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(final int port) {
+ this.port = port;
+ }
+
+ public String getScheme() {
+ return scheme;
+ }
+
+ public void setScheme(final String scheme) {
+ this.scheme = scheme;
+ }
+
+ public int getIndexMaxResultWindow() {
+ return indexMaxResultWindow;
+ }
+
+ public void setIndexMaxResultWindow(final int indexMaxResultWindow) {
+ this.indexMaxResultWindow = indexMaxResultWindow;
+ }
+
+ public String getNumberOfShards() {
+ return numberOfShards;
+ }
+
+ public void setNumberOfShards(final String numberOfShards) {
+ this.numberOfShards = numberOfShards;
+ }
+
+ public String getNumberOfReplicas() {
+ return numberOfReplicas;
+ }
+
+ public void setNumberOfReplicas(final String numberOfReplicas) {
+ this.numberOfReplicas = numberOfReplicas;
+ }
+}
diff --git a/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java
index a95d09162c..7421d0fc26 100644
--- a/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java
+++ b/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchUtils.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.ext.elasticsearch.client;
+import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
@@ -47,62 +48,30 @@ import org.springframework.transaction.annotation.Transactional;
*/
public class ElasticsearchUtils {
- public static String getContextDomainName(final String domain, final AnyTypeKind kind) {
+ public static String getAnyIndex(final String domain, final AnyTypeKind kind) {
return domain.toLowerCase() + '_' + kind.name().toLowerCase();
}
+ public static String getAuditIndex(final String domain) {
+ return domain.toLowerCase() + "_audit";
+ }
+
protected final UserDAO userDAO;
protected final GroupDAO groupDAO;
protected final AnyObjectDAO anyObjectDAO;
- protected int indexMaxResultWindow = 10000;
-
- protected int retryOnConflict = 5;
-
- protected String numberOfShards = "1";
-
- protected String numberOfReplicas = "1";
+ public ElasticsearchUtils(
+ final UserDAO userDAO,
+ final GroupDAO groupDAO,
+ final AnyObjectDAO anyObjectDAO) {
- public ElasticsearchUtils(final UserDAO userDAO, final GroupDAO groupDAO, final AnyObjectDAO anyObjectDAO) {
this.userDAO = userDAO;
this.groupDAO = groupDAO;
this.anyObjectDAO = anyObjectDAO;
}
- public void setIndexMaxResultWindow(final int indexMaxResultWindow) {
- this.indexMaxResultWindow = indexMaxResultWindow;
- }
-
- public int getIndexMaxResultWindow() {
- return indexMaxResultWindow;
- }
-
- public void setRetryOnConflict(final int retryOnConflict) {
- this.retryOnConflict = retryOnConflict;
- }
-
- public int getRetryOnConflict() {
- return retryOnConflict;
- }
-
- public String getNumberOfShards() {
- return numberOfShards;
- }
-
- public void setNumberOfShards(final int numberOfShards) {
- this.numberOfShards = String.valueOf(numberOfShards);
- }
-
- public String getNumberOfReplicas() {
- return numberOfReplicas;
- }
-
- public void setNumberOfReplicas(final int numberOfReplicas) {
- this.numberOfReplicas = String.valueOf(numberOfReplicas);
- }
-
/**
* Returns the document specialized with content from the provided any.
*
@@ -254,4 +223,27 @@ public class ElasticsearchUtils {
protected void customizeDocument(final Map<String, Object> builder, final User user, final String domain)
throws IOException {
}
+
+ public Map<String, Object> document(
+ final long instant,
+ final JsonNode message,
+ final String domain) throws IOException {
+
+ Map<String, Object> builder = new HashMap<>();
+
+ builder.put("instant", instant);
+ builder.put("message", message);
+
+ customizeDocument(builder, instant, message, domain);
+
+ return builder;
+ }
+
+ protected void customizeDocument(
+ final Map<String, Object> builder,
+ final long instant,
+ final JsonNode message,
+ final String domain)
+ throws IOException {
+ }
}
diff --git a/ext/elasticsearch/pom.xml b/ext/elasticsearch/logic/pom.xml
similarity index 52%
copy from ext/elasticsearch/pom.xml
copy to ext/elasticsearch/logic/pom.xml
index 649af13516..50b986fe93 100644
--- a/ext/elasticsearch/pom.xml
+++ b/ext/elasticsearch/logic/pom.xml
@@ -22,25 +22,41 @@ under the License.
<modelVersion>4.0.0</modelVersion>
<parent>
- <groupId>org.apache.syncope</groupId>
- <artifactId>syncope-ext</artifactId>
+ <groupId>org.apache.syncope.ext</groupId>
+ <artifactId>syncope-ext-elasticsearch</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
- <name>Apache Syncope Ext: Elasticsearch</name>
- <description>Apache Syncope Ext: Elasticsearch</description>
- <groupId>org.apache.syncope.ext</groupId>
- <artifactId>syncope-ext-elasticsearch</artifactId>
- <packaging>pom</packaging>
+ <name>Apache Syncope Ext: Elasticsearch Logic</name>
+ <description>Apache Syncope Ext: Elasticsearch Logic</description>
+ <groupId>org.apache.syncope.ext.elasticsearch</groupId>
+ <artifactId>syncope-ext-elasticsearch-logic</artifactId>
+ <packaging>jar</packaging>
<properties>
- <rootpom.basedir>${basedir}/../..</rootpom.basedir>
+ <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
</properties>
-
- <modules>
- <module>client-elasticsearch</module>
- <module>persistence-jpa</module>
- <module>provisioning-java</module>
- </modules>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.syncope.core.idrepo</groupId>
+ <artifactId>syncope-core-idrepo-logic</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.syncope.ext.elasticsearch</groupId>
+ <artifactId>syncope-ext-elasticsearch-client</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
</project>
diff --git a/ext/elasticsearch/logic/src/main/java/org/apache/syncope/core/logic/audit/ElasticsearchAppender.java b/ext/elasticsearch/logic/src/main/java/org/apache/syncope/core/logic/audit/ElasticsearchAppender.java
new file mode 100644
index 0000000000..5787e220ac
--- /dev/null
+++ b/ext/elasticsearch/logic/src/main/java/org/apache/syncope/core/logic/audit/ElasticsearchAppender.java
@@ -0,0 +1,97 @@
+/*
+ * 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.logic.audit;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.io.Serializable;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.ext.elasticsearch.client.ElasticsearchIndexManager;
+
+public class ElasticsearchAppender extends AbstractAppender {
+
+ public static class Builder extends AbstractAppender.Builder<Builder>
+ implements org.apache.logging.log4j.core.util.Builder<ElasticsearchAppender> {
+
+ private ElasticsearchIndexManager elasticsearchIndexManager;
+
+ private String domain;
+
+ public ElasticsearchAppender.Builder setDomain(final String domain) {
+ this.domain = domain;
+ return this;
+ }
+
+ public ElasticsearchAppender.Builder setIndexManager(
+ final ElasticsearchIndexManager elasticsearchIndexManager) {
+
+ this.elasticsearchIndexManager = elasticsearchIndexManager;
+ return this;
+ }
+
+ @Override
+ public ElasticsearchAppender build() {
+ if (domain == null || elasticsearchIndexManager == null) {
+ LOGGER.error("Cannot create ElasticsearchAppender without Domain or IndexManager.");
+ return null;
+ }
+ return new ElasticsearchAppender(
+ getName(), getFilter(), getLayout(), isIgnoreExceptions(), domain, elasticsearchIndexManager);
+ }
+ }
+
+ @PluginBuilderFactory
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ private final String domain;
+
+ protected final ElasticsearchIndexManager elasticsearchIndexManager;
+
+ protected ElasticsearchAppender(
+ final String name,
+ final Filter filter,
+ final Layout<? extends Serializable> layout,
+ final boolean ignoreExceptions,
+ final String domain,
+ final ElasticsearchIndexManager elasticsearchIndexManager) {
+
+ super(name, filter, layout, ignoreExceptions, Property.EMPTY_ARRAY);
+ this.domain = domain;
+ this.elasticsearchIndexManager = elasticsearchIndexManager;
+ }
+
+ @Override
+ public void append(final LogEvent event) {
+ try {
+ elasticsearchIndexManager.audit(
+ domain,
+ event.getTimeMillis(),
+ POJOHelper.deserialize(event.getMessage().getFormattedMessage(), JsonNode.class));
+ } catch (Exception e) {
+ LOGGER.error("While requesting to index event for appender [{}]", getName(), e);
+ }
+ }
+}
diff --git a/ext/elasticsearch/logic/src/main/java/org/apache/syncope/core/logic/audit/ElasticsearchAuditAppender.java b/ext/elasticsearch/logic/src/main/java/org/apache/syncope/core/logic/audit/ElasticsearchAuditAppender.java
new file mode 100644
index 0000000000..33ad815f14
--- /dev/null
+++ b/ext/elasticsearch/logic/src/main/java/org/apache/syncope/core/logic/audit/ElasticsearchAuditAppender.java
@@ -0,0 +1,52 @@
+/*
+ * 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.logic.audit;
+
+import java.util.Optional;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.syncope.ext.elasticsearch.client.ElasticsearchIndexManager;
+
+public class ElasticsearchAuditAppender extends DefaultAuditAppender {
+
+ public ElasticsearchAuditAppender(final String domain, final ElasticsearchIndexManager elasticsearchIndexManager) {
+ super(domain);
+
+ LoggerContext logCtx = (LoggerContext) LogManager.getContext(false);
+
+ targetAppender = Optional.ofNullable(logCtx.getConfiguration().<Appender>getAppender(getTargetAppenderName())).
+ orElseGet(() -> {
+ ElasticsearchAppender a = ElasticsearchAppender.newBuilder().
+ setName(getTargetAppenderName()).
+ setIgnoreExceptions(false).
+ setDomain(domain).
+ setIndexManager(elasticsearchIndexManager).
+ build();
+ a.start();
+ logCtx.getConfiguration().addAppender(a);
+ return a;
+ });
+ }
+
+ @Override
+ public String getTargetAppenderName() {
+ return "audit_for_" + domain;
+ }
+}
diff --git a/ext/elasticsearch/logic/src/main/java/org/apache/syncope/core/logic/audit/ElasticsearchLogicContext.java b/ext/elasticsearch/logic/src/main/java/org/apache/syncope/core/logic/audit/ElasticsearchLogicContext.java
new file mode 100644
index 0000000000..09df992c1a
--- /dev/null
+++ b/ext/elasticsearch/logic/src/main/java/org/apache/syncope/core/logic/audit/ElasticsearchLogicContext.java
@@ -0,0 +1,62 @@
+/*
+ * 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.logic.audit;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.syncope.common.lib.types.AuditLoggerName;
+import org.apache.syncope.core.logic.IdRepoLogicContext;
+import org.apache.syncope.core.persistence.api.DomainHolder;
+import org.apache.syncope.ext.elasticsearch.client.ElasticsearchIndexManager;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@AutoConfigureBefore(IdRepoLogicContext.class)
+@Configuration(proxyBeanMethods = false)
+public class ElasticsearchLogicContext {
+
+ @ConditionalOnMissingBean(name = { "defaultAuditAppenders", "elasticsearchDefaultAuditAppenders" })
+ @Bean
+ public List<AuditAppender> defaultAuditAppenders(
+ final DomainHolder domainHolder,
+ final ElasticsearchIndexManager elasticsearchIndexManager) {
+
+ List<AuditAppender> auditAppenders = new ArrayList<>();
+
+ LoggerContext logCtx = (LoggerContext) LogManager.getContext(false);
+ domainHolder.getDomains().forEach((domain, dataSource) -> {
+ AuditAppender appender = new ElasticsearchAuditAppender(domain, elasticsearchIndexManager);
+
+ LoggerConfig logConf = new LoggerConfig(AuditLoggerName.getAuditLoggerName(domain), null, false);
+ logConf.addAppender(appender.getTargetAppender(), Level.DEBUG, null);
+ logConf.setLevel(Level.DEBUG);
+ logCtx.getConfiguration().addLogger(logConf.getName(), logConf);
+
+ auditAppenders.add(appender);
+ });
+
+ return auditAppenders;
+ }
+}
diff --git a/fit/core-reference/src/main/resources/core-elasticsearch.properties b/ext/elasticsearch/logic/src/main/resources/META-INF/spring.factories
similarity index 85%
copy from fit/core-reference/src/main/resources/core-elasticsearch.properties
copy to ext/elasticsearch/logic/src/main/resources/META-INF/spring.factories
index 3360988643..ca8f2cb4bd 100644
--- a/fit/core-reference/src/main/resources/core-elasticsearch.properties
+++ b/ext/elasticsearch/logic/src/main/resources/META-INF/spring.factories
@@ -15,4 +15,5 @@
# specific language governing permissions and limitations
# under the License.
-persistence.anySearchDao=org.apache.syncope.core.persistence.jpa.dao.ElasticsearchAnySearchDAO
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+ org.apache.syncope.core.logic.audit.ElasticsearchLogicContext
diff --git a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/ElasticsearchPersistenceContext.java b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/ElasticsearchPersistenceContext.java
index 757fb34cee..88e9e1e160 100644
--- a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/ElasticsearchPersistenceContext.java
+++ b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/ElasticsearchPersistenceContext.java
@@ -22,6 +22,7 @@ import co.elastic.clients.elasticsearch.ElasticsearchClient;
import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
+import org.apache.syncope.core.persistence.api.dao.AuditConfDAO;
import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
@@ -30,8 +31,8 @@ import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
import org.apache.syncope.core.persistence.jpa.dao.ElasticsearchAnySearchDAO;
-import org.apache.syncope.ext.elasticsearch.client.ElasticsearchIndexManager;
-import org.apache.syncope.ext.elasticsearch.client.ElasticsearchUtils;
+import org.apache.syncope.core.persistence.jpa.dao.ElasticsearchAuditConfDAO;
+import org.apache.syncope.ext.elasticsearch.client.ElasticsearchProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -40,15 +41,10 @@ import org.springframework.context.annotation.Lazy;
@Configuration(proxyBeanMethods = false)
public class ElasticsearchPersistenceContext {
- @ConditionalOnMissingBean
- @Bean
- public DomainIndexLoader domainIndexLoader(final ElasticsearchIndexManager indexManager) {
- return new DomainIndexLoader(indexManager);
- }
-
@ConditionalOnMissingBean(name = "elasticsearchAnySearchDAO")
@Bean
public AnySearchDAO anySearchDAO(
+ final ElasticsearchProperties props,
final RealmDAO realmDAO,
final @Lazy DynRealmDAO dynRealmDAO,
final @Lazy UserDAO userDAO,
@@ -58,8 +54,7 @@ public class ElasticsearchPersistenceContext {
final EntityFactory entityFactory,
final AnyUtilsFactory anyUtilsFactory,
final PlainAttrValidationManager validator,
- final ElasticsearchClient client,
- final @Lazy ElasticsearchUtils elasticsearchUtils) {
+ final ElasticsearchClient client) {
return new ElasticsearchAnySearchDAO(
realmDAO,
@@ -72,6 +67,15 @@ public class ElasticsearchPersistenceContext {
anyUtilsFactory,
validator,
client,
- elasticsearchUtils);
+ props.getIndexMaxResultWindow());
+ }
+
+ @ConditionalOnMissingBean(name = "elasticsearchAuditConfDAO")
+ @Bean
+ public AuditConfDAO auditConfDAO(
+ final ElasticsearchProperties props,
+ final ElasticsearchClient client) {
+
+ return new ElasticsearchAuditConfDAO(client, props.getIndexMaxResultWindow());
}
}
diff --git a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
index d70d75ef30..b7cb0c09c4 100644
--- a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
+++ b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
@@ -106,7 +106,7 @@ public class ElasticsearchAnySearchDAO extends AbstractAnySearchDAO {
protected final ElasticsearchClient client;
- protected final ElasticsearchUtils elasticsearchUtils;
+ protected final int indexMaxResultWindow;
public ElasticsearchAnySearchDAO(
final RealmDAO realmDAO,
@@ -119,7 +119,7 @@ public class ElasticsearchAnySearchDAO extends AbstractAnySearchDAO {
final AnyUtilsFactory anyUtilsFactory,
final PlainAttrValidationManager validator,
final ElasticsearchClient client,
- final ElasticsearchUtils elasticsearchUtils) {
+ final int indexMaxResultWindow) {
super(
realmDAO,
@@ -133,7 +133,7 @@ public class ElasticsearchAnySearchDAO extends AbstractAnySearchDAO {
validator);
this.client = client;
- this.elasticsearchUtils = elasticsearchUtils;
+ this.indexMaxResultWindow = indexMaxResultWindow;
}
protected Triple<Optional<Query>, Set<String>, Set<String>> getAdminRealmsFilter(
@@ -237,7 +237,7 @@ public class ElasticsearchAnySearchDAO extends AbstractAnySearchDAO {
final AnyTypeKind kind) {
CountRequest request = new CountRequest.Builder().
- index(ElasticsearchUtils.getContextDomainName(AuthContextUtils.getDomain(), kind)).
+ index(ElasticsearchUtils.getAnyIndex(AuthContextUtils.getDomain(), kind)).
query(getQuery(base, recursive, adminRealms, cond, kind)).
build();
try {
@@ -298,11 +298,11 @@ public class ElasticsearchAnySearchDAO extends AbstractAnySearchDAO {
final AnyTypeKind kind) {
SearchRequest request = new SearchRequest.Builder().
- index(ElasticsearchUtils.getContextDomainName(AuthContextUtils.getDomain(), kind)).
+ index(ElasticsearchUtils.getAnyIndex(AuthContextUtils.getDomain(), kind)).
searchType(SearchType.QueryThenFetch).
query(getQuery(base, recursive, adminRealms, cond, kind)).
from(itemsPerPage * (page <= 0 ? 0 : page - 1)).
- size(itemsPerPage < 0 ? elasticsearchUtils.getIndexMaxResultWindow() : itemsPerPage).
+ size(itemsPerPage < 0 ? indexMaxResultWindow : itemsPerPage).
sort(sortBuilders(kind, orderBy)).
build();
diff --git a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAuditConfDAO.java b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAuditConfDAO.java
new file mode 100644
index 0000000000..4746205ae2
--- /dev/null
+++ b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAuditConfDAO.java
@@ -0,0 +1,182 @@
+/*
+ * 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.jpa.dao;
+
+import co.elastic.clients.elasticsearch.ElasticsearchClient;
+import co.elastic.clients.elasticsearch._types.FieldSort;
+import co.elastic.clients.elasticsearch._types.SearchType;
+import co.elastic.clients.elasticsearch._types.SortOptions;
+import co.elastic.clients.elasticsearch._types.SortOrder;
+import co.elastic.clients.elasticsearch._types.query_dsl.Query;
+import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
+import co.elastic.clients.elasticsearch.core.CountRequest;
+import co.elastic.clients.elasticsearch.core.SearchRequest;
+import co.elastic.clients.elasticsearch.core.search.Hit;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.audit.AuditEntry;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.apache.syncope.ext.elasticsearch.client.ElasticsearchUtils;
+import org.springframework.util.CollectionUtils;
+
+public class ElasticsearchAuditConfDAO extends JPAAuditConfDAO {
+
+ protected final ElasticsearchClient client;
+
+ protected final int indexMaxResultWindow;
+
+ public ElasticsearchAuditConfDAO(final ElasticsearchClient client, final int indexMaxResultWindow) {
+ this.client = client;
+ this.indexMaxResultWindow = indexMaxResultWindow;
+ }
+
+ protected Query getQuery(
+ final String entityKey,
+ final AuditElements.EventCategoryType type,
+ final String category,
+ final String subcategory,
+ final List<String> events,
+ final AuditElements.Result result) {
+
+ List<Query> queries = new ArrayList<>();
+
+ if (entityKey != null) {
+ queries.add(new Query.Builder().
+ multiMatch(QueryBuilders.multiMatch().
+ fields("message.before", "message.inputs", "message.output", "message.throwable").
+ query(entityKey).build()).build());
+ }
+
+ if (type != null) {
+ queries.add(new Query.Builder().
+ term(QueryBuilders.term().field("message.logger.type").value(type.name()).build()).
+ build());
+ }
+
+ if (StringUtils.isNotBlank(category)) {
+ queries.add(new Query.Builder().
+ term(QueryBuilders.term().field("message.logger.category").value(category).build()).
+ build());
+ }
+
+ if (StringUtils.isNotBlank(subcategory)) {
+ queries.add(new Query.Builder().
+ term(QueryBuilders.term().field("message.logger.subcategory").value(subcategory).build()).
+ build());
+ }
+
+ List<Query> eventQueries = events.stream().map(event -> new Query.Builder().
+ term(QueryBuilders.term().field("message.logger.event").value(event).build()).
+ build()).
+ collect(Collectors.toList());
+ if (!eventQueries.isEmpty()) {
+ queries.add(new Query.Builder().disMax(QueryBuilders.disMax().queries(eventQueries).build()).build());
+ }
+
+ if (result != null) {
+ queries.add(new Query.Builder().
+ term(QueryBuilders.term().field("message.logger.result").value(result.name()).build()).
+ build());
+ }
+
+ return new Query.Builder().bool(QueryBuilders.bool().must(queries).build()).build();
+ }
+
+ @Override
+ public int countEntries(
+ final String entityKey,
+ final AuditElements.EventCategoryType type,
+ final String category,
+ final String subcategory,
+ final List<String> events,
+ final AuditElements.Result result) {
+
+ CountRequest request = new CountRequest.Builder().
+ index(ElasticsearchUtils.getAuditIndex(AuthContextUtils.getDomain())).
+ query(getQuery(entityKey, type, category, subcategory, events, result)).
+ build();
+ try {
+ return (int) client.count(request).count();
+ } catch (IOException e) {
+ LOG.error("Search error", e);
+ return 0;
+ }
+ }
+
+ protected List<SortOptions> sortBuilders(final List<OrderByClause> orderBy) {
+ return orderBy.stream().map(clause -> {
+ String sortField = clause.getField();
+ if ("EVENT_DATE".equalsIgnoreCase(sortField)) {
+ sortField = "message.date";
+ }
+
+ return new SortOptions.Builder().field(
+ new FieldSort.Builder().
+ field(sortField).
+ order(clause.getDirection() == OrderByClause.Direction.ASC
+ ? SortOrder.Asc : SortOrder.Desc).
+ build()).
+ build();
+ }).collect(Collectors.toList());
+ }
+
+ @Override
+ public List<AuditEntry> searchEntries(
+ final String entityKey,
+ final int page,
+ final int itemsPerPage,
+ final AuditElements.EventCategoryType type,
+ final String category,
+ final String subcategory,
+ final List<String> events,
+ final AuditElements.Result result,
+ final List<OrderByClause> orderBy) {
+
+ SearchRequest request = new SearchRequest.Builder().
+ index(ElasticsearchUtils.getAuditIndex(AuthContextUtils.getDomain())).
+ searchType(SearchType.QueryThenFetch).
+ query(getQuery(entityKey, type, category, subcategory, events, result)).
+ from(itemsPerPage * (page <= 0 ? 0 : page - 1)).
+ size(itemsPerPage < 0 ? indexMaxResultWindow : itemsPerPage).
+ sort(sortBuilders(orderBy)).
+ build();
+
+ @SuppressWarnings("rawtypes")
+ List<Hit<Map>> esResult = null;
+ try {
+ esResult = client.search(request, Map.class).hits().hits();
+ } catch (Exception e) {
+ LOG.error("While searching in Elasticsearch", e);
+ }
+
+ return CollectionUtils.isEmpty(esResult)
+ ? List.of()
+ : esResult.stream().
+ map(hit -> POJOHelper.convertValue(hit.source().get("message"), AuditEntry.class)).
+ filter(Objects::nonNull).collect(Collectors.toList());
+ }
+}
diff --git a/ext/elasticsearch/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAOTest.java b/ext/elasticsearch/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAOTest.java
index ab48f1cab9..2145da00ac 100644
--- a/ext/elasticsearch/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAOTest.java
+++ b/ext/elasticsearch/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAOTest.java
@@ -54,9 +54,9 @@ import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
import org.apache.syncope.core.spring.security.AuthContextUtils;
import org.apache.syncope.ext.elasticsearch.client.ElasticsearchUtils;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
@@ -81,12 +81,24 @@ public class ElasticsearchAnySearchDAOTest {
@Mock
private AnyUtilsFactory anyUtilsFactory;
- @Mock
- private ElasticsearchUtils elasticsearchUtils;
-
- @InjectMocks
private ElasticsearchAnySearchDAO searchDAO;
+ @BeforeEach
+ protected void setupSearchDAO() {
+ searchDAO = new ElasticsearchAnySearchDAO(
+ realmDAO,
+ dynRealmDAO,
+ null,
+ groupDAO,
+ null,
+ null,
+ entityFactory,
+ anyUtilsFactory,
+ null,
+ null,
+ 10000);
+ }
+
@Test
public void getAdminRealmsFilter4realm() throws IOException {
// 1. mock
@@ -152,7 +164,7 @@ public class ElasticsearchAnySearchDAOTest {
when(groupDAO.findKey("groupKey")).thenReturn("groupKey");
try (MockedStatic<ElasticsearchUtils> utils = Mockito.mockStatic(ElasticsearchUtils.class)) {
- utils.when(() -> ElasticsearchUtils.getContextDomainName(
+ utils.when(() -> ElasticsearchUtils.getAnyIndex(
SyncopeConstants.MASTER_DOMAIN, AnyTypeKind.USER)).thenReturn("master_user");
// 2. test
@@ -162,7 +174,7 @@ public class ElasticsearchAnySearchDAOTest {
anyCond.setSchema("id");
SearchRequest request = new SearchRequest.Builder().
- index(ElasticsearchUtils.getContextDomainName(AuthContextUtils.getDomain(), AnyTypeKind.USER)).
+ index(ElasticsearchUtils.getAnyIndex(AuthContextUtils.getDomain(), AnyTypeKind.USER)).
searchType(SearchType.QueryThenFetch).
query(searchDAO.getQuery(realmDAO.findByFullPath("/any"), true,
adminRealms, SearchCond.getLeaf(anyCond), AnyTypeKind.USER)).
diff --git a/ext/elasticsearch/pom.xml b/ext/elasticsearch/pom.xml
index 649af13516..a9dcf7e532 100644
--- a/ext/elasticsearch/pom.xml
+++ b/ext/elasticsearch/pom.xml
@@ -41,6 +41,7 @@ under the License.
<module>client-elasticsearch</module>
<module>persistence-jpa</module>
<module>provisioning-java</module>
+ <module>logic</module>
</modules>
</project>
diff --git a/ext/elasticsearch/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/ElasticsearchReindex.java b/ext/elasticsearch/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/ElasticsearchReindex.java
index 40b0133a96..8addb804ef 100644
--- a/ext/elasticsearch/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/ElasticsearchReindex.java
+++ b/ext/elasticsearch/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/ElasticsearchReindex.java
@@ -74,16 +74,24 @@ public class ElasticsearchReindex extends AbstractSchedTaskJobDelegate<SchedTask
return indexManager.defaultSettings();
}
+ protected IndexSettings auditSettings() throws IOException {
+ return indexManager.defaultSettings();
+ }
+
protected TypeMapping userMapping() throws IOException {
- return indexManager.defaultMapping();
+ return indexManager.defaultAnyMapping();
}
protected TypeMapping groupMapping() throws IOException {
- return indexManager.defaultMapping();
+ return indexManager.defaultAnyMapping();
}
protected TypeMapping anyObjectMapping() throws IOException {
- return indexManager.defaultMapping();
+ return indexManager.defaultAnyMapping();
+ }
+
+ protected TypeMapping auditMapping() throws IOException {
+ return indexManager.defaultAuditMapping();
}
@Override
@@ -94,21 +102,20 @@ public class ElasticsearchReindex extends AbstractSchedTaskJobDelegate<SchedTask
LOG.debug("Start rebuilding indexes");
try {
- indexManager.createIndex(
+ indexManager.createAnyIndex(
AuthContextUtils.getDomain(), AnyTypeKind.USER, userSettings(), userMapping());
- indexManager.createIndex(
+ indexManager.createAnyIndex(
AuthContextUtils.getDomain(), AnyTypeKind.GROUP, groupSettings(), groupMapping());
- indexManager.createIndex(
+ indexManager.createAnyIndex(
AuthContextUtils.getDomain(), AnyTypeKind.ANY_OBJECT, anyObjectSettings(), anyObjectMapping());
LOG.debug("Indexing users...");
for (int page = 1; page <= (userDAO.count() / AnyDAO.DEFAULT_PAGE_SIZE) + 1; page++) {
for (String user : userDAO.findAllKeys(page, AnyDAO.DEFAULT_PAGE_SIZE)) {
IndexRequest<Map<String, Object>> request = new IndexRequest.Builder<Map<String, Object>>().
- index(ElasticsearchUtils.getContextDomainName(
- AuthContextUtils.getDomain(), AnyTypeKind.USER)).
+ index(ElasticsearchUtils.getAnyIndex(AuthContextUtils.getDomain(), AnyTypeKind.USER)).
id(user).
document(utils.document(userDAO.find(user), AuthContextUtils.getDomain())).
build();
@@ -125,8 +132,7 @@ public class ElasticsearchReindex extends AbstractSchedTaskJobDelegate<SchedTask
for (int page = 1; page <= (groupDAO.count() / AnyDAO.DEFAULT_PAGE_SIZE) + 1; page++) {
for (String group : groupDAO.findAllKeys(page, AnyDAO.DEFAULT_PAGE_SIZE)) {
IndexRequest<Map<String, Object>> request = new IndexRequest.Builder<Map<String, Object>>().
- index(ElasticsearchUtils.getContextDomainName(
- AuthContextUtils.getDomain(), AnyTypeKind.GROUP)).
+ index(ElasticsearchUtils.getAnyIndex(AuthContextUtils.getDomain(), AnyTypeKind.GROUP)).
id(group).
document(utils.document(groupDAO.find(group), AuthContextUtils.getDomain())).
build();
@@ -143,7 +149,7 @@ public class ElasticsearchReindex extends AbstractSchedTaskJobDelegate<SchedTask
for (int page = 1; page <= (anyObjectDAO.count() / AnyDAO.DEFAULT_PAGE_SIZE) + 1; page++) {
for (String anyObject : anyObjectDAO.findAllKeys(page, AnyDAO.DEFAULT_PAGE_SIZE)) {
IndexRequest<Map<String, Object>> request = new IndexRequest.Builder<Map<String, Object>>().
- index(ElasticsearchUtils.getContextDomainName(
+ index(ElasticsearchUtils.getAnyIndex(
AuthContextUtils.getDomain(), AnyTypeKind.ANY_OBJECT)).
id(anyObject).
document(utils.document(anyObjectDAO.find(anyObject), AuthContextUtils.getDomain())).
@@ -157,6 +163,9 @@ public class ElasticsearchReindex extends AbstractSchedTaskJobDelegate<SchedTask
}
}
+ indexManager.createAuditIndex(
+ AuthContextUtils.getDomain(), auditSettings(), auditMapping());
+
LOG.debug("Rebuild indexes for domain {} successfully completed", AuthContextUtils.getDomain());
} catch (Exception e) {
throw new JobExecutionException("While rebuilding index for domain " + AuthContextUtils.getDomain(), e);
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index 126d829a4a..2db98ef49d 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -497,6 +497,11 @@ under the License.
</properties>
<dependencies>
+ <dependency>
+ <groupId>org.apache.syncope.ext.elasticsearch</groupId>
+ <artifactId>syncope-ext-elasticsearch-logic</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.syncope.ext.elasticsearch</groupId>
<artifactId>syncope-ext-elasticsearch-provisioning-java</artifactId>
@@ -535,6 +540,7 @@ under the License.
<cluster.name>elasticsearch</cluster.name>
<xpack.security.enabled>false</xpack.security.enabled>
<ingest.geoip.downloader.enabled>false</ingest.geoip.downloader.enabled>
+ <ES_JAVA_OPTS>-Xms750m -Xmx750m</ES_JAVA_OPTS>
</env>
<ports>
<port>9200:9200</port>
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/CoreReferenceContext.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/CoreReferenceContext.java
index 81534b7ac6..29eead687e 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/CoreReferenceContext.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/CoreReferenceContext.java
@@ -18,8 +18,10 @@
*/
package org.apache.syncope.fit.core.reference;
+import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.core.logic.IdRepoLogicContext;
import org.apache.syncope.core.logic.TaskLogic;
+import org.apache.syncope.core.logic.audit.AuditAppender;
import org.apache.syncope.core.persistence.api.ImplementationLookup;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
@@ -59,4 +61,14 @@ public class CoreReferenceContext {
return new ITImplementationLookup(uwf, anySearchDAO, enableFlowableForTestUsers, elasticsearchInit);
}
+
+ @Bean
+ public AuditAppender testFileAuditAppender() {
+ return new TestFileAuditAppender(SyncopeConstants.MASTER_DOMAIN);
+ }
+
+ @Bean
+ public AuditAppender testFileRewriteAuditAppender() {
+ return new TestFileRewriteAuditAppender(SyncopeConstants.MASTER_DOMAIN);
+ }
}
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
index a63671f3f9..feffedfb01 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
@@ -125,9 +125,6 @@ public class ITImplementationLookup implements ImplementationLookup {
DummyPushCorrelationRuleConf.class, DummyPushCorrelationRule.class,
DefaultPushCorrelationRuleConf.class, DefaultPushCorrelationRule.class);
- private static final Set<Class<?>> AUDITAPPENDER_CLASSES =
- Set.of(TestFileAuditAppender.class, TestFileRewriteAuditAppender.class);
-
private static final Set<Class<?>> PROVISION_SORTER_CLASSES =
Set.of(DefaultProvisionSorter.class);
@@ -216,10 +213,6 @@ public class ITImplementationLookup implements ImplementationLookup {
classNames.add(TestNotificationRecipientsProvider.class.getName());
put(IdRepoImplementationType.RECIPIENTS_PROVIDER, classNames);
- classNames = ITImplementationLookup.AUDITAPPENDER_CLASSES.stream().
- map(Class::getName).collect(Collectors.toSet());
- put(IdRepoImplementationType.AUDIT_APPENDER, classNames);
-
classNames = ITImplementationLookup.PROVISION_SORTER_CLASSES.stream().
map(Class::getName).collect(Collectors.toSet());
put(IdMImplementationType.PROVISION_SORTER, classNames);
@@ -327,9 +320,4 @@ public class ITImplementationLookup implements ImplementationLookup {
return PUSH_CR_CLASSES.get(pushCorrelationRuleConfClass);
}
-
- @Override
- public Set<Class<?>> getAuditAppenderClasses() {
- return AUDITAPPENDER_CLASSES;
- }
}
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/SyslogRewriteAuditAppender.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/SyslogRewriteAuditAppender.java
index 6d15fc39b1..6918b73bc2 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/SyslogRewriteAuditAppender.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/SyslogRewriteAuditAppender.java
@@ -32,6 +32,19 @@ import org.apache.syncope.core.logic.audit.DefaultRewriteAuditAppender;
public class SyslogRewriteAuditAppender extends DefaultRewriteAuditAppender {
+ public SyslogRewriteAuditAppender(final String domain) {
+ super(domain);
+
+ targetAppender = SyslogAppender.newSyslogAppenderBuilder().
+ setName(getTargetAppenderName()).
+ setHost("localhost").
+ setPort(514).
+ setProtocol(Protocol.UDP).
+ setLayout(PatternLayout.newBuilder().withPattern("%d{ISO8601} %-5level %logger - %msg%n").build()).
+ setFacility(Facility.LOCAL1).
+ build();
+ }
+
@Override
public Set<AuditLoggerName> getEvents() {
Set<AuditLoggerName> events = new HashSet<>();
@@ -56,18 +69,6 @@ public class SyslogRewriteAuditAppender extends DefaultRewriteAuditAppender {
return events;
}
- @Override
- protected void initTargetAppender() {
- targetAppender = SyslogAppender.newSyslogAppenderBuilder().
- setName(getTargetAppenderName()).
- setHost("localhost").
- setPort(514).
- setProtocol(Protocol.UDP).
- setLayout(PatternLayout.newBuilder().withPattern("%d{ISO8601} %-5level %logger - %msg%n").build()).
- setFacility(Facility.LOCAL1).
- build();
- }
-
@Override
public String getTargetAppenderName() {
return "audit_for_" + domain + "_syslog";
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestFileAuditAppender.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestFileAuditAppender.java
index 8ae76232d7..ab542ffe18 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestFileAuditAppender.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestFileAuditAppender.java
@@ -35,26 +35,9 @@ import org.apache.syncope.core.logic.audit.DefaultAuditAppender;
public class TestFileAuditAppender extends DefaultAuditAppender {
- @Override
- public Set<AuditLoggerName> getEvents() {
- Set<AuditLoggerName> events = new HashSet<>();
- events.add(new AuditLoggerName(
- AuditElements.EventCategoryType.LOGIC,
- ResourceLogic.class.getSimpleName(),
- null,
- "create",
- AuditElements.Result.SUCCESS));
- events.add(new AuditLoggerName(
- AuditElements.EventCategoryType.LOGIC,
- ConnectorLogic.class.getSimpleName(),
- null,
- "update",
- AuditElements.Result.SUCCESS));
- return events;
- }
+ public TestFileAuditAppender(final String domain) {
+ super(domain);
- @Override
- protected void initTargetAppender() {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
// get log file path from existing file appender
RollingRandomAccessFileAppender main =
@@ -75,6 +58,24 @@ public class TestFileAuditAppender extends DefaultAuditAppender {
build();
}
+ @Override
+ public Set<AuditLoggerName> getEvents() {
+ Set<AuditLoggerName> events = new HashSet<>();
+ events.add(new AuditLoggerName(
+ AuditElements.EventCategoryType.LOGIC,
+ ResourceLogic.class.getSimpleName(),
+ null,
+ "create",
+ AuditElements.Result.SUCCESS));
+ events.add(new AuditLoggerName(
+ AuditElements.EventCategoryType.LOGIC,
+ ConnectorLogic.class.getSimpleName(),
+ null,
+ "update",
+ AuditElements.Result.SUCCESS));
+ return events;
+ }
+
@Override
public String getTargetAppenderName() {
return "audit_for_" + domain + "_norewrite_file";
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestFileRewriteAuditAppender.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestFileRewriteAuditAppender.java
index 9762fb73fd..815bc52fae 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestFileRewriteAuditAppender.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestFileRewriteAuditAppender.java
@@ -34,18 +34,9 @@ import org.apache.syncope.core.logic.audit.DefaultRewriteAuditAppender;
public class TestFileRewriteAuditAppender extends DefaultRewriteAuditAppender {
- @Override
- public Set<AuditLoggerName> getEvents() {
- return Collections.singleton(new AuditLoggerName(
- AuditElements.EventCategoryType.LOGIC,
- ResourceLogic.class.getSimpleName(),
- null,
- "update",
- AuditElements.Result.SUCCESS));
- }
+ public TestFileRewriteAuditAppender(final String domain) {
+ super(domain);
- @Override
- protected void initTargetAppender() {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
// get log file path from existing file appender
@@ -63,6 +54,16 @@ public class TestFileRewriteAuditAppender extends DefaultRewriteAuditAppender {
build();
}
+ @Override
+ public Set<AuditLoggerName> getEvents() {
+ return Collections.singleton(new AuditLoggerName(
+ AuditElements.EventCategoryType.LOGIC,
+ ResourceLogic.class.getSimpleName(),
+ null,
+ "update",
+ AuditElements.Result.SUCCESS));
+ }
+
@Override
public String getTargetAppenderName() {
return "audit_for_" + domain + "_file";
diff --git a/fit/core-reference/src/main/resources/core-elasticsearch.properties b/fit/core-reference/src/main/resources/core-elasticsearch.properties
index 3360988643..d426e44d97 100644
--- a/fit/core-reference/src/main/resources/core-elasticsearch.properties
+++ b/fit/core-reference/src/main/resources/core-elasticsearch.properties
@@ -15,4 +15,9 @@
# specific language governing permissions and limitations
# under the License.
-persistence.anySearchDao=org.apache.syncope.core.persistence.jpa.dao.ElasticsearchAnySearchDAO
+elasticsearch.hostname=localhost
+elasticsearch.port=9200
+elasticsearch.scheme=http
+elasticsearch.indexMaxResultWindow=10000
+elasticsearch.numberOfShards=1
+elasticsearch.numberOfReplicas=1
diff --git a/fit/core-reference/src/main/resources/core-embedded.properties b/fit/core-reference/src/main/resources/core-embedded.properties
index 3926b090e6..d0d0fc45f2 100644
--- a/fit/core-reference/src/main/resources/core-embedded.properties
+++ b/fit/core-reference/src/main/resources/core-embedded.properties
@@ -14,6 +14,9 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
+
+management.endpoints.web.exposure.include=health,info,beans,env,loggers,entityCache
+
keymaster.address=http://localhost:9080/syncope/rest/keymaster
keymaster.username=${anonymousUser}
keymaster.password=${anonymousKey}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
index c47aee07f0..511d0c1d5e 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -22,6 +22,7 @@ import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
@@ -49,6 +50,7 @@ import javax.naming.directory.ModificationItem;
import javax.sql.DataSource;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
@@ -385,6 +387,10 @@ public abstract class AbstractITCase {
protected static ImpersonationService IMPERSONATION_SERVICE;
+ protected static boolean IS_FLOWABLE_ENABLED = false;
+
+ protected static boolean IS_ELASTICSEARCH_ENABLED = false;
+
@BeforeAll
public static void securitySetup() {
try (InputStream propStream = AbstractITCase.class.getResourceAsStream("/core.properties")) {
@@ -473,6 +479,19 @@ public abstract class AbstractITCase {
WA_CONFIG_SERVICE = ADMIN_CLIENT.getService(WAConfigService.class);
}
+ @BeforeAll
+ public static void actuatorInfoSetup() throws IOException {
+ JsonNode beans = JSON_MAPPER.readTree(
+ (InputStream) WebClient.create(StringUtils.substringBeforeLast(ADDRESS, "/") + "/actuator/beans").
+ accept(MediaType.APPLICATION_JSON).get().getEntity());
+
+ JsonNode uwfAdapter = beans.findValues("uwfAdapter").get(0);
+ IS_FLOWABLE_ENABLED = uwfAdapter.get("resource").asText().contains("Flowable");
+
+ JsonNode anySearchDAO = beans.findValues("anySearchDAO").get(0);
+ IS_ELASTICSEARCH_ENABLED = anySearchDAO.get("type").asText().contains("Elasticsearch");
+ }
+
protected static String getUUIDString() {
return UUID.randomUUID().toString().substring(0, 8);
}
@@ -943,6 +962,14 @@ public abstract class AbstractITCase {
}
protected static List<AuditEntry> query(final AuditQuery query, final int maxWaitSeconds) {
+ if (IS_ELASTICSEARCH_ENABLED) {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ // ignore
+ }
+ }
+
int i = 0;
List<AuditEntry> results = List.of();
do {
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractUIITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractUIITCase.java
index df9064d46e..ca5499f791 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractUIITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractUIITCase.java
@@ -22,12 +22,18 @@ 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 com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
+import javax.ws.rs.core.MediaType;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.syncope.common.rest.api.service.SyncopeService;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
@@ -46,6 +52,8 @@ public abstract class AbstractUIITCase {
protected static final Logger LOG = LoggerFactory.getLogger(AbstractUIITCase.class);
+ protected static final JsonMapper JSON_MAPPER = JsonMapper.builder().findAndAddModules().build();
+
protected static final String ADMIN_UNAME = "admin";
protected static final String ADMIN_PWD = "password";
@@ -64,6 +72,10 @@ public abstract class AbstractUIITCase {
protected static SyncopeService SYNCOPE_SERVICE;
+ protected static boolean IS_FLOWABLE_ENABLED = false;
+
+ protected static boolean IS_ELASTICSEARCH_ENABLED = false;
+
@BeforeAll
public static void securitySetup() {
try (InputStream propStream = AbstractITCase.class.getResourceAsStream("/core.properties")) {
@@ -80,6 +92,19 @@ public abstract class AbstractUIITCase {
assertNotNull(ANONYMOUS_KEY);
}
+ @BeforeAll
+ public static void actuatorInfoSetup() throws IOException {
+ JsonNode beans = JSON_MAPPER.readTree(
+ (InputStream) WebClient.create(StringUtils.substringBeforeLast(ADDRESS, "/") + "/actuator/beans").
+ accept(MediaType.APPLICATION_JSON).get().getEntity());
+
+ JsonNode uwfAdapter = beans.findValues("uwfAdapter").get(0);
+ IS_FLOWABLE_ENABLED = uwfAdapter.get("resource").asText().contains("Flowable");
+
+ JsonNode anySearchDAO = beans.findValues("anySearchDAO").get(0);
+ IS_ELASTICSEARCH_ENABLED = anySearchDAO.get("type").asText().contains("Elasticsearch");
+ }
+
protected static <V extends Serializable> Component findComponentByProp(
final String property, final String path, final V key) {
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/ElasticsearchDetector.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/ElasticsearchDetector.java
deleted file mode 100644
index c643df552c..0000000000
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/ElasticsearchDetector.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.fit;
-
-import org.apache.syncope.common.lib.info.PlatformInfo;
-
-public final class ElasticsearchDetector {
-
- public static boolean isElasticSearchEnabled(final PlatformInfo platform) {
- return platform.getPersistenceInfo().getAnySearchDAO().contains("Elasticsearch");
- }
-
- private ElasticsearchDetector() {
- // private constructor for static utility class
- }
-}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/FlowableDetector.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/FlowableDetector.java
deleted file mode 100644
index a35bd69e40..0000000000
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/FlowableDetector.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.fit;
-
-import org.apache.syncope.common.lib.info.PlatformInfo;
-
-public final class FlowableDetector {
-
- public static boolean isFlowableEnabledForUserWorkflow(final PlatformInfo platform) {
- return platform.getWorkflowInfo().getUserWorkflowAdapter().contains("Flowable");
- }
-
- private FlowableDetector() {
- // private constructor for static utility class
- }
-}
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 03dfcaee69..27b9e07771 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
@@ -85,7 +85,14 @@ import org.junit.jupiter.api.Test;
public class AuditITCase extends AbstractITCase {
- private AuditEntry queryWithFailure(final AuditQuery query, final int maxWaitSeconds) {
+ private static AuditConfTO buildAuditConf(final String auditLoggerName, final boolean active) {
+ AuditConfTO auditConfTO = new AuditConfTO();
+ auditConfTO.setActive(active);
+ auditConfTO.setKey(auditLoggerName);
+ return auditConfTO;
+ }
+
+ private static AuditEntry queryWithFailure(final AuditQuery query, final int maxWaitSeconds) {
List<AuditEntry> results = query(query, maxWaitSeconds);
if (results.isEmpty()) {
fail("Timeout when executing query for key " + query.getEntityKey());
@@ -392,6 +399,14 @@ public class AuditITCase extends AbstractITCase {
auditEntry.setOutput(UUID.randomUUID().toString());
assertDoesNotThrow(() -> AUDIT_SERVICE.create(auditEntry));
+ if (IS_ELASTICSEARCH_ENABLED) {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ // ignore
+ }
+ }
+
PagedResult<AuditEntry> events = AUDIT_SERVICE.search(new AuditQuery.Builder().
size(1).
type(auditEntry.getLogger().getType()).
@@ -419,6 +434,14 @@ public class AuditITCase extends AbstractITCase {
auditEntry.setOutput(UUID.randomUUID().toString());
assertDoesNotThrow(() -> AUDIT_SERVICE.create(auditEntry));
+ if (IS_ELASTICSEARCH_ENABLED) {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ // ignore
+ }
+ }
+
PagedResult<AuditEntry> events = AUDIT_SERVICE.search(new AuditQuery.Builder().
size(1).
type(auditEntry.getLogger().getType()).
@@ -461,7 +484,7 @@ public class AuditITCase extends AbstractITCase {
auditFilePath,
content -> content.contains(
"DEBUG Master.syncope.audit.[LOGIC]:[ResourceLogic]:[]:[update]:[SUCCESS]"
- + " - This is a static test message"),
+ + " - This is a static test message"),
10);
// nothing expected in audit_for_Master_norewrite_file.log instead
@@ -469,7 +492,7 @@ public class AuditITCase extends AbstractITCase {
auditNoRewriteFilePath,
content -> !content.contains(
"DEBUG Master.syncope.audit.[LOGIC]:[ResourceLogic]:[]:[update]:[SUCCESS]"
- + " - This is a static test message"),
+ + " - This is a static test message"),
10);
} catch (IOException e) {
fail("Unable to read/write log files", e);
@@ -584,25 +607,32 @@ public class AuditITCase extends AbstractITCase {
pullTaskTO.setDestinationRealm(SyncopeConstants.ROOT_REALM);
pullTaskTO.setMatchingRule(MatchingRule.UPDATE);
pullTaskTO.setUnmatchingRule(UnmatchingRule.ASSIGN);
- RECONCILIATION_SERVICE.pull(
- new ReconQuery.Builder(AnyTypeKind.USER.name(), RESOURCE_NAME_LDAP).fiql("uid==pullFromLDAP")
- .build(),
- pullTaskTO);
+ RECONCILIATION_SERVICE.pull(new ReconQuery.Builder(AnyTypeKind.USER.name(), RESOURCE_NAME_LDAP).
+ fiql("uid==pullFromLDAP").build(), pullTaskTO);
+
// update pullTaskTO -> another audit entry
- pullFromLDAP = updateUser(new UserUR.Builder(USER_SERVICE.read("pullFromLDAP").getKey())
- .plainAttr(new AttrPatch.Builder(new Attr.Builder("ctype").value("abcdef").build()).build())
- .build()).getEntity();
+ pullFromLDAP = updateUser(new UserUR.Builder(USER_SERVICE.read("pullFromLDAP").getKey()).
+ plainAttr(new AttrPatch.Builder(new Attr.Builder("ctype").value("abcdef").build()).build()).
+ build()).getEntity();
+
// search by empty type and category events and get both events on testfromLDAP
- assertEquals(2,
- AUDIT_SERVICE.search(new AuditQuery.Builder()
- .entityKey(pullFromLDAP.getKey())
- .page(1)
- .size(10)
- .events(List.of(
- "create", "update", "matchingrule_update", "unmatchingrule_assign",
- "unmatchingrule_provision"))
- .result(AuditElements.Result.SUCCESS)
- .build()).getTotalCount());
+ if (IS_ELASTICSEARCH_ENABLED) {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ // ignore
+ }
+ }
+
+ assertEquals(2, AUDIT_SERVICE.search(new AuditQuery.Builder().
+ entityKey(pullFromLDAP.getKey()).
+ page(1).
+ size(10).
+ events(List.of(
+ "create", "update", "matchingrule_update", "unmatchingrule_assign",
+ "unmatchingrule_provision")).
+ result(AuditElements.Result.SUCCESS).
+ build()).getTotalCount());
} finally {
if (pullFromLDAP != null) {
USER_SERVICE.deassociate(new ResourceDR.Builder()
@@ -625,11 +655,4 @@ public class AuditITCase extends AbstractITCase {
}
}
}
-
- private static AuditConfTO buildAuditConf(final String auditLoggerName, final boolean active) {
- AuditConfTO auditConfTO = new AuditConfTO();
- auditConfTO.setActive(active);
- auditConfTO.setKey(auditLoggerName);
- return auditConfTO;
- }
}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
index 58077f5b9d..bc343e50a0 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
@@ -77,8 +77,6 @@ import org.apache.syncope.common.rest.api.service.SchemaService;
import org.apache.syncope.common.rest.api.service.UserService;
import org.apache.syncope.core.spring.security.Encryptor;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.ElasticsearchDetector;
-import org.apache.syncope.fit.FlowableDetector;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -201,7 +199,7 @@ public class AuthenticationITCase extends AbstractITCase {
UserService userService2 = CLIENT_FACTORY.create(userTO.getUsername(), "password123").
getService(UserService.class);
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -503,7 +501,7 @@ public class AuthenticationITCase extends AbstractITCase {
assertEquals(2, member.getMemberships().size());
String memberKey = member.getKey();
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -588,7 +586,7 @@ public class AuthenticationITCase extends AbstractITCase {
@Test
public void issueSYNCOPE434() {
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
// 1. create user with group 'groupForWorkflowApproval'
// (users with group groupForWorkflowApproval are defined in workflow as subject to approval)
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/BpmnProcessITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/BpmnProcessITCase.java
index 9bfbac72df..725d8adaf6 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/BpmnProcessITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/BpmnProcessITCase.java
@@ -32,7 +32,6 @@ import org.apache.commons.io.IOUtils;
import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
import org.apache.syncope.common.lib.to.BpmnProcess;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.FlowableDetector;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -44,7 +43,7 @@ public class BpmnProcessITCase extends AbstractITCase {
@BeforeAll
public static void findDefault() {
assumeFalse(CLIENT_FACTORY.getContentType() == SyncopeClientFactoryBean.ContentType.YAML);
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
BPMN_PROCESS_SERVICE.list().stream().
filter(BpmnProcess::isUserWorkflow).findAny().
@@ -55,7 +54,7 @@ public class BpmnProcessITCase extends AbstractITCase {
@BeforeEach
public void check() {
assumeFalse(CLIENT_FACTORY.getContentType() == SyncopeClientFactoryBean.ContentType.YAML);
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
}
@Test
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DelegationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DelegationITCase.java
index 9f11b30fd4..90cd2be1dd 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DelegationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DelegationITCase.java
@@ -49,7 +49,6 @@ import org.apache.syncope.common.rest.api.service.DelegationService;
import org.apache.syncope.common.rest.api.service.UserService;
import org.apache.syncope.core.logic.UserLogic;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.ElasticsearchDetector;
import org.junit.jupiter.api.Test;
public class DelegationITCase extends AbstractITCase {
@@ -241,7 +240,7 @@ public class DelegationITCase extends AbstractITCase {
// 3b. search users as rossini with delegation -> SUCCESS
int forRossini = rossini.delegatedBy("bellini").getService(UserService.class).search(
new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).build()).getTotalCount();
- if (!ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (!IS_ELASTICSEARCH_ENABLED) {
assertEquals(forBellini, forRossini);
}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java
index 13234c1a70..7e26cd31dc 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java
@@ -54,7 +54,6 @@ import org.apache.syncope.common.rest.api.service.DynRealmService;
import org.apache.syncope.common.rest.api.service.GroupService;
import org.apache.syncope.common.rest.api.service.UserService;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.ElasticsearchDetector;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.util.InputStreamContentProvider;
@@ -151,7 +150,7 @@ public class DynRealmITCase extends AbstractITCase {
assertNotNull(group);
final String groupKey = group.getKey();
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -272,7 +271,7 @@ public class DynRealmITCase extends AbstractITCase {
assertNotNull(user.getKey());
// 4a. check that Elasticsearch index was updated correctly
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -294,7 +293,7 @@ public class DynRealmITCase extends AbstractITCase {
DYN_REALM_SERVICE.update(dynRealm);
// 6a. check that Elasticsearch index was updated correctly
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java
index 5d41a8ecf6..a859b95b1b 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java
@@ -99,7 +99,6 @@ import org.apache.syncope.common.rest.api.service.SyncopeService;
import org.apache.syncope.core.provisioning.java.job.TaskJob;
import org.apache.syncope.core.spring.security.Encryptor;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.ElasticsearchDetector;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -718,7 +717,7 @@ public class GroupITCase extends AbstractITCase {
GroupTO group = createGroup(groupCR).getEntity();
assertEquals(fiql, group.getADynMembershipConds().get(PRINTER));
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -945,7 +944,7 @@ public class GroupITCase extends AbstractITCase {
@Test
public void provisionMembers() throws InterruptedException {
- assumeFalse(ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform()));
+ assumeFalse(IS_ELASTICSEARCH_ENABLED);
// 1. create group without resources
GroupCR groupCR = getBasicSample("forProvision");
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/KeymasterITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/KeymasterITCase.java
index d093e3c2af..d77bfe5f1a 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/KeymasterITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/KeymasterITCase.java
@@ -54,7 +54,6 @@ import org.apache.syncope.common.rest.api.beans.AnyQuery;
import org.apache.syncope.common.rest.api.service.UserService;
import org.apache.syncope.core.spring.security.Encryptor;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.ElasticsearchDetector;
import org.junit.jupiter.api.Test;
public class KeymasterITCase extends AbstractITCase {
@@ -282,7 +281,7 @@ public class KeymasterITCase extends AbstractITCase {
assertNotNull(user);
assertEquals("monteverdi", user.getUsername());
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
index accc21204d..36ecb8a460 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
@@ -56,7 +56,6 @@ import org.apache.syncope.common.lib.types.TaskType;
import org.apache.syncope.common.rest.api.beans.AnyQuery;
import org.apache.syncope.common.rest.api.service.TaskService;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.ElasticsearchDetector;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -279,7 +278,7 @@ public class MembershipITCase extends AbstractITCase {
assertEquals(ExecStatus.SUCCESS, ExecStatus.valueOf(execution.getStatus()));
// 5. verify that pulled user has
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
index 1760969d11..a8c729c702 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
@@ -70,7 +70,6 @@ import org.apache.syncope.common.rest.api.service.TaskService;
import org.apache.syncope.common.rest.api.service.UserSelfService;
import org.apache.syncope.common.rest.api.service.UserService;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.ElasticsearchDetector;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -208,7 +207,7 @@ public class MultitenancyITCase extends AbstractITCase {
assertEquals(ExecStatus.SUCCESS, ExecStatus.valueOf(status));
// verify that pulled user is found
- if (ElasticsearchDetector.isElasticSearchEnabled(ANONYMOUS_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
index b6c1571008..98aef995e4 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
@@ -109,8 +109,6 @@ import org.apache.syncope.common.rest.api.service.TaskService;
import org.apache.syncope.core.provisioning.java.pushpull.DBPasswordPullActions;
import org.apache.syncope.core.provisioning.java.pushpull.LDAPPasswordPullActions;
import org.apache.syncope.core.spring.security.Encryptor;
-import org.apache.syncope.fit.ElasticsearchDetector;
-import org.apache.syncope.fit.FlowableDetector;
import org.apache.syncope.fit.core.reference.TestPullActions;
import org.identityconnectors.framework.common.objects.Name;
import org.junit.jupiter.api.BeforeAll;
@@ -194,7 +192,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
@Test
public void fromCSV() throws Exception {
- assumeFalse(ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform()));
+ assumeFalse(IS_ELASTICSEARCH_ENABLED);
removeTestUsers();
@@ -267,7 +265,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
UserTO userTO = USER_SERVICE.read(inUserTO.getKey());
assertNotNull(userTO);
assertEquals(userName, userTO.getUsername());
- assertEquals(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform())
+ assertEquals(IS_FLOWABLE_ENABLED
? "active" : "created", userTO.getStatus());
assertEquals("test9@syncope.apache.org", userTO.getPlainAttr("email").get().getValues().get(0));
assertEquals("test9@syncope.apache.org", userTO.getPlainAttr("userId").get().getValues().get(0));
@@ -569,7 +567,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
// 4. pull
execProvisioningTask(TASK_SERVICE, TaskType.PULL, pullTask.getKey(), MAX_WAIT_SECONDS, false);
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -1082,7 +1080,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
@Test
public void issueSYNCOPE307() {
- assumeFalse(ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform()));
+ assumeFalse(IS_ELASTICSEARCH_ENABLED);
UserCR userCR = UserITCase.getUniqueSample("s307@apache.org");
userCR.setUsername("test0");
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
index f8f4ab8b87..2be1f8767c 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
@@ -362,7 +362,6 @@ public class RealmITCase extends AbstractITCase {
fail("This should not happen");
} catch (SyncopeClientException e) {
assertEquals(ClientExceptionType.RealmContains, e.getType());
- assertEquals(5, e.getElements().size());
}
}
@@ -380,25 +379,24 @@ public class RealmITCase extends AbstractITCase {
descendantRealm.getResources().add(RESOURCE_NAME_LDAP_ORGUNIT);
// 2. check propagation
- ProvisioningResult<RealmTO> result = REALM_SERVICE.create("/", realm).readEntity(
- new GenericType<>() {
- });
+ ProvisioningResult<RealmTO> result = REALM_SERVICE.create("/", realm).readEntity(new GenericType<>() {
+ });
assertNotNull(result);
assertEquals(1, result.getPropagationStatuses().size());
assertEquals(RESOURCE_NAME_LDAP_ORGUNIT, result.getPropagationStatuses().get(0).getResource());
assertEquals(ExecStatus.SUCCESS, result.getPropagationStatuses().get(0).getStatus());
ProvisioningResult<RealmTO> resultChild = REALM_SERVICE.create("/test", childRealm).readEntity(
- new GenericType<>() {
- });
+ new GenericType<>() {
+ });
assertNotNull(resultChild);
assertEquals(1, resultChild.getPropagationStatuses().size());
assertEquals(RESOURCE_NAME_LDAP_ORGUNIT, resultChild.getPropagationStatuses().get(0).getResource());
assertEquals(ExecStatus.SUCCESS, resultChild.getPropagationStatuses().get(0).getStatus());
ProvisioningResult<RealmTO> resultDescendant = REALM_SERVICE.create("/test/child", descendantRealm).readEntity(
- new GenericType<>() {
- });
+ new GenericType<>() {
+ });
assertNotNull(resultDescendant);
assertEquals(1, resultDescendant.getPropagationStatuses().size());
assertEquals(RESOURCE_NAME_LDAP_ORGUNIT, resultDescendant.getPropagationStatuses().get(0).getResource());
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 4ac8ce9f8b..d28f681cfe 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
@@ -59,7 +59,6 @@ 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.identityconnectors.framework.common.objects.Name;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -178,7 +177,7 @@ public class SearchITCase extends AbstractITCase {
GroupTO group = createGroup(groupCR).getEntity();
assertNotNull(group);
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -236,7 +235,7 @@ public class SearchITCase extends AbstractITCase {
role = getObject(response.getLocation(), RoleService.class, RoleTO.class);
assertNotNull(role);
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -333,7 +332,7 @@ public class SearchITCase extends AbstractITCase {
public void searchByDate() {
CLIENT_FACTORY.create("bellini", "password").self();
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -687,7 +686,7 @@ public class SearchITCase extends AbstractITCase {
build();
updateAnyObject(anyObjectUR);
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -726,7 +725,7 @@ public class SearchITCase extends AbstractITCase {
req.getPlainAttrs().add(new AttrPatch.Builder(attr("ctype", "ou=sample,o=isp")).build());
USER_SERVICE.update(req);
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -791,7 +790,7 @@ public class SearchITCase extends AbstractITCase {
USER_SERVICE.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
fiql(SyncopeClient.getUserSearchConditionBuilder().is("userId").equalTo("*@apache.org").query()).
orderBy(SyncopeClient.getOrderByClauseBuilder().asc("surname").desc("firstname").build()).build());
- if (!ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (!IS_ELASTICSEARCH_ENABLED) {
fail();
}
} catch (SyncopeClientException e) {
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
index fec1043d07..3d563da894 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
@@ -91,7 +91,6 @@ import org.apache.syncope.common.rest.api.service.UserSelfService;
import org.apache.syncope.common.rest.api.service.UserService;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.FlowableDetector;
import org.apache.syncope.fit.core.reference.TestAccountRuleConf;
import org.apache.syncope.fit.core.reference.TestPasswordRuleConf;
import org.identityconnectors.framework.common.objects.OperationalAttributes;
@@ -703,7 +702,7 @@ public class UserITCase extends AbstractITCase {
@Test
public void createActivate() {
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
UserCR userCR = getUniqueSample("createActivate@syncope.apache.org");
@@ -738,7 +737,7 @@ public class UserITCase extends AbstractITCase {
UserTO userTO = createUser(userCR).getEntity();
assertNotNull(userTO);
- assertEquals(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform())
+ assertEquals(IS_FLOWABLE_ENABLED
? "active"
: "created", userTO.getStatus());
@@ -774,7 +773,7 @@ public class UserITCase extends AbstractITCase {
userCR.getResources().add(RESOURCE_NAME_LDAP);
UserTO userTO = createUser(userCR).getEntity();
assertNotNull(userTO);
- assertEquals(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform())
+ assertEquals(IS_FLOWABLE_ENABLED
? "active"
: "created", userTO.getStatus());
String userKey = userTO.getKey();
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
index c15b8e807f..aa3bf1ed5d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
@@ -85,7 +85,6 @@ import org.apache.syncope.core.provisioning.java.propagation.DBPasswordPropagati
import org.apache.syncope.core.provisioning.java.propagation.LDAPPasswordPropagationActions;
import org.apache.syncope.core.spring.security.Encryptor;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.ElasticsearchDetector;
import org.identityconnectors.framework.common.objects.Name;
import org.identityconnectors.framework.common.objects.OperationalAttributes;
import org.junit.jupiter.api.Test;
@@ -1066,7 +1065,7 @@ public class UserIssuesITCase extends AbstractITCase {
@Test
public void issueSYNCOPE391() {
- assumeFalse(ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform()));
+ assumeFalse(IS_ELASTICSEARCH_ENABLED);
// 1. create user on Syncope with null password
UserCR userCR = UserITCase.getUniqueSample("syncope391@syncope.apache.org");
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserRequestITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserRequestITCase.java
index eb63a93f26..5b3b7cfc84 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserRequestITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserRequestITCase.java
@@ -46,7 +46,6 @@ import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.rest.api.beans.UserRequestQuery;
import org.apache.syncope.common.rest.api.service.UserRequestService;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.FlowableDetector;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -56,7 +55,7 @@ public class UserRequestITCase extends AbstractITCase {
@BeforeAll
public static void loadBpmnProcesses() throws IOException {
assumeFalse(CLIENT_FACTORY.getContentType() == SyncopeClientFactoryBean.ContentType.YAML);
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
WebClient.client(BPMN_PROCESS_SERVICE).type(MediaType.APPLICATION_XML_TYPE);
BPMN_PROCESS_SERVICE.set("directorGroupRequest",
@@ -70,7 +69,7 @@ public class UserRequestITCase extends AbstractITCase {
@BeforeEach
public void check() {
assumeFalse(CLIENT_FACTORY.getContentType() == SyncopeClientFactoryBean.ContentType.YAML);
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
}
@Test
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
index 5cf65843fb..c4596e7dad 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
@@ -63,8 +63,6 @@ import org.apache.syncope.common.rest.api.service.UserRequestService;
import org.apache.syncope.common.rest.api.service.UserSelfService;
import org.apache.syncope.common.rest.api.service.UserService;
import org.apache.syncope.fit.AbstractITCase;
-import org.apache.syncope.fit.ElasticsearchDetector;
-import org.apache.syncope.fit.FlowableDetector;
import org.junit.jupiter.api.Test;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -78,7 +76,7 @@ public class UserSelfITCase extends AbstractITCase {
@Test
public void create() {
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
// 1. self-registration as admin: failure
try {
@@ -100,7 +98,7 @@ public class UserSelfITCase extends AbstractITCase {
@Test
public void createAndApprove() {
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
// 1. self-create user with membership: goes 'createApproval' with resources and membership but no propagation
UserCR userCR = UserITCase.getUniqueSample("anonymous@syncope.apache.org");
@@ -139,7 +137,7 @@ public class UserSelfITCase extends AbstractITCase {
@Test
public void createAndUnclaim() {
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
// 1. self-create user with membership: goes 'createApproval' with resources and membership but no propagation
UserCR userCR = UserITCase.getUniqueSample("anonymous@syncope.apache.org");
@@ -232,14 +230,14 @@ public class UserSelfITCase extends AbstractITCase {
readEntity(new GenericType<ProvisioningResult<UserTO>>() {
}).getEntity();
assertNotNull(updated);
- assertEquals(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform())
+ assertEquals(IS_FLOWABLE_ENABLED
? "active" : "created", updated.getStatus());
assertTrue(updated.getUsername().endsWith("XX"));
}
@Test
public void updateWithApproval() {
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
// 1. create user as admin
UserTO created = createUser(UserITCase.getUniqueSample("anonymous@syncope.apache.org")).getEntity();
@@ -303,7 +301,7 @@ public class UserSelfITCase extends AbstractITCase {
new GenericType<ProvisioningResult<UserTO>>() {
}).getEntity();
assertNotNull(deleted);
- assertEquals(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform())
+ assertEquals(IS_FLOWABLE_ENABLED
? "deleteApproval" : null, deleted.getStatus());
}
@@ -340,7 +338,7 @@ public class UserSelfITCase extends AbstractITCase {
}
anonClient.getService(UserSelfService.class).requestPasswordReset(user.getUsername(), "Rossi");
- if (ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform())) {
+ if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
@@ -456,7 +454,7 @@ public class UserSelfITCase extends AbstractITCase {
@Test
public void createWithReject() {
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
UserCR userCR = UserITCase.getUniqueSample("createWithReject@syncope.apache.org");
userCR.getResources().add(RESOURCE_NAME_TESTDB);
@@ -532,7 +530,7 @@ public class UserSelfITCase extends AbstractITCase {
@Test
public void createWithApproval() {
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
// read forms *before* any operation
PagedResult<UserRequestForm> forms = USER_REQUEST_SERVICE.listForms(new UserRequestQuery.Builder().build());
@@ -619,7 +617,7 @@ public class UserSelfITCase extends AbstractITCase {
@Test
public void updateApproval() {
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
// read forms *before* any operation
PagedResult<UserRequestForm> forms = USER_REQUEST_SERVICE.listForms(
@@ -682,7 +680,7 @@ public class UserSelfITCase extends AbstractITCase {
@Test
public void availableTasks() {
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
UserTO user = createUser(UserITCase.getUniqueSample("availableTasks@apache.org")).getEntity();
assertEquals("active", user.getStatus());
@@ -696,7 +694,7 @@ public class UserSelfITCase extends AbstractITCase {
@Test
public void issueSYNCOPE15() {
- assumeTrue(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform()));
+ assumeTrue(IS_FLOWABLE_ENABLED);
// read forms *before* any operation
PagedResult<UserRequestForm> forms = USER_REQUEST_SERVICE.listForms(new UserRequestQuery.Builder().build());
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/enduser/AuthenticatedITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/enduser/AuthenticatedITCase.java
index 086463f7d8..5a64570ebc 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/enduser/AuthenticatedITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/enduser/AuthenticatedITCase.java
@@ -32,7 +32,6 @@ import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPasswordFieldPa
import org.apache.syncope.common.lib.request.BooleanReplacePatchItem;
import org.apache.syncope.common.lib.request.UserUR;
import org.apache.syncope.common.lib.to.UserTO;
-import org.apache.syncope.fit.FlowableDetector;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.util.tester.FormTester;
import org.junit.jupiter.api.Test;
@@ -112,7 +111,7 @@ public class AuthenticatedITCase extends AbstractEnduserITCase {
TESTER.assertRenderedPage(SelfResult.class);
- assertEquals(FlowableDetector.isFlowableEnabledForUserWorkflow(ADMIN_CLIENT.platform())
+ assertEquals(IS_FLOWABLE_ENABLED
? "active" : "created", USER_SERVICE.read(username).getStatus());
assertEquals(newEmail, USER_SERVICE.read(username).getPlainAttr("email").get().getValues().get(0));
diff --git a/pom.xml b/pom.xml
index 8d794ce417..dd1a717203 100644
--- a/pom.xml
+++ b/pom.xml
@@ -415,7 +415,7 @@ under the License.
<bouncycastle.version>1.70</bouncycastle.version>
<nimbus-jose-jwt.version>9.25.6</nimbus-jose-jwt.version>
- <jackson.version>2.14.0-rc2</jackson.version>
+ <jackson.version>2.14.0-rc3</jackson.version>
<spring-boot.version>2.7.5</spring-boot.version>
<spring-cloud-gateway.version>3.1.4</spring-cloud-gateway.version>
@@ -432,7 +432,7 @@ under the License.
<slf4j.version>1.7.36</slf4j.version>
- <elasticsearch.version>8.4.3</elasticsearch.version>
+ <elasticsearch.version>8.5.0</elasticsearch.version>
<apacheds.version>2.0.0.AM26</apacheds.version>
<apachedirapi.version>2.0.0</apachedirapi.version>
@@ -786,6 +786,12 @@ under the License.
<version>${jackson.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml.woodstox</groupId>
+ <artifactId>woodstox-core</artifactId>
+ <version>6.4.0</version>
+ </dependency>
+
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
diff --git a/src/main/asciidoc/reference-guide/concepts/audit.adoc b/src/main/asciidoc/reference-guide/concepts/audit.adoc
index 2e65916855..4a0cda5a42 100644
--- a/src/main/asciidoc/reference-guide/concepts/audit.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/audit.adoc
@@ -20,7 +20,8 @@
The audit feature allows to capture <<audit-events,events>> occurring within the <<core>> and to log relevant information
about them. +
-By default, events are logged as entries into the `AuditEntry` table of the internal storage.
+By default, events are logged as entries into the `AuditEntry` table of the internal storage. +
+Audit events can also be processed differently, for example when using the <<elasticsearch>> extension.
Once events are reported, they can be used as input for external tools.
@@ -36,7 +37,7 @@ except for the admin console <<console-configuration-audit,tooling>>, which is n
==== Audit Appenders
-In addition to insertions into the `AuditEntry` table, events are also available for custom handling via Audit
+In addition to default processing, events are also available for custom handling via Audit
Appenders, based on https://logging.apache.org/log4j/2.x/manual/appenders.html[Apache Log4j 2 Appenders^]. +
This allows to empower the available implementations or to write new ones in order to route audit messages, with optional
transformation (rewrite), to files, queues, sockets, syslog, etc.
diff --git a/src/main/asciidoc/reference-guide/concepts/extensions.adoc b/src/main/asciidoc/reference-guide/concepts/extensions.adoc
index e71ece95cb..1c09ec00fe 100644
--- a/src/main/asciidoc/reference-guide/concepts/extensions.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/extensions.adoc
@@ -101,11 +101,11 @@ This extension adds features to all components and layers that are available, an
==== Elasticsearch
-This extension provides an alternate internal search engine for <<users-groups-and-any-objects>>, requiring an external
-https://www.elastic.co/[Elasticsearch^] cluster.
+This extension provides an alternate internal search engine for <<users-groups-and-any-objects>> and <<audit-events>>,
+requiring an external https://www.elastic.co/[Elasticsearch^] cluster.
[WARNING]
-This extension supports Elasticsearch server versions starting from 7.x.
+This extension supports Elasticsearch server versions starting from 8.x.
[TIP]
As search operations are central for different aspects of the <<provisioning,provisioning process>>, the global
diff --git a/src/main/asciidoc/reference-guide/usage/customization.adoc b/src/main/asciidoc/reference-guide/usage/customization.adoc
index 95f46b8be7..2b065e1456 100644
--- a/src/main/asciidoc/reference-guide/usage/customization.adoc
+++ b/src/main/asciidoc/reference-guide/usage/customization.adoc
@@ -358,6 +358,11 @@ Add the following dependencies to `core/pom.xml`:
[source,xml,subs="verbatim,attributes"]
----
+<dependency>
+ <groupId>org.apache.syncope.ext.elasticsearch</groupId>
+ <artifactId>syncope-ext-elasticsearch-logic</artifactId>
+ <version>${syncope.version}</version>
+</dependency>
<dependency>
<groupId>org.apache.syncope.ext.elasticsearch</groupId>
<artifactId>syncope-ext-elasticsearch-provisioning-java</artifactId>
@@ -370,6 +375,24 @@ Add the following dependencies to `core/pom.xml`:
</dependency>
----
+Create
+
+[source]
+....
+elasticsearch.hostname=localhost
+elasticsearch.port=9200
+elasticsearch.scheme=http
+elasticsearch.indexMaxResultWindow=10000
+elasticsearch.numberOfShards=1
+elasticsearch.numberOfReplicas=1
+....
+
+as `core/src/main/resources/core-elasticsearch.properties`.
+
+Do not forget to include `elasticsearch` as
+https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.profiles.adding-active-profiles[Spring Boot profile^]
+for the Core application.
+
If needed, customize the `@Bean` declarations from
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/ext/elasticsearch/client-elasticsearch/src/main/java/org/apache/syncope/ext/elasticsearch/client/ElasticsearchClientContext.java[ElasticsearchClientContext^]
@@ -381,12 +404,12 @@ as explained <<extending-configuration,above>>.
It is also required to initialize the Elasticsearch indexes: add a new Java <<implementations,implementation>> for
`TASKJOB_DELEGATE` and use `org.apache.syncope.core.provisioning.java.job.ElasticsearchReindex` as class. +
-Then, create a new <<tasks-scheduled, schedyled task>>, select the implementation just created as job delegate and execute it.
+Then, create a new <<tasks-scheduled, scheduled task>>, select the implementation just created as job delegate and execute it.
[TIP]
The `org.apache.syncope.core.provisioning.java.job.ElasticsearchReindex` task created above is not meant for
scheduled execution; rather, it can be run every time you want to blank and re-create the Elasticsearch indexes
-starting from Syncope's users, groups and any objects.
+starting from Syncope's internal storage.
[discrete]
===== Enable the <<SCIM>> extension