RM-1315: Manage Permissions is not working for folder inside Holds/Unfiled Records

* unit tests to show unfiled and holds permissions working correctly
 * fixed issues exposed by above
 * minor refactor for FilePlanPermissionService implementation to reduce complexity
 * added unit test execution to local build target



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@66102 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2014-04-01 23:53:16 +00:00
parent c7facab5a9
commit 09648f9829
10 changed files with 478 additions and 180 deletions

View File

@@ -39,7 +39,7 @@
<delete dir="${app.folder}" failonerror="true" /> <delete dir="${app.folder}" failonerror="true" />
</target> </target>
<target name="alfresco:amp" depends="cleanTarget, install"> <target name="alfresco:amp" depends="cleanTarget, unitTest">
<exec executable="${mvn.exec}" failonerror="true"> <exec executable="${mvn.exec}" failonerror="true">
<arg value="alfresco:amp" /> <arg value="alfresco:amp" />
</exec> </exec>

View File

@@ -25,4 +25,12 @@
</target> </target>
<target name="prepareEnv" depends="copyDBDriver, copyDevContextFile" description="" /> <target name="prepareEnv" depends="copyDBDriver, copyDevContextFile" description="" />
<target name="unitTest" depends="install">
<exec executable="${mvn.exec}" failonerror="true">
<arg value="test" />
<arg value="-Dtest=AllUnitTestSuite" />
</exec>
</target>
</project> </project>

View File

@@ -489,9 +489,6 @@
init-method="init"> init-method="init">
<property name="permissionService" ref="PermissionService"/> <property name="permissionService" ref="PermissionService"/>
<property name="policyComponent" ref="policyComponent"/> <property name="policyComponent" ref="policyComponent"/>
<property name="filePlanService" ref="FilePlanService" />
<property name="recordService" ref="RecordService" />
<property name="recordFolderService" ref="RecordFolderService" />
</bean> </bean>
<bean id="FilePlanPermissionService" class="org.springframework.aop.framework.ProxyFactoryBean"> <bean id="FilePlanPermissionService" class="org.springframework.aop.framework.ProxyFactoryBean">

View File

@@ -139,6 +139,8 @@ public interface FilePlanService
NodeRef createUnfiledContainer(NodeRef filePlan); NodeRef createUnfiledContainer(NodeRef filePlan);
/** /**
* Gets the hold container for a given file plan. Returns
* null if none.
* *
* @param filePlan * @param filePlan
* @return * @return

View File

@@ -30,8 +30,6 @@ 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.capability.RMPermissionModel; 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.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService; import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService; import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority; import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
@@ -41,7 +39,6 @@ import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.domain.node.NodeDAO;
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.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteInfo;
@@ -51,9 +48,6 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.extensions.surf.util.I18NUtil; import org.springframework.extensions.surf.util.I18NUtil;
/** /**
@@ -63,9 +57,7 @@ import org.springframework.extensions.surf.util.I18NUtil;
* @since 2.1 * @since 2.1
*/ */
public class FilePlanServiceImpl extends ServiceBaseImpl public class FilePlanServiceImpl extends ServiceBaseImpl
implements FilePlanService, implements FilePlanService
RecordsManagementModel,
ApplicationContextAware
{ {
/** I18N */ /** I18N */
private final static String MSG_DUP_ROOT = "rm.service.dup-root"; private final static String MSG_DUP_ROOT = "rm.service.dup-root";
@@ -85,18 +77,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
/** RM site file plan container */ /** RM site file plan container */
private static final String FILE_PLAN_CONTAINER = "documentLibrary"; private static final String FILE_PLAN_CONTAINER = "documentLibrary";
/** 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;
}
/** /**
* NOTE: for some reason spring couldn't cope with the circular references between these two * NOTE: for some reason spring couldn't cope with the circular references between these two
* beans so we need to grab this one manually. * beans so we need to grab this one manually.
@@ -124,14 +104,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
return (NodeDAO)applicationContext.getBean("nodeDAO"); return (NodeDAO)applicationContext.getBean("nodeDAO");
} }
/**
* @return internal node service
*/
protected NodeService getInternalNodeService()
{
return (NodeService)applicationContext.getBean("nodeService");
}
/** /**
* @return site service * @return site service
*/ */
@@ -140,14 +112,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
return (SiteService)applicationContext.getBean("SiteService"); return (SiteService)applicationContext.getBean("SiteService");
} }
/**
* @return record service
*/
protected RecordService getRecordService()
{
return (RecordService)applicationContext.getBean("RecordService");
}
/** /**
* @return record folder service * @return record folder service
*/ */
@@ -164,20 +128,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
return (TransferService)applicationContext.getBean("RmTransferService"); return (TransferService)applicationContext.getBean("RmTransferService");
} }
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isFilePlanComponent(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isFilePlanComponent(NodeRef nodeRef)
{
boolean result = false;
if (getInternalNodeService().exists(nodeRef) &&
getInternalNodeService().hasAspect(nodeRef, ASPECT_FILE_PLAN_COMPONENT))
{
result = true;
}
return result;
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#getFilePlanComponentKind(org.alfresco.service.cmr.repository.NodeRef) * @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#getFilePlanComponentKind(org.alfresco.service.cmr.repository.NodeRef)
*/ */
@@ -201,7 +151,7 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
{ {
result = FilePlanComponentKind.RECORD_FOLDER; result = FilePlanComponentKind.RECORD_FOLDER;
} }
else if (getRecordService().isRecord(nodeRef)) else if (isRecord(nodeRef))
{ {
result = FilePlanComponentKind.RECORD; result = FilePlanComponentKind.RECORD;
} }
@@ -279,14 +229,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
return result; return result;
} }
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isFilePlan(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isFilePlan(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_FILE_PLAN);
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#getFilePlans() * @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#getFilePlans()
*/ */
@@ -470,25 +412,18 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
containerType, containerType,
properties).getChildRef(); properties).getChildRef();
// set inheritance to false
getPermissionService().setInheritParentPermissions(container, false);
// if (!inheritPermissions) // give all roles read permissions on the container by default
// { getPermissionService().setPermission(container, allRoles, RMPermissionModel.READ_RECORDS, true);
// set inheritance to false
getPermissionService().setInheritParentPermissions(container, false);
getPermissionService().setPermission(container, allRoles, RMPermissionModel.READ_RECORDS, true);
getPermissionService().setPermission(container, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
getPermissionService().setPermission(container, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
getPermissionService().setPermission(container, "Administrator", RMPermissionModel.FILING, true);
// TODO set the admin users to have filing permissions on the unfiled container!!! // setup the extended reader permissions
// TODO we will need to be able to get a list of the admin roles from the service getPermissionService().setPermission(container, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
// } getPermissionService().setPermission(container, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
// else
// { // setup the administrator permissions
// just inherit eveything getPermissionService().setPermission(container, "Administrator", RMPermissionModel.FILING, true);
// TODO will change this when we are able to set permissions on holds and transfers!
// getPermissionService().setInheritParentPermissions(container, true);
// }
return container; return container;
} }
@@ -605,23 +540,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
} }
} }
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isFilePlanContainer(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
public boolean isFilePlanContainer(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_RECORDS_MANAGEMENT_CONTAINER);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isRecordCategory(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isRecordCategory(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_RECORD_CATEGORY);
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#createRecordCategory(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, org.alfresco.service.namespace.QName, java.util.Map) * @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#createRecordCategory(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, org.alfresco.service.namespace.QName, java.util.Map)
*/ */

View File

@@ -25,10 +25,6 @@ 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.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
@@ -37,7 +33,6 @@ import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
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.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
@@ -54,8 +49,7 @@ import org.apache.commons.logging.LogFactory;
* @since 2.1 * @since 2.1
*/ */
public class FilePlanPermissionServiceImpl extends ServiceBaseImpl public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
implements FilePlanPermissionService, implements FilePlanPermissionService
RecordsManagementModel
{ {
/** Permission service */ /** Permission service */
protected PermissionService permissionService; protected PermissionService permissionService;
@@ -63,15 +57,6 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
/** Policy component */ /** Policy component */
protected PolicyComponent policyComponent; protected PolicyComponent policyComponent;
/** File plan service */
protected FilePlanService filePlanService;
/** Record service */
protected RecordService recordService;
/** Record folder service */
protected RecordFolderService recordFolderService;
/** Logger */ /** Logger */
protected static Log logger = LogFactory.getLog(FilePlanPermissionServiceImpl.class); protected static Log logger = LogFactory.getLog(FilePlanPermissionServiceImpl.class);
@@ -110,14 +95,6 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
this.permissionService = permissionService; this.permissionService = permissionService;
} }
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/** /**
* @param policyComponent policy component * @param policyComponent policy component
*/ */
@@ -126,30 +103,6 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
this.policyComponent = policyComponent; this.policyComponent = policyComponent;
} }
/**
* @param filePlanService file plan service
*/
public void setFilePlanService(FilePlanService filePlanService)
{
this.filePlanService = filePlanService;
}
/**
* @param recordService record service
*/
public void setRecordService(RecordService recordService)
{
this.recordService = recordService;
}
/**
* @param recordFolderService record folder service
*/
public void setRecordFolderService(RecordFolderService recordFolderService)
{
this.recordFolderService = recordFolderService;
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService#setupRecordCategoryPermissions(org.alfresco.service.cmr.repository.NodeRef) * @see org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService#setupRecordCategoryPermissions(org.alfresco.service.cmr.repository.NodeRef)
*/ */
@@ -175,7 +128,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
{ {
public Object doWork() public Object doWork()
{ {
boolean fillingOnly = filePlanService.isFilePlan(parentNodeRef); boolean fillingOnly = isFilePlan(parentNodeRef);
// since this is not a root category, inherit from parent // since this is not a root category, inherit from parent
Set<AccessPermission> perms = permissionService.getAllSetPermissions(parentNodeRef); Set<AccessPermission> perms = permissionService.getAllSetPermissions(parentNodeRef);
@@ -258,7 +211,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
*/ */
public void onAddRecord(final NodeRef record, final QName aspectTypeQName) public void onAddRecord(final NodeRef record, final QName aspectTypeQName)
{ {
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() runAs(new AuthenticationUtil.RunAsWork<Object>()
{ {
public Object doWork() public Object doWork()
{ {
@@ -412,7 +365,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
{ {
if (nodeService.exists(nodeRef)) if (nodeService.exists(nodeRef))
{ {
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() runAs(new AuthenticationUtil.RunAsWork<Object>()
{ {
public Object doWork() public Object doWork()
{ {
@@ -438,17 +391,18 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
ParameterCheck.mandatory("authority", authority); ParameterCheck.mandatory("authority", authority);
ParameterCheck.mandatory("permission", permission); ParameterCheck.mandatory("permission", permission);
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
{ {
public Boolean doWork() throws Exception public Boolean doWork() throws Exception
{ {
if (filePlanService.isFilePlan(nodeRef)) if (isFilePlan(nodeRef))
{ {
setPermissionDown(nodeRef, authority, permission); setPermissionDown(nodeRef, authority, permission);
} }
else if (filePlanService.isFilePlanContainer(nodeRef) || else if (isFilePlanContainer(nodeRef) ||
recordFolderService.isRecordFolder(nodeRef) || isRecordFolder(nodeRef) ||
recordService.isRecord(nodeRef)) isRecord(nodeRef) ||
isHold(nodeRef))
{ {
setReadPermissionUp(nodeRef, authority); setReadPermissionUp(nodeRef, authority);
setPermissionDown(nodeRef, authority, permission); setPermissionDown(nodeRef, authority, permission);
@@ -463,7 +417,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
return null; return null;
} }
}, AuthenticationUtil.getSystemUserName()); });
} }
/** /**
@@ -475,7 +429,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
private void setReadPermissionUp(NodeRef nodeRef, String authority) private void setReadPermissionUp(NodeRef nodeRef, String authority)
{ {
NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef(); NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef();
if (parent != null && filePlanService.isFilePlanComponent(parent)) if (parent != null && isFilePlanComponent(parent))
{ {
setReadPermissionUpImpl(parent, authority); setReadPermissionUpImpl(parent, authority);
} }
@@ -492,7 +446,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
setPermissionImpl(nodeRef, authority, RMPermissionModel.READ_RECORDS); setPermissionImpl(nodeRef, authority, RMPermissionModel.READ_RECORDS);
NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef(); NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef();
if (parent != null && filePlanService.isFilePlanComponent(parent)) if (parent != null && isFilePlanComponent(parent))
{ {
setReadPermissionUpImpl(parent, authority); setReadPermissionUpImpl(parent, authority);
} }
@@ -513,17 +467,17 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
// set permissions // set permissions
setPermissionImpl(nodeRef, authority, permission); setPermissionImpl(nodeRef, authority, permission);
if (filePlanService.isFilePlanContainer(nodeRef) || if (isFilePlanContainer(nodeRef) ||
recordFolderService.isRecordFolder(nodeRef)) isRecordFolder(nodeRef))
{ {
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 (filePlanService.isFilePlanContainer(child) || if (isFilePlanContainer(child) ||
recordFolderService.isRecordFolder(child) || isRecordFolder(child) ||
recordService.isRecord(child) || isRecord(child) ||
instanceOf(child, TYPE_HOLD) || isHold(child) ||
instanceOf(child, TYPE_TRANSFER)) instanceOf(child, TYPE_TRANSFER))
{ {
setPermissionDown(child, authority, permission); setPermissionDown(child, authority, permission);
@@ -556,7 +510,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
*/ */
public void deletePermission(final NodeRef nodeRef, final String authority, final String permission) public void deletePermission(final NodeRef nodeRef, final String authority, final String permission)
{ {
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
{ {
public Boolean doWork() throws Exception public Boolean doWork() throws Exception
{ {
@@ -566,17 +520,17 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
// Delete permission on this node // Delete permission on this node
permissionService.deletePermission(nodeRef, authority, permission); permissionService.deletePermission(nodeRef, authority, permission);
if (filePlanService.isFilePlanContainer(nodeRef) || if (isFilePlanContainer(nodeRef) ||
recordFolderService.isRecordFolder(nodeRef)) isRecordFolder(nodeRef))
{ {
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 (filePlanService.isFilePlanContainer(child) || if (isFilePlanContainer(child) ||
recordFolderService.isRecordFolder(child) || isRecordFolder(child) ||
recordService.isRecord(child)|| isRecord(child)||
instanceOf(child, TYPE_HOLD) || isHold(child) ||
instanceOf(child, TYPE_TRANSFER)) instanceOf(child, TYPE_TRANSFER))
{ {
deletePermission(child, authority, permission); deletePermission(child, authority, permission);
@@ -587,6 +541,6 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
return null; return null;
} }
}, AuthenticationUtil.getSystemUserName()); });
} }
} }

View File

@@ -31,6 +31,9 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyMap; import org.alfresco.util.PropertyMap;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/** /**
* Helper base class for service implementations. * Helper base class for service implementations.
@@ -38,7 +41,7 @@ import org.alfresco.util.PropertyMap;
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.1 * @since 2.1
*/ */
public class ServiceBaseImpl implements RecordsManagementModel public class ServiceBaseImpl implements RecordsManagementModel, ApplicationContextAware
{ {
/** Node service */ /** Node service */
protected NodeService nodeService; protected NodeService nodeService;
@@ -46,6 +49,18 @@ public class ServiceBaseImpl implements RecordsManagementModel
/** Dictionary service */ /** Dictionary service */
protected DictionaryService dictionaryService; protected DictionaryService dictionaryService;
/** Application context */
protected ApplicationContext applicationContext;
/**
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
/** /**
* @param nodeService node service * @param nodeService node service
*/ */
@@ -62,6 +77,60 @@ public class ServiceBaseImpl implements RecordsManagementModel
this.dictionaryService = dictionaryService; this.dictionaryService = dictionaryService;
} }
/**
* Indicates whether the given node is a file plan component or not.
* <p>
* Exposed in the FilePlan service.
*
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isFilePlanComponent(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isFilePlanComponent(NodeRef nodeRef)
{
boolean result = false;
// use the internal node service to prevent redirection of security checking.
NodeService myNodeService = (NodeService)applicationContext.getBean("nodeService");
if (myNodeService.exists(nodeRef) &&
myNodeService.hasAspect(nodeRef, ASPECT_FILE_PLAN_COMPONENT))
{
result = true;
}
return result;
}
/**
* Indicates whether the given node is a file plan or not.
* <p>
* Exposed in the FilePlan service.
*
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isFilePlan(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isFilePlan(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_FILE_PLAN);
}
/**
* Indicates whether the given node is a file plan container or not.
*
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isFilePlanContainer(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isFilePlanContainer(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_RECORDS_MANAGEMENT_CONTAINER);
}
/**
* Indicates whether the given node is a record category or not.
*
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#isRecordCategory(org.alfresco.service.cmr.repository.NodeRef)
*/
public boolean isRecordCategory(NodeRef nodeRef)
{
return instanceOf(nodeRef, TYPE_RECORD_CATEGORY);
}
/** /**
* Indicates whether the given node is a record folder or not. * Indicates whether the given node is a record folder or not.
* <p> * <p>

View File

@@ -0,0 +1,263 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.security;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Spy;
/**
* File plan permission service implementation unit test.
* <p>
* Primarily tests the file plan permission service interaction with the
* permission service.
*
* @author Roy Wetherall
* @since 2.2
*/
public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
{
/** test authority */
protected static final String AUTHORITY = "anAuthority";
/** unfiled nodes */
protected NodeRef unfiledRecordContainer;
protected NodeRef unfiledRecordFolder;
protected NodeRef unfiledRecordFolderChild;
protected NodeRef unfiledRecord;
/** held nodes */
protected NodeRef holdContainer;
protected NodeRef hold;
protected NodeRef heldRecord;
/** file plan permission service implementation */
@Spy @InjectMocks FilePlanPermissionServiceImpl filePlanPermissionService;
/**
* @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest#before()
*/
@Override
public void before()
{
super.before();
// mock up run as methods
mockRunAsMethods(filePlanPermissionService);
// initialize node's
unfiledRecordContainer = generateContainerNodeRef(TYPE_UNFILED_RECORD_CONTAINER);
unfiledRecordFolder = generateContainerNodeRef(TYPE_UNFILED_RECORD_FOLDER);
unfiledRecordFolderChild = generateContainerNodeRef(TYPE_UNFILED_RECORD_FOLDER);
unfiledRecord = generateRecord();
holdContainer = generateContainerNodeRef(TYPE_HOLD_CONTAINER);
hold = generateHoldNodeRef("my test hold");
heldRecord = generateRecord();
// setup parent hierarchy
makePrimaryParentOf(filePlan, generateNodeRef(ContentModel.TYPE_FOLDER));
makePrimaryParentOf(unfiledRecordFolder, unfiledRecordContainer);
makePrimaryParentOf(unfiledRecordContainer, filePlan);
makePrimaryParentOf(hold, holdContainer);
makePrimaryParentOf(holdContainer, filePlan);
// setup child hierarchy
makeChildrenOf(unfiledRecordFolder, unfiledRecordFolderChild);
makeChildrenOf(unfiledRecordFolderChild, unfiledRecord);
makeChildrenOf(hold, heldRecord);
}
/**
* Helper method to generate a container node ref of a perticular type.
*
* @param type type of node reference
* @return {@link NodeRef} node reference that behaves like a container of the type given.
*/
private NodeRef generateContainerNodeRef(QName type)
{
NodeRef nodeRef = generateNodeRef(type);
setupAsFilePlanComponent(nodeRef);
doReturn(true).when(filePlanPermissionService).isFilePlanContainer(nodeRef);
return nodeRef;
}
/**
* Set read permission on unfiled record folder.
*/
@Test
public void setReadPermissionOnUnfiledRecordFolder()
{
// set read permission on unfiled record folder
filePlanPermissionService.setPermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.READ_RECORDS);
// verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordContainer, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify READ permission set down hierarchy
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordFolderChild, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService, times(1)).setPermission(unfiledRecord, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
}
/**
* Set filling permission on unfiled record folder
*/
@Test
public void setReadAndFilePermissionOnUnfileRecordFolder()
{
// set read permission on unfiled record folder
filePlanPermissionService.setPermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.FILING);
// verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.FILING, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordContainer, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify FILING permission set down hierarchy
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordFolderChild, AUTHORITY, RMPermissionModel.FILING, true);
verify(mockedPermissionService, times(1)).setPermission(unfiledRecord, AUTHORITY, RMPermissionModel.FILING, true);
}
/**
* Remove permission from unfiled record folders.
*/
@Test
public void deletePermissionFromUnfiledRecordFolder()
{
// delete read permission from unfiled record folder
filePlanPermissionService.deletePermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.READ_RECORDS);
// verify permission deleted on target node
verify(mockedPermissionService, times(1)).deletePermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.READ_RECORDS);
// verify no permissions deleted up the hierarchy
verify(mockedPermissionService, never()).deletePermission(eq(unfiledRecordContainer), eq(AUTHORITY), anyString());
verify(mockedPermissionService, never()).deletePermission(eq(filePlan), eq(AUTHORITY), anyString());
// verify READ permission removed down hierarchy
verify(mockedPermissionService, times(1)).deletePermission(unfiledRecordFolderChild, AUTHORITY, RMPermissionModel.READ_RECORDS);
verify(mockedPermissionService, times(1)).deletePermission(unfiledRecord, AUTHORITY, RMPermissionModel.READ_RECORDS);
}
/**
* Set read permission on hold container
*/
public void setReadPermissionOnHoldContainer()
{
// set read permission on hold
filePlanPermissionService.setPermission(holdContainer, AUTHORITY, RMPermissionModel.READ_RECORDS);
// verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(holdContainer, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify READ permission set on hold
verify(mockedPermissionService, times(1)).setPermission(hold, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify permission not set on child of hold
verify(mockedPermissionService, never()).setPermission(eq(heldRecord), eq(AUTHORITY), anyString(), eq(true));
}
/**
* Set filing permission on hold container
*/
public void setFilingPermissionOnHoldContainer()
{
// set read permission on hold
filePlanPermissionService.setPermission(holdContainer, AUTHORITY, RMPermissionModel.FILING);
// verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(holdContainer, AUTHORITY, RMPermissionModel.FILING, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify FILING permission set on hold
verify(mockedPermissionService, times(1)).setPermission(hold, AUTHORITY, RMPermissionModel.FILING, true);
// verify permission not set on child of hold
verify(mockedPermissionService, never()).setPermission(eq(heldRecord), eq(AUTHORITY), anyString(), eq(true));
}
/**
* Set read permission on hold.
*/
@Test
public void setReadPermissionOnHold()
{
// set read permission on hold
filePlanPermissionService.setPermission(hold, AUTHORITY, RMPermissionModel.READ_RECORDS);
// verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(hold, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(holdContainer, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify permission not set on child of hold
verify(mockedPermissionService, never()).setPermission(eq(heldRecord), eq(AUTHORITY), anyString(), eq(true));
}
/**
* Set filing permission on hold.
*/
@Test
public void setFilingPermissionOnHold()
{
// set filing permission on hold
filePlanPermissionService.setPermission(hold, AUTHORITY, RMPermissionModel.FILING);
// verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(hold, AUTHORITY, RMPermissionModel.FILING, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(holdContainer, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify permission not set on child of hold
verify(mockedPermissionService, never()).setPermission(eq(heldRecord), eq(AUTHORITY), anyString(), eq(true));
}
}

View File

@@ -26,6 +26,7 @@ import org.alfresco.module.org_alfresco_module_rm.record.RecordServiceImplUnitTe
import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldPostUnitTest; import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldPostUnitTest;
import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldPutUnitTest; import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldPutUnitTest;
import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldsGetUnitTest; import org.alfresco.module.org_alfresco_module_rm.script.hold.HoldsGetUnitTest;
import org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionServiceImplUnitTest;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses; import org.junit.runners.Suite.SuiteClasses;
@@ -46,7 +47,8 @@ import org.junit.runners.Suite.SuiteClasses;
TransferEvaluatorUnitTest.class, TransferEvaluatorUnitTest.class,
HoldsGetUnitTest.class, HoldsGetUnitTest.class,
HoldPostUnitTest.class, HoldPostUnitTest.class,
HoldPutUnitTest.class HoldPutUnitTest.class,
FilePlanPermissionServiceImplUnitTest.class
}) })
public class AllUnitTestSuite public class AllUnitTestSuite
{ {

View File

@@ -19,7 +19,9 @@
package org.alfresco.module.org_alfresco_module_rm.test.util; package org.alfresco.module.org_alfresco_module_rm.test.util;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -34,14 +36,18 @@ import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService;
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.record.RecordService; import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService; import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
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.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.QNamePattern; import org.alfresco.service.namespace.QNamePattern;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.GUID; import org.alfresco.util.GUID;
import org.alfresco.util.collections.CollectionUtils; import org.alfresco.util.collections.CollectionUtils;
import org.junit.Before; import org.junit.Before;
@@ -49,6 +55,9 @@ import org.junit.Rule;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.context.ApplicationContext;
/** /**
* Base unit test. * Base unit test.
@@ -72,12 +81,17 @@ public class BaseUnitTest implements RecordsManagementModel
@Mock(name="dictionaryService") protected DictionaryService mockedDictionaryService; @Mock(name="dictionaryService") protected DictionaryService mockedDictionaryService;
@Mock(name="namespaceService") protected NamespaceService mockedNamespaceService; @Mock(name="namespaceService") protected NamespaceService mockedNamespaceService;
@Mock(name="identifierService") protected IdentifierService mockedIdentifierService; @Mock(name="identifierService") protected IdentifierService mockedIdentifierService;
@Mock(name="permissionService") protected PermissionService mockedPermissionService;
/** rm service mocks */
@Mock(name="filePlanService") protected FilePlanService mockedFilePlanService; @Mock(name="filePlanService") protected FilePlanService mockedFilePlanService;
@Mock(name="recordFolderService") protected RecordFolderService mockedRecordFolderService; @Mock(name="recordFolderService") protected RecordFolderService mockedRecordFolderService;
@Mock(name="recordService") protected RecordService mockedRecordService; @Mock(name="recordService") protected RecordService mockedRecordService;
@Mock(name="holdService") protected HoldService mockedHoldService; @Mock(name="holdService") protected HoldService mockedHoldService;
/** application context mock */
@Mock(name="applicationContext") protected ApplicationContext mockedApplicationContext;
/** expected exception rule */ /** expected exception rule */
@Rule @Rule
public ExpectedException exception = ExpectedException.none(); public ExpectedException exception = ExpectedException.none();
@@ -90,8 +104,12 @@ public class BaseUnitTest implements RecordsManagementModel
{ {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
// setup application context
doReturn(mockedNodeService).when(mockedApplicationContext).getBean("nodeService");
// setup file plan // setup file plan
filePlan = generateNodeRef(TYPE_FILE_PLAN); filePlan = generateNodeRef(TYPE_FILE_PLAN);
setupAsFilePlanComponent(filePlan);
doReturn(true).when(mockedFilePlanService).isFilePlan(filePlan); doReturn(true).when(mockedFilePlanService).isFilePlan(filePlan);
// setup basic file plan component // setup basic file plan component
@@ -113,7 +131,6 @@ public class BaseUnitTest implements RecordsManagementModel
doReturn(result).when(mockedNodeService).getParentAssocs(record); doReturn(result).when(mockedNodeService).getParentAssocs(record);
doReturn(Collections.singletonList(recordFolder)).when(mockedRecordFolderService).getRecordFolders(record); doReturn(Collections.singletonList(recordFolder)).when(mockedRecordFolderService).getRecordFolders(record);
doReturn(Collections.singletonList(record)).when(mockedRecordService).getRecords(recordFolder); doReturn(Collections.singletonList(record)).when(mockedRecordService).getRecords(recordFolder);
} }
/** /**
@@ -207,4 +224,72 @@ public class BaseUnitTest implements RecordsManagementModel
} }
return nodeRef; return nodeRef;
} }
/**
* Helper method to make one node the primary parent of the other.
* <p>
* Assumes the cm:contains assoc type.
*
* @param child
* @param parent
*/
protected void makePrimaryParentOf(NodeRef child, NodeRef parent)
{
doReturn(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, parent, generateQName(), child))
.when(mockedNodeService)
.getPrimaryParent(child);
}
/**
* Helper method to make a number of nodes children of another.
* <p>
* Assumes the cm:contains assoc type.
*
* @param parent
* @param children
*/
protected void makeChildrenOf(NodeRef parent, NodeRef ... children)
{
List<ChildAssociationRef> assocs = new ArrayList<ChildAssociationRef>(children.length);
for (NodeRef child : children)
{
assocs.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, parent, generateQName(), child));
}
doReturn(assocs).when(mockedNodeService).getChildAssocs(parent, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
}
/**
* Helper method to mock up calls to 'run as' methods
* on base service implementation.
*
* @param service
*/
@SuppressWarnings("unchecked")
protected void mockRunAsMethods(ServiceBaseImpl service)
{
doAnswer(new Answer<Object>()
{
@SuppressWarnings("rawtypes")
@Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
RunAsWork work = (RunAsWork)invocation.getArguments()[0];
return work.doWork();
}
}).when(service).runAsSystem(any(RunAsWork.class));
doAnswer(new Answer<Object>()
{
@SuppressWarnings("rawtypes")
@Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
RunAsWork work = (RunAsWork)invocation.getArguments()[0];
return work.doWork();
}
}).when(service).runAs(any(RunAsWork.class), anyString());
}
} }