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 2019/12/06 15:59:32 UTC
[syncope] 01/02: SYNCOPE-1511: History management for admin console
UI (#141)
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
commit 886d9711858389a83586eb883fd685035fd94692
Author: Misagh Moayyed <mm...@gmail.com>
AuthorDate: Thu Dec 5 17:28:12 2019 +0400
SYNCOPE-1511: History management for admin console UI (#141)
---
.../console/audit/AuditHistoryDirectoryPanel.java | 322 +++++++++++++++++++++
.../client/console/audit/AuditHistoryModal.java | 55 ++++
.../client/console/audit/HistoryAuditDetails.java | 236 +++++++++++++++
.../client/console/commons/IdRepoConstants.java | 2 +
.../console/panels/AnyObjectDirectoryPanel.java | 23 ++
.../client/console/panels/DirectoryPanel.java | 2 +-
.../client/console/panels/GroupDirectoryPanel.java | 27 +-
.../client/console/panels/UserDirectoryPanel.java | 22 ++
.../console/rest/AuditHistoryRestClient.java | 57 ++++
.../wicket/markup/html/form/ActionLink.java | 1 +
.../client/console/audit/AuditHistoryModal.html | 26 ++
.../AuditHistoryModal.properties} | 5 +-
.../AuditHistoryModal_it.properties} | 5 +-
.../AuditHistoryModal_ja.properties} | 5 +-
.../AuditHistoryModal_pt_BR.properties} | 5 +-
.../AuditHistoryModal_ru.properties} | 5 +-
.../client/console/audit/HistoryAuditDetails.html | 29 ++
.../HistoryAuditDetails.properties} | 5 +-
.../HistoryAuditDetails_it.properties} | 5 +-
.../HistoryAuditDetails_ja.properties} | 5 +-
.../HistoryAuditDetails_pt_BR.properties} | 5 +-
.../HistoryAuditDetails_ru.properties} | 5 +-
...operties => AnyObjectDirectoryPanel.properties} | 3 +-
...rties => AnyObjectDirectoryPanel_it.properties} | 3 +-
...rties => AnyObjectDirectoryPanel_ja.properties} | 3 +-
...es => AnyObjectDirectoryPanel_pt_BR.properties} | 3 +-
...rties => AnyObjectDirectoryPanel_ru.properties} | 3 +-
.../console/panels/GroupDirectoryPanel.properties | 1 +
.../panels/GroupDirectoryPanel_it.properties | 1 +
.../panels/GroupDirectoryPanel_ja.properties | 1 +
.../panels/GroupDirectoryPanel_pt_BR.properties | 1 +
.../panels/GroupDirectoryPanel_ru.properties | 1 +
.../console/panels/UserDirectoryPanel.properties | 1 +
.../panels/UserDirectoryPanel_it.properties | 1 +
.../panels/UserDirectoryPanel_ja.properties | 1 +
.../panels/UserDirectoryPanel_pt_BR.properties | 1 +
.../panels/UserDirectoryPanel_ru.properties | 1 +
.../markup/html/form/ActionsPanel.properties | 4 +
.../markup/html/form/ActionsPanel_it.properties | 4 +
.../markup/html/form/ActionsPanel_ja.properties | 4 +
.../markup/html/form/ActionsPanel_pt_BR.properties | 6 +-
.../markup/html/form/ActionsPanel_ru.properties | 4 +
.../src/test/resources/domains/MasterContent.xml | 27 +-
.../src/test/resources/domains/MasterContent.xml | 27 +-
.../provisioning/api/serialization/POJOHelper.java | 12 +
.../provisioning/java/DefaultAuditManager.java | 5 +
.../java/data/AuditDataBinderImpl.java | 6 +-
.../org/apache/syncope/fit/core/AuditITCase.java | 86 +++++-
48 files changed, 1002 insertions(+), 60 deletions(-)
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDirectoryPanel.java
new file mode 100644
index 0000000..e45775e
--- /dev/null
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDirectoryPanel.java
@@ -0,0 +1,322 @@
+/*
+ * 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.client.console.audit;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.audit.AuditHistoryDirectoryPanel.AuditHistoryProvider;
+import org.apache.syncope.client.console.commons.IdRepoConstants;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.panels.AjaxDataTablePanel;
+import org.apache.syncope.client.console.panels.DirectoryPanel;
+import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.syncope.client.console.rest.AnyObjectRestClient;
+import org.apache.syncope.client.console.rest.AuditHistoryRestClient;
+import org.apache.syncope.client.console.rest.GroupRestClient;
+import org.apache.syncope.client.console.rest.UserRestClient;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.client.ui.commons.DirectoryDataProvider;
+import org.apache.syncope.client.ui.commons.panels.ModalPanel;
+import org.apache.syncope.common.lib.AnyOperations;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.request.AnyObjectUR;
+import org.apache.syncope.common.lib.request.GroupUR;
+import org.apache.syncope.common.lib.request.UserUR;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AuditEntryTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.ProvisioningResult;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.IdRepoEntitlement;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+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.extensions.markup.html.repeater.util.SortParam;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.StringResourceModel;
+
+public class AuditHistoryDirectoryPanel extends
+ DirectoryPanel<AuditEntryTO, AuditEntryTO, AuditHistoryProvider, AuditHistoryRestClient>
+ implements ModalPanel {
+
+ private static final long serialVersionUID = -8248734710505211261L;
+
+ private static final int TOTAL_AUDIT_HISTORY_COMPARISONS = 25;
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ private final BaseModal<?> baseModal;
+
+ private final MultilevelPanel multiLevelPanelRef;
+
+ private final AnyTO anyTO;
+
+ private final AnyTypeKind anyTypeKind;
+
+ public AuditHistoryDirectoryPanel(
+ final BaseModal<?> baseModal,
+ final MultilevelPanel multiLevelPanelRef,
+ final PageReference pageRef,
+ final AnyTO anyTO) {
+
+ super(MultilevelPanel.FIRST_LEVEL_ID, pageRef);
+ disableCheckBoxes();
+
+ this.baseModal = baseModal;
+ this.multiLevelPanelRef = multiLevelPanelRef;
+ this.anyTO = anyTO;
+
+ anyTypeKind = AnyTypeKind.fromTOClass(anyTO.getClass());
+ initResultTable();
+ }
+
+ /**
+ * Restore an object based on the audit record.
+ *
+ * Note that for user objects, the original audit record masks
+ * the password and the security answer; so we cannot use the audit
+ * record to resurrect the entry based on mask data. The method behavior
+ * below will reset the audit record such that the current security answer
+ * and the password for the object are always maintained, and such properties
+ * for the user cannot be restored using audit records.
+ *
+ * @param entryBean the entry bean
+ * @param anyTO the any to
+ * @return the response
+ */
+ private static ProvisioningResult<? extends AnyTO> restore(final AuditEntryTO entryBean,
+ final AnyTO anyTO) {
+ try {
+ String json = getJSONFromAuditEntry(entryBean);
+ if (anyTO instanceof UserTO) {
+ UserTO userTO = MAPPER.readValue(json, UserTO.class);
+ UserUR req = AnyOperations.diff(userTO, anyTO, false);
+ req.setPassword(null);
+ req.setSecurityAnswer(null);
+ return new UserRestClient().update(anyTO.getETagValue(), req);
+ }
+ if (anyTO instanceof GroupTO) {
+ GroupTO groupTO = MAPPER.readValue(json, GroupTO.class);
+ GroupUR req = AnyOperations.diff(groupTO, anyTO, false);
+ return new GroupRestClient().update(anyTO.getETagValue(), req);
+ }
+ if (anyTO instanceof AnyObjectTO) {
+ AnyObjectTO anyObjectTO = MAPPER.readValue(json, AnyObjectTO.class);
+ AnyObjectUR req = AnyOperations.diff(anyObjectTO, anyTO, false);
+ return new AnyObjectRestClient().update(anyTO.getETagValue(), req);
+ }
+ } catch (final Exception e) {
+ LOG.error("Could not restore object for {}", anyTO, e);
+ }
+ throw SyncopeClientException.build(ClientExceptionType.InvalidAnyObject);
+ }
+
+ private static String getJSONFromAuditEntry(final AuditEntryTO entryBean) throws JsonProcessingException {
+ final String json;
+ if (entryBean.getBefore() == null) {
+ json = MAPPER.readTree(entryBean.getOutput()).get("entity").toPrettyString();
+ } else {
+ json = entryBean.getBefore();
+ }
+ return json;
+ }
+
+ private static SortParam<String> getSortParam() {
+ return new SortParam<>("event_date", false);
+ }
+
+ private static AuditElements.Result getQueryableAuditResult() {
+ return AuditElements.Result.SUCCESS;
+ }
+
+ private static List<String> getQueryableAuditEvents() {
+ return Arrays.asList("create", "update");
+ }
+
+ @Override
+ protected AuditHistoryDirectoryPanel.AuditHistoryProvider dataProvider() {
+ return new AuditHistoryProvider(rows);
+ }
+
+ @Override
+ protected String paginatorRowsKey() {
+ return IdRepoConstants.PREF_AUDIT_HISTORY_PAGINATOR_ROWS;
+ }
+
+ @Override
+ protected List<IColumn<AuditEntryTO, String>> getColumns() {
+ final List<IColumn<AuditEntryTO, String>> columns = new ArrayList<>();
+ columns.add(new PropertyColumn<>(
+ new StringResourceModel("who", this), "who"));
+ columns.add(new DatePropertyColumn<>(
+ new StringResourceModel("date", this), null, "date"));
+ return columns;
+ }
+
+ @Override
+ protected void resultTableCustomChanges(
+ final AjaxDataTablePanel.Builder<AuditEntryTO, String> resultTableBuilder) {
+ resultTableBuilder.setMultiLevelPanel(baseModal, multiLevelPanelRef);
+ }
+
+ @Override
+ protected ActionsPanel<AuditEntryTO> getActions(final IModel<AuditEntryTO> model) {
+ final ActionsPanel<AuditEntryTO> panel = super.getActions(model);
+
+ panel.add(new ActionLink<AuditEntryTO>() {
+
+ private static final long serialVersionUID = -6745431735457245600L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final AuditEntryTO modelObject) {
+ AuditHistoryDirectoryPanel.this.getTogglePanel().close(target);
+ viewAuditHistory(modelObject, target);
+ target.add(modal);
+ }
+ }, ActionLink.ActionType.VIEW, IdRepoEntitlement.AUDIT_READ);
+
+ final String auditRestoreEntitlement;
+ switch (this.anyTypeKind) {
+ case USER:
+ auditRestoreEntitlement = IdRepoEntitlement.USER_UPDATE;
+ break;
+ case GROUP:
+ auditRestoreEntitlement = IdRepoEntitlement.GROUP_UPDATE;
+ break;
+ default:
+ auditRestoreEntitlement = IdRepoEntitlement.ANYTYPE_UPDATE;
+ break;
+ }
+
+ panel.add(new ActionLink<AuditEntryTO>() {
+
+ private static final long serialVersionUID = -6745431735457245600L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final AuditEntryTO modelObject) {
+ try {
+ AuditHistoryDirectoryPanel.this.getTogglePanel().close(target);
+ ProvisioningResult<? extends AnyTO> result = restore(modelObject, anyTO);
+ anyTO.setLastChangeDate(new Date(Long.parseLong(result.getEntity().getETagValue())));
+ target.add(container);
+ } catch (SyncopeClientException e) {
+ LOG.error("While restoring {}", anyTypeKind, e);
+ SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
+ ? e.getClass().getName() : e.getMessage());
+ }
+ ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+ }
+ }, ActionLink.ActionType.RESTORE, auditRestoreEntitlement);
+
+ return panel;
+ }
+
+ @Override
+ protected Collection<ActionLink.ActionType> getBatches() {
+ return Collections.emptyList();
+ }
+
+ private void viewAuditHistory(final AuditEntryTO auditEntryBean, final AjaxRequestTarget target) {
+ List<AuditEntryTO> search = AuditHistoryRestClient.search(anyTO.getKey(),
+ 0,
+ TOTAL_AUDIT_HISTORY_COMPARISONS,
+ getSortParam(),
+ getQueryableAuditEvents(),
+ getQueryableAuditResult());
+
+ multiLevelPanelRef.next(
+ new StringResourceModel("audit.diff.view", this).getObject(),
+ new HistoryAuditDetails(modal, auditEntryBean,
+ getPage().getPageReference(), toAuditEntryTOs(search), anyTO, anyTypeKind), target);
+ }
+
+ private List<AuditEntryTO> toAuditEntryTOs(final List<AuditEntryTO> search) {
+ return search
+ .stream()
+ .map(entry -> {
+ AuditEntryTO bean = new AuditEntryTO();
+ bean.setKey(anyTO.getKey());
+ bean.setBefore(entry.getBefore());
+ bean.setDate(entry.getDate());
+ bean.setEvent(entry.getEvent());
+ bean.getInputs().addAll(entry.getInputs());
+ bean.setLoggerName(entry.getLoggerName());
+ bean.setOutput(entry.getOutput());
+ bean.setResult(entry.getResult());
+ bean.setSubCategory(entry.getSubCategory());
+ bean.setThrowable(entry.getThrowable());
+ bean.setWho(entry.getWho());
+ return bean;
+ })
+ .collect(Collectors.toList());
+ }
+
+ protected class AuditHistoryProvider extends DirectoryDataProvider<AuditEntryTO> {
+
+ private static final long serialVersionUID = 415113175628260864L;
+
+ AuditHistoryProvider(final int paginatorRows) {
+ super(paginatorRows);
+ }
+
+ @Override
+ public Iterator<? extends AuditEntryTO> iterator(final long first, final long count) {
+ return getAuditEntryBeans(first, count).iterator();
+ }
+
+ @Override
+ public long size() {
+ return AuditHistoryRestClient.count(anyTO.getKey(), getQueryableAuditEvents(), getQueryableAuditResult());
+ }
+
+ @Override
+ public IModel<AuditEntryTO> model(final AuditEntryTO auditEntryBean) {
+ return new CompoundPropertyModel<>(auditEntryBean);
+ }
+
+ private List<AuditEntryTO> getAuditEntryBeans(final long first, final long count) {
+ int page = (int) first / paginatorRows;
+ return AuditHistoryRestClient.search(anyTO.getKey(),
+ Math.max(page, 0) + 1,
+ Long.valueOf(count).intValue(),
+ getSortParam(),
+ getQueryableAuditEvents(),
+ getQueryableAuditResult());
+ }
+ }
+}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryModal.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryModal.java
new file mode 100644
index 0000000..d4c8d7c
--- /dev/null
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryModal.java
@@ -0,0 +1,55 @@
+/*
+ * 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.client.console.audit;
+
+import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.ui.commons.panels.ModalPanel;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.markup.html.panel.Panel;
+
+public class AuditHistoryModal<T extends AnyTO> extends Panel implements ModalPanel {
+
+ private static final long serialVersionUID = 1066124171682570080L;
+
+ protected final AuditHistoryDirectoryPanel directoryPanel;
+
+ public AuditHistoryModal(
+ final BaseModal<?> baseModal,
+ final PageReference pageReference,
+ final T entity) {
+
+ super(BaseModal.CONTENT_ID);
+
+ final MultilevelPanel mlp = new MultilevelPanel("history");
+ mlp.setOutputMarkupId(true);
+ this.directoryPanel = getDirectoryPanel(mlp, baseModal, pageReference, entity);
+ add(mlp.setFirstLevel(this.directoryPanel));
+ }
+
+ protected AuditHistoryDirectoryPanel getDirectoryPanel(
+ final MultilevelPanel mlp,
+ final BaseModal<?> baseModal,
+ final PageReference pageReference,
+ final T entity) {
+
+ return new AuditHistoryDirectoryPanel(baseModal, mlp, pageReference, entity);
+ }
+}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/HistoryAuditDetails.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/HistoryAuditDetails.java
new file mode 100644
index 0000000..5e47d7c
--- /dev/null
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/HistoryAuditDetails.java
@@ -0,0 +1,236 @@
+/*
+ * 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.client.console.audit;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.panels.AbstractModalPanel;
+import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.JsonDiffPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.JsonEditorPanel;
+import org.apache.syncope.client.ui.commons.Constants;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AuditEntryTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.PropertyModel;
+
+public class HistoryAuditDetails extends MultilevelPanel.SecondLevel {
+
+ private static final String KEY_CURRENT = "current";
+
+ private static final long serialVersionUID = -7400543686272100483L;
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ private final AuditEntryTO selected;
+
+ private final List<AuditEntryTO> availableTOs;
+
+ private final AnyTypeKind anyTypeKind;
+
+ private AbstractModalPanel<String> jsonPanel;
+
+ private final AnyTO currentTO;
+
+ public HistoryAuditDetails(final BaseModal<?> baseModal, final AuditEntryTO selected,
+ final PageReference pageRef, final List<AuditEntryTO> availableTOs,
+ final AnyTO currentTO, final AnyTypeKind anyTypeKind) {
+ super();
+ this.availableTOs = availableTOs.stream()
+ .filter(object -> !selected.equals(object) && selected.getBefore() != null)
+ .collect(Collectors.toList());
+ this.selected = selected;
+ this.anyTypeKind = anyTypeKind;
+ this.currentTO = currentTO;
+
+ addCurrentInstanceConf();
+ Form<?> form = initDropdownDiffConfForm();
+ add(form);
+ form.setVisible(!this.availableTOs.isEmpty());
+
+ showConfigurationSinglePanel();
+ }
+
+ private void showConfigurationSinglePanel() {
+ Pair<String, String> info = getJSONInfo(selected);
+
+ jsonPanel = new JsonEditorPanel(null, new PropertyModel<>(info, "right"), true, null) {
+
+ private static final long serialVersionUID = -8927036362466990179L;
+
+ @Override
+ public void onSubmit(final AjaxRequestTarget target) {
+ modal.close(target);
+ }
+ };
+ jsonPanel.setOutputMarkupId(true);
+
+ addOrReplace(jsonPanel);
+ }
+
+ private void showConfigurationDiffPanel(final List<AuditEntryTO> entries) {
+ List<Pair<String, String>> infos = new ArrayList<>();
+ entries.forEach(entry -> infos.add(getJSONInfo(entry)));
+
+ jsonPanel = new JsonDiffPanel(null, new PropertyModel<>(infos.get(0), "value"),
+ new PropertyModel<>(infos.get(1), "value"), null) {
+
+ private static final long serialVersionUID = -8927036362466990179L;
+
+ @Override
+ public void onSubmit(final AjaxRequestTarget target) {
+ modal.close(target);
+ }
+ };
+
+ replace(jsonPanel);
+ }
+
+ private String getSanitizedTOAsJSON(final AnyTO anyTO) throws Exception {
+ if (this.anyTypeKind == AnyTypeKind.USER) {
+ UserTO userTO = (UserTO) anyTO;
+ userTO.setPassword(null);
+ userTO.setSecurityAnswer(null);
+ return MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(userTO);
+ }
+ return MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(anyTO);
+ }
+
+ private Pair<String, String> getJSONInfo(final AuditEntryTO auditEntryBean) {
+ try {
+ final String content;
+ if (auditEntryBean.getBefore() == null) {
+ content = MAPPER.readTree(auditEntryBean.getOutput()).get("entity").toPrettyString();
+ } else {
+ content = auditEntryBean.getBefore();
+ }
+
+ AnyTO userTO = MAPPER.readValue(content, anyTypeKind.getTOClass());
+ String json = getSanitizedTOAsJSON(userTO);
+ return Pair.of(auditEntryBean.getKey(), json);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static <T extends AuditEntryTO> Map<String, String> getDropdownNamesMap(final List<T> entries) {
+ Map<String, String> map = new LinkedHashMap<>();
+ for (AuditEntryTO audit : entries) {
+ String value = audit.getWho()
+ + " - " + SyncopeConsoleSession.get().getDateFormat().format(audit.getDate());
+ if (audit.getKey().equalsIgnoreCase(KEY_CURRENT)) {
+ value += " - " + audit.getKey();
+ }
+ map.put(audit.getKey(), value);
+ }
+ return map;
+ }
+
+ private Form<?> initDropdownDiffConfForm() {
+ final Form<AuditEntryTO> form = new Form<>("form");
+ form.setModel(new CompoundPropertyModel<>(selected));
+ form.setOutputMarkupId(true);
+
+ final Map<String, String> namesMap = getDropdownNamesMap(availableTOs);
+ List<String> keys = new ArrayList<>(namesMap.keySet());
+
+ final AjaxDropDownChoicePanel<String> dropdownElem = new AjaxDropDownChoicePanel<>(
+ "compareDropdown",
+ getString("compare"),
+ new PropertyModel<>(selected, "key"),
+ false);
+ dropdownElem.setChoices(keys);
+ dropdownElem.setChoiceRenderer(new IChoiceRenderer<String>() {
+
+ private static final long serialVersionUID = -6265603675261014912L;
+
+ @Override
+ public Object getDisplayValue(final String value) {
+ return namesMap.get(value) == null ? value : namesMap.get(value);
+ }
+
+ @Override
+ public String getIdValue(final String value, final int i) {
+ return value;
+ }
+
+ @Override
+ public String getObject(
+ final String id, final IModel<? extends List<? extends String>> choices) {
+ return id;
+ }
+ });
+ dropdownElem.setNullValid(false);
+ dropdownElem.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+ private static final long serialVersionUID = -1107858522700306810L;
+
+ @Override
+ protected void onUpdate(final AjaxRequestTarget target) {
+ List<AuditEntryTO> elemsToCompare = new ArrayList<>();
+ elemsToCompare.add(selected);
+
+ final String selectedKey = dropdownElem.getModelObject();
+ if (selectedKey != null) {
+ if (!selectedKey.isEmpty()) {
+ AuditEntryTO confToCompare = availableTOs.stream().
+ filter(object -> object.getKey().equals(selectedKey)).findAny().orElse(null);
+ elemsToCompare.add(confToCompare);
+ showConfigurationDiffPanel(elemsToCompare);
+ } else {
+ showConfigurationSinglePanel();
+ }
+ }
+ target.add(jsonPanel);
+ }
+ });
+ form.add(dropdownElem);
+
+ return form;
+ }
+
+ private void addCurrentInstanceConf() {
+ try {
+ AuditEntryTO entryBean = new AuditEntryTO();
+ entryBean.setKey(KEY_CURRENT);
+ entryBean.setWho(currentTO.getCreator());
+ entryBean.setDate(currentTO.getCreationDate());
+ entryBean.setBefore(MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(currentTO));
+ availableTOs.add(entryBean);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/IdRepoConstants.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/IdRepoConstants.java
index 52c9932..60dc743 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/IdRepoConstants.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/IdRepoConstants.java
@@ -66,6 +66,8 @@ public final class IdRepoConstants {
public static final String PREF_ACCESS_TOKEN_PAGINATOR_ROWS = "accessToken.paginator.rows";
+ public static final String PREF_AUDIT_HISTORY_PAGINATOR_ROWS = "audit.history.paginator.rows";
+
public static final String PREF_NOTIFICATION_PAGINATOR_ROWS = "notification.paginator.rows";
public static final String PREF_IMPLEMENTATION_PAGINATOR_ROWS = "implementation.paginator.rows";
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
index 2c39540..fe48e23 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
@@ -26,6 +26,7 @@ import org.apache.syncope.client.console.SyncopeWebApplication;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.commons.IdRepoConstants;
import org.apache.syncope.client.ui.commons.Constants;
+import org.apache.syncope.client.console.audit.AuditHistoryModal;
import org.apache.syncope.client.console.notifications.NotificationTasks;
import org.apache.syncope.client.console.pages.BasePage;
import org.apache.syncope.client.console.rest.AnyObjectRestClient;
@@ -46,6 +47,7 @@ import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
@@ -170,6 +172,27 @@ public class AnyObjectDirectoryPanel extends AnyDirectoryPanel<AnyObjectTO, AnyO
}
}, ActionType.NOTIFICATION_TASKS, IdRepoEntitlement.TASK_LIST);
}
+ panel.add(new ActionLink<AnyObjectTO>() {
+
+ private static final long serialVersionUID = -2878723352517770644L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final AnyObjectTO ignore) {
+ IModel<AnyWrapper<AnyObjectTO>> formModel = new CompoundPropertyModel<>(
+ new AnyWrapper<>(new AnyObjectRestClient().read(model.getObject().getKey())));
+ altDefaultModal.setFormModel(formModel);
+
+ target.add(altDefaultModal.setContent(new AuditHistoryModal<>(
+ altDefaultModal,
+ pageRef,
+ formModel.getObject().getInnerObject())));
+
+ altDefaultModal.header(new StringResourceModel("auditHistory.title", model));
+
+ altDefaultModal.show(true);
+ }
+ }, ActionType.VIEW_AUDIT_HISTORY, IdRepoEntitlement.AUDIT_LIST).
+ setRealms(realm, model.getObject().getDynRealms());
panel.add(new ActionLink<AnyObjectTO>() {
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java
index 326b9e0..8d946d0 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java
@@ -279,7 +279,7 @@ public abstract class DirectoryPanel<
dataProvider = dataProvider();
final int currentPage = Optional.ofNullable(resultTable)
- .map(table -> (create ? (int) table.getPageCount() - 1 : (int) table.getCurrentPage())).orElse(0);
+ .map(table -> (create ? (int) table.getPageCount() - 1 : (int) table.getCurrentPage())).orElse(0);
// take care of restClient handle: maybe not useful to keep into
AjaxDataTablePanel.Builder<T, String> resultTableBuilder = new AjaxDataTablePanel.Builder<T, String>(
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java
index 9754ffd..645e628 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java
@@ -28,6 +28,7 @@ import org.apache.syncope.client.console.SyncopeWebApplication;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.commons.IdRepoConstants;
import org.apache.syncope.client.ui.commons.Constants;
+import org.apache.syncope.client.console.audit.AuditHistoryModal;
import org.apache.syncope.client.console.layout.FormLayoutInfoUtils;
import org.apache.syncope.client.console.notifications.NotificationTasks;
import org.apache.syncope.client.console.pages.BasePage;
@@ -62,6 +63,7 @@ import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDa
import org.apache.wicket.event.Broadcast;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
@@ -113,7 +115,7 @@ public class GroupDirectoryPanel extends AnyDirectoryPanel<GroupTO, GroupRestCli
SyncopeClient.getUserSearchConditionBuilder().is("key").notNullValue()).query();
panel = new UserDirectoryPanel.Builder(
- AnyTypeClassRestClient.list(anyTypeTO.getClasses()), anyTypeTO.getKey(), pageRef).
+ AnyTypeClassRestClient.list(anyTypeTO.getClasses()), anyTypeTO.getKey(), pageRef).
setRealm(SyncopeConstants.ROOT_REALM).
setFiltered(true).
setFiql(query).
@@ -133,7 +135,7 @@ public class GroupDirectoryPanel extends AnyDirectoryPanel<GroupTO, GroupRestCli
SyncopeClient.getUserSearchConditionBuilder().is("key").notNullValue()).query();
panel = new AnyObjectDirectoryPanel.Builder(
- AnyTypeClassRestClient.list(anyTypeTO.getClasses()), anyTypeTO.getKey(), pageRef).
+ AnyTypeClassRestClient.list(anyTypeTO.getClasses()), anyTypeTO.getKey(), pageRef).
setRealm(SyncopeConstants.ROOT_REALM).
setFiltered(true).
setFiql(query).
@@ -343,6 +345,27 @@ public class GroupDirectoryPanel extends AnyDirectoryPanel<GroupTO, GroupRestCli
panel.add(new ActionLink<GroupTO>() {
+ private static final long serialVersionUID = -2878723352517770644L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final GroupTO ignore) {
+ IModel<GroupWrapper> formModel = new CompoundPropertyModel<>(
+ new GroupWrapper(new GroupRestClient().read(model.getObject().getKey())));
+ target.add(altDefaultModal.setContent(new AuditHistoryModal<>(
+ altDefaultModal,
+ pageRef,
+ formModel.getObject().getInnerObject())));
+
+ altDefaultModal.header(new Model<>(
+ getString("auditHistory.title", new Model<>(new AnyWrapper<>(model.getObject())))));
+
+ altDefaultModal.show(true);
+ }
+ }, ActionType.VIEW_AUDIT_HISTORY, IdRepoEntitlement.AUDIT_LIST).
+ setRealms(realm, model.getObject().getDynRealms());
+
+ panel.add(new ActionLink<GroupTO>() {
+
private static final long serialVersionUID = -7978723352517770644L;
@Override
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java
index 4e083cc..9593000 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java
@@ -28,6 +28,7 @@ import org.apache.syncope.client.console.SyncopeWebApplication;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.commons.IdRepoConstants;
import org.apache.syncope.client.ui.commons.Constants;
+import org.apache.syncope.client.console.audit.AuditHistoryModal;
import org.apache.syncope.client.console.notifications.NotificationTasks;
import org.apache.syncope.client.console.pages.BasePage;
import org.apache.syncope.client.console.rest.UserRestClient;
@@ -275,6 +276,27 @@ public class UserDirectoryPanel extends AnyDirectoryPanel<UserTO, UserRestClient
panel.add(new ActionLink<UserTO>() {
+ private static final long serialVersionUID = -1978723352517770644L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final UserTO ignore) {
+ IModel<UserWrapper> formModel = new CompoundPropertyModel<>(
+ new UserWrapper(new UserRestClient().read(model.getObject().getKey())));
+ target.add(altDefaultModal.setContent(new AuditHistoryModal<>(
+ altDefaultModal,
+ pageRef,
+ formModel.getObject().getInnerObject())));
+
+ altDefaultModal.header(new Model<>(
+ getString("auditHistory.title", new Model<>(new AnyWrapper<>(model.getObject())))));
+
+ altDefaultModal.show(true);
+ }
+ }, ActionType.VIEW_AUDIT_HISTORY, IdRepoEntitlement.AUDIT_LIST).
+ setRealms(realm, model.getObject().getDynRealms());
+
+ panel.add(new ActionLink<UserTO>() {
+
private static final long serialVersionUID = -7978723352517770644L;
@Override
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/rest/AuditHistoryRestClient.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/rest/AuditHistoryRestClient.java
new file mode 100644
index 0000000..0818859
--- /dev/null
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/rest/AuditHistoryRestClient.java
@@ -0,0 +1,57 @@
+/*
+ * 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.client.console.rest;
+
+import java.util.List;
+import org.apache.syncope.common.lib.to.AuditEntryTO;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.common.rest.api.beans.AuditQuery;
+import org.apache.syncope.common.rest.api.service.AuditService;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+
+public class AuditHistoryRestClient extends BaseRestClient {
+
+ private static final long serialVersionUID = -381814125643246243L;
+
+ public static List<AuditEntryTO> search(
+ final String key,
+ final int page,
+ final int size,
+ final SortParam<String> sort,
+ final List<String> events,
+ final AuditElements.Result result) {
+
+ AuditQuery query = new AuditQuery.Builder(key).
+ page(page).
+ size(size).
+ events(events).
+ result(result).
+ orderBy(toOrderBy(sort)).
+ build();
+ return getService(AuditService.class).search(query).getResult();
+ }
+
+ public static int count(final String key, final List<String> events, final AuditElements.Result result) {
+ AuditQuery query = new AuditQuery.Builder(key).
+ events(events).
+ result(result).
+ build();
+ return getService(AuditService.class).search(query).getTotalCount();
+ }
+}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
index 5416be7..cc0d073 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
@@ -106,6 +106,7 @@ public abstract class ActionLink<T extends Serializable> implements Serializable
VIEW_DETAILS("read"),
MANAGE_APPROVAL("edit"),
EDIT_APPROVAL("edit"),
+ VIEW_AUDIT_HISTORY("read"),
EXTERNAL_EDITOR("externalEditor");
private final String actionId;
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal.html
new file mode 100644
index 0000000..48c38ea
--- /dev/null
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal.html
@@ -0,0 +1,26 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+<wicket:panel>
+ <div class="panel-group box-group">
+ <wicket:child/>
+ </div>
+ <span wicket:id="history">[History]</span>
+</wicket:panel>
+</html>
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal.properties
index 07164b4..e2abe89 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal.properties
@@ -14,5 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+who=Who
+date=Date
+audit.diff.view=Configuration
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_it.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_it.properties
index 07164b4..e2abe89 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_it.properties
@@ -14,5 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+who=Who
+date=Date
+audit.diff.view=Configuration
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_ja.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_ja.properties
index 07164b4..e2abe89 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_ja.properties
@@ -14,5 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+who=Who
+date=Date
+audit.diff.view=Configuration
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_pt_BR.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_pt_BR.properties
index 07164b4..e2abe89 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_pt_BR.properties
@@ -14,5 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+who=Who
+date=Date
+audit.diff.view=Configuration
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_ru.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_ru.properties
index 07164b4..e2abe89 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/AuditHistoryModal_ru.properties
@@ -14,5 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+who=Who
+date=Date
+audit.diff.view=Configuration
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails.html
new file mode 100644
index 0000000..da89934
--- /dev/null
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails.html
@@ -0,0 +1,29 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+ <wicket:panel>
+
+ <form wicket:id="form">
+ <span wicket:id="compareDropdown"></span>
+ </form>
+
+ <div wicket:id="content"></div>
+
+ </wicket:panel>
+</html>
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails.properties
index 07164b4..b1406fe 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails.properties
@@ -14,5 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+history.view=History view
+compare=Compare with
+current=Current
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_it.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_it.properties
index 07164b4..e128bca 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_it.properties
@@ -14,5 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+history.view=Storico vista
+compare=paragonare con
+current=presente
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_ja.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_ja.properties
index 07164b4..b1406fe 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_ja.properties
@@ -14,5 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+history.view=History view
+compare=Compare with
+current=Current
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_pt_BR.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_pt_BR.properties
index 07164b4..b1406fe 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_pt_BR.properties
@@ -14,5 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+history.view=History view
+compare=Compare with
+current=Current
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_ru.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_ru.properties
index 07164b4..b1406fe 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/audit/HistoryAuditDetails_ru.properties
@@ -14,5 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+history.view=History view
+compare=Compare with
+current=Current
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.properties
index 07164b4..441f190 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.properties
@@ -14,5 +14,4 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+auditHistory.title=${type} ${name} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_it.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_it.properties
index 07164b4..441f190 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_it.properties
@@ -14,5 +14,4 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+auditHistory.title=${type} ${name} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_ja.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_ja.properties
index 07164b4..441f190 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_ja.properties
@@ -14,5 +14,4 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+auditHistory.title=${type} ${name} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_pt_BR.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_pt_BR.properties
index 07164b4..441f190 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_pt_BR.properties
@@ -14,5 +14,4 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+auditHistory.title=${type} ${name} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_ru.properties
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_ru.properties
index 07164b4..441f190 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel_ru.properties
@@ -14,5 +14,4 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.name}
-group.members=${right} members of ${left.name}
+auditHistory.title=${type} ${name} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
index 07164b4..7c1cb8c 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel.properties
@@ -16,3 +16,4 @@
# under the License.
any.edit=Edit ${anyTO.type} ${anyTO.name}
group.members=${right} members of ${left.name}
+auditHistory.title=${anyTO.type} ${anyTO.name} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_it.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_it.properties
index bd97397..8566276 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_it.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_it.properties
@@ -16,3 +16,4 @@
# under the License.
any.edit=Modifica ${anyTO.type} ${anyTO.name}
group.members=Membri ${right} di '${left.name}'
+auditHistory.title=${anyTO.type} ${anyTO.name} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_ja.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_ja.properties
index 0267d65..2f0982a 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_ja.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_ja.properties
@@ -16,3 +16,4 @@
# under the License.
any.edit=${anyTO.type} ${anyTO.name} \u3092\u7de8\u96c6
group.members=${left.name} \u306e ${right} \u30e1\u30f3\u30d0\u30fc
+auditHistory.title=${anyTO.type} ${anyTO.name} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_pt_BR.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_pt_BR.properties
index 9fb316d..b5730e2 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_pt_BR.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_pt_BR.properties
@@ -16,3 +16,4 @@
# under the License.
any.edit=Alterar ${anyTO.type} ${anyTO.name}
group.members=${right} members of ${left.name}
+auditHistory.title=${anyTO.type} ${anyTO.name} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_ru.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_ru.properties
index 94a1bd9..84e3f7b 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_ru.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/GroupDirectoryPanel_ru.properties
@@ -17,3 +17,4 @@
#
any.edit=\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c ${anyTO.type} ${anyTO.name}
group.members=${right} \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u0438 ${left.name}
+auditHistory.title=${anyTO.type} ${anyTO.name} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
index 6acf5db..1d4db0d 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
@@ -18,3 +18,4 @@ any.edit=Edit ${anyTO.type} ${anyTO.username}
any.propagation.tasks=Propagation tasks for ${type} ${username}
any.notification.tasks=Notification tasks for ${type} ${username}
linkedAccounts.title=Manage user accounts
+auditHistory.title=${anyTO.type} ${anyTO.username} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_it.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_it.properties
index 38fa14d..ef6c91a 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_it.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_it.properties
@@ -18,3 +18,4 @@ any.edit=Modifica ${anyTO.type} ${anyTO.username}
any.propagation.tasks=Task di propagazione per ${type} ${username}
any.notification.tasks=Task di notifica per ${type} ${username}
linkedAccounts.title=Gestisci account utente
+auditHistory.title=${anyTO.type} ${anyTO.username} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ja.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ja.properties
index 9107368..a2193e2 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ja.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ja.properties
@@ -18,3 +18,4 @@ any.edit=${anyTO.type} ${anyTO.username} \u3092\u7de8\u96c6
any.propagation.tasks=${type} ${username} \u306e\u4f1d\u64ad\u30bf\u30b9\u30af
any.notification.tasks=${type} ${username} \u306e\u901a\u77e5\u30bf\u30b9\u30af
linkedAccounts.title=\u30e6\u30fc\u30b6\u30fc\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u7ba1\u7406\u3059\u308b
+auditHistory.title=${anyTO.type} ${anyTO.username} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_pt_BR.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_pt_BR.properties
index 865e74d..84d5d86 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_pt_BR.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_pt_BR.properties
@@ -18,3 +18,4 @@ any.edit=Alterar ${anyTO.type} ${anyTO.username}
any.propagation.tasks=Propagation tasks for ${type} ${username}
any.notification.tasks=Notification tasks for ${type} ${username}
linkedAccounts.title=Gerenciar contas de usu\u00e1rio
+auditHistory.title=${anyTO.type} ${anyTO.username} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ru.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ru.properties
index 53e0e86..378c49a 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ru.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ru.properties
@@ -19,3 +19,4 @@ any.edit=\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c ${anyTO.type} ${anyTO.
any.propagation.tasks=\u0417\u0430\u0434\u0430\u0447\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0434\u043b\u044f ${type} ${username}
any.notification.tasks=\u0417\u0430\u0434\u0430\u0447\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0434\u043b\u044f ${type} ${username}
linkedAccounts.title=\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0443\u0447\u0435\u0442\u043d\u044b\u043c\u0438 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439
+auditHistory.title=${anyTO.type} ${anyTO.username} history
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties
index 3d26fa9..163ece9 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties
@@ -277,3 +277,7 @@ manage_accounts.alt=manage accounts icon
workflow_modeler.class=fa fa-picture-o
workflow_modeler.title=workflow modeler
workflow_modeler.alt=workflow modeler icon
+
+view_audit_history.class=fa fa-history
+view_audit_history.title=history management
+view_audit_history.alt=history management icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties
index ee38bd0..bea031c 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties
@@ -268,3 +268,7 @@ reconciliation_pull.alt=reconciliation pull icon
manage_accounts.class=fa fa-users
manage_accounts.title=gestisci account
manage_accounts.alt=manage accounts icon
+
+view_audit_history.class=fa fa-history
+view_audit_history.title=storico modifiche
+view_audit_history.alt=storico modifiche icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties
index a6422d1..8b73d1e 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties
@@ -269,3 +269,7 @@ reconciliation_pull.alt=\u7167\u5408\u30d7\u30eb icon
manage_accounts.class=fa fa-users
manage_accounts.title=\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u7ba1\u7406\u3059\u308b
manage_accounts.alt=\u30a2\u30ab\u30a6\u30f3\u30c8\u7ba1\u7406\u30a2\u30a4\u30b3\u30f3
+
+view_audit_history.class=fa fa-history
+view_audit_history.title=history management
+view_audit_history.alt=history management icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties
index ccc7a37..9daea41 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties
@@ -282,6 +282,6 @@ manage_accounts.class=fa fa-users
manage_accounts.title=manage accounts
manage_accounts.alt=manage accounts icon
-workflow_modeler.class=fa fa-picture-o
-workflow_modeler.title=workflow modeler
-workflow_modeler.alt=workflow modeler icon
+view_audit_history.class=fa fa-history
+view_audit_history.title=history management
+view_audit_history.alt=history management icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties
index ada11f2..f7a3b90 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties
@@ -268,3 +268,7 @@ reconciliation_pull.alt=reconciliation pull icon
manage_accounts.class=fa fa-users
manage_accounts.title=manage accounts
manage_accounts.alt=manage accounts icon
+
+view_audit_history.class=fa fa-history
+view_audit_history.title=history management
+view_audit_history.alt=history management icon
diff --git a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
index c5a7509..5a11d41 100644
--- a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
@@ -2340,7 +2340,26 @@ $$ }
<SecurityQuestion id="887028ea-66fc-41e7-b397-620d7ea6dfbb" content="What's your mother's maiden name?"/>
<SyncopeLogger logName="syncope.audit.[LOGIC]:[SyncopeLogic]:[]:[isSelfRegAllowed]:[SUCCESS]" logLevel="DEBUG" logType="AUDIT"/>
-
+
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[assign]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[assign]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[create]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[create]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[delete]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[delete]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[deprovision]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[deprovision]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[link]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[link]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[provision]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[provision]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[unassign]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[unassign]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[unlink]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[unlink]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[update]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[update]:[SUCCESS]" logLevel="DEBUG"/>
+
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[assign]:[FAILURE]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[assign]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[confirmPasswordReset]:[FAILURE]" logLevel="DEBUG"/>
@@ -2357,12 +2376,8 @@ $$ }
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[mustChangePassword]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[provision]:[FAILURE]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[provision]:[SUCCESS]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[read]:[FAILURE]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[read]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[requestPasswordReset]:[FAILURE]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[requestPasswordReset]:[SUCCESS]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[search]:[FAILURE]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[search]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[selfCreate]:[FAILURE]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[selfCreate]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[selfDelete]:[FAILURE]" logLevel="DEBUG"/>
@@ -2390,8 +2405,6 @@ $$ }
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[own]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[provisionMembers]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[provision]:[SUCCESS]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[read]:[SUCCESS]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[search]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[unassign]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[unlink]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[update]:[SUCCESS]" logLevel="DEBUG"/>
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 490dc16..8c7fa09 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -2427,7 +2427,26 @@ $$ }
<SecurityQuestion id="887028ea-66fc-41e7-b397-620d7ea6dfbb" content="What's your mother's maiden name?"/>
<SyncopeLogger logName="syncope.audit.[LOGIC]:[SyncopeLogic]:[]:[isSelfRegAllowed]:[SUCCESS]" logLevel="DEBUG" logType="AUDIT"/>
-
+
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[assign]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[assign]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[create]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[create]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[delete]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[delete]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[deprovision]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[deprovision]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[link]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[link]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[provision]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[provision]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[unassign]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[unassign]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[unlink]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[unlink]:[SUCCESS]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[update]:[FAILURE]" logLevel="DEBUG"/>
+ <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[AnyObjectLogic]:[]:[update]:[SUCCESS]" logLevel="DEBUG"/>
+
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[assign]:[FAILURE]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[assign]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[confirmPasswordReset]:[FAILURE]" logLevel="DEBUG"/>
@@ -2444,12 +2463,8 @@ $$ }
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[mustChangePassword]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[provision]:[FAILURE]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[provision]:[SUCCESS]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[read]:[FAILURE]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[read]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[requestPasswordReset]:[FAILURE]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[requestPasswordReset]:[SUCCESS]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[search]:[FAILURE]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[search]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[selfCreate]:[FAILURE]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[selfCreate]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[UserLogic]:[]:[selfDelete]:[FAILURE]" logLevel="DEBUG"/>
@@ -2477,8 +2492,6 @@ $$ }
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[own]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[provisionMembers]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[provision]:[SUCCESS]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[read]:[SUCCESS]" logLevel="DEBUG"/>
- <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[search]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[unassign]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[unlink]:[SUCCESS]" logLevel="DEBUG"/>
<SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[GroupLogic]:[]:[update]:[SUCCESS]" logLevel="DEBUG"/>
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/serialization/POJOHelper.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/serialization/POJOHelper.java
index af99906..c7b8faa 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/serialization/POJOHelper.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/serialization/POJOHelper.java
@@ -64,6 +64,18 @@ public final class POJOHelper {
return result;
}
+ public static String serializeWithDefaultPrettyPrinter(final Object object) {
+ String result = null;
+
+ try {
+ result = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(object);
+ } catch (Exception e) {
+ LOG.error("During serialization", e);
+ }
+
+ return result;
+ }
+
public static <T extends Object> T deserialize(final String serialized, final Class<T> reference) {
T result = null;
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java
index d5b9df6..374c717 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java
@@ -35,6 +35,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
+import java.util.Date;
+
@Transactional(readOnly = true)
public class DefaultAuditManager implements AuditManager {
@@ -52,6 +54,7 @@ public class DefaultAuditManager implements AuditManager {
AuditEntry auditEntry = AuditEntryImpl.builder().
who(who).
logger(new AuditLoggerName(type, category, subcategory, event, Result.SUCCESS)).
+ date(new Date()).
build();
org.apache.syncope.core.persistence.api.entity.Logger syncopeLogger =
loggerDAO.find(auditEntry.getLogger().toLoggerName());
@@ -64,6 +67,7 @@ public class DefaultAuditManager implements AuditManager {
auditEntry = AuditEntryImpl.builder()
.who(who)
.logger(new AuditLoggerName(type, category, subcategory, event, Result.FAILURE))
+ .date(new Date())
.build();
syncopeLogger = loggerDAO.find(auditEntry.getLogger().toLoggerName());
auditRequested = syncopeLogger != null && syncopeLogger.getLevel() == LoggerLevel.DEBUG;
@@ -110,6 +114,7 @@ public class DefaultAuditManager implements AuditManager {
before(before).
output(throwable == null ? output : throwable.getMessage()).
input(input).
+ date(new Date()).
build();
org.apache.syncope.core.persistence.api.entity.Logger syncopeLogger =
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java
index de49702..4937503 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java
@@ -47,18 +47,18 @@ public class AuditDataBinderImpl implements AuditDataBinder {
}
if (auditEntry.getBefore() != null) {
- auditEntryTO.setBefore(POJOHelper.serialize(auditEntry.getBefore()));
+ auditEntryTO.setBefore(POJOHelper.serializeWithDefaultPrettyPrinter(auditEntry.getBefore()));
}
if (auditEntry.getInput() != null) {
auditEntryTO.getInputs().addAll(Arrays.stream(auditEntry.getInput()).
filter(Objects::nonNull).
- map(POJOHelper::serialize).
+ map(POJOHelper::serializeWithDefaultPrettyPrinter).
collect(Collectors.toList()));
}
if (auditEntry.getOutput() != null) {
- auditEntryTO.setOutput(POJOHelper.serialize(auditEntry.getOutput()));
+ auditEntryTO.setOutput(POJOHelper.serializeWithDefaultPrettyPrinter(auditEntry.getOutput()));
}
return auditEntryTO;
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 7fa4904..cff5d47 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
@@ -18,22 +18,32 @@
*/
package org.apache.syncope.fit.core;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.List;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
import org.apache.syncope.common.lib.to.AuditEntryTO;
import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.PagedResult;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.common.rest.api.beans.AnyQuery;
import org.apache.syncope.common.rest.api.beans.AuditQuery;
import org.apache.syncope.fit.AbstractITCase;
import org.junit.jupiter.api.Test;
public class AuditITCase extends AbstractITCase {
- private AuditEntryTO query(final AuditQuery query, final int maxWaitSeconds) {
+ private static final int MAX_WAIT_SECONDS = 30;
+
+ private static AuditEntryTO query(final AuditQuery query, final int maxWaitSeconds, final boolean failIfEmpty) {
int i = 0;
List<AuditEntryTO> results = List.of();
do {
@@ -47,20 +57,39 @@ public class AuditITCase extends AbstractITCase {
i++;
} while (results.isEmpty() && i < maxWaitSeconds);
if (results.isEmpty()) {
- fail("Timeout when executing query for key " + query.getEntityKey());
+ if (failIfEmpty) {
+ fail("Timeout when executing query for key " + query.getEntityKey());
+ }
+ return null;
}
return results.get(0);
}
@Test
+ public void userReadAndSearchYieldsNoAudit() {
+ PagedResult<UserTO> users = userService.search(
+ new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).page(1).size(2).build());
+ assertNotNull(users);
+ assertFalse(users.getResult().isEmpty());
+
+ users.getResult().forEach(user -> assertNotNull(userService.read(user.getKey())));
+
+ users.getResult().forEach(user -> {
+ AuditQuery query = new AuditQuery.Builder(user.getKey()).build();
+ AuditEntryTO entry = query(query, MAX_WAIT_SECONDS, false);
+ assertNull(entry);
+ });
+ }
+
+ @Test
public void findByUser() {
UserTO userTO = createUser(UserITCase.getUniqueSample("audit@syncope.org")).getEntity();
assertNotNull(userTO.getKey());
AuditQuery query = new AuditQuery.Builder(userTO.getKey()).orderBy("event_date desc").
page(1).size(1).build();
- AuditEntryTO entry = query(query, 50);
+ AuditEntryTO entry = query(query, MAX_WAIT_SECONDS, true);
assertEquals(userTO.getKey(), entry.getKey());
userService.delete(userTO.getKey());
}
@@ -79,7 +108,7 @@ public class AuditITCase extends AbstractITCase {
event("create").
result(AuditElements.Result.SUCCESS).
build();
- AuditEntryTO entry = query(query, 50);
+ AuditEntryTO entry = query(query, MAX_WAIT_SECONDS, true);
assertEquals(userTO.getKey(), entry.getKey());
userService.delete(userTO.getKey());
}
@@ -91,8 +120,51 @@ public class AuditITCase extends AbstractITCase {
AuditQuery query = new AuditQuery.Builder(groupTO.getKey()).orderBy("event_date desc").
page(1).size(1).build();
- AuditEntryTO entry = query(query, 50);
+ AuditEntryTO entry = query(query, MAX_WAIT_SECONDS, true);
assertEquals(groupTO.getKey(), entry.getKey());
groupService.delete(groupTO.getKey());
}
+
+ @Test
+ public void groupReadAndSearchYieldsNoAudit() {
+ PagedResult<GroupTO> groups = groupService.search(
+ new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).build());
+ assertNotNull(groups);
+ assertFalse(groups.getResult().isEmpty());
+
+ groups.getResult().forEach(groupTO -> assertNotNull(groupService.read(groupTO.getKey())));
+
+ groups.getResult().forEach(groupTO -> {
+ AuditQuery query = new AuditQuery.Builder(groupTO.getKey()).build();
+ AuditEntryTO entry = query(query, MAX_WAIT_SECONDS, false);
+ assertNull(entry);
+ });
+ }
+
+ @Test
+ public void findByAnyObject() {
+ AnyObjectTO anyObjectTO = createAnyObject(AnyObjectITCase.getSample("Italy")).getEntity();
+ assertNotNull(anyObjectTO.getKey());
+ AuditQuery query = new AuditQuery.Builder(anyObjectTO.getKey()).orderBy("event_date desc").
+ page(1).size(1).build();
+ AuditEntryTO entry = query(query, MAX_WAIT_SECONDS, true);
+ assertEquals(anyObjectTO.getKey(), entry.getKey());
+ anyObjectService.delete(anyObjectTO.getKey());
+ }
+
+ @Test
+ public void anyObjectReadAndSearchYieldsNoAudit() {
+ PagedResult<AnyObjectTO> anyObjects = anyObjectService.search(
+ new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
+ fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(getUUIDString()).query()).
+ build());
+ assertNotNull(anyObjects);
+ assertTrue(anyObjects.getResult().isEmpty());
+
+ anyObjects.getResult().forEach(anyObjectTO -> {
+ AuditQuery query = new AuditQuery.Builder(anyObjectTO.getKey()).build();
+ AuditEntryTO entry = query(query, MAX_WAIT_SECONDS, false);
+ assertNull(entry);
+ });
+ }
}