From 6b54f8f9f897fa2143d73e6552a493f152fce404 Mon Sep 17 00:00:00 2001 From: Roy Wetherall Date: Thu, 27 Sep 2012 07:12:52 +0000 Subject: [PATCH] RM: Inplace filing prototype * extension of seciruty service to allow management of extended readers * extended reader maintained within file plan hierarchy * support ready for removal (ie move) and overlapping of readers in hirearchy (maintained in reference counting map) * general rename to "Unfiled Records" rather than "New Records" * File plan unfiled records filter * Unit tests * Correct permissions on created unfiled container (file for admin as per file plan root) * record readers dynamic authority applied to file plan components on bootstrap and creation git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/INPLACE@42063 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../org_alfresco_module_rm/action-context.xml | 2 +- .../rm-capabilities-group-context.xml | 1 + .../model/recordsModel.xml | 17 +- .../org_alfresco_module_rm/module-context.xml | 4 +- .../rm-public-services-security-context.xml | 1 + .../rm-service-context.xml | 8 +- .../rm-ui-evaluators-context.xml | 2 + .../documentlibrary-v2/rm-filters.lib.js | 7 + .../documentlibrary/rm-treenode.get.js | 2 +- .../RecordsManagementService.java | 8 + .../RecordsManagementServiceImpl.java | 9 + .../action/dm/CreateRecordAction.java | 40 +--- .../capability/RMAfterInvocationProvider.java | 3 + .../capability/RMSecurityCommon.java | 11 +- .../capability/impl/CreateCapability.java | 8 + .../model/RecordsManagementModel.java | 10 +- .../model/behaviour/FilePlanType.java | 35 +-- .../model/behaviour/RmSiteType.java | 65 +++--- .../record/RecordService.java | 1 + .../record/RecordServiceImpl.java | 2 +- .../ExtendedReaderDynamicAuthority.java} | 103 +++++---- .../RecordsManagementSecurityService.java | 27 +++ .../RecordsManagementSecurityServiceImpl.java | 216 ++++++++++++++++-- ...ordsManagementSecurityServiceImplTest.java | 151 ++++++++++++ .../test/service/RecordServiceTestImpl.java | 13 +- ...ordsManagementSecurityServiceImplTest.java | 2 +- .../test/util/BaseRMTestCase.java | 12 +- 27 files changed, 567 insertions(+), 193 deletions(-) rename rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/{permission/RecordReadersDynamicAuthority.java => security/ExtendedReaderDynamicAuthority.java} (61%) create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/NewRecordsManagementSecurityServiceImplTest.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/action-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/action-context.xml index b308c58434..3179870f95 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/action-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/action-context.xml @@ -15,7 +15,7 @@ - + diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-group-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-group-context.xml index 8b06e20f26..555f89a78d 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-group-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-group-context.xml @@ -6,6 +6,7 @@ + diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml index 754d382efd..50d4493ca5 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml @@ -90,8 +90,8 @@ - - New Records Container + + Unfiled Record Container rma:recordsManagementContainer @@ -624,14 +624,14 @@ - - New Records + + Unfiled Records true false - rma:newRecordsContainer + rma:unfiledRecordContainer true true @@ -844,13 +844,12 @@ - + - + - d:text - true + d:any diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml index 139c502bb0..6c663e725c 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml @@ -46,12 +46,12 @@ - + - + + diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml index 937a12005d..d27cff9d0d 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml @@ -67,6 +67,7 @@ org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isFilePlanComponent=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.getFilePlanComponentKind=ACL_NODE.0.sys:base.ReadProperties, RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.getFilePlanComponentKindFromType=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isRecordsManagementContainer=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isFilePlan=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isRecordCategory=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isRecordFolder=RM.Read.0 @@ -480,7 +481,12 @@ org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.createRole=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.updateRole=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.deleteRole=RM_ALLOW - org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.assignRoleToAuthority=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.assignRoleToAuthority=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.getExtendedReaders=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.setExtendedReaders=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.removeExtendedReaders=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.removeAllExtendedReaders=RM_ALLOW + org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.*=RM_DENY ]]> diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-ui-evaluators-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-ui-evaluators-context.xml index 72a35ea07a..925fa0cee7 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-ui-evaluators-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-ui-evaluators-context.xml @@ -7,6 +7,7 @@ class="org.alfresco.module.org_alfresco_module_rm.jscript.app.JSONConversionComponent" parent="baseJsonConversionComponent"> + @@ -14,6 +15,7 @@ abstract="true"> + diff --git a/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-filters.lib.js b/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-filters.lib.js index 25a0234d47..fa31ed974e 100644 --- a/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-filters.lib.js +++ b/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-filters.lib.js @@ -179,6 +179,13 @@ Filters.getFilterParams = function RecordsManagementFilter_getFilterParams(filte filterParams.query = "+PARENT:\"" + filterData + "\""; } break; + + case "unfiledRecords": + filterParams.variablePath = false; + filterQuery = "+PATH:\"" + parsedArgs.pathNode.qnamePath + "/rma:Unfiled_x0020_Records/*\""; + filterParams.query = filterQuery + filterQueryDefaults; + + break; default: filterParams.variablePath = false; diff --git a/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/rm-treenode.get.js b/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/rm-treenode.get.js index 09c27856d2..8dd5e01d78 100644 --- a/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/rm-treenode.get.js +++ b/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/rm-treenode.get.js @@ -120,7 +120,7 @@ function itemIsAllowed(item) var typeShort = String(item.typeShort); // Don't show Hold and Transfer top-level containers - if (typeShort == "rma:hold" || typeShort == "rma:transfer") + if (typeShort == "rma:hold" || typeShort == "rma:transfer" || typeShort == "rma:unfiledRecordContainer") { return false; } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementService.java index cf6fe257c5..3d25fb2bfe 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementService.java @@ -73,6 +73,14 @@ public interface RecordsManagementService */ FilePlanComponentKind getFilePlanComponentKindFromType(QName type); + /** + * Indicates whether the given node is a records management container or not. + * + * @param nodeRef node reference + * @return boolean true if node is a record container, false otherwise. + */ + boolean isRecordsManagementContainer(NodeRef nodeRef); + /** * Indicates whether the given node is file plan node or not. * diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceImpl.java index 6c09f8bea4..eef43031b7 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementServiceImpl.java @@ -436,6 +436,15 @@ public class RecordsManagementServiceImpl implements RecordsManagementService, return instanceOf(nodeRef, TYPE_FILE_PLAN); } + /** + * @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementService#isRecordsManagementContainer(org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + public boolean isRecordsManagementContainer(NodeRef nodeRef) + { + return instanceOf(nodeRef, TYPE_RECORDS_MANAGEMENT_CONTAINER); + } + /** * Utility method to safely and quickly determine if a node is a type (or sub-type) of the one specified. */ diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java index 6da56869ab..89f8c020e2 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java @@ -18,19 +18,14 @@ */ package org.alfresco.module.org_alfresco_module_rm.action.dm; -import java.io.Serializable; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementService; -import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; -import org.alfresco.module.org_alfresco_module_rm.permission.RecordReadersDynamicAuthority; -import org.alfresco.module.org_alfresco_module_rm.record.RecordService; +import org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService; import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; @@ -40,7 +35,6 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; /** @@ -56,8 +50,8 @@ public class CreateRecordAction extends ActionExecuterAbstractBase public static final String NAME = "create-record"; private RecordsManagementService recordsManagementService; - - private RecordService recordService; + + private RecordsManagementSecurityService recordsManagementSecurityService; private PermissionService permissionService; @@ -68,9 +62,9 @@ public class CreateRecordAction extends ActionExecuterAbstractBase this.recordsManagementService = recordsManagementService; } - public void setRecordService(RecordService recordService) + public void setRecordsManagementSecurityService(RecordsManagementSecurityService recordsManagementSecurityService) { - this.recordService = recordService; + this.recordsManagementSecurityService = recordsManagementSecurityService; } public void setPermissionService(PermissionService permissionService) @@ -111,29 +105,15 @@ public class CreateRecordAction extends ActionExecuterAbstractBase { throw new AlfrescoRuntimeException("Unable to create record, because new record container could not be found."); } - + // move the document into the file plan nodeService.moveNode(actionedUponNodeRef, newRecordContainer, ContentModel.ASSOC_CONTAINS, parentAssoc.getQName()); // maintain the original primary location nodeService.addChild(parentAssoc.getParentRef(), actionedUponNodeRef, parentAssoc.getTypeQName(), parentAssoc.getQName()); - // add extended security information to the record - Map props = new HashMap(1); - props.put(PROP_READERS, (Serializable)readers); - nodeService.addAspect(actionedUponNodeRef, ASPECT_EXTENDED_RECORD_SECURITY, props); - - // add permission so readers can still 'see' the new record - // Note: using the regular permission service as we don't want to reflect this permission up (and down) the - // hierarchy - permissionService.setPermission(actionedUponNodeRef, - RecordReadersDynamicAuthority.RECORD_READERS, - RMPermissionModel.READ_RECORDS, - true); - permissionService.setPermission(filePlan, - RecordReadersDynamicAuthority.RECORD_READERS, - RMPermissionModel.VIEW_RECORDS, - true); + // set the readers + recordsManagementSecurityService.setExtendedReaders(actionedUponNodeRef, readers); return null; } @@ -141,13 +121,13 @@ public class CreateRecordAction extends ActionExecuterAbstractBase } else { - throw new AlfrescoRuntimeException("Unable to file file plan."); + throw new AlfrescoRuntimeException("Unable to find file plan."); } } private NodeRef getNewRecordContainer(NodeRef filePlan) { - List assocs = nodeService.getChildAssocs(filePlan, ASSOC_NEW_RECORDS, RegexQNamePattern.MATCH_ALL); + List assocs = nodeService.getChildAssocs(filePlan, ASSOC_UNFILED_RECORDS, RegexQNamePattern.MATCH_ALL); if (assocs.size() != 1) { throw new AlfrescoRuntimeException("Error getting the new record container, because the container cannot be indentified."); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMAfterInvocationProvider.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMAfterInvocationProvider.java index e0ca52355d..7d725a9d1a 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMAfterInvocationProvider.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMAfterInvocationProvider.java @@ -61,6 +61,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; +/** + * RM After Invocation Provider + */ public class RMAfterInvocationProvider extends RMSecurityCommon implements AfterInvocationProvider, InitializingBean { diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMSecurityCommon.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMSecurityCommon.java index d2dde825dc..756faefff9 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMSecurityCommon.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMSecurityCommon.java @@ -31,6 +31,9 @@ import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.PermissionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; /** * @author Roy Wetherall @@ -42,10 +45,11 @@ public class RMSecurityCommon private static Log logger = LogFactory.getLog(RMSecurityCommon.class); + private ApplicationContext applicationContext; + protected NodeService nodeService; protected PermissionService permissionService; protected RecordsManagementService rmService; - protected RecordService recordService; protected RMCaveatConfigComponent caveatConfigComponent; public void setNodeService(NodeService nodeService) @@ -63,11 +67,6 @@ public class RMSecurityCommon this.rmService = rmService; } - public void setRecordService(RecordService recordService) - { - this.recordService = recordService; - } - public void setCaveatConfigComponent(RMCaveatConfigComponent caveatConfigComponent) { this.caveatConfigComponent = caveatConfigComponent; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/impl/CreateCapability.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/impl/CreateCapability.java index e4acc7b194..c606f4a7b7 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/impl/CreateCapability.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/impl/CreateCapability.java @@ -26,6 +26,7 @@ import net.sf.acegisecurity.vote.AccessDecisionVoter; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.capability.declarative.DeclarativeCapability; +import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.namespace.QName; @@ -37,6 +38,13 @@ import org.alfresco.service.namespace.QName; */ public class CreateCapability extends DeclarativeCapability { + private RecordService recordService; + + public void setRecordService(RecordService recordService) + { + this.recordService = recordService; + } + /** * @see org.alfresco.module.org_alfresco_module_rm.capability.Capability#evaluate(org.alfresco.service.cmr.repository.NodeRef) */ diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java index 992059c02a..6a18bf9a60 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java @@ -57,8 +57,8 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel // Records management root container public static final QName TYPE_FILE_PLAN = QName.createQName(RM_URI, "filePlan"); - // New records container - public static final QName TYPE_NEW_RECORDS_CONTAINER = QName.createQName(RM_URI, "newRecordsContainer"); + // Unfiled record container + public static final QName TYPE_UNFILED_RECORD_CONTAINER = QName.createQName(RM_URI, "unfiledRecordContainer"); // Disposition instructions aspect public static final QName ASPECT_SCHEDULED = QName.createQName(RM_URI, "scheduled"); @@ -170,7 +170,7 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel public static final QName ASPECT_RECORDS_MANAGEMENT_ROOT = QName.createQName(RM_URI, "recordsManagementRoot"); public static final QName ASSOC_HOLDS = QName.createQName(RM_URI, "holds"); public static final QName ASSOC_TRANSFERS = QName.createQName(RM_URI, "transfers"); - public static final QName ASSOC_NEW_RECORDS = QName.createQName(RM_URI, "newRecords"); + public static final QName ASSOC_UNFILED_RECORDS = QName.createQName(RM_URI, "unfiledRecords"); // Hold type public static final QName TYPE_HOLD = QName.createQName(RM_URI, "hold"); @@ -224,7 +224,7 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel public static final QName PROP_RS_DISPOITION_AUTHORITY = QName.createQName(RM_URI, "recordSearchDispositionAuthority"); public static final QName PROP_RS_HOLD_REASON = QName.createQName(RM_URI, "recordSearchHoldReason"); - // Extended record security aspect - public static final QName ASPECT_EXTENDED_RECORD_SECURITY = QName.createQName(RM_URI, "extendedRecordSecurity"); + // Extended readers aspect + public static final QName ASPECT_EXTENDED_READERS = QName.createQName(RM_URI, "extendedReaders"); public static final QName PROP_READERS = QName.createQName(RM_URI, "readers"); } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/FilePlanType.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/FilePlanType.java index 5f961b6185..350e2ea7a9 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/FilePlanType.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/FilePlanType.java @@ -18,21 +18,12 @@ */ package org.alfresco.module.org_alfresco_module_rm.model.behaviour; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.repo.node.NodeServicePolicies; -import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; -import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.namespace.QName; /** * Behaviour associated with the file plan type @@ -82,10 +73,10 @@ public class FilePlanType implements RecordsManagementModel, */ public void init() { - policyComponent.bindClassBehaviour( - NodeServicePolicies.OnCreateNodePolicy.QNAME, - TYPE_FILE_PLAN, - new JavaBehaviour(this, "onCreateNode", NotificationFrequency.TRANSACTION_COMMIT)); + // policyComponent.bindClassBehaviour( + // NodeServicePolicies.OnCreateNodePolicy.QNAME, + // TYPE_FILE_PLAN, + // new JavaBehaviour(this, "onCreateNode", NotificationFrequency.TRANSACTION_COMMIT)); } /** @@ -94,22 +85,6 @@ public class FilePlanType implements RecordsManagementModel, @Override public void onCreateNode(ChildAssociationRef assoc) { - // grab the newly created file plan - NodeRef filePlan = assoc.getChildRef(); - - // create the properties map - Map properties = new HashMap(1); - properties.put(ContentModel.PROP_NAME, NAME_NR_CONTAINER); - - // create the 'new records' folder - NodeRef container = nodeService.createNode( - filePlan, - ASSOC_NEW_RECORDS, - QName.createQName(RM_URI, NAME_NR_CONTAINER), - TYPE_NEW_RECORDS_CONTAINER, - properties).getChildRef(); - - // set inheritance to false - permissionService.setInheritParentPermissions(container, false); + // TODO refactor the file plan behaviours from the service code } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RmSiteType.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RmSiteType.java index c66039c5a0..51a0ea48de 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RmSiteType.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RmSiteType.java @@ -56,6 +56,9 @@ public class RmSiteType implements RecordsManagementModel, /** Record Management Search Service */ private RecordsManagementSearchService recordsManagementSearchService; + /** Behaviour */ + JavaBehaviour behaviour = new JavaBehaviour(this, "onCreateNode", NotificationFrequency.FIRST_EVENT); + /** * Set the policy component * @param policyComponent policy component @@ -99,7 +102,7 @@ public class RmSiteType implements RecordsManagementModel, policyComponent.bindClassBehaviour( NodeServicePolicies.OnCreateNodePolicy.QNAME, TYPE_RM_SITE, - new JavaBehaviour(this, "onCreateNode", NotificationFrequency.FIRST_EVENT)); + behaviour); } /** @@ -108,33 +111,41 @@ public class RmSiteType implements RecordsManagementModel, @Override public void onCreateNode(ChildAssociationRef childAssocRef) { - final NodeRef rmSite = childAssocRef.getChildRef(); - - // Do not execute behaviour if this has been created in the archive store - if(rmSite.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE) == true) - { - // This is not the spaces store - probably the archive store - return; - } - - if (nodeService.exists(rmSite) == true) - { - AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + behaviour.disable(); + try + { + final NodeRef rmSite = childAssocRef.getChildRef(); + + // Do not execute behaviour if this has been created in the archive store + if(rmSite.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE) == true) { - public Object doWork() + // This is not the spaces store - probably the archive store + return; + } + + if (nodeService.exists(rmSite) == true) + { + AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { - SiteInfo siteInfo = siteService.getSite(rmSite); - if (siteInfo != null) - { - // Create the file plan component - siteService.createContainer(siteInfo.getShortName(), COMPONENT_DOCUMENT_LIBRARY, TYPE_FILE_PLAN, null); - - // Add the reports - recordsManagementSearchService.addReports(siteInfo.getShortName()); - } - return null; - } - }, AuthenticationUtil.getAdminUserName()); - } + public Object doWork() + { + SiteInfo siteInfo = siteService.getSite(rmSite); + if (siteInfo != null) + { + // Create the file plan component + siteService.createContainer(siteInfo.getShortName(), COMPONENT_DOCUMENT_LIBRARY, TYPE_FILE_PLAN, null); + + // Add the reports + recordsManagementSearchService.addReports(siteInfo.getShortName()); + } + return null; + } + }, AuthenticationUtil.getAdminUserName()); + } + } + finally + { + behaviour.enable(); + } } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java index 90746b8511..8b4df14e4b 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java @@ -25,6 +25,7 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; /** + * Record Service Interface. * * @author Roy Wetherall * @since 2.1 diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java index 839611cf91..e39f5ef22c 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java @@ -88,7 +88,7 @@ public class RecordServiceImpl implements RecordService, RecordsManagementModel { policyComponent.bindAssociationBehaviour( QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateChildAssociation"), - TYPE_NEW_RECORDS_CONTAINER, + TYPE_UNFILED_RECORD_CONTAINER, ContentModel.ASSOC_CONTAINS, new JavaBehaviour(this, "onCreateNewRecord", NotificationFrequency.TRANSACTION_COMMIT)); } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/permission/RecordReadersDynamicAuthority.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java similarity index 61% rename from rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/permission/RecordReadersDynamicAuthority.java rename to rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java index 0b3452e7bf..8eaf471512 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/permission/RecordReadersDynamicAuthority.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java @@ -16,13 +16,10 @@ * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ -package org.alfresco.module.org_alfresco_module_rm.permission; +package org.alfresco.module.org_alfresco_module_rm.security; -import java.util.List; import java.util.Set; -import org.alfresco.module.org_alfresco_module_rm.FilePlanComponentKind; -import org.alfresco.module.org_alfresco_module_rm.RecordsManagementService; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.repo.security.permissions.DynamicAuthority; import org.alfresco.repo.security.permissions.PermissionReference; @@ -30,44 +27,42 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.namespace.QName; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** + * Extended readers dynamic authority implementation. + * * @author Roy Wetherall * @since 2.1 */ -public class RecordReadersDynamicAuthority implements DynamicAuthority, RecordsManagementModel, ApplicationContextAware +public class ExtendedReaderDynamicAuthority implements DynamicAuthority, + RecordsManagementModel, + ApplicationContextAware { - public static final String RECORD_READERS = "ROLE_RECORD_READERS"; - - private RecordsManagementService recordsManagementService; - - private NodeService nodeService; + /** Extended reader role */ + public static final String EXTENDED_READER = "ROLE_EXTENDED_READER"; + /** Authority service */ private AuthorityService authorityService; + /** Records management security service */ + private RecordsManagementSecurityService recordsManagementSecurityService; + + /** Node service */ + private NodeService nodeService; + + /** Application context */ private ApplicationContext applicationContext; - private RecordsManagementService getRecordsManagementService() - { - if (recordsManagementService == null) - { - recordsManagementService = (RecordsManagementService)applicationContext.getBean("recordsManagementService"); - } - return recordsManagementService; - } - - private NodeService getNodeService() - { - if (nodeService == null) - { - nodeService = (NodeService)applicationContext.getBean("nodeService"); - } - return nodeService; - } + // NOTE: we get the services directly from the application context in this way to avoid + // cyclic relationships and issues when loading the application context + /** + * @return authority service + */ private AuthorityService getAuthorityService() { if (authorityService == null) @@ -76,7 +71,34 @@ public class RecordReadersDynamicAuthority implements DynamicAuthority, RecordsM } return authorityService; } + + /** + * @return records management security service + */ + public RecordsManagementSecurityService getRecordsManagementSecurityService() + { + if (recordsManagementSecurityService == null) + { + recordsManagementSecurityService = (RecordsManagementSecurityService)applicationContext.getBean("recordsManagementSecurityService"); + } + return recordsManagementSecurityService; + } + + /** + * @return node service + */ + public NodeService getNodeService() + { + if (nodeService == null) + { + nodeService = (NodeService)applicationContext.getBean("nodeService"); + } + return nodeService; + } + /** + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { @@ -89,34 +111,37 @@ public class RecordReadersDynamicAuthority implements DynamicAuthority, RecordsM @Override public String getAuthority() { - return RECORD_READERS; + return EXTENDED_READER; } /** * @see org.alfresco.repo.security.permissions.DynamicAuthority#hasAuthority(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) */ - @SuppressWarnings("unchecked") @Override public boolean hasAuthority(NodeRef nodeRef, String userName) { boolean result = false; - FilePlanComponentKind kind = getRecordsManagementService().getFilePlanComponentKind(nodeRef); - if (FilePlanComponentKind.RECORD.equals(kind) == true) + if (getNodeService().hasAspect(nodeRef, ASPECT_EXTENDED_READERS) == true) { - if (getNodeService().hasAspect(nodeRef, ASPECT_EXTENDED_RECORD_SECURITY) == true) + Set readers = getRecordsManagementSecurityService().getExtendedReaders(nodeRef); + if (readers != null) { - List readers = (List)nodeService.getProperty(nodeRef, PROP_READERS); for (String reader : readers) { - if (reader.startsWith("GROUP_") == true) + if ("GROUP_EVERYONE".equals(reader) == true) { + // 'eveyone' has read + result = true; + break; + } + else if (reader.startsWith("GROUP_") == true) + { + // check group to see if the user is contained Set contained = getAuthorityService().getContainedAuthorities(AuthorityType.USER, reader, false); if (contained.isEmpty() == false && contained.contains(userName) == true) { - System.out.println("User " + userName + " is contained in the read group " + reader); - result = true; break; } @@ -126,8 +151,6 @@ public class RecordReadersDynamicAuthority implements DynamicAuthority, RecordsM // presume we have a user if (reader.equals(userName) == true) { - System.out.println("User " + userName + " matches read user " + reader); - result = true; break; } @@ -135,10 +158,6 @@ public class RecordReadersDynamicAuthority implements DynamicAuthority, RecordsM } } } - else if (FilePlanComponentKind.FILE_PLAN.equals(kind) == true) - { - result = true; - } return result; } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityService.java index 7cb8b18895..c782db6611 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityService.java @@ -152,4 +152,31 @@ public interface RecordsManagementSecurityService * @param permission permission */ void deletePermission(NodeRef nodeRef, String authority, String permission); + + /** + * + * @param nodeRef + * @return + */ + Set getExtendedReaders(NodeRef nodeRef); + + /** + * + * @param nodeRef + * @param readers + */ + void setExtendedReaders(NodeRef nodeRef, Set readers); + + /** + * + * @param nodeRef + * @param readers + */ + void removeExtendedReaders(NodeRef nodeRef, Set readers); + + /** + * + * @param nodeRef + */ + void removeAllExtendedReaders(NodeRef nodeRef); } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityServiceImpl.java index 9ae1855e1e..c80ff5a520 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/RecordsManagementSecurityServiceImpl.java @@ -22,8 +22,11 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.Serializable; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; @@ -56,6 +59,9 @@ import org.apache.commons.logging.LogFactory; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; /** * Records management permission service implementation @@ -63,7 +69,8 @@ import org.json.JSONObject; * @author Roy Wetherall */ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSecurityService, - RecordsManagementModel + RecordsManagementModel, + ApplicationContextAware { /** Capability service */ @@ -90,9 +97,24 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe /** Records management role zone */ public static final String RM_ROLE_ZONE_PREFIX = "rmRoleZone"; + /** Unfiled record container name */ + private static final String NAME_UNFILED_CONTAINER = "Unfiled Records"; + /** Logger */ private static Log logger = LogFactory.getLog(RecordsManagementSecurityServiceImpl.class); + /** Application context */ + private ApplicationContext applicationContext; + + /** + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + this.applicationContext = applicationContext; + } + /** * Set the capability service * @@ -204,9 +226,9 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe if (nodeService.exists(rmRootNode) == true) { - AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + NodeRef unfiledContainer = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { - public Object doWork() + public NodeRef doWork() { // Create "all" role group for root node String allRoles = authorityService.createAuthority(AuthorityType.GROUP, getAllRolesGroupShortName(rmRootNode), "All Roles", null); @@ -214,16 +236,47 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe // Set the permissions permissionService.setInheritParentPermissions(rmRootNode, false); permissionService.setPermission(rmRootNode, allRoles, RMPermissionModel.READ_RECORDS, true); - - return null; + permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true); + permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.VIEW_RECORDS, true); + + // Create the unfiled record container + return createUnfiledContainer(rmRootNode, allRoles); } }, AuthenticationUtil.getSystemUserName()); // Bootstrap in the default set of roles for the newly created root node - bootstrapDefaultRoles(rmRootNode); + bootstrapDefaultRoles(rmRootNode, unfiledContainer); } } + /** + * Creates unfiled container node and sets up permissions + * + * @param rmRootNode + * @param allRoles + */ + private NodeRef createUnfiledContainer(NodeRef rmRootNode, String allRoles) + { + // create the properties map + Map properties = new HashMap(1); + properties.put(ContentModel.PROP_NAME, NAME_UNFILED_CONTAINER); + + // create the unfiled container + NodeRef container = nodeService.createNode( + rmRootNode, + ASSOC_UNFILED_RECORDS, + QName.createQName(RM_URI, NAME_UNFILED_CONTAINER), + TYPE_UNFILED_RECORD_CONTAINER, + properties).getChildRef(); + + // set inheritance to false + permissionService.setInheritParentPermissions(container, false); + permissionService.setPermission(container, allRoles, RMPermissionModel.READ_RECORDS, true); + permissionService.setPermission(container, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true); + + return container; + } + /** * Delete root node behaviour * @@ -293,17 +346,20 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe Set perms = permissionService.getAllSetPermissions(catNodeRef); for (AccessPermission perm : perms) { - AccessStatus accessStatus = perm.getAccessStatus(); - boolean allow = false; - if (AccessStatus.ALLOWED.equals(accessStatus) == true) - { - allow = true; - } - permissionService.setPermission( - folderNodeRef, - perm.getAuthority(), - perm.getPermission(), - allow); + if (ExtendedReaderDynamicAuthority.EXTENDED_READER.equals(perm.getAuthority()) == false) + { + AccessStatus accessStatus = perm.getAccessStatus(); + boolean allow = false; + if (AccessStatus.ALLOWED.equals(accessStatus) == true) + { + allow = true; + } + permissionService.setPermission( + folderNodeRef, + perm.getAuthority(), + perm.getPermission(), + allow); + } } return null; @@ -324,8 +380,11 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe { public Object doWork() { - // Break inheritance + // break inheritance permissionService.setInheritParentPermissions(nodeRef, false); + + // set extended reader permissions + permissionService.setPermission(nodeRef, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true); return null; } @@ -352,7 +411,12 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe /** * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#bootstrapDefaultRoles(org.alfresco.service.cmr.repository.NodeRef) */ - public void bootstrapDefaultRoles(final NodeRef rmRootNode) + public void bootstrapDefaultRoles(NodeRef rmRootNode) + { + bootstrapDefaultRoles(rmRootNode, null); + } + + private void bootstrapDefaultRoles(final NodeRef rmRootNode, final NodeRef unfiledContainer) { AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { @@ -434,7 +498,12 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe // Add any additional admin permissions if (isAdmin == true) { + // Admin has filing permissionService.setPermission(rmRootNode, role.getRoleGroupName(), RMPermissionModel.FILING, true); + if (unfiledContainer != null) + { + permissionService.setPermission(unfiledContainer, role.getRoleGroupName(), RMPermissionModel.FILING, true); + } // Add the creating user to the administration group String user = AuthenticationUtil.getFullyAuthenticatedUser(); @@ -597,6 +666,12 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe }, AuthenticationUtil.getSystemUserName()); } + /** + * + * @param rmRootNode + * @param roleAuthority + * @return + */ private Set getCapabilitiesImpl(NodeRef rmRootNode, String roleAuthority) { Set permissions = permissionService.getAllSetPermissions(rmRootNode); @@ -636,7 +711,7 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe }, AuthenticationUtil.getSystemUserName()).booleanValue(); } - /* + /** * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#hasRMAdminRole(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) */ public boolean hasRMAdminRole(NodeRef rmRootNode, String user) @@ -791,7 +866,7 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe public Boolean doWork() throws Exception { if (recordsManagementService.isFilePlan(nodeRef) == false && - recordsManagementService.isRecordCategory(nodeRef) == true) + recordsManagementService.isRecordsManagementContainer(nodeRef) == true) { setReadPermissionUp(nodeRef, authority); setPermissionDown(nodeRef, authority, permission); @@ -841,13 +916,13 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe private void setPermissionDown(NodeRef nodeRef, String authority, String permission) { setPermissionImpl(nodeRef, authority, permission); - if (recordsManagementService.isRecordCategory(nodeRef) == true) + if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true) { List assocs = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); for (ChildAssociationRef assoc : assocs) { NodeRef child = assoc.getChildRef(); - if (recordsManagementService.isRecordCategory(child) == true || + if (recordsManagementService.isRecordsManagementContainer(child) == true || recordsManagementService.isRecordFolder(child) == true) { setPermissionDown(child, authority, permission); @@ -886,13 +961,13 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe // Delete permission on this node permissionService.deletePermission(nodeRef, authority, permission); - if (recordsManagementService.isRecordCategory(nodeRef) == true) + if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true) { List assocs = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); for (ChildAssociationRef assoc : assocs) { NodeRef child = assoc.getChildRef(); - if (recordsManagementService.isRecordCategory(child) == true || + if (recordsManagementService.isRecordsManagementContainer(child) == true || recordsManagementService.isRecordFolder(child) == true) { deletePermission(child, authority, permission); @@ -904,4 +979,95 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe } }, AuthenticationUtil.getSystemUserName()); } + + @SuppressWarnings("unchecked") + @Override + public Set getExtendedReaders(NodeRef nodeRef) + { + NodeService nodeService = (NodeService)applicationContext.getBean("nodeService"); + Set result = null; + + Map readerMap = (Map)nodeService.getProperty(nodeRef, PROP_READERS); + if (readerMap != null) + { + result = readerMap.keySet(); + } + + return result; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#setExtendedReaders(org.alfresco.service.cmr.repository.NodeRef, java.util.Set) + */ + @SuppressWarnings("unchecked") + @Override + public void setExtendedReaders(NodeRef nodeRef, Set readers) + { + ParameterCheck.mandatory("nodeRef", nodeRef); + ParameterCheck.mandatory("readers", readers); + + NodeService nodeService = (NodeService)applicationContext.getBean("nodeService"); + RecordsManagementService recordsManagementService = (RecordsManagementService)applicationContext.getBean("recordsManagementService"); + + if (nodeRef != null && + readers.isEmpty() == false) + { + // add the aspect if missing + if (nodeService.hasAspect(nodeRef, ASPECT_EXTENDED_READERS) == false) + { + nodeService.addAspect(nodeRef, ASPECT_EXTENDED_READERS, null); + } + + // get reader map + Map readersMap = (Map)nodeService.getProperty(nodeRef, PROP_READERS); + if (readersMap == null) + { + // create reader map + readersMap = new HashMap(7); + } + + for (String reader : readers) + { + if (readersMap.containsKey(reader) == true) + { + // increment reference count + Integer count = readersMap.get(reader); + readersMap.put(reader, Integer.valueOf(count.intValue()+1)); + } + else + { + // add reader with initial count + readersMap.put(reader, Integer.valueOf(1)); + } + } + + // set the readers property (this will in turn apply the aspect if required) + nodeService.setProperty(nodeRef, PROP_READERS, (Serializable)readersMap); + + // apply the extended readers up the file plan primary hierarchy + NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef(); + if (parent != null && + recordsManagementService.isFilePlanComponent(parent) == true) + { + setExtendedReaders(parent, readers); + } + } + } + + @Override + public void removeExtendedReaders(NodeRef nodeRef, Set readers) + { + // TODO Auto-generated method stub + + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#removeAllExtendedReaders(org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + public void removeAllExtendedReaders(NodeRef nodeRef) + { + // TODO Auto-generated method stub + + } } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/NewRecordsManagementSecurityServiceImplTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/NewRecordsManagementSecurityServiceImplTest.java new file mode 100644 index 0000000000..938768a545 --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/NewRecordsManagementSecurityServiceImplTest.java @@ -0,0 +1,151 @@ + +package org.alfresco.module.org_alfresco_module_rm.test.service; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Records management security service test. + * + * @author Roy Wetherall + */ +public class NewRecordsManagementSecurityServiceImplTest extends BaseRMTestCase +{ + private NodeRef record; + private NodeRef recordToo; + + @Override + protected boolean isUserTest() + { + return true; + } + + @Override + protected void setupTestDataImpl() + { + super.setupTestDataImpl(); + + record = utils.createRecord(rmFolder, "record.txt"); + recordToo = utils.createRecord(rmFolder, "recordToo.txt"); + } + + + // TODO testGetProtectedAspects + + // TODO getProtectedProperties + + // TODO bootstrapDefaultRoles + + // TODO getRoles + + // TODO getRolesByUser + + // TODO getRole + + // TODO existsRole + + // TODO hasRMAdminRole + + // TODO createRole + + // TODO updateRole + + // TODO deleteRole + + // TODO assignRoleToAuthority + + // TODO setPermission + + // TODO deletePermission + + public void testExtendedReaders() + { + doTestInTransaction(new Test() + { + public Void run() + { + assertFalse(hasExtendedReadersAspect(filePlan)); + assertFalse(hasExtendedReadersAspect(rmContainer)); + assertFalse(hasExtendedReadersAspect(rmFolder)); + assertFalse(hasExtendedReadersAspect(record)); + + assertNull(securityService.getExtendedReaders(record)); + + Set extendedReaders = new HashSet(2); + extendedReaders.add("monkey"); + extendedReaders.add("elephant"); + + securityService.setExtendedReaders(record, extendedReaders); + + Map testMap = new HashMap(2); + testMap.put("monkey", Integer.valueOf(1)); + testMap.put("elephant", Integer.valueOf(1)); + + test(filePlan, testMap); + test(rmContainer, testMap); + test(rmFolder, testMap); + test(record, testMap); + + Set extendedReadersToo = new HashSet(2); + extendedReadersToo.add("monkey"); + extendedReadersToo.add("snake"); + + securityService.setExtendedReaders(recordToo, extendedReadersToo); + + Map testMapToo = new HashMap(2); + testMapToo.put("monkey", Integer.valueOf(1)); + testMapToo.put("snake", Integer.valueOf(1)); + + Map testMapThree = new HashMap(3); + testMapThree.put("monkey", Integer.valueOf(2)); + testMapThree.put("elephant", Integer.valueOf(1)); + testMapThree.put("snake", Integer.valueOf(1)); + + test(filePlan, testMapThree); + test(rmContainer, testMapThree); + test(rmFolder, testMapThree); + test(recordToo, testMapToo); + + return null; + } + + private boolean hasExtendedReadersAspect(NodeRef nodeRef) + { + return nodeService.hasAspect(nodeRef, ASPECT_EXTENDED_READERS); + } + + private void test(NodeRef nodeRef, Map testMap) + { + assertTrue(hasExtendedReadersAspect(nodeRef)); + + Map readersMap = (Map)nodeService.getProperty(nodeRef, PROP_READERS); + assertNotNull(readersMap); + assertEquals(testMap.size(), readersMap.size()); + + for (Map.Entry entry: testMap.entrySet()) + { + assertTrue(readersMap.containsKey(entry.getKey())); + assertEquals(entry.getValue(), readersMap.get(entry.getKey())); + + } + + Set readers = securityService.getExtendedReaders(nodeRef); + assertNotNull(readers); + assertEquals(testMap.size(), readers.size()); + } + }); + } + + // TODO getExtendedReaders + + // TODO setExtendedReaders + + // TODO removeExtendedReaders + + // TODO removeAllExtendedReaders +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/RecordServiceTestImpl.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/RecordServiceTestImpl.java index d9cd74d926..9bd4d054bf 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/RecordServiceTestImpl.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/RecordServiceTestImpl.java @@ -20,8 +20,9 @@ package org.alfresco.module.org_alfresco_module_rm.test.service; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.action.dm.CreateRecordAction; +import org.alfresco.module.org_alfresco_module_rm.capability.Capability; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; -import org.alfresco.module.org_alfresco_module_rm.permission.RecordReadersDynamicAuthority; +import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.site.SiteModel; @@ -132,8 +133,6 @@ public class RecordServiceTestImpl extends BaseRMTestCase { public Void run() { - //assertFalse(rmService.isRecord(dmDocument)); - assertEquals(AccessStatus.DENIED, dmPermissionService.hasPermission(dmDocument, RMPermissionModel.READ_RECORDS)); assertEquals(AccessStatus.DENIED, dmPermissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS)); @@ -149,6 +148,14 @@ public class RecordServiceTestImpl extends BaseRMTestCase assertEquals(AccessStatus.ALLOWED, dmPermissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS)); assertTrue(rmService.isRecord(dmDocument)); + + // + Capability createCapability = capabilityService.getCapability("Create"); + assertNotNull(createCapability); + createCapability.evaluate(dmDocument); + + + }; }, dmUserName); diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/RecordsManagementSecurityServiceImplTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/RecordsManagementSecurityServiceImplTest.java index 76838128a3..a1872523a8 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/RecordsManagementSecurityServiceImplTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/RecordsManagementSecurityServiceImplTest.java @@ -56,7 +56,7 @@ import org.alfresco.util.GUID; import org.alfresco.util.PropertyMap; /** - * Event service implementation unit test + * Security service implementation unit test * * @author Roy Wetherall */ diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java index 8dc01dd7c6..e0ef5ac41f 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java @@ -49,6 +49,7 @@ import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.MutableAuthenticationService; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; @@ -104,6 +105,7 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase protected PersonService personService; protected TransactionService transactionService; protected FileFolderService fileFolderService; + protected PermissionService permissionService; /** RM Services */ protected RecordsManagementService rmService; @@ -260,6 +262,7 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase personService = (PersonService)this.applicationContext.getBean("PersonService"); transactionService = (TransactionService)applicationContext.getBean("TransactionService"); fileFolderService = (FileFolderService)applicationContext.getBean("FileFolderService"); + permissionService = (PermissionService)applicationContext.getBean("PermissionService"); // Get RM services rmService = (RecordsManagementService)applicationContext.getBean("RecordsManagementService"); @@ -329,15 +332,6 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase setupTestDataImpl(); return null; } - - // check that the new records container has been created for the file plan - public void test(Void arg0) throws Exception - { - // NodeRef newRecordsContainer = recordService.getNewRecordContainer(filePlan); - // assertNotNull(newRecordsContainer); - // assertEquals(TYPE_NEW_RECORDS_CONTAINER, nodeService.getType(newRecordsContainer)); - - }; }, AuthenticationUtil.getSystemUserName()); }