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
This commit is contained in:
Roy Wetherall
2012-09-27 07:12:52 +00:00
parent 58bb845f42
commit 6b54f8f9f8
27 changed files with 567 additions and 193 deletions

View File

@@ -15,7 +15,7 @@
<!-- Create record action --> <!-- Create record action -->
<bean id="create-record" parent="action-executer" class="org.alfresco.module.org_alfresco_module_rm.action.dm.CreateRecordAction"> <bean id="create-record" parent="action-executer" class="org.alfresco.module.org_alfresco_module_rm.action.dm.CreateRecordAction">
<property name="recordsManagementService" ref="RecordsManagementService"/> <property name="recordsManagementService" ref="RecordsManagementService"/>
<property name="recordService" ref="RecordService" /> <property name="recordsManagementSecurityService" ref="RecordsManagementSecurityService" />
<property name="permissionService" ref="PermissionService" /> <property name="permissionService" ref="PermissionService" />
<property name="nodeService" ref="NodeService" /> <property name="nodeService" ref="NodeService" />
<property name="applicableTypes"> <property name="applicableTypes">

View File

@@ -6,6 +6,7 @@
<bean id="rmCreate" <bean id="rmCreate"
parent="rmBaseCapability" parent="rmBaseCapability"
class="org.alfresco.module.org_alfresco_module_rm.capability.impl.CreateCapability"> class="org.alfresco.module.org_alfresco_module_rm.capability.impl.CreateCapability">
<property name="recordService" ref="recordService"/>
<property name="name" value="Create"/> <property name="name" value="Create"/>
<property name="private" value="true"/> <property name="private" value="true"/>
</bean> </bean>

View File

@@ -90,8 +90,8 @@
</type> </type>
<type name="rma:newRecordsContainer"> <type name="rma:unfiledRecordContainer">
<title>New Records Container</title> <title>Unfiled Record Container</title>
<parent>rma:recordsManagementContainer</parent> <parent>rma:recordsManagementContainer</parent>
</type> </type>
@@ -624,14 +624,14 @@
</target> </target>
</child-association> </child-association>
<child-association name="rma:newRecords"> <child-association name="rma:unfiledRecords">
<title>New Records</title> <title>Unfiled Records</title>
<source> <source>
<mandatory>true</mandatory> <mandatory>true</mandatory>
<many>false</many> <many>false</many>
</source> </source>
<target> <target>
<class>rma:newRecordsContainer</class> <class>rma:unfiledRecordContainer</class>
<mandatory>true</mandatory> <mandatory>true</mandatory>
<many>true</many> <many>true</many>
</target> </target>
@@ -844,13 +844,12 @@
</mandatory-aspects> </mandatory-aspects>
</aspect> </aspect>
<!-- Details used for DM-RM security mapping --> <!-- Extended readers for RM object -->
<!-- @since 2.1 --> <!-- @since 2.1 -->
<aspect name="rma:extendedRecordSecurity"> <aspect name="rma:extendedReaders">
<properties> <properties>
<property name="rma:readers"> <property name="rma:readers">
<type>d:text</type> <type>d:any</type>
<multiple>true</multiple>
</property> </property>
</properties> </properties>
</aspect> </aspect>

View File

@@ -46,12 +46,12 @@
<list> <list>
<ref bean="ownerDynamicAuthority" /> <ref bean="ownerDynamicAuthority" />
<ref bean="lockOwnerDynamicAuthority" /> <ref bean="lockOwnerDynamicAuthority" />
<ref bean="recordReadersDynamicAuthority" /> <ref bean="extendedReaderDynamicAuthority" />
</list> </list>
</property> </property>
</bean> </bean>
<bean id="recordReadersDynamicAuthority" class="org.alfresco.module.org_alfresco_module_rm.permission.RecordReadersDynamicAuthority" /> <bean id="extendedReaderDynamicAuthority" class="org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority" />
<!-- Bootstrap records management data --> <!-- Bootstrap records management data -->
<bean id="org_alfresco_module_rm_bootstrapData" <bean id="org_alfresco_module_rm_bootstrapData"

View File

@@ -48,6 +48,7 @@
<property name="permissionService" ref="permissionService"/> <property name="permissionService" ref="permissionService"/>
<property name="recordsManagementService" ref="recordsManagementService"/> <property name="recordsManagementService" ref="recordsManagementService"/>
<property name="caveatConfigComponent" ref="caveatConfigComponent"/> <property name="caveatConfigComponent" ref="caveatConfigComponent"/>
<!-- <property name="recordService" ref="recordService"/> -->
</bean> </bean>
<!-- ====== --> <!-- ====== -->

View File

@@ -67,6 +67,7 @@
org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isFilePlanComponent=RM.Read.0 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.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.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.isFilePlan=RM.Read.0
org.alfresco.module.org_alfresco_module_rm.RecordsManagementService.isRecordCategory=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 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.createRole=RM_ALLOW
org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService.updateRole=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.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
]]> ]]>
</value> </value>
</property> </property>

View File

@@ -7,6 +7,7 @@
class="org.alfresco.module.org_alfresco_module_rm.jscript.app.JSONConversionComponent" class="org.alfresco.module.org_alfresco_module_rm.jscript.app.JSONConversionComponent"
parent="baseJsonConversionComponent"> parent="baseJsonConversionComponent">
<property name="recordsManagementService" ref="RecordsManagementService"/> <property name="recordsManagementService" ref="RecordsManagementService"/>
<property name="recordService" ref="RecordService"/>
<property name="capabilityService" ref="CapabilityService"/> <property name="capabilityService" ref="CapabilityService"/>
</bean> </bean>
@@ -14,6 +15,7 @@
abstract="true"> abstract="true">
<property name="jsonConversionComponent" ref="jsonConversionComponent"/> <property name="jsonConversionComponent" ref="jsonConversionComponent"/>
<property name="recordsManagementService" ref="RecordsManagementService"/> <property name="recordsManagementService" ref="RecordsManagementService"/>
<property name="recordService" ref="RecordService"/>
<property name="nodeService" ref="NodeService"/> <property name="nodeService" ref="NodeService"/>
<property name="namespaceService" ref="NamespaceService"/> <property name="namespaceService" ref="NamespaceService"/>
<property name="capabilityService" ref="CapabilityService"/> <property name="capabilityService" ref="CapabilityService"/>

View File

@@ -179,6 +179,13 @@ Filters.getFilterParams = function RecordsManagementFilter_getFilterParams(filte
filterParams.query = "+PARENT:\"" + filterData + "\""; filterParams.query = "+PARENT:\"" + filterData + "\"";
} }
break; break;
case "unfiledRecords":
filterParams.variablePath = false;
filterQuery = "+PATH:\"" + parsedArgs.pathNode.qnamePath + "/rma:Unfiled_x0020_Records/*\"";
filterParams.query = filterQuery + filterQueryDefaults;
break;
default: default:
filterParams.variablePath = false; filterParams.variablePath = false;

View File

@@ -120,7 +120,7 @@ function itemIsAllowed(item)
var typeShort = String(item.typeShort); var typeShort = String(item.typeShort);
// Don't show Hold and Transfer top-level containers // 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; return false;
} }

View File

@@ -73,6 +73,14 @@ public interface RecordsManagementService
*/ */
FilePlanComponentKind getFilePlanComponentKindFromType(QName type); 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. * Indicates whether the given node is file plan node or not.
* *

View File

@@ -436,6 +436,15 @@ public class RecordsManagementServiceImpl implements RecordsManagementService,
return instanceOf(nodeRef, TYPE_FILE_PLAN); 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. * Utility method to safely and quickly determine if a node is a type (or sub-type) of the one specified.
*/ */

View File

@@ -18,19 +18,14 @@
*/ */
package org.alfresco.module.org_alfresco_module_rm.action.dm; 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.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.RecordsManagementService; 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.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.permission.RecordReadersDynamicAuthority; import org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; 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.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
/** /**
@@ -56,8 +50,8 @@ public class CreateRecordAction extends ActionExecuterAbstractBase
public static final String NAME = "create-record"; public static final String NAME = "create-record";
private RecordsManagementService recordsManagementService; private RecordsManagementService recordsManagementService;
private RecordService recordService; private RecordsManagementSecurityService recordsManagementSecurityService;
private PermissionService permissionService; private PermissionService permissionService;
@@ -68,9 +62,9 @@ public class CreateRecordAction extends ActionExecuterAbstractBase
this.recordsManagementService = recordsManagementService; this.recordsManagementService = recordsManagementService;
} }
public void setRecordService(RecordService recordService) public void setRecordsManagementSecurityService(RecordsManagementSecurityService recordsManagementSecurityService)
{ {
this.recordService = recordService; this.recordsManagementSecurityService = recordsManagementSecurityService;
} }
public void setPermissionService(PermissionService permissionService) 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."); throw new AlfrescoRuntimeException("Unable to create record, because new record container could not be found.");
} }
// move the document into the file plan // move the document into the file plan
nodeService.moveNode(actionedUponNodeRef, newRecordContainer, ContentModel.ASSOC_CONTAINS, parentAssoc.getQName()); nodeService.moveNode(actionedUponNodeRef, newRecordContainer, ContentModel.ASSOC_CONTAINS, parentAssoc.getQName());
// maintain the original primary location // maintain the original primary location
nodeService.addChild(parentAssoc.getParentRef(), actionedUponNodeRef, parentAssoc.getTypeQName(), parentAssoc.getQName()); nodeService.addChild(parentAssoc.getParentRef(), actionedUponNodeRef, parentAssoc.getTypeQName(), parentAssoc.getQName());
// add extended security information to the record // set the readers
Map<QName, Serializable> props = new HashMap<QName, Serializable>(1); recordsManagementSecurityService.setExtendedReaders(actionedUponNodeRef, readers);
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);
return null; return null;
} }
@@ -141,13 +121,13 @@ public class CreateRecordAction extends ActionExecuterAbstractBase
} }
else else
{ {
throw new AlfrescoRuntimeException("Unable to file file plan."); throw new AlfrescoRuntimeException("Unable to find file plan.");
} }
} }
private NodeRef getNewRecordContainer(NodeRef filePlan) private NodeRef getNewRecordContainer(NodeRef filePlan)
{ {
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(filePlan, ASSOC_NEW_RECORDS, RegexQNamePattern.MATCH_ALL); List<ChildAssociationRef> assocs = nodeService.getChildAssocs(filePlan, ASSOC_UNFILED_RECORDS, RegexQNamePattern.MATCH_ALL);
if (assocs.size() != 1) if (assocs.size() != 1)
{ {
throw new AlfrescoRuntimeException("Error getting the new record container, because the container cannot be indentified."); throw new AlfrescoRuntimeException("Error getting the new record container, because the container cannot be indentified.");

View File

@@ -61,6 +61,9 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
/**
* RM After Invocation Provider
*/
public class RMAfterInvocationProvider extends RMSecurityCommon public class RMAfterInvocationProvider extends RMSecurityCommon
implements AfterInvocationProvider, InitializingBean implements AfterInvocationProvider, InitializingBean
{ {

View File

@@ -31,6 +31,9 @@ import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/** /**
* @author Roy Wetherall * @author Roy Wetherall
@@ -42,10 +45,11 @@ public class RMSecurityCommon
private static Log logger = LogFactory.getLog(RMSecurityCommon.class); private static Log logger = LogFactory.getLog(RMSecurityCommon.class);
private ApplicationContext applicationContext;
protected NodeService nodeService; protected NodeService nodeService;
protected PermissionService permissionService; protected PermissionService permissionService;
protected RecordsManagementService rmService; protected RecordsManagementService rmService;
protected RecordService recordService;
protected RMCaveatConfigComponent caveatConfigComponent; protected RMCaveatConfigComponent caveatConfigComponent;
public void setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
@@ -63,11 +67,6 @@ public class RMSecurityCommon
this.rmService = rmService; this.rmService = rmService;
} }
public void setRecordService(RecordService recordService)
{
this.recordService = recordService;
}
public void setCaveatConfigComponent(RMCaveatConfigComponent caveatConfigComponent) public void setCaveatConfigComponent(RMCaveatConfigComponent caveatConfigComponent)
{ {
this.caveatConfigComponent = caveatConfigComponent; this.caveatConfigComponent = caveatConfigComponent;

View File

@@ -26,6 +26,7 @@ import net.sf.acegisecurity.vote.AccessDecisionVoter;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; 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.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.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
@@ -37,6 +38,13 @@ import org.alfresco.service.namespace.QName;
*/ */
public class CreateCapability extends DeclarativeCapability 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) * @see org.alfresco.module.org_alfresco_module_rm.capability.Capability#evaluate(org.alfresco.service.cmr.repository.NodeRef)
*/ */

View File

@@ -57,8 +57,8 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel
// Records management root container // Records management root container
public static final QName TYPE_FILE_PLAN = QName.createQName(RM_URI, "filePlan"); public static final QName TYPE_FILE_PLAN = QName.createQName(RM_URI, "filePlan");
// New records container // Unfiled record container
public static final QName TYPE_NEW_RECORDS_CONTAINER = QName.createQName(RM_URI, "newRecordsContainer"); public static final QName TYPE_UNFILED_RECORD_CONTAINER = QName.createQName(RM_URI, "unfiledRecordContainer");
// Disposition instructions aspect // Disposition instructions aspect
public static final QName ASPECT_SCHEDULED = QName.createQName(RM_URI, "scheduled"); 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 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_HOLDS = QName.createQName(RM_URI, "holds");
public static final QName ASSOC_TRANSFERS = QName.createQName(RM_URI, "transfers"); 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 // Hold type
public static final QName TYPE_HOLD = QName.createQName(RM_URI, "hold"); 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_DISPOITION_AUTHORITY = QName.createQName(RM_URI, "recordSearchDispositionAuthority");
public static final QName PROP_RS_HOLD_REASON = QName.createQName(RM_URI, "recordSearchHoldReason"); public static final QName PROP_RS_HOLD_REASON = QName.createQName(RM_URI, "recordSearchHoldReason");
// Extended record security aspect // Extended readers aspect
public static final QName ASPECT_EXTENDED_RECORD_SECURITY = QName.createQName(RM_URI, "extendedRecordSecurity"); public static final QName ASPECT_EXTENDED_READERS = QName.createQName(RM_URI, "extendedReaders");
public static final QName PROP_READERS = QName.createQName(RM_URI, "readers"); public static final QName PROP_READERS = QName.createQName(RM_URI, "readers");
} }

View File

@@ -18,21 +18,12 @@
*/ */
package org.alfresco.module.org_alfresco_module_rm.model.behaviour; 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.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent; 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.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
/** /**
* Behaviour associated with the file plan type * Behaviour associated with the file plan type
@@ -82,10 +73,10 @@ public class FilePlanType implements RecordsManagementModel,
*/ */
public void init() public void init()
{ {
policyComponent.bindClassBehaviour( // policyComponent.bindClassBehaviour(
NodeServicePolicies.OnCreateNodePolicy.QNAME, // NodeServicePolicies.OnCreateNodePolicy.QNAME,
TYPE_FILE_PLAN, // TYPE_FILE_PLAN,
new JavaBehaviour(this, "onCreateNode", NotificationFrequency.TRANSACTION_COMMIT)); // new JavaBehaviour(this, "onCreateNode", NotificationFrequency.TRANSACTION_COMMIT));
} }
/** /**
@@ -94,22 +85,6 @@ public class FilePlanType implements RecordsManagementModel,
@Override @Override
public void onCreateNode(ChildAssociationRef assoc) public void onCreateNode(ChildAssociationRef assoc)
{ {
// grab the newly created file plan // TODO refactor the file plan behaviours from the service code
NodeRef filePlan = assoc.getChildRef();
// create the properties map
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(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);
} }
} }

View File

@@ -56,6 +56,9 @@ public class RmSiteType implements RecordsManagementModel,
/** Record Management Search Service */ /** Record Management Search Service */
private RecordsManagementSearchService recordsManagementSearchService; private RecordsManagementSearchService recordsManagementSearchService;
/** Behaviour */
JavaBehaviour behaviour = new JavaBehaviour(this, "onCreateNode", NotificationFrequency.FIRST_EVENT);
/** /**
* Set the policy component * Set the policy component
* @param policyComponent policy component * @param policyComponent policy component
@@ -99,7 +102,7 @@ public class RmSiteType implements RecordsManagementModel,
policyComponent.bindClassBehaviour( policyComponent.bindClassBehaviour(
NodeServicePolicies.OnCreateNodePolicy.QNAME, NodeServicePolicies.OnCreateNodePolicy.QNAME,
TYPE_RM_SITE, TYPE_RM_SITE,
new JavaBehaviour(this, "onCreateNode", NotificationFrequency.FIRST_EVENT)); behaviour);
} }
/** /**
@@ -108,33 +111,41 @@ public class RmSiteType implements RecordsManagementModel,
@Override @Override
public void onCreateNode(ChildAssociationRef childAssocRef) public void onCreateNode(ChildAssociationRef childAssocRef)
{ {
final NodeRef rmSite = childAssocRef.getChildRef(); behaviour.disable();
try
// Do not execute behaviour if this has been created in the archive store {
if(rmSite.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE) == true) final NodeRef rmSite = childAssocRef.getChildRef();
{
// This is not the spaces store - probably the archive store // Do not execute behaviour if this has been created in the archive store
return; if(rmSite.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE) == true)
}
if (nodeService.exists(rmSite) == true)
{
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{ {
public Object doWork() // This is not the spaces store - probably the archive store
return;
}
if (nodeService.exists(rmSite) == true)
{
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{ {
SiteInfo siteInfo = siteService.getSite(rmSite); public Object doWork()
if (siteInfo != null) {
{ SiteInfo siteInfo = siteService.getSite(rmSite);
// Create the file plan component if (siteInfo != null)
siteService.createContainer(siteInfo.getShortName(), COMPONENT_DOCUMENT_LIBRARY, TYPE_FILE_PLAN, null); {
// Create the file plan component
// Add the reports siteService.createContainer(siteInfo.getShortName(), COMPONENT_DOCUMENT_LIBRARY, TYPE_FILE_PLAN, null);
recordsManagementSearchService.addReports(siteInfo.getShortName());
} // Add the reports
return null; recordsManagementSearchService.addReports(siteInfo.getShortName());
} }
}, AuthenticationUtil.getAdminUserName()); return null;
} }
}, AuthenticationUtil.getAdminUserName());
}
}
finally
{
behaviour.enable();
}
} }
} }

View File

@@ -25,6 +25,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
/** /**
* Record Service Interface.
* *
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.1 * @since 2.1

View File

@@ -88,7 +88,7 @@ public class RecordServiceImpl implements RecordService, RecordsManagementModel
{ {
policyComponent.bindAssociationBehaviour( policyComponent.bindAssociationBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateChildAssociation"), QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateChildAssociation"),
TYPE_NEW_RECORDS_CONTAINER, TYPE_UNFILED_RECORD_CONTAINER,
ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS,
new JavaBehaviour(this, "onCreateNewRecord", NotificationFrequency.TRANSACTION_COMMIT)); new JavaBehaviour(this, "onCreateNewRecord", NotificationFrequency.TRANSACTION_COMMIT));
} }

View File

@@ -16,13 +16,10 @@
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
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 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.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.security.permissions.DynamicAuthority; import org.alfresco.repo.security.permissions.DynamicAuthority;
import org.alfresco.repo.security.permissions.PermissionReference; 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.repository.NodeService;
import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.namespace.QName;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
/** /**
* Extended readers dynamic authority implementation.
*
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.1 * @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"; /** Extended reader role */
public static final String EXTENDED_READER = "ROLE_EXTENDED_READER";
private RecordsManagementService recordsManagementService;
private NodeService nodeService;
/** Authority service */
private AuthorityService authorityService; private AuthorityService authorityService;
/** Records management security service */
private RecordsManagementSecurityService recordsManagementSecurityService;
/** Node service */
private NodeService nodeService;
/** Application context */
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
private RecordsManagementService getRecordsManagementService() // NOTE: we get the services directly from the application context in this way to avoid
{ // cyclic relationships and issues when loading the application context
if (recordsManagementService == null)
{
recordsManagementService = (RecordsManagementService)applicationContext.getBean("recordsManagementService");
}
return recordsManagementService;
}
private NodeService getNodeService()
{
if (nodeService == null)
{
nodeService = (NodeService)applicationContext.getBean("nodeService");
}
return nodeService;
}
/**
* @return authority service
*/
private AuthorityService getAuthorityService() private AuthorityService getAuthorityService()
{ {
if (authorityService == null) if (authorityService == null)
@@ -76,7 +71,34 @@ public class RecordReadersDynamicAuthority implements DynamicAuthority, RecordsM
} }
return authorityService; 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 @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{ {
@@ -89,34 +111,37 @@ public class RecordReadersDynamicAuthority implements DynamicAuthority, RecordsM
@Override @Override
public String getAuthority() 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) * @see org.alfresco.repo.security.permissions.DynamicAuthority#hasAuthority(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
*/ */
@SuppressWarnings("unchecked")
@Override @Override
public boolean hasAuthority(NodeRef nodeRef, String userName) public boolean hasAuthority(NodeRef nodeRef, String userName)
{ {
boolean result = false; boolean result = false;
FilePlanComponentKind kind = getRecordsManagementService().getFilePlanComponentKind(nodeRef); if (getNodeService().hasAspect(nodeRef, ASPECT_EXTENDED_READERS) == true)
if (FilePlanComponentKind.RECORD.equals(kind) == true)
{ {
if (getNodeService().hasAspect(nodeRef, ASPECT_EXTENDED_RECORD_SECURITY) == true) Set<String> readers = getRecordsManagementSecurityService().getExtendedReaders(nodeRef);
if (readers != null)
{ {
List<String> readers = (List<String>)nodeService.getProperty(nodeRef, PROP_READERS);
for (String reader : 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<String> contained = getAuthorityService().getContainedAuthorities(AuthorityType.USER, reader, false); Set<String> contained = getAuthorityService().getContainedAuthorities(AuthorityType.USER, reader, false);
if (contained.isEmpty() == false && if (contained.isEmpty() == false &&
contained.contains(userName) == true) contained.contains(userName) == true)
{ {
System.out.println("User " + userName + " is contained in the read group " + reader);
result = true; result = true;
break; break;
} }
@@ -126,8 +151,6 @@ public class RecordReadersDynamicAuthority implements DynamicAuthority, RecordsM
// presume we have a user // presume we have a user
if (reader.equals(userName) == true) if (reader.equals(userName) == true)
{ {
System.out.println("User " + userName + " matches read user " + reader);
result = true; result = true;
break; break;
} }
@@ -135,10 +158,6 @@ public class RecordReadersDynamicAuthority implements DynamicAuthority, RecordsM
} }
} }
} }
else if (FilePlanComponentKind.FILE_PLAN.equals(kind) == true)
{
result = true;
}
return result; return result;
} }

View File

@@ -152,4 +152,31 @@ public interface RecordsManagementSecurityService
* @param permission permission * @param permission permission
*/ */
void deletePermission(NodeRef nodeRef, String authority, String permission); void deletePermission(NodeRef nodeRef, String authority, String permission);
/**
*
* @param nodeRef
* @return
*/
Set<String> getExtendedReaders(NodeRef nodeRef);
/**
*
* @param nodeRef
* @param readers
*/
void setExtendedReaders(NodeRef nodeRef, Set<String> readers);
/**
*
* @param nodeRef
* @param readers
*/
void removeExtendedReaders(NodeRef nodeRef, Set<String> readers);
/**
*
* @param nodeRef
*/
void removeAllExtendedReaders(NodeRef nodeRef);
} }

View File

@@ -22,8 +22,11 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
@@ -56,6 +59,9 @@ import org.apache.commons.logging.LogFactory;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/** /**
* Records management permission service implementation * Records management permission service implementation
@@ -63,7 +69,8 @@ import org.json.JSONObject;
* @author Roy Wetherall * @author Roy Wetherall
*/ */
public class RecordsManagementSecurityServiceImpl implements RecordsManagementSecurityService, public class RecordsManagementSecurityServiceImpl implements RecordsManagementSecurityService,
RecordsManagementModel RecordsManagementModel,
ApplicationContextAware
{ {
/** Capability service */ /** Capability service */
@@ -90,9 +97,24 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
/** Records management role zone */ /** Records management role zone */
public static final String RM_ROLE_ZONE_PREFIX = "rmRoleZone"; public static final String RM_ROLE_ZONE_PREFIX = "rmRoleZone";
/** Unfiled record container name */
private static final String NAME_UNFILED_CONTAINER = "Unfiled Records";
/** Logger */ /** Logger */
private static Log logger = LogFactory.getLog(RecordsManagementSecurityServiceImpl.class); 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 * Set the capability service
* *
@@ -204,9 +226,9 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
if (nodeService.exists(rmRootNode) == true) if (nodeService.exists(rmRootNode) == true)
{ {
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() NodeRef unfiledContainer = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<NodeRef>()
{ {
public Object doWork() public NodeRef doWork()
{ {
// Create "all" role group for root node // Create "all" role group for root node
String allRoles = authorityService.createAuthority(AuthorityType.GROUP, getAllRolesGroupShortName(rmRootNode), "All Roles", null); String allRoles = authorityService.createAuthority(AuthorityType.GROUP, getAllRolesGroupShortName(rmRootNode), "All Roles", null);
@@ -214,16 +236,47 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
// Set the permissions // Set the permissions
permissionService.setInheritParentPermissions(rmRootNode, false); permissionService.setInheritParentPermissions(rmRootNode, false);
permissionService.setPermission(rmRootNode, allRoles, RMPermissionModel.READ_RECORDS, true); permissionService.setPermission(rmRootNode, allRoles, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
return null; permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.VIEW_RECORDS, true);
// Create the unfiled record container
return createUnfiledContainer(rmRootNode, allRoles);
} }
}, AuthenticationUtil.getSystemUserName()); }, AuthenticationUtil.getSystemUserName());
// Bootstrap in the default set of roles for the newly created root node // 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<QName, Serializable> properties = new HashMap<QName, Serializable>(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 * Delete root node behaviour
* *
@@ -293,17 +346,20 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
Set<AccessPermission> perms = permissionService.getAllSetPermissions(catNodeRef); Set<AccessPermission> perms = permissionService.getAllSetPermissions(catNodeRef);
for (AccessPermission perm : perms) for (AccessPermission perm : perms)
{ {
AccessStatus accessStatus = perm.getAccessStatus(); if (ExtendedReaderDynamicAuthority.EXTENDED_READER.equals(perm.getAuthority()) == false)
boolean allow = false; {
if (AccessStatus.ALLOWED.equals(accessStatus) == true) AccessStatus accessStatus = perm.getAccessStatus();
{ boolean allow = false;
allow = true; if (AccessStatus.ALLOWED.equals(accessStatus) == true)
} {
permissionService.setPermission( allow = true;
folderNodeRef, }
perm.getAuthority(), permissionService.setPermission(
perm.getPermission(), folderNodeRef,
allow); perm.getAuthority(),
perm.getPermission(),
allow);
}
} }
return null; return null;
@@ -324,8 +380,11 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
{ {
public Object doWork() public Object doWork()
{ {
// Break inheritance // break inheritance
permissionService.setInheritParentPermissions(nodeRef, false); permissionService.setInheritParentPermissions(nodeRef, false);
// set extended reader permissions
permissionService.setPermission(nodeRef, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
return null; 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) * @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<Object>() AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{ {
@@ -434,7 +498,12 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
// Add any additional admin permissions // Add any additional admin permissions
if (isAdmin == true) if (isAdmin == true)
{ {
// Admin has filing
permissionService.setPermission(rmRootNode, role.getRoleGroupName(), RMPermissionModel.FILING, true); 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 // Add the creating user to the administration group
String user = AuthenticationUtil.getFullyAuthenticatedUser(); String user = AuthenticationUtil.getFullyAuthenticatedUser();
@@ -597,6 +666,12 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
}, AuthenticationUtil.getSystemUserName()); }, AuthenticationUtil.getSystemUserName());
} }
/**
*
* @param rmRootNode
* @param roleAuthority
* @return
*/
private Set<String> getCapabilitiesImpl(NodeRef rmRootNode, String roleAuthority) private Set<String> getCapabilitiesImpl(NodeRef rmRootNode, String roleAuthority)
{ {
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(rmRootNode); Set<AccessPermission> permissions = permissionService.getAllSetPermissions(rmRootNode);
@@ -636,7 +711,7 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
}, AuthenticationUtil.getSystemUserName()).booleanValue(); }, AuthenticationUtil.getSystemUserName()).booleanValue();
} }
/* /**
* @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#hasRMAdminRole(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) * @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) public boolean hasRMAdminRole(NodeRef rmRootNode, String user)
@@ -791,7 +866,7 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
public Boolean doWork() throws Exception public Boolean doWork() throws Exception
{ {
if (recordsManagementService.isFilePlan(nodeRef) == false && if (recordsManagementService.isFilePlan(nodeRef) == false &&
recordsManagementService.isRecordCategory(nodeRef) == true) recordsManagementService.isRecordsManagementContainer(nodeRef) == true)
{ {
setReadPermissionUp(nodeRef, authority); setReadPermissionUp(nodeRef, authority);
setPermissionDown(nodeRef, authority, permission); setPermissionDown(nodeRef, authority, permission);
@@ -841,13 +916,13 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
private void setPermissionDown(NodeRef nodeRef, String authority, String permission) private void setPermissionDown(NodeRef nodeRef, String authority, String permission)
{ {
setPermissionImpl(nodeRef, authority, permission); setPermissionImpl(nodeRef, authority, permission);
if (recordsManagementService.isRecordCategory(nodeRef) == true) if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true)
{ {
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef assoc : assocs) for (ChildAssociationRef assoc : assocs)
{ {
NodeRef child = assoc.getChildRef(); NodeRef child = assoc.getChildRef();
if (recordsManagementService.isRecordCategory(child) == true || if (recordsManagementService.isRecordsManagementContainer(child) == true ||
recordsManagementService.isRecordFolder(child) == true) recordsManagementService.isRecordFolder(child) == true)
{ {
setPermissionDown(child, authority, permission); setPermissionDown(child, authority, permission);
@@ -886,13 +961,13 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
// Delete permission on this node // Delete permission on this node
permissionService.deletePermission(nodeRef, authority, permission); permissionService.deletePermission(nodeRef, authority, permission);
if (recordsManagementService.isRecordCategory(nodeRef) == true) if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true)
{ {
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef assoc : assocs) for (ChildAssociationRef assoc : assocs)
{ {
NodeRef child = assoc.getChildRef(); NodeRef child = assoc.getChildRef();
if (recordsManagementService.isRecordCategory(child) == true || if (recordsManagementService.isRecordsManagementContainer(child) == true ||
recordsManagementService.isRecordFolder(child) == true) recordsManagementService.isRecordFolder(child) == true)
{ {
deletePermission(child, authority, permission); deletePermission(child, authority, permission);
@@ -904,4 +979,95 @@ public class RecordsManagementSecurityServiceImpl implements RecordsManagementSe
} }
}, AuthenticationUtil.getSystemUserName()); }, AuthenticationUtil.getSystemUserName());
} }
@SuppressWarnings("unchecked")
@Override
public Set<String> getExtendedReaders(NodeRef nodeRef)
{
NodeService nodeService = (NodeService)applicationContext.getBean("nodeService");
Set<String> result = null;
Map<String, Integer> readerMap = (Map<String, Integer>)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<String> 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<String, Integer> readersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_READERS);
if (readersMap == null)
{
// create reader map
readersMap = new HashMap<String, Integer>(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<String> 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
}
} }

View File

@@ -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<Void>()
{
public Void run()
{
assertFalse(hasExtendedReadersAspect(filePlan));
assertFalse(hasExtendedReadersAspect(rmContainer));
assertFalse(hasExtendedReadersAspect(rmFolder));
assertFalse(hasExtendedReadersAspect(record));
assertNull(securityService.getExtendedReaders(record));
Set<String> extendedReaders = new HashSet<String>(2);
extendedReaders.add("monkey");
extendedReaders.add("elephant");
securityService.setExtendedReaders(record, extendedReaders);
Map<String, Integer> testMap = new HashMap<String, Integer>(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<String> extendedReadersToo = new HashSet<String>(2);
extendedReadersToo.add("monkey");
extendedReadersToo.add("snake");
securityService.setExtendedReaders(recordToo, extendedReadersToo);
Map<String, Integer> testMapToo = new HashMap<String, Integer>(2);
testMapToo.put("monkey", Integer.valueOf(1));
testMapToo.put("snake", Integer.valueOf(1));
Map<String, Integer> testMapThree = new HashMap<String, Integer>(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<String, Integer> testMap)
{
assertTrue(hasExtendedReadersAspect(nodeRef));
Map<String, Integer> readersMap = (Map<String,Integer>)nodeService.getProperty(nodeRef, PROP_READERS);
assertNotNull(readersMap);
assertEquals(testMap.size(), readersMap.size());
for (Map.Entry<String, Integer> entry: testMap.entrySet())
{
assertTrue(readersMap.containsKey(entry.getKey()));
assertEquals(entry.getValue(), readersMap.get(entry.getKey()));
}
Set<String> readers = securityService.getExtendedReaders(nodeRef);
assertNotNull(readers);
assertEquals(testMap.size(), readers.size());
}
});
}
// TODO getExtendedReaders
// TODO setExtendedReaders
// TODO removeExtendedReaders
// TODO removeAllExtendedReaders
}

View File

@@ -20,8 +20,9 @@ package org.alfresco.module.org_alfresco_module_rm.test.service;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.action.dm.CreateRecordAction; 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.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.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.site.SiteModel; import org.alfresco.repo.site.SiteModel;
@@ -132,8 +133,6 @@ public class RecordServiceTestImpl extends BaseRMTestCase
{ {
public Void run() public Void run()
{ {
//assertFalse(rmService.isRecord(dmDocument));
assertEquals(AccessStatus.DENIED, dmPermissionService.hasPermission(dmDocument, RMPermissionModel.READ_RECORDS)); assertEquals(AccessStatus.DENIED, dmPermissionService.hasPermission(dmDocument, RMPermissionModel.READ_RECORDS));
assertEquals(AccessStatus.DENIED, dmPermissionService.hasPermission(filePlan, RMPermissionModel.VIEW_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)); assertEquals(AccessStatus.ALLOWED, dmPermissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS));
assertTrue(rmService.isRecord(dmDocument)); assertTrue(rmService.isRecord(dmDocument));
//
Capability createCapability = capabilityService.getCapability("Create");
assertNotNull(createCapability);
createCapability.evaluate(dmDocument);
}; };
}, },
dmUserName); dmUserName);

View File

@@ -56,7 +56,7 @@ import org.alfresco.util.GUID;
import org.alfresco.util.PropertyMap; import org.alfresco.util.PropertyMap;
/** /**
* Event service implementation unit test * Security service implementation unit test
* *
* @author Roy Wetherall * @author Roy Wetherall
*/ */

View File

@@ -49,6 +49,7 @@ import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.MutableAuthenticationService; 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.security.PersonService;
import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteService;
@@ -104,6 +105,7 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase
protected PersonService personService; protected PersonService personService;
protected TransactionService transactionService; protected TransactionService transactionService;
protected FileFolderService fileFolderService; protected FileFolderService fileFolderService;
protected PermissionService permissionService;
/** RM Services */ /** RM Services */
protected RecordsManagementService rmService; protected RecordsManagementService rmService;
@@ -260,6 +262,7 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase
personService = (PersonService)this.applicationContext.getBean("PersonService"); personService = (PersonService)this.applicationContext.getBean("PersonService");
transactionService = (TransactionService)applicationContext.getBean("TransactionService"); transactionService = (TransactionService)applicationContext.getBean("TransactionService");
fileFolderService = (FileFolderService)applicationContext.getBean("FileFolderService"); fileFolderService = (FileFolderService)applicationContext.getBean("FileFolderService");
permissionService = (PermissionService)applicationContext.getBean("PermissionService");
// Get RM services // Get RM services
rmService = (RecordsManagementService)applicationContext.getBean("RecordsManagementService"); rmService = (RecordsManagementService)applicationContext.getBean("RecordsManagementService");
@@ -329,15 +332,6 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase
setupTestDataImpl(); setupTestDataImpl();
return null; 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()); AuthenticationUtil.getSystemUserName());
} }