diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditAddToHoldTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditAddToHoldTests.java index 6a291f1e87..d911e81585 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditAddToHoldTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditAddToHoldTests.java @@ -151,21 +151,6 @@ public class AuditAddToHoldTests extends BaseRMRestTest }; } - /** - * Data provider with invalid users that can not add content to a hold - * - * @return the userModel - */ - @DataProvider (name = "invalidUsersForAddToHold") - public Object[][] getInvalidUsersForAddToHold() - { - return new UserModel[][] - { - { rmManagerNoReadOnHold }, - { rmManagerNoReadOnNode } - }; - } - /** * Given a document/record/record folder is added to a hold * When I view the audit log @@ -269,11 +254,11 @@ public class AuditAddToHoldTests extends BaseRMRestTest /** * Given a document is added to a hold - * When I view the audit log as an user with no Read permissions over the hold or the document + * When I view the audit log as an user with no Read permissions over the document * Then the add to hold entry isn't visible */ - @Test (dataProvider = "invalidUsersForAddToHold") - public void addToHoldAuditEntryNotVisible(UserModel user) + @Test + public void addToHoldAuditEntryNotVisible() { STEP("Create a new file"); FileModel contentToBeAdded = dataContent.usingAdmin().usingSite(privateSite) @@ -285,7 +270,33 @@ public class AuditAddToHoldTests extends BaseRMRestTest STEP("Check that an user with no Read permissions can't see the entry for the add to hold event."); assertTrue("The list of events should not contain Add to Hold entry ", - rmAuditService.getAuditEntriesFilteredByEvent(user, ADD_TO_HOLD).isEmpty()); + rmAuditService.getAuditEntriesFilteredByEvent(rmManagerNoReadOnNode, ADD_TO_HOLD).isEmpty()); + } + + /** + * Given a document is added to a hold + * When I view the audit log as an user with no Read permissions over the hold + * Then the the hold name is replaced in the add to hold entry + */ + @Test + public void addToHoldAuditEntryHoldNameNotVisible() + { + STEP("Create a new file"); + FileModel contentToBeAdded = dataContent.usingAdmin().usingSite(privateSite) + .createContent(CMISUtil.DocumentType.TEXT_PLAIN); + rmAuditService.clearAuditLog(); + + STEP("Add file to hold."); + holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), contentToBeAdded.getNodeRefWithoutVersion(), HOLD1); + + auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(rmManagerNoReadOnHold, ADD_TO_HOLD); + + STEP("Check that an user with no Read permissions can't see the hold name in the add to hold event."); + String replacementHoldName = "You don't have permission to view this hold."; + assertEquals("The list of events should contain the Add to Hold entry", 1, auditEntries.size()); + assertTrue("The hold name should not be visible in the Add to Hold entry ", + auditEntries.stream().anyMatch(entry -> entry.getChangedValues().contains( + ImmutableMap.of("new", replacementHoldName, "previous", "", "name", "Hold Name")))); } @AfterClass (alwaysRun = true) diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditRemoveFromHoldTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditRemoveFromHoldTests.java index 2aa77a25ff..1f5b6c2d69 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditRemoveFromHoldTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/audit/AuditRemoveFromHoldTests.java @@ -162,21 +162,6 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest }; } - /** - * Data provider with invalid users that can not remove content from a hold - * - * @return the userModel - */ - @DataProvider (name = "invalidUsersForRemoveFromHold") - public Object[][] getInvalidUsersForRemoveFromHold() - { - return new UserModel[][] - { - { rmManagerNoReadOnHold }, - { rmManagerNoReadOnNode } - }; - } - /** * Given a document/record/record folder is removed from a hold * When I view the audit log @@ -280,11 +265,11 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest /** * Given a document/record/record folder is removed from a hold - * When I view the audit log as an user with no Read permissions over the hold or the node + * When I view the audit log as an user with no Read permissions over the node * Then the remove from hold entry isn't visible */ - @Test (dataProvider = "invalidUsersForRemoveFromHold") - public void removeFromHoldAuditEntryNotVisible(UserModel user) + @Test + public void removeFromHoldAuditEntryNotVisible() { STEP("Add content to a hold."); FileModel heldFile = dataContent.usingAdmin().usingSite(privateSite) @@ -298,7 +283,35 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest STEP("Check that an user with no Read permissions can't see the entry for the remove from hold event."); assertTrue("The list of events should not contain Remove from Hold entry ", - rmAuditService.getAuditEntriesFilteredByEvent(user, REMOVE_FROM_HOLD).isEmpty()); + rmAuditService.getAuditEntriesFilteredByEvent(rmManagerNoReadOnNode, REMOVE_FROM_HOLD).isEmpty()); + } + + /** + * Given a document/record/record folder is removed from a hold + * When I view the audit log as an user with no Read permissions over the hold + * Then the the hold name is replaced in the remove from hold entry + */ + @Test + public void removeFromHoldAuditEntryHoldNameNotVisible() + { + STEP("Add content to a hold."); + FileModel heldFile = dataContent.usingAdmin().usingSite(privateSite) + .createContent(CMISUtil.DocumentType.TEXT_PLAIN); + holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), heldFile.getNodeRefWithoutVersion(), HOLD1); + + rmAuditService.clearAuditLog(); + + STEP("Remove held content from the hold."); + holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), heldFile.getNodeRefWithoutVersion(), HOLD1); + + auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(rmManagerNoReadOnHold, REMOVE_FROM_HOLD); + + STEP("Check that an user with no Read permissions can't see the hold name in the remove from hold event."); + String replacementHoldName = "You don't have permission to view this hold."; + assertEquals("The list of events should contain the Remove from Hold entry", 1, auditEntries.size()); + assertTrue("The hold name should not be visible in the Remove from Hold entry ", + auditEntries.stream().anyMatch(entry -> entry.getChangedValues().contains( + ImmutableMap.of("new", "", "previous", replacementHoldName, "name", "Hold Name")))); } @AfterClass (alwaysRun = true) diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/audit-service.properties b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/audit-service.properties index b5e7c4079c..acafc32979 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/audit-service.properties +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/audit-service.properties @@ -17,6 +17,7 @@ rm.audit.createHold=Create Hold rm.audit.deleteHold=Delete Hold rm.audit.addToHold=Add To Hold rm.audit.removeFromHold=Remove From Hold +rm.audit.holdPermission-Error=You don't have permission to view this hold. rm.audit.audit-start=Audit Start rm.audit.audit-stop=Audit Stop rm.audit.audit-clear=Audit Clear 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 ccaba88ffc..3b5c7eee06 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 @@ -941,6 +941,7 @@ + cm:lastThumbnailModification @@ -1533,7 +1534,6 @@ - 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 72cb924a53..924c4ec25d 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 @@ -61,6 +61,8 @@ 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.hold.HoldService; +import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.repo.audit.AuditComponent; import org.alfresco.repo.audit.model.AuditApplication; import org.alfresco.repo.content.MimetypeMap; @@ -195,6 +197,10 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean private static final String AUDIT_EVENT_VIEW = "audit.view"; private static final String MSG_AUDIT_VIEW = "rm.audit.audit-view"; + private static final QName PROPERTY_HOLD_NAME = QName.createQName(RecordsManagementModel.RM_URI, "Hold Name"); + private static final QName PROPERTY_HOLD_NODEREF = QName.createQName(RecordsManagementModel.RM_URI, "Hold NodeRef"); + private static final String HOLD_PERMISSION_DENIED_MSG = "rm.audit.holdPermission-Error"; + private PolicyComponent policyComponent; private DictionaryService dictionaryService; private TransactionService transactionService; @@ -208,6 +214,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean private NamespaceService namespaceService; protected CapabilityService capabilityService; protected PermissionService permissionService; + protected HoldService holdService; private boolean shutdown = false; @@ -333,6 +340,15 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean this.permissionService = permissionService; } + /** + * + * @param holdService + */ + public void setHoldService(HoldService holdService) + { + this.holdService = holdService; + } + /** * @see org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService#registerAuditEvent(java.lang.String, java.lang.String) */ @@ -687,7 +703,8 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean /** * Helper method to remove system properties from maps * - * @param properties + * @param before properties before event + * @param after properties after event */ private void removeAuditProperties(Map before, Map after) { @@ -864,220 +881,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean } // define the callback - AuditQueryCallback callback = new AuditQueryCallback() - { - private boolean firstEntry = true; - - - @Override - public boolean valuesRequired() - { - return true; - } - - /** - * Just log the error, but continue - */ - @Override - public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error) - { - logger.warn(errorMsg, error); - return true; - } - - @Override - @SuppressWarnings("unchecked") - public boolean handleAuditEntry( - Long entryId, - String applicationName, - String user, - long time, - Map values) - { - // Check for context shutdown - if (shutdown) - { - return false; - } - - - Date timestamp = new Date(time); - String eventName = null; - String fullName = null; - String userRoles = null; - NodeRef nodeRef = null; - String nodeName = null; - String nodeType = null; - String nodeIdentifier = null; - String namePath = null; - Map beforeProperties = null; - Map afterProperties = null; - - if (values.containsKey(RM_AUDIT_DATA_EVENT_NAME)) - { - // This data is /RM/event/... - eventName = (String) values.get(RM_AUDIT_DATA_EVENT_NAME); - fullName = (String) values.get(RM_AUDIT_DATA_PERSON_FULLNAME); - userRoles = (String) values.get(RM_AUDIT_DATA_PERSON_ROLES); - nodeRef = (NodeRef) values.get(RM_AUDIT_DATA_NODE_NODEREF); - nodeName = (String) values.get(RM_AUDIT_DATA_NODE_NAME); - QName nodeTypeQname = (QName) values.get(RM_AUDIT_DATA_NODE_TYPE); - nodeIdentifier = (String) values.get(RM_AUDIT_DATA_NODE_IDENTIFIER); - namePath = (String) values.get(RM_AUDIT_DATA_NODE_NAMEPATH); - beforeProperties = (Map) values.get(RM_AUDIT_DATA_NODE_CHANGES_BEFORE); - afterProperties = (Map) values.get(RM_AUDIT_DATA_NODE_CHANGES_AFTER); - - // Convert some of the values to recognizable forms - nodeType = null; - if (nodeTypeQname != null) - { - TypeDefinition typeDef = dictionaryService.getType(nodeTypeQname); - nodeType = (typeDef != null) ? typeDef.getTitle(dictionaryService) : null; - } - } - else if (values.containsKey(DOD5015_AUDIT_DATA_EVENT_NAME)) - { - // This data is /RM/event/... - eventName = (String) values.get(DOD5015_AUDIT_DATA_EVENT_NAME); - fullName = (String) values.get(DOD5015_AUDIT_DATA_PERSON_FULLNAME); - userRoles = (String) values.get(DOD5015_AUDIT_DATA_PERSON_ROLES); - nodeRef = (NodeRef) values.get(DOD5015_AUDIT_DATA_NODE_NODEREF); - nodeName = (String) values.get(DOD5015_AUDIT_DATA_NODE_NAME); - QName nodeTypeQname = (QName) values.get(DOD5015_AUDIT_DATA_NODE_TYPE); - nodeIdentifier = (String) values.get(DOD5015_AUDIT_DATA_NODE_IDENTIFIER); - namePath = (String) values.get(DOD5015_AUDIT_DATA_NODE_NAMEPATH); - beforeProperties = (Map) values.get( DOD5015_AUDIT_DATA_NODE_CHANGES_BEFORE); - afterProperties = (Map) values.get(DOD5015_AUDIT_DATA_NODE_CHANGES_AFTER); - - // Convert some of the values to recognizable forms - nodeType = null; - if (nodeTypeQname != null) - { - TypeDefinition typeDef = dictionaryService.getType(nodeTypeQname); - nodeType = (typeDef != null) ? typeDef.getTitle(dictionaryService) : null; - } - } - else if (values.containsKey(RM_AUDIT_DATA_LOGIN_USERNAME)) - { - user = (String) values.get(RM_AUDIT_DATA_LOGIN_USERNAME); - if (values.containsKey(RM_AUDIT_DATA_LOGIN_ERROR)) - { - eventName = RM_AUDIT_EVENT_LOGIN_FAILURE; - // The user didn't log in - fullName = user; - } - else - { - eventName = RM_AUDIT_EVENT_LOGIN_SUCCESS; - fullName = (String) values.get(RM_AUDIT_DATA_LOGIN_FULLNAME); - } - } - else if (values.containsKey(DOD5015_AUDIT_DATA_LOGIN_USERNAME)) - { - user = (String) values.get(DOD5015_AUDIT_DATA_LOGIN_USERNAME); - if (values.containsKey(DOD5015_AUDIT_DATA_LOGIN_ERROR)) - { - eventName = RM_AUDIT_EVENT_LOGIN_FAILURE; - // The user didn't log in - fullName = user; - } - else - { - eventName = RM_AUDIT_EVENT_LOGIN_SUCCESS; - fullName = (String) values.get(DOD5015_AUDIT_DATA_LOGIN_FULLNAME); - } - } - else - { - // This is not recognisable data - logger.warn( - "Unable to process audit entry for RM. Unexpected data: \n" + - " Entry: " + entryId + "\n" + - " Data: " + values); - // Skip it - return true; - } - - if (nodeRef != null && nodeService.exists(nodeRef) && - ((filePlanService.isFilePlanComponent(nodeRef) && - !AccessStatus.ALLOWED.equals( - capabilityService.getCapabilityAccessState(nodeRef, ACCESS_AUDIT_CAPABILITY))) - || (!AccessStatus.ALLOWED.equals(permissionService.hasPermission(nodeRef, PermissionService.READ))))) - { - return true; - } - - // TODO: Refactor this to use the builder pattern - RecordsManagementAuditEntry entry = new RecordsManagementAuditEntry( - timestamp, - user, - fullName, - // A concatenated string of roles - userRoles, - nodeRef, - nodeName, - nodeType, - eventName, - nodeIdentifier, - namePath, - beforeProperties, - afterProperties); - - // write out the entry to the file in requested format - writeEntryToFile(entry); - - if (results != null) - { - results.add(entry); - } - - if (logger.isDebugEnabled()) - { - logger.debug(" " + entry); - } - - // Keep going - return true; - } - - private void writeEntryToFile(RecordsManagementAuditEntry entry) - { - if (writer == null) - { - return; - } - try - { - if (!firstEntry) - { - if (reportFormat == ReportFormat.HTML) - { - writer.write("\n"); - } - else - { - writer.write(","); - } - } - else - { - firstEntry = false; - } - - // write the entry to the file - if (reportFormat == ReportFormat.JSON) - { - writer.write("\n\t\t"); - } - - writeAuditTrailEntry(writer, entry, reportFormat); - } - catch (IOException ioe) - { - throw new AlfrescoRuntimeException(MSG_TRAIL_FILE_FAIL, ioe); - } - } - }; + AuditQueryCallback callback = new AuditTrailQueryCallback(results, writer, reportFormat); String user = params.getUser(); Long fromTime = getFromDateTime(params.getDateFrom()); @@ -1174,7 +978,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean /** * Gets the start of the from date - * @see org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditServiceImpl.getStartOfDay() + * @see org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditServiceImpl#getStartOfDay(java.util.Date) * * @param date The date for which the start should be retrieved. * @return Returns null if the given date is null, otherwise the start of the given day. @@ -1216,7 +1020,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean /** * Gets the end of the from date - * @see org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditServiceImpl.getEndOfDay() + * @see org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditServiceImpl#getEndOfDay(java.util.Date) * * @param date The date for which the end should be retrieved. * @return Returns null if the given date is null, otherwise the end of the given day. @@ -1912,4 +1716,270 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean { auditEvent(nodeRef, action.getName()); } + + private class AuditTrailQueryCallback implements AuditQueryCallback + { + private final List results; + private final Writer writer; + private final ReportFormat reportFormat; + private boolean firstEntry; + + public AuditTrailQueryCallback(List results, Writer writer, ReportFormat reportFormat) + { + this.results = results; + this.writer = writer; + this.reportFormat = reportFormat; + firstEntry = true; + } + + + @Override + public boolean valuesRequired() + { + return true; + } + + /** + * Just log the error, but continue + */ + @Override + public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error) + { + logger.warn(errorMsg, error); + return true; + } + + @Override + @SuppressWarnings("unchecked") + public boolean handleAuditEntry( + Long entryId, + String applicationName, + String user, + long time, + Map values) + { + // Check for context shutdown + if (shutdown) + { + return false; + } + + + Date timestamp = new Date(time); + String eventName = null; + String fullName = null; + String userRoles = null; + NodeRef nodeRef = null; + String nodeName = null; + String nodeType = null; + String nodeIdentifier = null; + String namePath = null; + Map beforeProperties = null; + Map afterProperties = null; + + if (values.containsKey(RM_AUDIT_DATA_EVENT_NAME)) + { + // This data is /RM/event/... + eventName = (String) values.get(RM_AUDIT_DATA_EVENT_NAME); + fullName = (String) values.get(RM_AUDIT_DATA_PERSON_FULLNAME); + userRoles = (String) values.get(RM_AUDIT_DATA_PERSON_ROLES); + nodeRef = (NodeRef) values.get(RM_AUDIT_DATA_NODE_NODEREF); + nodeName = (String) values.get(RM_AUDIT_DATA_NODE_NAME); + QName nodeTypeQname = (QName) values.get(RM_AUDIT_DATA_NODE_TYPE); + nodeIdentifier = (String) values.get(RM_AUDIT_DATA_NODE_IDENTIFIER); + namePath = (String) values.get(RM_AUDIT_DATA_NODE_NAMEPATH); + beforeProperties = (Map) values.get(RM_AUDIT_DATA_NODE_CHANGES_BEFORE); + afterProperties = (Map) values.get(RM_AUDIT_DATA_NODE_CHANGES_AFTER); + + // Convert some of the values to recognizable forms + if (nodeTypeQname != null) + { + TypeDefinition typeDef = dictionaryService.getType(nodeTypeQname); + nodeType = (typeDef != null) ? typeDef.getTitle(dictionaryService) : null; + } + } + else if (values.containsKey(DOD5015_AUDIT_DATA_EVENT_NAME)) + { + // This data is /DOD5015/event/... + eventName = (String) values.get(DOD5015_AUDIT_DATA_EVENT_NAME); + fullName = (String) values.get(DOD5015_AUDIT_DATA_PERSON_FULLNAME); + userRoles = (String) values.get(DOD5015_AUDIT_DATA_PERSON_ROLES); + nodeRef = (NodeRef) values.get(DOD5015_AUDIT_DATA_NODE_NODEREF); + nodeName = (String) values.get(DOD5015_AUDIT_DATA_NODE_NAME); + QName nodeTypeQname = (QName) values.get(DOD5015_AUDIT_DATA_NODE_TYPE); + nodeIdentifier = (String) values.get(DOD5015_AUDIT_DATA_NODE_IDENTIFIER); + namePath = (String) values.get(DOD5015_AUDIT_DATA_NODE_NAMEPATH); + beforeProperties = (Map) values.get( DOD5015_AUDIT_DATA_NODE_CHANGES_BEFORE); + afterProperties = (Map) values.get(DOD5015_AUDIT_DATA_NODE_CHANGES_AFTER); + + // Convert some of the values to recognizable forms + if (nodeTypeQname != null) + { + TypeDefinition typeDef = dictionaryService.getType(nodeTypeQname); + nodeType = (typeDef != null) ? typeDef.getTitle(dictionaryService) : null; + } + } + else if (values.containsKey(RM_AUDIT_DATA_LOGIN_USERNAME)) + { + user = (String) values.get(RM_AUDIT_DATA_LOGIN_USERNAME); + if (values.containsKey(RM_AUDIT_DATA_LOGIN_ERROR)) + { + eventName = RM_AUDIT_EVENT_LOGIN_FAILURE; + // The user didn't log in + fullName = user; + } + else + { + eventName = RM_AUDIT_EVENT_LOGIN_SUCCESS; + fullName = (String) values.get(RM_AUDIT_DATA_LOGIN_FULLNAME); + } + } + else if (values.containsKey(DOD5015_AUDIT_DATA_LOGIN_USERNAME)) + { + user = (String) values.get(DOD5015_AUDIT_DATA_LOGIN_USERNAME); + if (values.containsKey(DOD5015_AUDIT_DATA_LOGIN_ERROR)) + { + eventName = RM_AUDIT_EVENT_LOGIN_FAILURE; + // The user didn't log in + fullName = user; + } + else + { + eventName = RM_AUDIT_EVENT_LOGIN_SUCCESS; + fullName = (String) values.get(DOD5015_AUDIT_DATA_LOGIN_FULLNAME); + } + } + else + { + // This is not recognisable data + logger.warn( + "Unable to process audit entry for RM. Unexpected data: \n" + + " Entry: " + entryId + "\n" + + " Data: " + values); + // Skip it + return true; + } + + if (nodeRef != null && nodeService.exists(nodeRef)) + { + if ((filePlanService.isFilePlanComponent(nodeRef) && + !AccessStatus.ALLOWED.equals( + capabilityService.getCapabilityAccessState(nodeRef, ACCESS_AUDIT_CAPABILITY))) || + (!AccessStatus.ALLOWED.equals(permissionService.hasPermission(nodeRef, PermissionService.READ)))) + { + return true; + } + + checkPermissionIfHoldInProperties(beforeProperties); + checkPermissionIfHoldInProperties(afterProperties); + } + + // remove any hold node refs from view + removeHoldNodeRefIfPresent(beforeProperties); + removeHoldNodeRefIfPresent(afterProperties); + + // TODO: Refactor this to use the builder pattern + RecordsManagementAuditEntry entry = new RecordsManagementAuditEntry( + timestamp, + user, + fullName, + // A concatenated string of roles + userRoles, + nodeRef, + nodeName, + nodeType, + eventName, + nodeIdentifier, + namePath, + beforeProperties, + afterProperties); + + // write out the entry to the file in requested format + writeEntryToFile(entry); + + if (results != null) + { + results.add(entry); + } + + if (logger.isDebugEnabled()) + { + logger.debug(" " + entry); + } + + // Keep going + return true; + } + + /** + * Helper method to check permission on the hold, if any, from the given event properties + * @param eventProperties event properties + */ + private void checkPermissionIfHoldInProperties(Map eventProperties) + { + NodeRef holdNodeRef = eventProperties != null ? (NodeRef) eventProperties.get(PROPERTY_HOLD_NODEREF) : null; + if (holdNodeRef != null) + { + if (!AccessStatus.ALLOWED.equals( + permissionService.hasPermission(holdNodeRef, PermissionService.READ))) + { + eventProperties.replace(PROPERTY_HOLD_NAME, I18NUtil.getMessage(HOLD_PERMISSION_DENIED_MSG)); + } + } + } + + /** + * Helper method to remove the hold node ref, if any, from the given event properties + * @param eventProperties event properties + */ + private void removeHoldNodeRefIfPresent(Map eventProperties) + { + if (eventProperties != null) + { + eventProperties.remove(PROPERTY_HOLD_NODEREF); + } + } + + /** + * Helper method to write the audit entry to file + * @param entry audit entry + */ + private void writeEntryToFile(RecordsManagementAuditEntry entry) + { + if (writer == null) + { + return; + } + try + { + if (!firstEntry) + { + if (reportFormat == ReportFormat.HTML) + { + writer.write("\n"); + } + else + { + writer.write(","); + } + } + else + { + firstEntry = false; + } + + // write the entry to the file + if (reportFormat == ReportFormat.JSON) + { + writer.write("\n\t\t"); + } + + writeAuditTrailEntry(writer, entry, reportFormat); + } + catch (IOException ioe) + { + throw new AlfrescoRuntimeException(MSG_TRAIL_FILE_FAIL, ioe); + } + } + } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/event/HoldUtils.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/event/HoldUtils.java index 641b7f016d..d8faecc72e 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/event/HoldUtils.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/event/HoldUtils.java @@ -47,18 +47,22 @@ class HoldUtils { /** A QName to display for the hold name. */ public static final QName HOLD_NAME = QName.createQName(RecordsManagementModel.RM_URI, "Hold Name"); + /** A QName to display for the hold node ref. */ + public static final QName HOLD_NODEREF = QName.createQName(RecordsManagementModel.RM_URI, "Hold NodeRef"); + /** - * Create a properties map containing the hold name for the given hold. + * Create a properties map containing the hold name and node ref for the given hold. * * @param nodeRef The nodeRef of the hold. * @param nodeService The node service. - * @return A map containing the name of the hold. + * @return A map containing the name and noderef of the hold. */ static Map makePropertiesMap(NodeRef nodeRef, NodeService nodeService) { Map auditProperties = new HashMap<>(); auditProperties.put(HOLD_NAME, nodeService.getProperty(nodeRef, ContentModel.PROP_NAME)); + auditProperties.put(HOLD_NODEREF, nodeRef); return auditProperties; } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImpl.java index 869da2ca2d..141b25cee1 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImpl.java @@ -43,7 +43,6 @@ import java.util.stream.Stream; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; -import org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService; import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; @@ -119,9 +118,6 @@ public class HoldServiceImpl extends ServiceBaseImpl /** Permission service */ private PermissionService permissionService; - /** records management audit service */ - private RecordsManagementAuditService recordsManagementAuditService; - /** Capability service */ private CapabilityService capabilityService; @@ -168,14 +164,6 @@ public class HoldServiceImpl extends ServiceBaseImpl this.permissionService = permissionService; } - /** - * @param recordsManagementAuditService records management audit service - */ - public void setRecordsManagementAuditService(RecordsManagementAuditService recordsManagementAuditService) - { - this.recordsManagementAuditService = recordsManagementAuditService; - } - /** * @param capabilityService capability service */