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 2023/12/12 16:14:47 UTC
(syncope) branch 3_0_X updated: [SYNCOPE-1791] Improving Audit conf management
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch 3_0_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/3_0_X by this push:
new ad28f966f0 [SYNCOPE-1791] Improving Audit conf management
ad28f966f0 is described below
commit ad28f966f09fd73d6bf5a45f6ee1661ce3234de5
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Tue Dec 12 16:50:11 2023 +0100
[SYNCOPE-1791] Improving Audit conf management
---
.../client/console/events/EventCategoryPanel.java | 338 +++++++++++----------
.../client/console/events/EventSelectionPanel.java | 76 ++---
.../client/console/events/SelectedEventsPanel.java | 46 +--
.../notifications/NotificationDirectoryPanel.java | 18 +-
.../notifications/NotificationWizardBuilder.java | 12 +-
.../apache/syncope/client/console/pages/Audit.java | 39 +--
.../client/console/rest/AuditRestClient.java | 4 +-
.../syncope/common/lib/types/AuditLoggerName.java | 203 ++++++-------
.../common/lib/types/AuditLoggerNameTest.java | 36 +++
.../syncope/core/logic/IdMLogicTestContext.java | 6 +
.../org/apache/syncope/core/logic/AuditLogic.java | 60 ++--
.../syncope/core/logic/IdRepoLogicContext.java | 11 +-
.../syncope/core/logic/init/AuditAccessor.java | 30 +-
.../syncope/core/logic/init/AuditLoader.java | 32 +-
.../syncope/core/logic/IdRepoLogicTestContext.java | 6 +
.../java/pushpull/LDAPMembershipPullActions.java | 8 +-
.../pushpull/LDAPMembershipPullActionsTest.java | 35 +--
.../org/apache/syncope/fit/core/AuditITCase.java | 80 ++++-
.../test/resources/CustomAuditLogicActions.groovy | 47 +++
19 files changed, 599 insertions(+), 488 deletions(-)
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/EventCategoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/EventCategoryPanel.java
index cbad77a315..983f259af3 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/EventCategoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/EventCategoryPanel.java
@@ -18,10 +18,9 @@
*/
package org.apache.syncope.client.console.events;
-import java.util.HashSet;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
@@ -55,9 +54,54 @@ public abstract class EventCategoryPanel extends Panel {
private static final long serialVersionUID = 6429053774964787734L;
- private final List<EventCategory> eventCategoryTOs;
+ protected static class ChangeCategoryEvent {
- private final EventCategory eventCategoryTO = new EventCategory();
+ protected final AjaxRequestTarget target;
+
+ protected final Panel changedPanel;
+
+ ChangeCategoryEvent(final AjaxRequestTarget target, final Panel changedPanel) {
+ this.target = target;
+ this.changedPanel = changedPanel;
+ }
+
+ public AjaxRequestTarget getTarget() {
+ return target;
+ }
+
+ public Panel getChangedPanel() {
+ return changedPanel;
+ }
+ }
+
+ protected static List<String> filter(
+ final List<EventCategory> categories,
+ final EventCategoryType type) {
+
+ return categories.stream().
+ filter(c -> type == c.getType() && StringUtils.isNotEmpty(c.getCategory())).
+ map(EventCategory::getCategory).
+ distinct().
+ sorted().
+ collect(Collectors.toList());
+ }
+
+ protected static List<String> filter(
+ final List<EventCategory> categories,
+ final EventCategoryType type,
+ final String category) {
+
+ return categories.stream().
+ filter(c -> type == c.getType() && StringUtils.equals(category, c.getCategory())).
+ map(EventCategory::getCategory).
+ distinct().
+ sorted().
+ collect(Collectors.toList());
+ }
+
+ private final List<EventCategory> eventCategories;
+
+ private final EventCategory eventCategory = new EventCategory();
private final WebMarkupContainer categoryContainer;
@@ -79,7 +123,7 @@ public abstract class EventCategoryPanel extends Panel {
public EventCategoryPanel(
final String id,
- final List<EventCategory> eventCategoryTOs,
+ final List<EventCategory> eventCategories,
final IModel<List<String>> model) {
super(id);
@@ -88,7 +132,7 @@ public abstract class EventCategoryPanel extends Panel {
selectedEventsPanel = new SelectedEventsPanel("selectedEventsPanel", model);
add(selectedEventsPanel);
- this.eventCategoryTOs = eventCategoryTOs;
+ this.eventCategories = eventCategories;
categoryContainer = new WebMarkupContainer("categoryContainer");
categoryContainer.setOutputMarkupId(true);
@@ -104,9 +148,12 @@ public abstract class EventCategoryPanel extends Panel {
type = new AjaxDropDownChoicePanel<>(
"type",
"type",
- new PropertyModel<>(eventCategoryTO, "type"),
+ new PropertyModel<>(eventCategory, "type"),
false);
- type.setChoices(List.of(EventCategoryType.values()));
+ type.setChoices(eventCategories.stream().
+ map(EventCategory::getType).distinct().
+ sorted(Comparator.comparing(EventCategoryType::name)).
+ collect(Collectors.toList()));
type.setChoiceRenderer(new IChoiceRenderer<>() {
private static final long serialVersionUID = 2317134950949778735L;
@@ -123,7 +170,9 @@ public abstract class EventCategoryPanel extends Panel {
@Override
public EventCategoryType getObject(
- final String id, final IModel<? extends List<? extends EventCategoryType>> choices) {
+ final String id,
+ final IModel<? extends List<? extends EventCategoryType>> choices) {
+
return choices.getObject().stream().filter(object -> object.name().equals(id)).findAny().orElse(null);
}
});
@@ -142,9 +191,9 @@ public abstract class EventCategoryPanel extends Panel {
category = new AjaxDropDownChoicePanel<>(
"category",
"category",
- new PropertyModel<>(eventCategoryTO, "category"),
+ new PropertyModel<>(eventCategory, "category"),
false);
- category.setChoices(filter(eventCategoryTOs, type.getModelObject()));
+ category.setChoices(filter(eventCategories, type.getModelObject()));
categoryContainer.add(category);
category.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
@@ -160,9 +209,9 @@ public abstract class EventCategoryPanel extends Panel {
subcategory = new AjaxDropDownChoicePanel<>(
"subcategory",
"subcategory",
- new PropertyModel<>(eventCategoryTO, "subcategory"),
+ new PropertyModel<>(eventCategory, "subcategory"),
false);
- subcategory.setChoices(filter(eventCategoryTOs, type.getModelObject(), category.getModelObject()));
+ subcategory.setChoices(filter(eventCategories, type.getModelObject(), category.getModelObject()));
categoryContainer.add(subcategory);
subcategory.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
@@ -191,22 +240,22 @@ public abstract class EventCategoryPanel extends Panel {
@Override
public void onClick(final AjaxRequestTarget target, final EventCategory ignore) {
if (StringUtils.isNotBlank(custom.getModelObject())) {
- Pair<EventCategory, AuditElements.Result> parsed = AuditLoggerName.parseEventCategory(custom.
- getModelObject());
+ Pair<EventCategory, AuditElements.Result> parsed =
+ AuditLoggerName.parseEventCategory(custom.getModelObject());
- String eventString = AuditLoggerName.buildEvent(
- parsed.getKey().getType(),
- null,
- null,
- parsed.getKey().getEvents().isEmpty()
- ? StringUtils.EMPTY : parsed.getKey().getEvents().iterator().next(),
- parsed.getValue());
+ AuditLoggerName auditLoggerName = new AuditLoggerName(
+ parsed.getLeft().getType(),
+ null,
+ null,
+ parsed.getLeft().getEvents().isEmpty()
+ ? StringUtils.EMPTY : parsed.getLeft().getEvents().iterator().next(),
+ parsed.getRight());
custom.setModelObject(StringUtils.EMPTY);
send(EventCategoryPanel.this.getPage(), Broadcast.BREADTH, new EventSelectionChanged(
- target,
- Set.of(eventString),
- Set.of()));
+ target,
+ Set.of(auditLoggerName),
+ Set.of()));
target.add(categoryContainer);
}
}
@@ -218,22 +267,22 @@ public abstract class EventCategoryPanel extends Panel {
@Override
public void onClick(final AjaxRequestTarget target, final EventCategory ignore) {
if (StringUtils.isNotBlank(custom.getModelObject())) {
- Pair<EventCategory, AuditElements.Result> parsed = AuditLoggerName.parseEventCategory(custom.
- getModelObject());
+ Pair<EventCategory, AuditElements.Result> parsed =
+ AuditLoggerName.parseEventCategory(custom.getModelObject());
- String eventString = AuditLoggerName.buildEvent(
- parsed.getKey().getType(),
- null,
- null,
- parsed.getKey().getEvents().isEmpty()
- ? StringUtils.EMPTY : parsed.getKey().getEvents().iterator().next(),
- parsed.getValue());
+ AuditLoggerName auditLoggerName = new AuditLoggerName(
+ parsed.getLeft().getType(),
+ null,
+ null,
+ parsed.getLeft().getEvents().isEmpty()
+ ? StringUtils.EMPTY : parsed.getLeft().getEvents().iterator().next(),
+ parsed.getRight());
custom.setModelObject(StringUtils.EMPTY);
send(EventCategoryPanel.this.getPage(), Broadcast.BREADTH, new EventSelectionChanged(
- target,
- Set.of(),
- Set.of(eventString)));
+ target,
+ Set.of(),
+ Set.of(auditLoggerName)));
target.add(categoryContainer);
}
}
@@ -245,7 +294,7 @@ public abstract class EventCategoryPanel extends Panel {
actionsPanel.setEnabled(false);
actionsPanel.setMarkupId("inline-actions");
- eventsContainer.add(new EventSelectionPanel("eventsPanel", eventCategoryTO, model) {
+ eventsContainer.add(new EventSelectionPanel("eventsPanel", eventCategory, model) {
private static final long serialVersionUID = 3513194801190026082L;
@@ -256,106 +305,84 @@ public abstract class EventCategoryPanel extends Panel {
});
}
- private static List<String> filter(final List<EventCategory> eventCategoryTOs, final EventCategoryType type) {
- Set<String> res = new HashSet<>();
-
- eventCategoryTOs.stream().filter(eventCategory
- -> type == eventCategory.getType() && StringUtils.isNotEmpty(eventCategory.getCategory())).
- forEachOrdered(eventCategory -> res.add(eventCategory.getCategory()));
-
- return res.stream().sorted().collect(Collectors.toList());
- }
-
- private static List<String> filter(
- final List<EventCategory> eventCategoryTOs, final EventCategoryType type, final String category) {
-
- Set<String> res = new HashSet<>();
-
- eventCategoryTOs.stream().filter(eventCategory
- -> type == eventCategory.getType() && StringUtils.equals(category, eventCategory.getCategory())
- && StringUtils.isNotEmpty(eventCategory.getSubcategory())).
- forEachOrdered(eventCategory -> res.add(eventCategory.getSubcategory()));
-
- return res.stream().sorted().collect(Collectors.toList());
- }
-
@Override
public void onEvent(final IEvent<?> event) {
if (event.getPayload() instanceof ChangeCategoryEvent) {
// update objects ....
- eventCategoryTO.getEvents().clear();
-
- final ChangeCategoryEvent change = (ChangeCategoryEvent) event.getPayload();
-
- final Panel changedPanel = change.getChangedPanel();
- if (null != changedPanel.getId()) {
- switch (changedPanel.getId()) {
- case "type":
- eventCategoryTO.setType(type.getModelObject());
- eventCategoryTO.setCategory(null);
- eventCategoryTO.setSubcategory(null);
- if (type.getModelObject() == EventCategoryType.CUSTOM) {
- category.setChoices(List.of());
- subcategory.setChoices(List.of());
- category.setEnabled(false);
- subcategory.setEnabled(false);
- custom.setVisible(true);
- custom.setEnabled(true);
- actionsPanel.setVisible(true);
- actionsPanel.setEnabled(true);
- } else {
- category.setChoices(filter(eventCategoryTOs, type.getModelObject()));
- subcategory.setChoices(List.of());
- category.setEnabled(true);
- subcategory.setEnabled(true);
- custom.setVisible(false);
- custom.setEnabled(false);
- actionsPanel.setVisible(false);
- actionsPanel.setEnabled(false);
- }
- change.getTarget().add(categoryContainer);
- break;
-
- case "category":
- subcategory.setChoices(
- filter(eventCategoryTOs, type.getModelObject(), category.getModelObject()));
- eventCategoryTO.setCategory(category.getModelObject());
- eventCategoryTO.setSubcategory(null);
- change.getTarget().add(categoryContainer);
- break;
-
- default:
- eventCategoryTO.setSubcategory(subcategory.getModelObject());
- break;
- }
+ eventCategory.getEvents().clear();
+
+ ChangeCategoryEvent change = (ChangeCategoryEvent) event.getPayload();
+
+ switch (change.getChangedPanel().getId()) {
+ case "type":
+ eventCategory.setType(type.getModelObject());
+ eventCategory.setCategory(null);
+ eventCategory.setSubcategory(null);
+ if (type.getModelObject() == EventCategoryType.CUSTOM
+ || type.getModelObject() == EventCategoryType.WA) {
+
+ category.setChoices(List.of());
+ subcategory.setChoices(List.of());
+ category.setEnabled(false);
+ subcategory.setEnabled(false);
+ custom.setVisible(true);
+ custom.setEnabled(true);
+ actionsPanel.setVisible(true);
+ actionsPanel.setEnabled(true);
+ } else {
+ category.setChoices(filter(eventCategories, type.getModelObject()));
+ subcategory.setChoices(List.of());
+ category.setEnabled(true);
+ subcategory.setEnabled(true);
+ custom.setVisible(false);
+ custom.setEnabled(false);
+ actionsPanel.setVisible(false);
+ actionsPanel.setEnabled(false);
+ }
+ change.getTarget().add(categoryContainer);
+ break;
+
+ case "category":
+ subcategory.setChoices(
+ filter(eventCategories, type.getModelObject(), category.getModelObject()));
+ eventCategory.setCategory(category.getModelObject());
+ eventCategory.setSubcategory(null);
+ change.getTarget().add(categoryContainer);
+ break;
+
+ default:
+ eventCategory.setSubcategory(subcategory.getModelObject());
+ break;
}
updateEventsContainer(change.getTarget());
} else if (event.getPayload() instanceof InspectSelectedEvent) {
// update objects ....
- eventCategoryTO.getEvents().clear();
+ eventCategory.getEvents().clear();
InspectSelectedEvent inspectSelectedEvent = (InspectSelectedEvent) event.getPayload();
- Map.Entry<EventCategory, AuditElements.Result> categoryEvent =
+ Pair<EventCategory, AuditElements.Result> categoryEvent =
AuditLoggerName.parseEventCategory(inspectSelectedEvent.getEvent());
- eventCategoryTO.setType(categoryEvent.getKey().getType());
- category.setChoices(filter(eventCategoryTOs, type.getModelObject()));
+ eventCategory.setType(categoryEvent.getLeft().getType());
+ category.setChoices(filter(eventCategories, type.getModelObject()));
- eventCategoryTO.setCategory(categoryEvent.getKey().getCategory());
- subcategory.setChoices(filter(eventCategoryTOs, type.getModelObject(), category.getModelObject()));
+ eventCategory.setCategory(categoryEvent.getLeft().getCategory());
+ subcategory.setChoices(filter(eventCategories, type.getModelObject(), category.getModelObject()));
- eventCategoryTO.setSubcategory(categoryEvent.getKey().getSubcategory());
+ eventCategory.setSubcategory(categoryEvent.getLeft().getSubcategory());
+
+ if (categoryEvent.getLeft().getType() == EventCategoryType.CUSTOM
+ || categoryEvent.getLeft().getType() == EventCategoryType.WA) {
- if (categoryEvent.getKey().getType() == EventCategoryType.CUSTOM) {
custom.setModelObject(AuditLoggerName.buildEvent(
- categoryEvent.getKey().getType(),
- categoryEvent.getKey().getCategory(),
- categoryEvent.getKey().getSubcategory(),
- categoryEvent.getKey().getEvents().isEmpty()
- ? StringUtils.EMPTY : categoryEvent.getKey().getEvents().iterator().next(),
- categoryEvent.getValue()));
+ categoryEvent.getLeft().getType(),
+ categoryEvent.getLeft().getCategory(),
+ categoryEvent.getLeft().getSubcategory(),
+ categoryEvent.getLeft().getEvents().isEmpty()
+ ? StringUtils.EMPTY : categoryEvent.getLeft().getEvents().iterator().next(),
+ categoryEvent.getRight()));
category.setEnabled(false);
subcategory.setEnabled(false);
@@ -377,40 +404,6 @@ public abstract class EventCategoryPanel extends Panel {
}
}
- private void setEvents() {
- for (Iterator<EventCategory> itor = eventCategoryTOs.iterator();
- itor.hasNext() && eventCategoryTO.getEvents().isEmpty();) {
-
- EventCategory eventCategory = itor.next();
- if (eventCategory.getType() == eventCategoryTO.getType()
- && StringUtils.equals(eventCategory.getCategory(), eventCategoryTO.getCategory())
- && StringUtils.equals(eventCategory.getSubcategory(), eventCategoryTO.getSubcategory())) {
-
- eventCategoryTO.getEvents().addAll(eventCategory.getEvents());
- }
- }
- }
-
- private static class ChangeCategoryEvent {
-
- private final AjaxRequestTarget target;
-
- private final Panel changedPanel;
-
- ChangeCategoryEvent(final AjaxRequestTarget target, final Panel changedPanel) {
- this.target = target;
- this.changedPanel = changedPanel;
- }
-
- public AjaxRequestTarget getTarget() {
- return target;
- }
-
- public Panel getChangedPanel() {
- return changedPanel;
- }
- }
-
/**
* To be extended in order to add actions on events.
*
@@ -420,22 +413,35 @@ public abstract class EventCategoryPanel extends Panel {
// nothing by default
}
- private void authorizeList() {
- getListAuthRoles().forEach(
- role -> MetaDataRoleAuthorizationStrategy.authorize(selectedEventsPanel, RENDER, role));
+ protected abstract List<String> getListAuthRoles();
+
+ protected void authorizeList() {
+ getListAuthRoles().forEach(r -> MetaDataRoleAuthorizationStrategy.authorize(selectedEventsPanel, RENDER, r));
}
- private void authorizeChanges() {
- getChangeAuthRoles().forEach(role -> {
- MetaDataRoleAuthorizationStrategy.authorize(categoryContainer, RENDER, role);
- MetaDataRoleAuthorizationStrategy.authorize(eventsContainer, RENDER, role);
+ protected abstract List<String> getChangeAuthRoles();
+
+ protected void authorizeChanges() {
+ getChangeAuthRoles().forEach(r -> {
+ MetaDataRoleAuthorizationStrategy.authorize(categoryContainer, RENDER, r);
+ MetaDataRoleAuthorizationStrategy.authorize(eventsContainer, RENDER, r);
});
}
- private void updateEventsContainer(final AjaxRequestTarget target) {
- setEvents();
+ protected void updateEventsContainer(final AjaxRequestTarget target) {
+ for (Iterator<EventCategory> itor = eventCategories.iterator();
+ itor.hasNext() && eventCategory.getEvents().isEmpty();) {
- eventsContainer.addOrReplace(new EventSelectionPanel("eventsPanel", eventCategoryTO, model) {
+ EventCategory ec = itor.next();
+ if (eventCategory.getType() == ec.getType()
+ && StringUtils.equals(eventCategory.getCategory(), ec.getCategory())
+ && StringUtils.equals(eventCategory.getSubcategory(), ec.getSubcategory())) {
+
+ eventCategory.getEvents().addAll(ec.getEvents());
+ }
+ }
+
+ eventsContainer.addOrReplace(new EventSelectionPanel("eventsPanel", eventCategory, model) {
private static final long serialVersionUID = 3513194801190026082L;
@@ -446,8 +452,4 @@ public abstract class EventCategoryPanel extends Panel {
});
target.add(eventsContainer);
}
-
- protected abstract List<String> getListAuthRoles();
-
- protected abstract List<String> getChangeAuthRoles();
}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/EventSelectionPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/EventSelectionPanel.java
index 6eb92fcf29..0ec214acee 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/EventSelectionPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/EventSelectionPanel.java
@@ -48,11 +48,11 @@ public abstract class EventSelectionPanel extends Panel {
private final Set<String> selected = new HashSet<>();
- public EventSelectionPanel(final String id, final EventCategory eventCategoryTO, final IModel<List<String>> model) {
+ public EventSelectionPanel(final String id, final EventCategory eventCategory, final IModel<List<String>> model) {
super(id);
setOutputMarkupId(true);
- List<String> events = getEvents(eventCategoryTO);
+ List<String> events = getEvents(eventCategory);
// needed to avoid model reset: model have to be managed into SelectedEventsPanel
selected.addAll(model.getObject());
@@ -64,21 +64,21 @@ public abstract class EventSelectionPanel extends Panel {
@Override
protected void onUpdate(final AjaxRequestTarget target) {
- Set<String> toBeRemoved = new HashSet<>();
- Set<String> toBeAdded = new HashSet<>();
-
- getEvents(eventCategoryTO).forEach(event -> {
- String eventString = AuditLoggerName.buildEvent(
- eventCategoryTO.getType(),
- eventCategoryTO.getCategory(),
- eventCategoryTO.getSubcategory(),
+ Set<AuditLoggerName> toBeRemoved = new HashSet<>();
+ Set<AuditLoggerName> toBeAdded = new HashSet<>();
+
+ getEvents(eventCategory).forEach(event -> {
+ AuditLoggerName auditLoggerName = new AuditLoggerName(
+ eventCategory.getType(),
+ eventCategory.getCategory(),
+ eventCategory.getSubcategory(),
event,
AuditElements.Result.SUCCESS);
- if (successGroup.getModelObject().contains(eventString)) {
- toBeAdded.add(eventString);
+ if (successGroup.getModelObject().contains(auditLoggerName.toString())) {
+ toBeAdded.add(auditLoggerName);
} else {
- toBeRemoved.add(eventString);
+ toBeRemoved.add(auditLoggerName);
}
});
@@ -113,13 +113,13 @@ public abstract class EventSelectionPanel extends Panel {
@Override
protected void populateItem(final ListItem<String> item) {
item.add(new Check<>("successCheck",
- new Model<>(AuditLoggerName.buildEvent(
- eventCategoryTO.getType(),
- eventCategoryTO.getCategory(),
- eventCategoryTO.getSubcategory(),
- item.getModelObject(),
- AuditElements.Result.SUCCESS)),
- successGroup));
+ new Model<>(AuditLoggerName.buildEvent(
+ eventCategory.getType(),
+ eventCategory.getCategory(),
+ eventCategory.getSubcategory(),
+ item.getModelObject(),
+ AuditElements.Result.SUCCESS)),
+ successGroup));
}
};
successGroup.add(successView);
@@ -131,21 +131,21 @@ public abstract class EventSelectionPanel extends Panel {
@Override
protected void onUpdate(final AjaxRequestTarget target) {
- Set<String> toBeRemoved = new HashSet<>();
- Set<String> toBeAdded = new HashSet<>();
-
- getEvents(eventCategoryTO).forEach(event -> {
- String eventString = AuditLoggerName.buildEvent(
- eventCategoryTO.getType(),
- eventCategoryTO.getCategory(),
- eventCategoryTO.getSubcategory(),
+ Set<AuditLoggerName> toBeRemoved = new HashSet<>();
+ Set<AuditLoggerName> toBeAdded = new HashSet<>();
+
+ getEvents(eventCategory).forEach(event -> {
+ AuditLoggerName auditLoggerName = new AuditLoggerName(
+ eventCategory.getType(),
+ eventCategory.getCategory(),
+ eventCategory.getSubcategory(),
event,
AuditElements.Result.FAILURE);
- if (failureGroup.getModelObject().contains(eventString)) {
- toBeAdded.add(eventString);
+ if (failureGroup.getModelObject().contains(auditLoggerName.toString())) {
+ toBeAdded.add(auditLoggerName);
} else {
- toBeRemoved.add(eventString);
+ toBeRemoved.add(auditLoggerName);
}
});
@@ -169,13 +169,13 @@ public abstract class EventSelectionPanel extends Panel {
@Override
protected void populateItem(final ListItem<String> item) {
item.add(new Check<>("failureCheck",
- new Model<>(AuditLoggerName.buildEvent(
- eventCategoryTO.getType(),
- eventCategoryTO.getCategory(),
- eventCategoryTO.getSubcategory(),
- item.getModelObject(),
- AuditElements.Result.FAILURE)),
- failureGroup));
+ new Model<>(AuditLoggerName.buildEvent(
+ eventCategory.getType(),
+ eventCategory.getCategory(),
+ eventCategory.getSubcategory(),
+ item.getModelObject(),
+ AuditElements.Result.FAILURE)),
+ failureGroup));
}
};
failureGroup.add(failureView);
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/SelectedEventsPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/SelectedEventsPanel.java
index b3c40091bc..cb04d68599 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/SelectedEventsPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/events/SelectedEventsPanel.java
@@ -18,9 +18,11 @@
*/
package org.apache.syncope.client.console.events;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.syncope.client.ui.commons.Constants;
+import org.apache.syncope.common.lib.types.AuditLoggerName;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.event.Broadcast;
@@ -51,18 +53,18 @@ public class SelectedEventsPanel extends Panel {
add(selectionContainer);
ListMultipleChoice<String> selectedEvents =
- new ListMultipleChoice<>("selectedEvents", new ListModel<>(), model) {
-
- private static final long serialVersionUID = 1226677544225737338L;
-
- @Override
- protected void onComponentTag(final ComponentTag tag) {
- super.onComponentTag(tag);
- tag.remove("size");
- tag.remove("multiple");
- tag.put("size", 5);
- }
- };
+ new ListMultipleChoice<>("selectedEvents", new ListModel<>(), model) {
+
+ private static final long serialVersionUID = 1226677544225737338L;
+
+ @Override
+ protected void onComponentTag(final ComponentTag tag) {
+ super.onComponentTag(tag);
+ tag.remove("size");
+ tag.remove("multiple");
+ tag.put("size", 5);
+ }
+ };
selectedEvents.setMaxRows(5);
selectedEvents.setChoiceRenderer(new IChoiceRenderer<>() {
@@ -103,12 +105,13 @@ public class SelectedEventsPanel extends Panel {
EventSelectionChanged eventSelectionChanged = (EventSelectionChanged) event.getPayload();
eventSelectionChanged.getToBeRemoved().
- forEach(toBeRemoved -> model.getObject().remove(toBeRemoved));
+ forEach(toBeRemoved -> model.getObject().remove(toBeRemoved.toString()));
eventSelectionChanged.getToBeAdded().stream().
- filter(toBeAdded -> !model.getObject().contains(toBeAdded)).
- forEach(toBeAdded -> model.getObject().add(toBeAdded));
+ filter(toBeAdded -> !model.getObject().contains(toBeAdded.toString())).
+ forEach(toBeAdded -> model.getObject().add(toBeAdded.toString()));
+ Collections.sort(model.getObject());
eventSelectionChanged.getTarget().add(selectionContainer);
}
}
@@ -137,14 +140,15 @@ public class SelectedEventsPanel extends Panel {
private final AjaxRequestTarget target;
- private final Set<String> toBeRemoved;
+ private final Set<AuditLoggerName> toBeRemoved;
- private final Set<String> toBeAdded;
+ private final Set<AuditLoggerName> toBeAdded;
public EventSelectionChanged(
final AjaxRequestTarget target,
- final Set<String> toBeAdded,
- final Set<String> toBeRemoved) {
+ final Set<AuditLoggerName> toBeAdded,
+ final Set<AuditLoggerName> toBeRemoved) {
+
this.target = target;
this.toBeAdded = toBeAdded;
this.toBeRemoved = toBeRemoved;
@@ -154,11 +158,11 @@ public class SelectedEventsPanel extends Panel {
return target;
}
- public Set<String> getToBeRemoved() {
+ public Set<AuditLoggerName> getToBeRemoved() {
return toBeRemoved;
}
- public Set<String> getToBeAdded() {
+ public Set<AuditLoggerName> getToBeAdded() {
return toBeAdded;
}
}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationDirectoryPanel.java
index a3791f049b..367741f93b 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationDirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationDirectoryPanel.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
+import java.util.stream.Collectors;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.commons.DirectoryDataProvider;
import org.apache.syncope.client.console.commons.IdRepoConstants;
@@ -44,7 +45,9 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
import org.apache.syncope.client.ui.commons.Constants;
import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.audit.EventCategory;
import org.apache.syncope.common.lib.to.NotificationTO;
+import org.apache.syncope.common.lib.types.AuditElements;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -53,6 +56,7 @@ import org.apache.wicket.event.Broadcast;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
@@ -77,6 +81,18 @@ public class NotificationDirectoryPanel
@SpringBean
protected SchemaRestClient schemaRestClient;
+ protected final IModel<List<EventCategory>> eventCategories = new LoadableDetachableModel<List<EventCategory>>() {
+
+ private static final long serialVersionUID = 4659376149825914247L;
+
+ @Override
+ protected List<EventCategory> load() {
+ // cannot notify about WA events
+ return auditRestClient.listEvents().stream().
+ filter(c -> c.getType() != AuditElements.EventCategoryType.WA).collect(Collectors.toList());
+ }
+ };
+
protected final BaseModal<String> utilityModal = new BaseModal<>(Constants.OUTER);
public NotificationDirectoryPanel(
@@ -97,10 +113,10 @@ public class NotificationDirectoryPanel
addNewItemPanelBuilder(new NotificationWizardBuilder(
new NotificationTO(),
notificationRestClient,
- auditRestClient,
anyTypeRestClient,
implementationRestClient,
schemaRestClient,
+ eventCategories,
pageRef), true);
initResultTable();
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationWizardBuilder.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationWizardBuilder.java
index d506b3bfe2..c4f0a8d4dd 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationWizardBuilder.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationWizardBuilder.java
@@ -33,7 +33,6 @@ import org.apache.syncope.client.console.panels.search.GroupSearchPanel;
import org.apache.syncope.client.console.panels.search.SearchClause;
import org.apache.syncope.client.console.panels.search.UserSearchPanel;
import org.apache.syncope.client.console.rest.AnyTypeRestClient;
-import org.apache.syncope.client.console.rest.AuditRestClient;
import org.apache.syncope.client.console.rest.ImplementationRestClient;
import org.apache.syncope.client.console.rest.NotificationRestClient;
import org.apache.syncope.client.console.rest.SchemaRestClient;
@@ -45,6 +44,7 @@ import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.audit.EventCategory;
import org.apache.syncope.common.lib.to.AnyTypeTO;
import org.apache.syncope.common.lib.to.DerSchemaTO;
import org.apache.syncope.common.lib.to.ImplementationTO;
@@ -78,30 +78,30 @@ public class NotificationWizardBuilder extends BaseAjaxWizardBuilder<Notificatio
protected final NotificationRestClient notificationRestClient;
- protected final AuditRestClient auditRestClient;
-
protected final AnyTypeRestClient anyTypeRestClient;
protected final ImplementationRestClient implementationRestClient;
protected final SchemaRestClient schemaRestClient;
+ protected final IModel<List<EventCategory>> eventCategories;
+
public NotificationWizardBuilder(
final NotificationTO notificationTO,
final NotificationRestClient notificationRestClient,
- final AuditRestClient auditRestClient,
final AnyTypeRestClient anyTypeRestClient,
final ImplementationRestClient implementationRestClient,
final SchemaRestClient schemaRestClient,
+ final IModel<List<EventCategory>> eventCategories,
final PageReference pageRef) {
super(new NotificationWrapper(notificationTO), pageRef);
this.notificationRestClient = notificationRestClient;
- this.auditRestClient = auditRestClient;
this.anyTypeRestClient = anyTypeRestClient;
this.implementationRestClient = implementationRestClient;
this.schemaRestClient = schemaRestClient;
+ this.eventCategories = eventCategories;
}
@Override
@@ -182,7 +182,7 @@ public class NotificationWizardBuilder extends BaseAjaxWizardBuilder<Notificatio
add(new EventCategoryPanel(
"eventSelection",
- auditRestClient.listEvents(),
+ eventCategories.getObject(),
new PropertyModel<>(modelObject.getInnerObject(), "events")) {
private static final long serialVersionUID = 6429053774964787735L;
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Audit.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Audit.java
index fe1ae591b2..6a824f8724 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Audit.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Audit.java
@@ -21,19 +21,17 @@ package org.apache.syncope.client.console.pages;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
import org.apache.syncope.client.console.events.EventCategoryPanel;
import org.apache.syncope.client.console.events.SelectedEventsPanel;
import org.apache.syncope.client.console.rest.AuditRestClient;
import org.apache.syncope.common.lib.audit.EventCategory;
-import org.apache.syncope.common.lib.types.AuditElements;
import org.apache.syncope.common.lib.types.AuditLoggerName;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.wicket.event.IEvent;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.util.ListModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
@@ -46,8 +44,7 @@ public class Audit extends BasePage {
@SpringBean
protected AuditRestClient auditRestClient;
- protected final LoadableDetachableModel<List<EventCategory>> eventCategories =
- new LoadableDetachableModel<List<EventCategory>>() {
+ protected final IModel<List<EventCategory>> eventCategories = new LoadableDetachableModel<List<EventCategory>>() {
private static final long serialVersionUID = 4659376149825914247L;
@@ -105,35 +102,9 @@ public class Audit extends BasePage {
SelectedEventsPanel.EventSelectionChanged eventSelectionChanged =
(SelectedEventsPanel.EventSelectionChanged) event.getPayload();
- eventSelectionChanged.getToBeRemoved().forEach(toBeRemoved -> {
- Pair<EventCategory, AuditElements.Result> eventCategory =
- AuditLoggerName.parseEventCategory(toBeRemoved);
-
- AuditLoggerName auditLoggerName = new AuditLoggerName(
- eventCategory.getKey().getType(),
- eventCategory.getKey().getCategory(),
- eventCategory.getKey().getSubcategory(),
- CollectionUtils.isEmpty(eventCategory.getKey().getEvents())
- ? null : eventCategory.getKey().getEvents().iterator().next(),
- eventCategory.getValue());
-
- auditRestClient.disableAudit(auditLoggerName);
- });
-
- eventSelectionChanged.getToBeAdded().forEach(toBeAdded -> {
- Pair<EventCategory, AuditElements.Result> eventCategory =
- AuditLoggerName.parseEventCategory(toBeAdded);
-
- AuditLoggerName auditLoggerName = new AuditLoggerName(
- eventCategory.getKey().getType(),
- eventCategory.getKey().getCategory(),
- eventCategory.getKey().getSubcategory(),
- CollectionUtils.isEmpty(eventCategory.getKey().getEvents())
- ? null : eventCategory.getKey().getEvents().iterator().next(),
- eventCategory.getValue());
-
- auditRestClient.enableAudit(auditLoggerName);
- });
+ eventSelectionChanged.getToBeRemoved().forEach(auditRestClient::delete);
+
+ eventSelectionChanged.getToBeAdded().forEach(auditRestClient::enable);
}
}
});
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/rest/AuditRestClient.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/rest/AuditRestClient.java
index 92f81033e2..3a5a5d5c8e 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/rest/AuditRestClient.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/rest/AuditRestClient.java
@@ -50,14 +50,14 @@ public class AuditRestClient extends BaseRestClient {
collect(Collectors.toList());
}
- public void enableAudit(final AuditLoggerName auditLoggerName) {
+ public void enable(final AuditLoggerName auditLoggerName) {
AuditConfTO audit = new AuditConfTO();
audit.setKey(auditLoggerName.toAuditKey());
audit.setActive(true);
getService(AuditService.class).set(audit);
}
- public void disableAudit(final AuditLoggerName auditLoggerName) {
+ public void delete(final AuditLoggerName auditLoggerName) {
try {
getService(AuditService.class).delete(auditLoggerName.toAuditKey());
} catch (SyncopeClientException e) {
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java
index 5750fcd9dd..3e978b5393 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java
@@ -20,7 +20,6 @@ package org.apache.syncope.common.lib.types;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
-import java.text.ParseException;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
@@ -46,97 +45,13 @@ public class AuditLoggerName implements BaseBean {
return domain + '.' + loggerName;
}
- private final EventCategoryType type;
-
- private final String category;
-
- private final String subcategory;
-
- private final String event;
-
- private final Result result;
-
- @JsonCreator
- public AuditLoggerName(
- @JsonProperty("type") final AuditElements.EventCategoryType type,
- @JsonProperty("category") final String category,
- @JsonProperty("subcategory") final String subcategory,
- @JsonProperty("event") final String event,
- @JsonProperty("result") final Result result) {
-
- super();
-
- this.type = Optional.ofNullable(type).orElse(EventCategoryType.CUSTOM);
- this.category = category;
- this.subcategory = subcategory;
- this.event = event;
- this.result = Optional.ofNullable(result).orElse(Result.SUCCESS);
- }
-
- public AuditElements.EventCategoryType getType() {
- return type;
- }
-
- public String getEvent() {
- return event;
- }
-
- public String getCategory() {
- return category;
- }
-
- public Result getResult() {
- return result;
- }
-
- public String getSubcategory() {
- return subcategory;
- }
-
- public String toAuditKey() {
- return new StringBuilder().append(AUDIT_PREFIX).append('.').
- append(buildEvent(type, category, subcategory, event, result)).toString();
- }
-
- @Override
- public int hashCode() {
- return new HashCodeBuilder().
- append(type).
- append(category).
- append(subcategory).
- append(event).
- append(result).
- build();
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final AuditLoggerName other = (AuditLoggerName) obj;
- return new EqualsBuilder().
- append(type, other.type).
- append(category, other.category).
- append(subcategory, other.subcategory).
- append(event, other.event).
- append(result, other.result).
- build();
- }
-
- public static AuditLoggerName fromAuditKey(final String key) throws ParseException {
+ public static AuditLoggerName fromAuditKey(final String key) {
if (StringUtils.isBlank(key)) {
throw new IllegalArgumentException("Null value not permitted");
}
if (!key.startsWith(AUDIT_PREFIX)) {
- throw new ParseException("Audit logger name must start with " + AUDIT_PREFIX, 0);
+ throw new IllegalArgumentException("Audit logger name must start with " + AUDIT_PREFIX);
}
Map.Entry<EventCategory, Result> eventCategory = parseEventCategory(key.replace(AUDIT_PREFIX + '.', ""));
@@ -163,23 +78,7 @@ public class AuditLoggerName implements BaseBean {
condition = Result.SUCCESS;
eventCategory.getEvents().add(event);
} else {
- EventCategoryType type;
-
- if (EventCategoryType.PROPAGATION.name().equals(elements[0])) {
- type = EventCategoryType.PROPAGATION;
- } else if (EventCategoryType.PULL.name().equals(elements[0])) {
- type = EventCategoryType.PULL;
- } else if (EventCategoryType.PUSH.name().equals(elements[0])) {
- type = EventCategoryType.PUSH;
- } else {
- try {
- type = EventCategoryType.valueOf(elements[0]);
- } catch (Exception e) {
- type = EventCategoryType.CUSTOM;
- }
- }
-
- eventCategory.setType(type);
+ eventCategory.setType(EventCategoryType.valueOf(elements[0]));
eventCategory.setCategory(StringUtils.isNotEmpty(elements[1]) ? elements[1] : null);
@@ -205,7 +104,7 @@ public class AuditLoggerName implements BaseBean {
* @param category event category.
* @param subcategory event subcategory.
* @param event event.
- * @param condition result value condition.
+ * @param result result value condition.
* @return event string.
*/
public static String buildEvent(
@@ -213,7 +112,7 @@ public class AuditLoggerName implements BaseBean {
final String category,
final String subcategory,
final String event,
- final AuditElements.Result condition) {
+ final AuditElements.Result result) {
StringBuilder eventBuilder = new StringBuilder();
@@ -235,12 +134,100 @@ public class AuditLoggerName implements BaseBean {
}
eventBuilder.append(']');
- if (condition != null) {
+ if (result != null) {
eventBuilder.append(":[").
- append(condition).
+ append(result).
append(']');
}
return eventBuilder.toString();
}
+
+ private final EventCategoryType type;
+
+ private final String category;
+
+ private final String subcategory;
+
+ private final String event;
+
+ private final Result result;
+
+ @JsonCreator
+ public AuditLoggerName(
+ @JsonProperty("type") final AuditElements.EventCategoryType type,
+ @JsonProperty("category") final String category,
+ @JsonProperty("subcategory") final String subcategory,
+ @JsonProperty("event") final String event,
+ @JsonProperty("result") final Result result) {
+
+ super();
+
+ this.type = Optional.ofNullable(type).orElse(EventCategoryType.CUSTOM);
+ this.category = category;
+ this.subcategory = subcategory;
+ this.event = event;
+ this.result = Optional.ofNullable(result).orElse(Result.SUCCESS);
+ }
+
+ public AuditElements.EventCategoryType getType() {
+ return type;
+ }
+
+ public String getEvent() {
+ return event;
+ }
+
+ public String getCategory() {
+ return category;
+ }
+
+ public Result getResult() {
+ return result;
+ }
+
+ public String getSubcategory() {
+ return subcategory;
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder().
+ append(type).
+ append(category).
+ append(subcategory).
+ append(event).
+ append(result).
+ build();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final AuditLoggerName other = (AuditLoggerName) obj;
+ return new EqualsBuilder().
+ append(type, other.type).
+ append(category, other.category).
+ append(subcategory, other.subcategory).
+ append(event, other.event).
+ append(result, other.result).
+ build();
+ }
+
+ @Override
+ public String toString() {
+ return buildEvent(type, category, subcategory, event, result);
+ }
+
+ public String toAuditKey() {
+ return AUDIT_PREFIX + "." + toString();
+ }
}
diff --git a/common/idrepo/lib/src/test/java/org/apache/syncope/common/lib/types/AuditLoggerNameTest.java b/common/idrepo/lib/src/test/java/org/apache/syncope/common/lib/types/AuditLoggerNameTest.java
new file mode 100644
index 0000000000..582068c794
--- /dev/null
+++ b/common/idrepo/lib/src/test/java/org/apache/syncope/common/lib/types/AuditLoggerNameTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.common.lib.types;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class AuditLoggerNameTest {
+
+ @Test
+ void custom() {
+ AuditLoggerName aln = new AuditLoggerName(
+ AuditElements.EventCategoryType.CUSTOM, null, null, "MY_EVENT", AuditElements.Result.SUCCESS);
+ assertEquals("syncope.audit.[CUSTOM]:[]:[]:[MY_EVENT]:[SUCCESS]", aln.toAuditKey());
+ assertEquals("[CUSTOM]:[]:[]:[MY_EVENT]:[SUCCESS]", aln.toString());
+
+ assertEquals(aln, AuditLoggerName.fromAuditKey(aln.toAuditKey()));
+ }
+}
diff --git a/core/idm/logic/src/test/java/org/apache/syncope/core/logic/IdMLogicTestContext.java b/core/idm/logic/src/test/java/org/apache/syncope/core/logic/IdMLogicTestContext.java
index d7855a3941..e010822542 100644
--- a/core/idm/logic/src/test/java/org/apache/syncope/core/logic/IdMLogicTestContext.java
+++ b/core/idm/logic/src/test/java/org/apache/syncope/core/logic/IdMLogicTestContext.java
@@ -33,6 +33,7 @@ import org.apache.syncope.core.provisioning.api.ImplementationLookup;
import org.apache.syncope.core.provisioning.java.ProvisioningContext;
import org.apache.syncope.core.spring.security.SecurityContext;
import org.apache.syncope.core.workflow.java.WorkflowContext;
+import org.springframework.boot.logging.LoggingSystem;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -61,6 +62,11 @@ public class IdMLogicTestContext {
return mock(JavaMailSender.class);
}
+ @Bean
+ public LoggingSystem loggingSystem() {
+ return mock(LoggingSystem.class);
+ }
+
@Bean
public ImplementationLookup implementationLookup() {
return new DummyImplementationLookup();
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 267f19f575..296a44e22a 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
@@ -29,7 +29,6 @@ import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.tuple.Pair;
-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;
@@ -59,6 +58,8 @@ 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.boot.logging.LogLevel;
+import org.springframework.boot.logging.LoggingSystem;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
@@ -86,13 +87,16 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditConfTO> {
protected final List<AuditAppender> auditAppenders;
+ protected final LoggingSystem loggingSystem;
+
public AuditLogic(
final AuditConfDAO auditConfDAO,
final ExternalResourceDAO resourceDAO,
final EntityFactory entityFactory,
final AuditDataBinder binder,
final AuditManager auditManager,
- final List<AuditAppender> auditAppenders) {
+ final List<AuditAppender> auditAppenders,
+ final LoggingSystem loggingSystem) {
this.auditConfDAO = auditConfDAO;
this.resourceDAO = resourceDAO;
@@ -100,6 +104,7 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditConfTO> {
this.binder = binder;
this.auditManager = auditManager;
this.auditAppenders = auditAppenders;
+ this.loggingSystem = loggingSystem;
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.AUDIT_LIST + "')")
@@ -126,7 +131,7 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditConfTO> {
audit.setActive(auditTO.isActive());
audit = auditConfDAO.save(audit);
- setLevel(audit.getKey(), audit.isActive() ? Level.DEBUG : Level.OFF);
+ setLevel(audit.getKey(), audit.isActive() ? LogLevel.DEBUG : LogLevel.OFF);
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.AUDIT_DELETE + "')")
@@ -135,23 +140,21 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditConfTO> {
orElseThrow(() -> new NotFoundException("Audit " + key));
auditConfDAO.delete(audit);
- setLevel(audit.getKey(), Level.OFF);
+ setLevel(audit.getKey(), LogLevel.OFF);
}
- protected void setLevel(final String key, final Level level) {
+ protected void setLevel(final String key, final LogLevel level) {
String auditLoggerName = AuditLoggerName.getAuditEventLoggerName(AuthContextUtils.getDomain(), key);
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
auditAppenders.stream().
filter(appender -> appender.getEvents().stream().
anyMatch(event -> key.equalsIgnoreCase(event.toAuditKey()))).
forEach(auditAppender -> AuditLoader.addAppenderToLoggerContext(logCtx, auditAppender, logConf));
- logConf.setLevel(level);
- logCtx.updateLoggers();
+ loggingSystem.setLogLevel(auditLoggerName, level);
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.AUDIT_LIST + "') "
@@ -163,16 +166,35 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditConfTO> {
}
}
- // use set to avoid duplications or null elements
Set<EventCategory> events = new HashSet<>();
+ EventCategory authenticationEventCategory = new EventCategory();
+ authenticationEventCategory.setCategory(AuditElements.AUTHENTICATION_CATEGORY);
+ authenticationEventCategory.getEvents().add(AuditElements.LOGIN_EVENT);
+ events.add(authenticationEventCategory);
+
+ events.add(new EventCategory(EventCategoryType.PROPAGATION));
+ events.add(new EventCategory(EventCategoryType.PULL));
+ events.add(new EventCategory(EventCategoryType.PUSH));
+
+ EventCategory pullTaskEventCategory = new EventCategory(EventCategoryType.TASK);
+ pullTaskEventCategory.setCategory(PullJobDelegate.class.getSimpleName());
+ events.add(pullTaskEventCategory);
+
+ EventCategory pushTaskEventCategory = new EventCategory(EventCategoryType.TASK);
+ pushTaskEventCategory.setCategory(PushJobDelegate.class.getSimpleName());
+ events.add(pushTaskEventCategory);
+
+ events.add(new EventCategory(EventCategoryType.WA));
+ events.add(new EventCategory(EventCategoryType.CUSTOM));
+
try {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(
- SystemPropertyUtils.resolvePlaceholders(this.getClass().getPackage().getName()))
+ SystemPropertyUtils.resolvePlaceholders(getClass().getPackage().getName()))
+ "/**/*.class";
Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
@@ -197,16 +219,6 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditConfTO> {
}
}
- // SYNCOPE-608
- EventCategory authenticationControllerEvents = new EventCategory();
- authenticationControllerEvents.setCategory(AuditElements.AUTHENTICATION_CATEGORY);
- authenticationControllerEvents.getEvents().add(AuditElements.LOGIN_EVENT);
- events.add(authenticationControllerEvents);
-
- events.add(new EventCategory(EventCategoryType.PROPAGATION));
- events.add(new EventCategory(EventCategoryType.PULL));
- events.add(new EventCategory(EventCategoryType.PUSH));
-
for (AnyTypeKind anyTypeKind : AnyTypeKind.values()) {
resourceDAO.findAll().forEach(resource -> {
EventCategory propEventCategory = new EventCategory(EventCategoryType.PROPAGATION);
@@ -243,14 +255,6 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditConfTO> {
events.add(pushEventCategory);
});
}
-
- EventCategory eventCategory = new EventCategory(EventCategoryType.TASK);
- eventCategory.setCategory(PullJobDelegate.class.getSimpleName());
- events.add(eventCategory);
-
- eventCategory = new EventCategory(EventCategoryType.TASK);
- eventCategory.setCategory(PushJobDelegate.class.getSimpleName());
- events.add(eventCategory);
} catch (Exception e) {
LOG.error("Failure retrieving audit/notification events", e);
}
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 b4d3ae3c4d..0c90c765b6 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
@@ -107,6 +107,7 @@ import org.apache.syncope.core.provisioning.api.rules.RuleEnforcer;
import org.apache.syncope.core.provisioning.java.utils.TemplateUtils;
import org.apache.syncope.core.spring.security.SecurityProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.logging.LoggingSystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@@ -133,8 +134,8 @@ public class IdRepoLogicContext {
@ConditionalOnMissingBean
@Bean
- public AuditAccessor auditAccessor(final AuditConfDAO auditConfDAO) {
- return new AuditAccessor(auditConfDAO);
+ public AuditAccessor auditAccessor(final AuditConfDAO auditConfDAO, final LoggingSystem loggingSystem) {
+ return new AuditAccessor(auditConfDAO, loggingSystem);
}
@ConditionalOnMissingBean
@@ -251,7 +252,8 @@ public class IdRepoLogicContext {
final EntityFactory entityFactory,
final AuditDataBinder binder,
final AuditManager auditManager,
- final List<AuditAppender> auditAppenders) {
+ final List<AuditAppender> auditAppenders,
+ final LoggingSystem loggingSystem) {
return new AuditLogic(
auditConfDAO,
@@ -259,7 +261,8 @@ public class IdRepoLogicContext {
entityFactory,
binder,
auditManager,
- auditAppenders);
+ auditAppenders,
+ loggingSystem);
}
@ConditionalOnMissingBean
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/AuditAccessor.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/AuditAccessor.java
index 3aed0ccca6..5393915b16 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/AuditAccessor.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/AuditAccessor.java
@@ -18,16 +18,11 @@
*/
package org.apache.syncope.core.logic.init;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import org.apache.logging.log4j.Level;
-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.persistence.api.dao.AuditConfDAO;
-import org.apache.syncope.core.persistence.api.entity.AuditConf;
import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.springframework.boot.logging.LogLevel;
+import org.springframework.boot.logging.LoggingSystem;
import org.springframework.transaction.annotation.Transactional;
/**
@@ -39,22 +34,17 @@ public class AuditAccessor {
protected final AuditConfDAO auditConfDAO;
- public AuditAccessor(final AuditConfDAO auditConfDAO) {
+ protected final LoggingSystem loggingSystem;
+
+ public AuditAccessor(final AuditConfDAO auditConfDAO, final LoggingSystem loggingSystem) {
this.auditConfDAO = auditConfDAO;
+ this.loggingSystem = loggingSystem;
}
@Transactional
- public void synchronizeLoggingWithAudit(final LoggerContext ctx) {
- Map<String, AuditConf> audits = auditConfDAO.findAll().stream().
- collect(Collectors.toMap(
- audit -> AuditLoggerName.getAuditEventLoggerName(AuthContextUtils.getDomain(), audit.getKey()),
- Function.identity()));
-
- audits.forEach((logger, audit) -> {
- LoggerConfig logConf = ctx.getConfiguration().getLoggerConfig(logger);
- logConf.setLevel(audit.isActive() ? Level.DEBUG : Level.OFF);
- });
-
- ctx.updateLoggers();
+ public void synchronizeLoggingWithAudit() {
+ auditConfDAO.findAll().forEach(auditConf -> loggingSystem.setLogLevel(
+ AuditLoggerName.getAuditEventLoggerName(AuthContextUtils.getDomain(), auditConf.getKey()),
+ auditConf.isActive() ? LogLevel.DEBUG : LogLevel.OFF));
}
}
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 828f272201..c43eb12ae6 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
@@ -25,7 +25,6 @@ import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
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.audit.AuditAppender;
@@ -41,20 +40,20 @@ public class AuditLoader implements SyncopeCoreLoader {
final AuditAppender auditAppender,
final LoggerConfig eventLogConf) {
- Appender targetAppender = ctx.getConfiguration().getAppender(auditAppender.getTargetAppenderName());
- if (targetAppender == null) {
- targetAppender = auditAppender.getTargetAppender();
- }
+ Appender targetAppender = Optional.ofNullable(
+ ctx.getConfiguration().getAppender(auditAppender.getTargetAppenderName())).map(Appender.class::cast).
+ orElseGet(() -> 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);
- }
+ auditAppender.getRewriteAppender().ifPresentOrElse(
+ rewriteAppender -> {
+ rewriteAppender.start();
+ eventLogConf.addAppender(rewriteAppender, Level.DEBUG, null);
+ },
+ () -> eventLogConf.addAppender(targetAppender, Level.DEBUG, null));
+
+ ctx.updateLoggers();
}
protected final AuditAccessor auditAccessor;
@@ -68,14 +67,13 @@ public class AuditLoader implements SyncopeCoreLoader {
@Override
public int getOrder() {
- return 300;
+ return 500;
}
@Override
public void load(final String domain, final DataSource datasource) {
LoggerContext logCtx = (LoggerContext) LogManager.getContext(false);
- // SYNCOPE-1144 For each custom audit appender class add related appenders to log4j logger
auditAppenders.forEach(auditAppender -> auditAppender.getEvents().stream().
map(event -> AuditLoggerName.getAuditEventLoggerName(domain, event.toAuditKey())).
forEach(domainAuditLoggerName -> {
@@ -85,9 +83,9 @@ public class AuditLoader implements SyncopeCoreLoader {
if (isRootLogConf) {
eventLogConf = new LoggerConfig(domainAuditLoggerName, null, false);
}
+ eventLogConf.setLevel(Level.DEBUG);
addAppenderToLoggerContext(logCtx, auditAppender, eventLogConf);
- eventLogConf.setLevel(Level.DEBUG);
if (isRootLogConf) {
logCtx.getConfiguration().addLogger(domainAuditLoggerName, eventLogConf);
@@ -95,10 +93,8 @@ public class AuditLoader implements SyncopeCoreLoader {
}));
AuthContextUtils.callAsAdmin(domain, () -> {
- auditAccessor.synchronizeLoggingWithAudit(logCtx);
+ auditAccessor.synchronizeLoggingWithAudit();
return null;
});
-
- logCtx.updateLoggers();
}
}
diff --git a/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/IdRepoLogicTestContext.java b/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/IdRepoLogicTestContext.java
index 9a1aead870..e764e074cd 100644
--- a/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/IdRepoLogicTestContext.java
+++ b/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/IdRepoLogicTestContext.java
@@ -33,6 +33,7 @@ import org.apache.syncope.core.provisioning.api.ImplementationLookup;
import org.apache.syncope.core.provisioning.java.ProvisioningContext;
import org.apache.syncope.core.spring.security.SecurityContext;
import org.apache.syncope.core.workflow.java.WorkflowContext;
+import org.springframework.boot.logging.LoggingSystem;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -61,6 +62,11 @@ public class IdRepoLogicTestContext {
return mock(JavaMailSender.class);
}
+ @Bean
+ public LoggingSystem loggingSystem() {
+ return mock(LoggingSystem.class);
+ }
+
@Bean
public ImplementationLookup implementationLookup() {
return new DummyImplementationLookup();
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
index 509ab4c9f6..8da5d1e231 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
@@ -155,8 +155,8 @@ public class LDAPMembershipPullActions implements PullActions {
groupDAO.findUMemberships(groupDAO.find(entity.getKey())).forEach(uMembership -> {
Set<String> memb = membershipsBefore.computeIfAbsent(
- uMembership.getLeftEnd().getKey(),
- k -> Collections.synchronizedSet(new HashSet<>()));
+ uMembership.getLeftEnd().getKey(),
+ k -> Collections.synchronizedSet(new HashSet<>()));
memb.add(entity.getKey());
});
}
@@ -192,8 +192,8 @@ public class LDAPMembershipPullActions implements PullActions {
profile.getConnector());
if (match.isPresent()) {
Set<String> memb = membershipsAfter.computeIfAbsent(
- match.get().getAny().getKey(),
- k -> Collections.synchronizedSet(new HashSet<>()));
+ match.get().getAny().getKey(),
+ k -> Collections.synchronizedSet(new HashSet<>()));
memb.add(entity.getKey());
} else {
LOG.warn("Could not find matching user for {}", membValue);
diff --git a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java
index f89210118a..1b1462b274 100644
--- a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java
+++ b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java
@@ -28,7 +28,6 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -59,7 +58,6 @@ import org.apache.syncope.core.provisioning.api.Connector;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
import org.apache.syncope.core.provisioning.api.rules.PullMatch;
import org.apache.syncope.core.provisioning.java.AbstractTest;
-import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.ConnectorObject;
import org.identityconnectors.framework.common.objects.SyncDelta;
import org.identityconnectors.framework.common.objects.Uid;
@@ -97,8 +95,6 @@ public class LDAPMembershipPullActionsTest extends AbstractTest {
@Mock
private ProvisioningReport result;
- private Map<String, Set<String>> membershipsAfter;
-
@Mock
private ProvisioningTask<?> pullTask;
@@ -121,6 +117,8 @@ public class LDAPMembershipPullActionsTest extends AbstractTest {
private AnyUR anyReq;
+ private Map<String, Set<String>> membershipsAfter;
+
private Map<String, Set<String>> membershipsBefore;
private User user;
@@ -130,25 +128,25 @@ public class LDAPMembershipPullActionsTest extends AbstractTest {
@BeforeEach
public void initTest() {
user = entityFactory.newEntity(User.class);
+ ReflectionTestUtils.setField(user, "id", UUID.randomUUID().toString());
+
UMembership uMembership = entityFactory.newEntity(UMembership.class);
uMembership.setLeftEnd(user);
- ReflectionTestUtils.setField(user, "id", UUID.randomUUID().toString());
- List<UMembership> uMembList = List.of(uMembership);
anyReq = new UserUR();
+
membershipsBefore = new HashMap<>();
- membershipsAfter = new HashMap<>();
ReflectionTestUtils.setField(ldapMembershipPullActions, "membershipsBefore", membershipsBefore);
+ membershipsAfter = new HashMap<>();
ReflectionTestUtils.setField(ldapMembershipPullActions, "membershipsAfter", membershipsAfter);
- lenient().when(groupDAO.findUMemberships(groupDAO.find(anyString()))).thenReturn(uMembList);
+ lenient().when(groupDAO.findUMemberships(groupDAO.find(anyString()))).thenReturn(List.of(uMembership));
ConnConfPropSchema connConfPropSchema = new ConnConfPropSchema();
connConfPropSchema.setName("testSchemaName");
ConnConfProperty connConfProperty = new ConnConfProperty();
connConfProperty.setSchema(connConfPropSchema);
- connConfProperties = new HashSet<>();
- connConfProperties.add(connConfProperty);
+ connConfProperties = Set.of(connConfProperty);
lenient().when(profile.getTask()).thenAnswer(ic -> pullTask);
lenient().when(pullTask.getResource()).thenReturn(resource);
@@ -170,23 +168,20 @@ public class LDAPMembershipPullActionsTest extends AbstractTest {
public void beforeUpdateWithGroupTOAndEmptyMemberships() throws JobExecutionException {
entity = new GroupTO();
entity.setKey(UUID.randomUUID().toString());
- Set<String> expected = new HashSet<>();
- expected.add(entity.getKey());
ldapMembershipPullActions.beforeUpdate(profile, syncDelta, entity, anyReq);
assertTrue(entity instanceof GroupTO);
assertEquals(1, membershipsBefore.get(user.getKey()).size());
- assertEquals(expected, membershipsBefore.get(user.getKey()));
+ assertEquals(Set.of(entity.getKey()), membershipsBefore.get(user.getKey()));
}
@Test
public void beforeUpdate() throws JobExecutionException {
entity = new UserTO();
entity.setKey(UUID.randomUUID().toString());
- Set<String> memb = new HashSet<>();
- memb.add(entity.getKey());
- membershipsBefore.put(user.getKey(), memb);
+
+ membershipsBefore.put(user.getKey(), Set.of(entity.getKey()));
ldapMembershipPullActions.beforeUpdate(profile, syncDelta, entity, anyReq);
@@ -197,17 +192,15 @@ public class LDAPMembershipPullActionsTest extends AbstractTest {
@Test
public void after() throws JobExecutionException {
entity = new GroupTO();
- String expectedUid = UUID.randomUUID().toString();
- Attribute attribute = new Uid(expectedUid);
- List<String> expected = List.of(expectedUid);
+ entity.setKey(UUID.randomUUID().toString());
- when(connectorObj.getAttributeByName(anyString())).thenReturn(attribute);
+ when(connectorObj.getAttributeByName(anyString())).thenReturn(new Uid(UUID.randomUUID().toString()));
when(inboundMatcher.match(any(AnyType.class), anyString(), any(ExternalResource.class), any(Connector.class))).
thenReturn(Optional.of(new PullMatch(MatchType.ANY, user)));
ldapMembershipPullActions.after(profile, syncDelta, entity, result);
assertEquals(1, membershipsAfter.get(user.getKey()).size());
- assertEquals(expected, attribute.getValue());
+ assertEquals(entity.getKey(), membershipsAfter.get(user.getKey()).iterator().next());
}
}
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 25b83886b7..a3bcd2040d 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
@@ -44,12 +44,16 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
+import javax.ws.rs.core.Response;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.syncope.client.lib.SyncopeClient;
import org.apache.syncope.common.lib.Attr;
+import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.audit.AuditEntry;
import org.apache.syncope.common.lib.audit.EventCategory;
+import org.apache.syncope.common.lib.request.AnyObjectUR;
import org.apache.syncope.common.lib.request.AttrPatch;
import org.apache.syncope.common.lib.request.ResourceDR;
import org.apache.syncope.common.lib.request.UserUR;
@@ -58,9 +62,11 @@ import org.apache.syncope.common.lib.to.AuditConfTO;
import org.apache.syncope.common.lib.to.ConnInstanceTO;
import org.apache.syncope.common.lib.to.ConnPoolConfTO;
import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.ImplementationTO;
import org.apache.syncope.common.lib.to.PagedResult;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.to.RealmTO;
import org.apache.syncope.common.lib.to.ResourceTO;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
@@ -68,10 +74,13 @@ import org.apache.syncope.common.lib.types.AuditElements;
import org.apache.syncope.common.lib.types.AuditLoggerName;
import org.apache.syncope.common.lib.types.ConnConfProperty;
import org.apache.syncope.common.lib.types.ConnectorCapability;
+import org.apache.syncope.common.lib.types.IdRepoImplementationType;
+import org.apache.syncope.common.lib.types.ImplementationEngine;
import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.ResourceDeassociationAction;
import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.common.rest.api.RESTHeaders;
import org.apache.syncope.common.rest.api.beans.AnyQuery;
import org.apache.syncope.common.rest.api.beans.AuditQuery;
import org.apache.syncope.common.rest.api.beans.ReconQuery;
@@ -593,13 +602,13 @@ public class AuditITCase extends AbstractITCase {
@Test
public void issueSYNCOPE1695() {
// add audit conf for pull
- AUDIT_SERVICE.set(
- buildAuditConf("syncope.audit.[PULL]:[USER]:[resource-ldap]:[matchingrule_update]:[SUCCESS]", true));
- AUDIT_SERVICE.set(
- buildAuditConf("syncope.audit.[PULL]:[USER]:[resource-ldap]:[unmatchingrule_assign]:[SUCCESS]", true));
- AUDIT_SERVICE.set(
- buildAuditConf("syncope.audit.[PULL]:[USER]:[resource-ldap]:[unmatchingrule_provision]:[SUCCESS]",
- true));
+ AUDIT_SERVICE.set(buildAuditConf(
+ "syncope.audit.[PULL]:[USER]:[resource-ldap]:[matchingrule_update]:[SUCCESS]", true));
+ AUDIT_SERVICE.set(buildAuditConf(
+ "syncope.audit.[PULL]:[USER]:[resource-ldap]:[unmatchingrule_assign]:[SUCCESS]", true));
+ AUDIT_SERVICE.set(buildAuditConf(
+ "syncope.audit.[PULL]:[USER]:[resource-ldap]:[unmatchingrule_provision]:[SUCCESS]", true));
+
UserTO pullFromLDAP = null;
try {
// pull from resource-ldap -> generates an audit entry
@@ -644,16 +653,57 @@ public class AuditITCase extends AbstractITCase {
USER_SERVICE.delete(pullFromLDAP.getKey());
// restore previous audit
- AUDIT_SERVICE.set(
- buildAuditConf("syncope.audit.[PULL]:[USER]:[resource-ldap]:[matchingrule_update]:[SUCCESS]",
- false));
- AUDIT_SERVICE.set(
- buildAuditConf("syncope.audit.[PULL]:[USER]:[resource-ldap]:[unmatchingrule_assign]:[SUCCESS]",
- false));
AUDIT_SERVICE.set(buildAuditConf(
- "syncope.audit.[PULL]:[USER]:[resource-ldap]:[unmatchingrule_provision]:[SUCCESS]",
- false));
+ "syncope.audit.[PULL]:[USER]:[resource-ldap]:[matchingrule_update]:[SUCCESS]", false));
+ AUDIT_SERVICE.set(buildAuditConf(
+ "syncope.audit.[PULL]:[USER]:[resource-ldap]:[unmatchingrule_assign]:[SUCCESS]", false));
+ AUDIT_SERVICE.set(buildAuditConf(
+ "syncope.audit.[PULL]:[USER]:[resource-ldap]:[unmatchingrule_provision]:[SUCCESS]", false));
}
}
}
+
+ @Test
+ public void issueSYNCOPE1791() throws IOException {
+ ImplementationTO logicActions;
+ try {
+ logicActions = IMPLEMENTATION_SERVICE.read(
+ IdRepoImplementationType.LOGIC_ACTIONS, "CustomAuditLogicActions");
+ } catch (SyncopeClientException e) {
+ logicActions = new ImplementationTO();
+ logicActions.setKey("CustomAuditLogicActions");
+ logicActions.setEngine(ImplementationEngine.GROOVY);
+ logicActions.setType(IdRepoImplementationType.LOGIC_ACTIONS);
+ logicActions.setBody(IOUtils.toString(
+ getClass().getResourceAsStream("/CustomAuditLogicActions.groovy"), StandardCharsets.UTF_8));
+ Response response = IMPLEMENTATION_SERVICE.create(logicActions);
+ logicActions = IMPLEMENTATION_SERVICE.read(
+ logicActions.getType(), response.getHeaderString(RESTHeaders.RESOURCE_KEY));
+ }
+ assertNotNull(logicActions);
+
+ RealmTO root = getRealm(SyncopeConstants.ROOT_REALM).orElseThrow();
+ root.getActions().add(logicActions.getKey());
+ REALM_SERVICE.update(root);
+
+ int before = AUDIT_SERVICE.search(
+ new AuditQuery.Builder().type(AuditElements.EventCategoryType.CUSTOM).build()).getTotalCount();
+ try {
+ AUDIT_SERVICE.set(buildAuditConf("syncope.audit.[CUSTOM]:[]:[]:[MY_EVENT]:[SUCCESS]", true));
+
+ AnyObjectTO printer = createAnyObject(AnyObjectITCase.getSample("syncope-1791")).getEntity();
+ updateAnyObject(new AnyObjectUR.Builder(printer.getKey()).
+ plainAttr(attrAddReplacePatch("location", "new" + getUUIDString())).
+ build());
+
+ int after = AUDIT_SERVICE.search(
+ new AuditQuery.Builder().type(AuditElements.EventCategoryType.CUSTOM).build()).getTotalCount();
+ assertEquals(before + 1, after);
+ } finally {
+ AUDIT_SERVICE.set(buildAuditConf("syncope.audit.[CUSTOM]:[]:[]:[MY_EVENT]:[SUCCESS]", false));
+
+ root.getActions().remove(logicActions.getKey());
+ REALM_SERVICE.update(root);
+ }
+ }
}
diff --git a/fit/core-reference/src/test/resources/CustomAuditLogicActions.groovy b/fit/core-reference/src/test/resources/CustomAuditLogicActions.groovy
new file mode 100644
index 0000000000..08fd8fe04f
--- /dev/null
+++ b/fit/core-reference/src/test/resources/CustomAuditLogicActions.groovy
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+import groovy.transform.CompileStatic
+import java.time.OffsetDateTime
+import org.apache.syncope.common.lib.request.AnyUR
+import org.apache.syncope.common.lib.types.AuditElements
+import org.apache.syncope.core.logic.api.LogicActions
+import org.apache.syncope.core.provisioning.api.AuditManager
+import org.apache.syncope.core.spring.security.AuthContextUtils
+import org.springframework.beans.factory.annotation.Autowired
+
+@CompileStatic
+class CustomAuditLogicActions implements LogicActions {
+
+ @Autowired
+ AuditManager auditManager;
+
+ @Override
+ <R extends AnyUR> R beforeUpdate(final R input) {
+ auditManager.audit(
+ AuthContextUtils.getWho(),
+ AuditElements.EventCategoryType.CUSTOM,
+ null,
+ null,
+ "MY_EVENT",
+ AuditElements.Result.SUCCESS,
+ "before",
+ OffsetDateTime.now().toString());
+ return input
+ }
+}