diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml index 7a31fd1b76..58628e9921 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml @@ -535,6 +535,8 @@ + + diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/job/RecordsManagementJob.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/job/RecordsManagementJob.java index 77bfa96e95..5cfebeb67c 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/job/RecordsManagementJob.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/job/RecordsManagementJob.java @@ -18,8 +18,11 @@ */ package org.alfresco.module.org_alfresco_module_rm.job; +import java.util.concurrent.atomic.AtomicBoolean; + import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.lock.JobLockService; +import org.alfresco.repo.lock.JobLockService.JobLockRefreshCallback; import org.alfresco.repo.lock.LockAcquisitionException; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; @@ -41,7 +44,7 @@ import org.quartz.JobExecutionException; */ public class RecordsManagementJob implements Job { - private static Log logger = LogFactory.getLog(RecordsManagementJob.class); + private static Log logger = LogFactory.getLog(RecordsManagementJob.class); private static final long DEFAULT_TIME = 30000L; @@ -55,6 +58,24 @@ public class RecordsManagementJob implements Job { return QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, jobName); } + + private class LockCallback implements JobLockRefreshCallback + { + final AtomicBoolean running = new AtomicBoolean(true); + + @Override + public boolean isActive() + { + return running.get(); + } + + @Override + public void lockReleased() + { + running.set(false); + } + } + /** * Attempts to get the lock. If the lock couldn't be taken, then null is returned. @@ -97,6 +118,7 @@ public class RecordsManagementJob implements Job throw new AlfrescoRuntimeException("Job name has not been specified."); } + final LockCallback lockCallback = new LockCallback(); AuthenticationUtil.runAs(new RunAsWork() { public Void doWork() @@ -107,15 +129,17 @@ public class RecordsManagementJob implements Job { try { + jobLockService.refreshLock(lockToken, getLockQName(), DEFAULT_TIME, lockCallback); // do work jobExecuter.execute(); } finally { - try - { - jobLockService.releaseLock(lockToken, getLockQName()); - } + try + { + lockCallback.running.set(false); + jobLockService.releaseLock(lockToken, getLockQName()); + } catch (LockAcquisitionException e) { // Ignore diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/AuditLogGet.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/AuditLogGet.java index 6cf968f99c..3acdbd1197 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/AuditLogGet.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/AuditLogGet.java @@ -21,9 +21,17 @@ package org.alfresco.module.org_alfresco_module_rm.script; import java.io.File; import java.io.IOException; +import org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditQueryParameters; +import org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService.ReportFormat; +import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; +import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.repo.web.scripts.content.ContentStreamer; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.AccessStatus; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptResponse; @@ -39,9 +47,16 @@ public class AuditLogGet extends BaseAuditRetrievalWebScript private static Log logger = LogFactory.getLog(AuditLogGet.class); private static final String PARAM_EXPORT = "export"; + private static final String ACCESS_AUDIT_CAPABILITY = "AccessAudit"; /** Content Streamer */ protected ContentStreamer contentStreamer; + + /** Capability service */ + protected CapabilityService capabilityService; + + /** File plan service */ + protected FilePlanService filePlanService; /** * @param contentStreamer @@ -50,6 +65,24 @@ public class AuditLogGet extends BaseAuditRetrievalWebScript { this.contentStreamer = contentStreamer; } + + /** + * + * @param capabilityService Capability Service + */ + public void setCapabilityService(CapabilityService capabilityService) + { + this.capabilityService = capabilityService; + } + + /** + * + * @param capabilityService Capability Service + */ + public void setFilePlanService(FilePlanService filePlanService) + { + this.filePlanService = filePlanService; + } @Override public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException @@ -58,8 +91,16 @@ public class AuditLogGet extends BaseAuditRetrievalWebScript try { + + RecordsManagementAuditQueryParameters queryParams = parseQueryParameters(req); + ReportFormat reportFormat = parseReportFormat(req); + + if( !userCanAccessAudit(queryParams) ) + { + throw new WebScriptException(Status.STATUS_FORBIDDEN, "Access denied because the user does not have the Access Audit capability"); + } // parse the parameters and get a file containing the audit trail - auditTrail = this.rmAuditService.getAuditTrailFile(parseQueryParameters(req), parseReportFormat(req)); + auditTrail = this.rmAuditService.getAuditTrailFile(queryParams, reportFormat); if (logger.isDebugEnabled()) { @@ -101,4 +142,15 @@ public class AuditLogGet extends BaseAuditRetrievalWebScript } } } + + private boolean userCanAccessAudit(RecordsManagementAuditQueryParameters queryParams) + { + NodeRef targetNode = queryParams.getNodeRef(); + if( targetNode == null ) + { + targetNode = filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID); + } + return AccessStatus.ALLOWED.equals( + capabilityService.getCapabilityAccessState(targetNode, ACCESS_AUDIT_CAPABILITY)); + } } \ No newline at end of file diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/webscript/AuditRestApiTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/webscript/AuditRestApiTest.java new file mode 100644 index 0000000000..d28c62d790 --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/webscript/AuditRestApiTest.java @@ -0,0 +1,72 @@ +package org.alfresco.module.org_alfresco_module_rm.test.legacy.webscript; + +import java.io.IOException; +import java.text.MessageFormat; + +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMWebScriptTestCase; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.GUID; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest; + + +public class AuditRestApiTest extends BaseRMWebScriptTestCase +{ + /** URL for the REST APIs */ + protected static final String GET_NODE_AUDITLOG_URL_FORMAT = "/api/node/{0}/rmauditlog"; + + private static final String USER_WITHOUT_AUDIT_CAPABILITY = GUID.generate(); + + private NodeRef record; + + public void testAuditAccessCapability() throws IOException + { + + String recordAuditUrl = MessageFormat.format(GET_NODE_AUDITLOG_URL_FORMAT,record.toString().replace("://", "/")); + + sendRequest(new GetRequest(recordAuditUrl), Status.STATUS_OK, AuthenticationUtil.getAdminUserName() ); + + sendRequest(new GetRequest(recordAuditUrl), Status.STATUS_FORBIDDEN, USER_WITHOUT_AUDIT_CAPABILITY ); + } + + @Override + protected void setupTestData() + { + super.setupTestData(); + + retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + @Override + public Object execute() throws Throwable + { + + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil + .getSystemUserName()); + + createUser(USER_WITHOUT_AUDIT_CAPABILITY); + + record = utils.createRecord(recordFolder, GUID.generate()); + + + return null; + } + }); + } + + @Override + protected void tearDownImpl() + { + super.tearDownImpl(); + + deleteUser(USER_WITHOUT_AUDIT_CAPABILITY); + } + + protected String getRMSiteId() + { + return filePlanService.DEFAULT_RM_SITE_ID; + } + + +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMWebScriptTestCase.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMWebScriptTestCase.java index 53fed575c1..ac9c6f6798 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMWebScriptTestCase.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMWebScriptTestCase.java @@ -279,7 +279,7 @@ public class BaseRMWebScriptTestCase extends BaseWebScriptTest assertNotNull("Could not create base folder", folder); // Create the site - siteId = GUID.generate(); + siteId = getRMSiteId(); siteInfo = siteService.createSite("rm-site-dashboard", siteId, "title", "descrition", SiteVisibility.PUBLIC, RecordsManagementModel.TYPE_RM_SITE); filePlan = siteService.getContainer(siteId, RmSiteType.COMPONENT_DOCUMENT_LIBRARY); assertNotNull("Site document library container was not created successfully.", filePlan); @@ -383,4 +383,9 @@ public class BaseRMWebScriptTestCase extends BaseWebScriptTest authorityService.deleteAuthority(groupName, true); } } + + protected String getRMSiteId() + { + return GUID.generate(); + } }