You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by di...@apache.org on 2020/08/06 09:04:00 UTC
[syncope] branch master updated: [SYNCOPE-1584] WA events
management (#210)
This is an automated email from the ASF dual-hosted git repository.
dimaayash 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 2e4be06 [SYNCOPE-1584] WA events management (#210)
2e4be06 is described below
commit 2e4be06d2b8460df7fd17a8e230adbd6f117ec13
Author: DimaAy <di...@tirasa.net>
AuthorDate: Thu Aug 6 11:03:53 2020 +0200
[SYNCOPE-1584] WA events management (#210)
* [SYNCOPE-1584] WA events management
addd ITcase
add wa test
wa audit test
* rename
---
.../src/test/resources/domains/MasterContent.xml | 2 +
.../org/apache/syncope/fit/core/LoggerITCase.java | 27 ++++++++
pom.xml | 5 ++
wa/starter/pom.xml | 4 ++
.../starter/audit/SyncopeWAAuditTrailManager.java | 3 +-
.../wa/starter/config/SyncopeWAConfiguration.java | 27 ++++++--
.../SyncopeWAEventRepository.java} | 76 ++++++++++++----------
.../audit/SyncopeWAAuditTrailManagerTest.java | 59 +++++++++++++++++
.../events/SyncopeWAEventRepositoryTest.java | 60 +++++++++++++++++
9 files changed, 224 insertions(+), 39 deletions(-)
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 324c3be..17f3dd4 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -2482,6 +2482,8 @@ $$ }
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[SyncopeLogic]:[]:[isSelfRegAllowed]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[WA]:[LoggerLogic]:[AUTHENTICATION]:[validate]:[SUCCESS]" logLevel="DEBUG"/>
+
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[WA]:[LoggerLogic]:[AuthenticationEvent]:[auth]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[ConnectorLogic]:[]:[create]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[ConnectorLogic]:[]:[update]:[SUCCESS]" logLevel="DEBUG"/>
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LoggerITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LoggerITCase.java
index 70171ff..227350f 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LoggerITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LoggerITCase.java
@@ -298,6 +298,33 @@ public class LoggerITCase extends AbstractITCase {
assertNotNull(events);
assertEquals(1, events.getSize());
}
+
+ @Test
+ public void saveAuthEvent() {
+ AuditEntry auditEntry = new AuditEntry();
+ auditEntry.setWho("syncope-user " + UUID.randomUUID().toString());
+ auditEntry.setLogger(new AuditLoggerName(
+ EventCategoryType.WA,
+ "LoggerLogic",
+ "AuthenticationEvent",
+ "auth",
+ AuditElements.Result.SUCCESS));
+ auditEntry.setDate(new Date());
+ auditEntry.setBefore(UUID.randomUUID().toString());
+ auditEntry.setOutput(UUID.randomUUID().toString());
+ assertDoesNotThrow(() -> loggerService.create(auditEntry));
+
+ PagedResult<AuditEntry> events = loggerService.search(new AuditQuery.Builder().
+ size(1).
+ type(auditEntry.getLogger().getType()).
+ category(auditEntry.getLogger().getCategory()).
+ subcategory(auditEntry.getLogger().getSubcategory()).
+ event(auditEntry.getLogger().getEvent()).
+ result(auditEntry.getLogger().getResult()).
+ build());
+ assertNotNull(events);
+ assertEquals(1, events.getSize());
+ }
@Test
public void customAuditAppender() throws IOException, InterruptedException {
diff --git a/pom.xml b/pom.xml
index 2f93b31..a7372d6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1402,6 +1402,11 @@ under the License.
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-core-events-api</artifactId>
+ <version>${cas.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-authentication</artifactId>
<version>${cas.version}</version>
</dependency>
diff --git a/wa/starter/pom.xml b/wa/starter/pom.xml
index f62cf31..2b9e7fd 100644
--- a/wa/starter/pom.xml
+++ b/wa/starter/pom.xml
@@ -76,6 +76,10 @@ under the License.
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-core-events-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-cookie</artifactId>
</dependency>
<dependency>
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManager.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManager.java
index b7f0ce5..42f1adc 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManager.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManager.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.wa.starter.audit;
+import com.fasterxml.jackson.core.JsonProcessingException;
import java.time.LocalDate;
import java.util.Map;
import java.util.Set;
@@ -76,7 +77,7 @@ public class SyncopeWAAuditTrailManager extends AbstractAuditTrailManager {
auditEntry.setLogger(auditLogger);
syncopeClient.getService(LoggerService.class).create(auditEntry);
- } catch (Exception e) {
+ } catch (JsonProcessingException e) {
LOG.error("During serialization", e);
}
}
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
index c53c8fa..421b2a5 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
@@ -26,11 +26,6 @@ import io.swagger.v3.oas.models.info.Info;
import org.apache.commons.lang3.StringUtils;
import com.warrenstrange.googleauth.IGoogleAuthenticator;
import io.swagger.v3.oas.models.security.SecurityScheme;
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStart;
import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStop;
@@ -79,6 +74,15 @@ import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.syncope.wa.starter.events.SyncopeWAEventRepository;
+import org.apereo.cas.support.events.CasEventRepository;
+import org.apereo.cas.support.events.CasEventRepositoryFilter;
+
public class SyncopeWAConfiguration {
@Autowired
@@ -196,6 +200,19 @@ public class SyncopeWAConfiguration {
return plan -> plan.registerAuditTrailManager(new SyncopeWAAuditTrailManager(restClient));
}
+ @ConditionalOnMissingBean(name = "syncopWaEventRepositoryFilter")
+ @Bean
+ public CasEventRepositoryFilter syncopeWAEventRepositoryFilter() {
+ return CasEventRepositoryFilter.noOp();
+ }
+
+ @Autowired
+ @Bean
+ public CasEventRepository casEventRepository(final WARestClient restClient) {
+ return new SyncopeWAEventRepository(syncopeWAEventRepositoryFilter(), restClient);
+ }
+
+
@Autowired
@Bean
public DelegatedClientFactoryCustomizer<Client<?>> delegatedClientCustomizer(final WARestClient restClient) {
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManager.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/events/SyncopeWAEventRepository.java
similarity index 50%
copy from wa/starter/src/main/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManager.java
copy to wa/starter/src/main/java/org/apache/syncope/wa/starter/events/SyncopeWAEventRepository.java
index b7f0ce5..fdcb4c3 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManager.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/events/SyncopeWAEventRepository.java
@@ -16,78 +16,88 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.wa.starter.audit;
+package org.apache.syncope.wa.starter.events;
-import java.time.LocalDate;
-import java.util.Map;
-import java.util.Set;
-import org.apereo.cas.audit.spi.AbstractAuditTrailManager;
+import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.lib.SyncopeClient;
import org.apache.syncope.common.lib.log.AuditEntry;
import org.apache.syncope.common.lib.types.AuditElements;
import org.apache.syncope.common.lib.types.AuditLoggerName;
import org.apache.syncope.common.rest.api.service.LoggerService;
import org.apache.syncope.wa.bootstrap.WARestClient;
-import org.apereo.inspektr.audit.AuditActionContext;
+import org.apereo.cas.support.events.CasEventRepositoryFilter;
+import org.apereo.cas.support.events.dao.AbstractCasEventRepository;
+import org.apereo.cas.support.events.dao.CasEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.syncope.client.lib.SyncopeClient;
+public class SyncopeWAEventRepository extends AbstractCasEventRepository {
-public class SyncopeWAAuditTrailManager extends AbstractAuditTrailManager {
-
- private static final Logger LOG = LoggerFactory.getLogger(SyncopeWAAuditTrailManager.class);
+ private static final Logger LOG = LoggerFactory.getLogger(SyncopeWAEventRepository.class);
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final WARestClient waRestClient;
- public SyncopeWAAuditTrailManager(final WARestClient restClient) {
- super(true);
+ public SyncopeWAEventRepository(final CasEventRepositoryFilter eventRepositoryFilter,
+ final WARestClient restClient) {
+ super(eventRepositoryFilter);
this.waRestClient = restClient;
}
+ public void put(final Map<String, String> properties, final String key, final String value) {
+ if (StringUtils.isNotBlank(value)) {
+ properties.put(key, value);
+ }
+ }
+
@Override
- protected void saveAuditRecord(final AuditActionContext audit) {
+ public void saveInternal(final CasEvent event) {
SyncopeClient syncopeClient = waRestClient.getSyncopeClient();
if (syncopeClient == null) {
LOG.debug("Syncope client is not yet ready to store audit record");
return;
}
- LOG.info("Loading application definitions");
+ LOG.info("Saving Cas events");
try {
- String output = OBJECT_MAPPER.writeValueAsString(Map.of("resource", audit.getResourceOperatedUpon(),
- "clientIpAddress", audit.getClientIpAddress(),
- "serverIpAddress", audit.getServerIpAddress()));
+ Map<String, String> properties = new HashMap<>();
+ if (event.getGeoLocation() != null) {
+ put(properties, "geoLatitude", event.getGeoLocation().getLatitude());
+ put(properties, "geoLongitude", event.getGeoLocation().getLongitude());
+ put(properties, "geoAccuracy", event.getGeoLocation().getAccuracy());
+ put(properties, "geoTimestamp", event.getGeoLocation().getTimestamp());
+ }
+ put(properties, "clientIpAddress", event.getClientIpAddress());
+ put(properties, "serverIpAddress", event.getServerIpAddress());
+
+ String output = OBJECT_MAPPER.writeValueAsString(properties);
AuditEntry auditEntry = new AuditEntry();
- auditEntry.setWho(audit.getPrincipal());
- auditEntry.setDate(audit.getWhenActionWasPerformed());
+ auditEntry.setWho(event.getPrincipalId());
+ if (event.getTimestamp() != null) {
+ auditEntry.setDate(new Date(event.getTimestamp()));
+ }
auditEntry.setOutput(output);
- AuditElements.Result result = StringUtils.containsIgnoreCase(audit.getActionPerformed(), "fail")
- ? AuditElements.Result.FAILURE
- : AuditElements.Result.SUCCESS;
-
AuditLoggerName auditLogger = new AuditLoggerName(AuditElements.EventCategoryType.WA,
- "LoggerLogic", AuditElements.AUTHENTICATION_CATEGORY.toUpperCase(),
- audit.getActionPerformed(), result);
-
+ "LoggerLogic", event.getType().toUpperCase(),
+ String.valueOf(event.getId()), AuditElements.Result.SUCCESS);
auditEntry.setLogger(auditLogger);
syncopeClient.getService(LoggerService.class).create(auditEntry);
- } catch (Exception e) {
+ } catch (JsonProcessingException e) {
LOG.error("During serialization", e);
}
}
@Override
- public Set<? extends AuditActionContext> getAuditRecordsSince(final LocalDate sinceDate) {
- throw new UnsupportedOperationException("Fetching audit events from WA is not supported");
+ public Collection<? extends CasEvent> load() {
+ throw new UnsupportedOperationException("Fetching authentication events from WA is not supported");
}
- @Override
- public void removeAll() {
- throw new UnsupportedOperationException("Removing audit events from WA is not supported");
- }
}
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManagerTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManagerTest.java
new file mode 100644
index 0000000..79d2a64
--- /dev/null
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManagerTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.wa.starter.audit;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Date;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.log.AuditEntry;
+import org.apache.syncope.common.rest.api.service.LoggerService;
+import org.apache.syncope.wa.bootstrap.WARestClient;
+import org.apache.syncope.wa.starter.AbstractTest;
+import org.apereo.inspektr.audit.AuditActionContext;
+import org.junit.jupiter.api.Test;
+
+public class SyncopeWAAuditTrailManagerTest extends AbstractTest {
+
+ private static LoggerService loggerService;
+
+ private static WARestClient getWaRestClient() {
+ WARestClient restClient = mock(WARestClient.class);
+ SyncopeClient syncopeClient = mock(SyncopeClient.class);
+ loggerService = mock(LoggerService.class);
+
+ when(restClient.getSyncopeClient()).thenReturn(syncopeClient);
+ when(syncopeClient.getService(LoggerService.class)).thenReturn(loggerService);
+
+ return restClient;
+ }
+
+ @Test
+ public void saveAuditRecord() {
+ AuditActionContext audit = new AuditActionContext("principal", "resourceOperatedUpon", "actionPerformed",
+ "applicationCode", new Date(), "clientIpAddress", "serverIpAddress");
+ SyncopeWAAuditTrailManager auditTrailManager = new SyncopeWAAuditTrailManager(getWaRestClient());
+ auditTrailManager.saveAuditRecord(audit);
+ verify(loggerService).create(any(AuditEntry.class));
+ }
+
+}
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/events/SyncopeWAEventRepositoryTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/events/SyncopeWAEventRepositoryTest.java
new file mode 100644
index 0000000..e823ed3
--- /dev/null
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/events/SyncopeWAEventRepositoryTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.wa.starter.events;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Map;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.log.AuditEntry;
+import org.apache.syncope.common.rest.api.service.LoggerService;
+import org.apache.syncope.wa.bootstrap.WARestClient;
+import org.apache.syncope.wa.starter.AbstractTest;
+import org.apereo.cas.support.events.CasEventRepositoryFilter;
+import org.apereo.cas.support.events.dao.CasEvent;
+import org.junit.jupiter.api.Test;
+
+public class SyncopeWAEventRepositoryTest extends AbstractTest {
+
+ private static LoggerService loggerService;
+
+ private static WARestClient getWaRestClient() {
+ WARestClient restClient = mock(WARestClient.class);
+ SyncopeClient syncopeClient = mock(SyncopeClient.class);
+ loggerService = mock(LoggerService.class);
+
+ when(restClient.getSyncopeClient()).thenReturn(syncopeClient);
+ when(syncopeClient.getService(LoggerService.class)).thenReturn(loggerService);
+
+ return restClient;
+ }
+
+ @Test
+ public void saveInternal() {
+ CasEvent event = new CasEvent(1L, "Auth", "principalId", "creationTime", Map.of("timestamp", "1"));
+ SyncopeWAEventRepository eventRepository = new SyncopeWAEventRepository(CasEventRepositoryFilter.noOp(),
+ getWaRestClient());
+ eventRepository.saveInternal(event);
+ verify(loggerService).create(any(AuditEntry.class));
+ }
+
+}