diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml index 01ac11f766..1d2f094680 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml @@ -932,6 +932,7 @@ + diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/RecordsManagementAuditServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/RecordsManagementAuditServiceImpl.java index 573dc9d2b4..138d3394a4 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/RecordsManagementAuditServiceImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/RecordsManagementAuditServiceImpl.java @@ -27,6 +27,9 @@ 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.File; 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.capability.CapabilityService; 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.model.AuditApplication; import org.alfresco.repo.content.MimetypeMap; @@ -72,6 +76,8 @@ import org.alfresco.service.cmr.repository.MLText; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.site.SiteInfo; +import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; @@ -186,6 +192,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean private DictionaryService dictionaryService; private TransactionService transactionService; private NodeService nodeService; + private SiteService siteService; private ContentService contentService; private AuditComponent auditComponent; private AuditService auditService; @@ -237,6 +244,13 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean 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 */ @@ -820,7 +834,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean * @param writer Writer to write the audit trail * @param reportFormat Format to write the audit trail in, ignored if writer is null */ - private void getAuditTrailImpl( + protected void getAuditTrailImpl( final RecordsManagementAuditQueryParameters params, final List results, final Writer writer, @@ -1091,7 +1105,16 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean } // Get audit entries - auditService.auditQuery(callback, dod5015AuditQueryParams, maxEntries); + SiteInfo siteInfo = siteService.getSite(DEFAULT_SITE_NAME); + if (siteInfo != null) + { + QName siteType = nodeService.getType(siteInfo.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); // finish off the audit trail report diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementAuditServiceImplTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementAuditServiceImplTest.java index e718bc84c4..79ad3909f5 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementAuditServiceImplTest.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementAuditServiceImplTest.java @@ -78,18 +78,18 @@ public class RecordsManagementAuditServiceImplTest extends BaseRMTestCase @Override public Void run() throws Exception { - // test start time recorded - testStartTime = new Date(); + // test start time recorded + testStartTime = new Date(); - // Stop and clear the log - rmAuditService.stopAuditLog(filePlan); - rmAuditService.clearAuditLog(filePlan); - rmAuditService.startAuditLog(filePlan); + // Stop and clear the log + rmAuditService.stopAuditLog(filePlan); + rmAuditService.clearAuditLog(filePlan); + rmAuditService.startAuditLog(filePlan); - // check that audit service is started - assertTrue(rmAuditService.isAuditLogEnabled(filePlan)); + // check that audit service is started + assertTrue(rmAuditService.isAuditLogEnabled(filePlan)); - return null; + return null; } }); } @@ -198,7 +198,7 @@ public class RecordsManagementAuditServiceImplTest extends BaseRMTestCase } }); } - + /** * Test getAuditTrail method and parameter filters. */ diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/audit/RecordsManagementAuditServiceImplUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/audit/RecordsManagementAuditServiceImplUnitTest.java new file mode 100644 index 0000000000..2f1b39fa0c --- /dev/null +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/audit/RecordsManagementAuditServiceImplUnitTest.java @@ -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 . + * #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 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 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 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 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)); + } +}