mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
RM-5344 Only gather DOD audit entries if there is a DOD RM site.
This creates an edge case where DOD audit entries are no longer displayed if a DOD RM site is deleted and then a standard RM site is created to replace it. However this seems like an unlikely use case, and there is a workaround of exporting the audit log before deleting the DOD RM site. Two audit queries are still made for DOD RM sites because DOD sites cause some standard audit entries to be created (e.g. the holds container created event, etc.).
This commit is contained in:
@@ -932,6 +932,7 @@
|
|||||||
<property name="dictionaryService" ref="dictionaryService" />
|
<property name="dictionaryService" ref="dictionaryService" />
|
||||||
<property name="transactionService" ref="transactionService" />
|
<property name="transactionService" ref="transactionService" />
|
||||||
<property name="nodeService" ref="nodeService" />
|
<property name="nodeService" ref="nodeService" />
|
||||||
|
<property name="siteService" ref="siteService" />
|
||||||
<property name="auditComponent" ref="auditComponent" />
|
<property name="auditComponent" ref="auditComponent" />
|
||||||
<property name="auditService" ref="auditService" />
|
<property name="auditService" ref="auditService" />
|
||||||
<property name="contentService" ref="ContentService" />
|
<property name="contentService" ref="ContentService" />
|
||||||
|
@@ -27,6 +27,9 @@
|
|||||||
|
|
||||||
package org.alfresco.module.org_alfresco_module_rm.audit;
|
package org.alfresco.module.org_alfresco_module_rm.audit;
|
||||||
|
|
||||||
|
import static org.alfresco.module.org_alfresco_module_rm.dod5015.DOD5015Model.TYPE_DOD_5015_SITE;
|
||||||
|
import static org.alfresco.module.org_alfresco_module_rm.model.rma.type.RmSiteType.DEFAULT_SITE_NAME;
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
@@ -51,6 +54,7 @@ import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementAction
|
|||||||
import org.alfresco.module.org_alfresco_module_rm.audit.event.AuditEvent;
|
import org.alfresco.module.org_alfresco_module_rm.audit.event.AuditEvent;
|
||||||
import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
|
import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
|
||||||
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
|
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.model.rma.type.RmSiteType;
|
||||||
import org.alfresco.repo.audit.AuditComponent;
|
import org.alfresco.repo.audit.AuditComponent;
|
||||||
import org.alfresco.repo.audit.model.AuditApplication;
|
import org.alfresco.repo.audit.model.AuditApplication;
|
||||||
import org.alfresco.repo.content.MimetypeMap;
|
import org.alfresco.repo.content.MimetypeMap;
|
||||||
@@ -72,6 +76,7 @@ import org.alfresco.service.cmr.repository.MLText;
|
|||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.security.AccessStatus;
|
import org.alfresco.service.cmr.security.AccessStatus;
|
||||||
|
import org.alfresco.service.cmr.site.SiteService;
|
||||||
import org.alfresco.service.namespace.NamespaceService;
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
@@ -186,6 +191,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
|
|||||||
private DictionaryService dictionaryService;
|
private DictionaryService dictionaryService;
|
||||||
private TransactionService transactionService;
|
private TransactionService transactionService;
|
||||||
private NodeService nodeService;
|
private NodeService nodeService;
|
||||||
|
private SiteService siteService;
|
||||||
private ContentService contentService;
|
private ContentService contentService;
|
||||||
private AuditComponent auditComponent;
|
private AuditComponent auditComponent;
|
||||||
private AuditService auditService;
|
private AuditService auditService;
|
||||||
@@ -237,6 +243,13 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
|
|||||||
this.nodeService = nodeService;
|
this.nodeService = nodeService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the site service (used to check the type of RM site created).
|
||||||
|
*
|
||||||
|
* @param siteService The site service.
|
||||||
|
*/
|
||||||
|
public void setSiteService(SiteService siteService) { this.siteService = siteService; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the ContentService instance
|
* Sets the ContentService instance
|
||||||
*/
|
*/
|
||||||
@@ -820,7 +833,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
|
|||||||
* @param writer Writer to write the audit trail
|
* @param writer Writer to write the audit trail
|
||||||
* @param reportFormat Format to write the audit trail in, ignored if writer is <code>null</code>
|
* @param reportFormat Format to write the audit trail in, ignored if writer is <code>null</code>
|
||||||
*/
|
*/
|
||||||
private void getAuditTrailImpl(
|
protected void getAuditTrailImpl(
|
||||||
final RecordsManagementAuditQueryParameters params,
|
final RecordsManagementAuditQueryParameters params,
|
||||||
final List<RecordsManagementAuditEntry> results,
|
final List<RecordsManagementAuditEntry> results,
|
||||||
final Writer writer,
|
final Writer writer,
|
||||||
@@ -1091,7 +1104,12 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get audit entries
|
// Get audit entries
|
||||||
auditService.auditQuery(callback, dod5015AuditQueryParams, maxEntries);
|
QName siteType = nodeService.getType(siteService.getSite(DEFAULT_SITE_NAME).getNodeRef());
|
||||||
|
if (siteType.equals(TYPE_DOD_5015_SITE))
|
||||||
|
{
|
||||||
|
auditService.auditQuery(callback, dod5015AuditQueryParams, maxEntries);
|
||||||
|
}
|
||||||
|
// We always need to make the standard query - regardless of the type of RM site (to get events like RM site created).
|
||||||
auditService.auditQuery(callback, auditQueryParams, maxEntries);
|
auditService.auditQuery(callback, auditQueryParams, maxEntries);
|
||||||
|
|
||||||
// finish off the audit trail report
|
// finish off the audit trail report
|
||||||
|
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Records Management Module
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* -
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
* -
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* -
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
* -
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.module.org_alfresco_module_rm.audit;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
|
import static org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService.ReportFormat.JSON;
|
||||||
|
import static org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditServiceImpl.DOD5015_AUDIT_APPLICATION_NAME;
|
||||||
|
import static org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditServiceImpl.RM_AUDIT_APPLICATION_NAME;
|
||||||
|
import static org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditServiceImpl.RM_AUDIT_PATH_ROOT;
|
||||||
|
import static org.alfresco.module.org_alfresco_module_rm.dod5015.DOD5015Model.TYPE_DOD_5015_SITE;
|
||||||
|
import static org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService.DEFAULT_RM_SITE_ID;
|
||||||
|
import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel.TYPE_RM_SITE;
|
||||||
|
import static org.alfresco.module.org_alfresco_module_rm.model.rma.type.RmSiteType.DEFAULT_SITE_NAME;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.mockito.MockitoAnnotations.initMocks;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
|
||||||
|
import org.alfresco.repo.audit.AuditComponent;
|
||||||
|
import org.alfresco.service.cmr.audit.AuditQueryParameters;
|
||||||
|
import org.alfresco.service.cmr.audit.AuditService;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.alfresco.service.cmr.site.SiteService;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link RecordsManagementAuditServiceImpl}.
|
||||||
|
*
|
||||||
|
* @author Tom Page
|
||||||
|
* @since 2.7
|
||||||
|
*/
|
||||||
|
public class RecordsManagementAuditServiceImplUnitTest
|
||||||
|
{
|
||||||
|
/** The maximum entries to return in the audit query. */
|
||||||
|
private static final int MAX_ENTRIES = 10;
|
||||||
|
/** A node representing the file plan root. */
|
||||||
|
private static final NodeRef FILE_PLAN_NODE = new NodeRef("file://plan/node");
|
||||||
|
/** A node representing the RM site. */
|
||||||
|
private static final NodeRef RM_SITE_NODE = new NodeRef("rm://site/node");
|
||||||
|
/** The class under test. */
|
||||||
|
@InjectMocks
|
||||||
|
private RecordsManagementAuditServiceImpl recordsManagementAuditServiceImpl;
|
||||||
|
@Mock
|
||||||
|
private NodeService mockNodeService;
|
||||||
|
@Mock
|
||||||
|
private SiteService mockSiteService;
|
||||||
|
@Mock
|
||||||
|
private AuditService mockAuditService;
|
||||||
|
@Mock
|
||||||
|
private FilePlanService mockFilePlanService;
|
||||||
|
@Mock
|
||||||
|
AuditComponent mockAuditComponent;
|
||||||
|
@Mock
|
||||||
|
private Writer mockWriter;
|
||||||
|
@Mock
|
||||||
|
private SiteInfo mockSiteInfo;
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<AuditQueryParameters> queryParamsCaptor;
|
||||||
|
|
||||||
|
/** Set up the mocks. */
|
||||||
|
@Before
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
initMocks(this);
|
||||||
|
|
||||||
|
when(mockFilePlanService.getFilePlanBySiteId(DEFAULT_RM_SITE_ID)).thenReturn(FILE_PLAN_NODE);
|
||||||
|
when(mockSiteService.getSite(DEFAULT_SITE_NAME)).thenReturn(mockSiteInfo);
|
||||||
|
when(mockSiteInfo.getNodeRef()).thenReturn(RM_SITE_NODE);
|
||||||
|
|
||||||
|
recordsManagementAuditServiceImpl.setIgnoredAuditProperties(emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that if the RM site is not a DOD site then the audit trail doesn't make a query for DOD events.
|
||||||
|
*
|
||||||
|
* @throws IOException Unexpected.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAuditWithoutDOD() throws IOException
|
||||||
|
{
|
||||||
|
RecordsManagementAuditQueryParameters params = new RecordsManagementAuditQueryParameters();
|
||||||
|
params.setMaxEntries(MAX_ENTRIES);
|
||||||
|
List<RecordsManagementAuditEntry> results = new ArrayList<>();
|
||||||
|
// Return a standard site type.
|
||||||
|
when(mockNodeService.getType(RM_SITE_NODE)).thenReturn(TYPE_RM_SITE);
|
||||||
|
|
||||||
|
// Call the method under test.
|
||||||
|
recordsManagementAuditServiceImpl.getAuditTrailImpl(params, results, mockWriter, JSON);
|
||||||
|
|
||||||
|
// Check that exactly one audit query was performed.
|
||||||
|
verify(mockAuditService, times(1))
|
||||||
|
.auditQuery(any(AuditService.AuditQueryCallback.class), queryParamsCaptor.capture(),
|
||||||
|
eq(MAX_ENTRIES));
|
||||||
|
// We always need to make the standard query - regardless of the type of RM site (to get events like RM site created).
|
||||||
|
assertEquals("The application name should be the standard RM application", RM_AUDIT_APPLICATION_NAME,
|
||||||
|
queryParamsCaptor.getValue().getApplicationName());
|
||||||
|
// Check that the event of viewing the audit log was itself audited.
|
||||||
|
verify(mockAuditComponent).recordAuditValues(eq(RM_AUDIT_PATH_ROOT), any(Map.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that if the RM site is a DOD site then the audit trail makes a query for DOD events and the standard events.
|
||||||
|
*
|
||||||
|
* @throws IOException Unexpected.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAuditWithDOD() throws IOException
|
||||||
|
{
|
||||||
|
RecordsManagementAuditQueryParameters params = new RecordsManagementAuditQueryParameters();
|
||||||
|
params.setMaxEntries(MAX_ENTRIES);
|
||||||
|
List<RecordsManagementAuditEntry> results = new ArrayList<>();
|
||||||
|
// Return a DOD site type.
|
||||||
|
when(mockNodeService.getType(RM_SITE_NODE)).thenReturn(TYPE_DOD_5015_SITE);
|
||||||
|
|
||||||
|
// Call the method under test.
|
||||||
|
recordsManagementAuditServiceImpl.getAuditTrailImpl(params, results, mockWriter, JSON);
|
||||||
|
|
||||||
|
// Check that two audit queries were performed (one for DOD events and one for standard events).
|
||||||
|
verify(mockAuditService, times(2))
|
||||||
|
.auditQuery(any(AuditService.AuditQueryCallback.class), queryParamsCaptor.capture(),
|
||||||
|
eq(MAX_ENTRIES));
|
||||||
|
Set<String> apps = queryParamsCaptor.getAllValues().stream().map(AuditQueryParameters::getApplicationName)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
// We always need to make the standard query - regardless of the type of RM site (to get events like RM site created).
|
||||||
|
assertEquals("Expected the standard audit query and the DOD audit query.",
|
||||||
|
Sets.newHashSet(RM_AUDIT_APPLICATION_NAME, DOD5015_AUDIT_APPLICATION_NAME), apps);
|
||||||
|
// Check that the event of viewing the audit log was itself audited.
|
||||||
|
verify(mockAuditComponent).recordAuditValues(eq(RM_AUDIT_PATH_ROOT), any(Map.class));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user