RM: Edit capability fixes and inplace capability roles

* capability for inplace user no longer defined by dynamic authorities (inheritance was incorrect)
  * default roles added to allow capabilities of reader and writer inplace users
  * record permission inheritance broken .. was on the todo list for a long time, but needed to be done now to ensure the correct inplace permissions where evaluated at the record level
  * unit tests
  * TODO ... patches to migrate to 2.1 for new roles and record permission inheritance change



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@49215 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2013-04-15 09:30:23 +00:00
parent e5f23a5ae8
commit 4654fbacce
15 changed files with 587 additions and 156 deletions

View File

@@ -205,7 +205,6 @@
<entry key="capabilityCondition.filling" value="true"/>
<entry key="capabilityCondition.cutoff" value="false"/>
<entry key="capabilityCondition.frozen" value="false"/>
<entry key="capabilityCondition.closed" value="false"/>
<entry key="capabilityCondition.declared" value="false"/>
</map>
</property>
@@ -227,7 +226,6 @@
<entry key="capabilityCondition.filling" value="true"/>
<entry key="capabilityCondition.cutoff" value="false"/>
<entry key="capabilityCondition.frozen" value="false"/>
<entry key="capabilityCondition.closed" value="false"/>
<entry key="capabilityCondition.declared" value="false"/>
</map>
</property>

View File

@@ -107,8 +107,8 @@
<list>
<ref bean="ownerDynamicAuthority" />
<ref bean="lockOwnerDynamicAuthority" />
<ref bean="extendedReaderDynamicAuthority" />
<ref bean="extendedWriterDynamicAuthority" />
<ref bean="extendedReaderDynamicAuthority" />
</list>
</property>
</bean>

View File

@@ -627,6 +627,8 @@
<property name="recordService" ref="recordService"/>
<property name="nodeService" ref="nodeService"/>
<property name="recordsManagementService" ref="recordsManagementService"/>
<property name="filePlanService" ref="filePlanService" />
<property name="filePlanRoleService" ref="filePlanRoleService" />
</bean>
<bean id="ExtendedSecurityService" class="org.springframework.aop.framework.ProxyFactoryBean">

View File

@@ -1,4 +1,23 @@
[
{
"name" : "ExtendedReaders",
"displayLabel" : "In-Place Readers",
"isAdmin" : false,
"capabilities" :
[
"ViewRecords"
]
},
{
"name" : "ExtendedWriters",
"displayLabel" : "In-Place Writers",
"isAdmin" : false,
"capabilities" :
[
"ViewRecords",
"EditNonRecordMetadata"
]
},
{
"name" : "User",
"displayLabel" : "Records Management User",

View File

@@ -24,8 +24,6 @@ import org.alfresco.repo.action.evaluator.ActionConditionEvaluatorAbstractBase;
import org.alfresco.service.cmr.action.ActionConditionDefinition;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.util.StringUtils;
/**
* Records management action condition evaluator abstract base implementation.
@@ -77,6 +75,7 @@ public abstract class RecordsManagementActionConditionEvaluatorAbstractBase exte
public void setBeanName(String name)
{
this.name = name;
super.setBeanName(name);
}
/**
@@ -92,31 +91,15 @@ public abstract class RecordsManagementActionConditionEvaluatorAbstractBase exte
*/
public String getLabel()
{
String label = I18NUtil.getMessage(this.getTitleKey());
if (label == null)
{
// default to the name of the action with first letter capitalised
label = StringUtils.capitalize(this.name);
}
return label;
return getActionConditionDefintion().getTitle();
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementAction#getDescription()
*/
public String getDescription()
{
String desc = I18NUtil.getMessage(this.getDescriptionKey());
if (desc == null)
{
// default to the name of the action with first letter capitalised
desc = StringUtils.capitalize(this.name);
}
return desc;
{
return getActionConditionDefintion().getDescription();
}
/**

View File

@@ -121,8 +121,8 @@ public class RMv21InPlacePatch extends AbstractModuleComponent
filePlanPermissionService.setPermission(filePlan, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING);
// set capabilities
permissionService.setPermission(filePlan, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.VIEW_RECORDS, true);
permissionService.setPermission(filePlan, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.EDIT_NON_RECORD_METADATA, true);
//permissionService.setPermission(filePlan, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.VIEW_RECORDS, true);
// permissionService.setPermission(filePlan, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.EDIT_NON_RECORD_METADATA, true);
// create unfiled container
filePlanService.createUnfiledContainer(filePlan);

View File

@@ -31,6 +31,7 @@ import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.RecordsManagementService;
import org.alfresco.module.org_alfresco_module_rm.capability.Capability;
import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule;
@@ -42,6 +43,8 @@ import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomM
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.model.security.ModelAccessDeniedException;
import org.alfresco.module.org_alfresco_module_rm.notification.RecordsManagementNotificationHelper;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.role.Role;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordServiceImpl;
import org.alfresco.repo.node.NodeServicePolicies;
@@ -59,6 +62,7 @@ import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
@@ -735,8 +739,69 @@ public class RecordServiceImpl implements RecordService,
logger.debug("Checking whether property " + property.toString() + " is editable for user " + AuthenticationUtil.getRunAsUser());
}
// DEBUG ...
FilePlanService fps = (FilePlanService)applicationContext.getBean("filePlanService");
FilePlanRoleService fprs = (FilePlanRoleService)applicationContext.getBean("filePlanRoleService");
PermissionService ps = (PermissionService)applicationContext.getBean("permissionService");
NodeRef filePlan = fps.getFilePlan(record);
Set<Role> roles = fprs.getRolesByUser(filePlan, AuthenticationUtil.getRunAsUser());
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... users roles");
}
for (Role role : roles)
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... user has role " + role.getName() + " with capabilities ");
}
for (Capability cap : role.getCapabilities())
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... " + cap.getName());
}
}
}
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... user has the following set permissions on the file plan");
}
Set<AccessPermission> perms = ps.getAllSetPermissions(filePlan);
for (AccessPermission perm : perms)
{
if (logger.isDebugEnabled() == true &&
(perm.getPermission().contains(RMPermissionModel.EDIT_NON_RECORD_METADATA) ||
perm.getPermission().contains(RMPermissionModel.EDIT_RECORD_METADATA)))
{
logger.debug(" ... " + perm.getAuthority() + " - " + perm.getPermission() + " - " + perm.getAccessStatus().toString());
}
}
if (ps.hasPermission(filePlan, RMPermissionModel.EDIT_NON_RECORD_METADATA).equals(AccessStatus.ALLOWED))
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... user has the edit non record metadata permission on the file plan");
}
}
// END DEBUG ...
boolean result = alwaysEditProperty(property);
if (result == false)
if (result == true)
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... property marked as always editable.");
}
}
else
{
boolean allowRecordEdit = false;
boolean allowNonRecordEdit = false;
@@ -747,17 +812,32 @@ public class RecordServiceImpl implements RecordService,
if (AccessStatus.ALLOWED.equals(accessNonRecord) == true)
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... user has edit nonrecord metadata capability");
}
allowNonRecordEdit = true;
}
if (AccessStatus.ALLOWED.equals(accessRecord) == true ||
AccessStatus.ALLOWED.equals(accessDeclaredRecord) == true)
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... user has edit record or declared metadata capability");
}
allowRecordEdit = true;
}
if (allowNonRecordEdit == true && allowRecordEdit == true)
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... so all properties can be edited.");
}
result = true;
}
else if (allowNonRecordEdit == true && allowRecordEdit == false)
@@ -765,16 +845,40 @@ public class RecordServiceImpl implements RecordService,
// can only edit non record properties
if (isRecordMetadata(property) == false)
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... property is not considered record metadata so editable.");
}
result = true;
}
else
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... property is considered record metadata so not editable.");
}
}
}
else if (allowNonRecordEdit == false && allowRecordEdit == true)
{
// can only edit record properties
if (isRecordMetadata(property) == true)
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... property is considered record metadata so editable.");
}
result = true;
}
}
else
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" ... property is not considered record metadata so not editable.");
}
}
}
// otherwise we can't edit any properties so just return the empty set
}

View File

@@ -37,6 +37,8 @@ public interface FilePlanRoleService
public static final String ROLE_SECURITY_OFFICER = "SecurityOfficer";
public static final String ROLE_RECORDS_MANAGER = "RecordsManager";
public static final String ROLE_ADMIN = "Administrator";
public static final String ROLE_EXTENDED_READERS = "ExtendedReaders";
public static final String ROLE_EXTENDED_WRITERS = "ExtendedWriters";
/**
* Returns the name of the container group for all roles of a specified file

View File

@@ -193,8 +193,8 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService,
permissionService.setPermission(rmRootNode, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
// set the capabilities
permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.VIEW_RECORDS, true);
permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.EDIT_NON_RECORD_METADATA, true);
// permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.VIEW_RECORDS, true);
// permissionService.setPermission(rmRootNode, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.EDIT_NON_RECORD_METADATA, true);
// Create the unfiled record container
return filePlanService.createUnfiledContainer(rmRootNode);

View File

@@ -48,5 +48,5 @@ public class ExtendedReaderDynamicAuthority extends ExtendedSecurityBaseDynamicA
protected Set<String> getAuthorites(NodeRef nodeRef)
{
return getExtendedSecurityService().getExtendedReaders(nodeRef);
}
}
}

View File

@@ -51,7 +51,7 @@ public abstract class ExtendedSecurityBaseDynamicAuthority implements DynamicAut
private NodeService nodeService;
/** Application context */
private ApplicationContext applicationContext;
protected ApplicationContext applicationContext;
// NOTE: we get the services directly from the application context in this way to avoid
// cyclic relationships and issues when loading the application context

View File

@@ -26,8 +26,10 @@ import java.util.Set;
import org.alfresco.model.RenditionModel;
import org.alfresco.module.org_alfresco_module_rm.RecordsManagementService;
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.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
@@ -37,6 +39,9 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.ParameterCheck;
@@ -51,6 +56,10 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
RecordsManagementModel,
NodeServicePolicies.OnMoveNodePolicy
{
/** Ad hoc properties used for reference counting */
private final static QName PROP_EXTENDED_READER_ROLE = QName.createQName(RM_URI, "extendedReaderRole");
private final static QName PROP_EXTENDED_WRITER_ROLE = QName.createQName(RM_URI, "extendedWriterRole");
/** Policy component */
private PolicyComponent policyComponent;
@@ -60,6 +69,12 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
/** Record service */
private RecordService recordService;
/** File plan service */
private FilePlanService filePlanService;
/** File plan role service */
private FilePlanRoleService filePlanRoleService;
/**
* @param policyComponent policy component
*/
@@ -84,6 +99,22 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
this.recordsManagementService = recordsManagementService;
}
/**
* @param filePlanService file plan service
*/
public void setFilePlanService(FilePlanService filePlanService)
{
this.filePlanService = filePlanService;
}
/**
* @param filePlanRoleService file plan role service
*/
public void setFilePlanRoleService(FilePlanRoleService filePlanRoleService)
{
this.filePlanRoleService = filePlanRoleService;
}
/**
* Init method
*/
@@ -151,7 +182,6 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#addExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set, boolean)
*/
@SuppressWarnings("unchecked")
@Override
public void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents)
{
@@ -160,55 +190,157 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
if (nodeRef != null)
{
// add the aspect if missing
if (nodeService.hasAspect(nodeRef, ASPECT_EXTENDED_SECURITY) == false)
{
nodeService.addAspect(nodeRef, ASPECT_EXTENDED_SECURITY, null);
}
addExtendedSecurityImpl(nodeRef, readers, writers, applyToParents);
}
}
@SuppressWarnings("unchecked")
private void addExtendedSecurityImpl(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
ParameterCheck.mandatory("applyToParents", applyToParents);
// add the aspect if missing
if (nodeService.hasAspect(nodeRef, ASPECT_EXTENDED_SECURITY) == false)
{
nodeService.addAspect(nodeRef, ASPECT_EXTENDED_SECURITY, null);
}
// update the readers map
if (readers != null && readers.size() != 0)
{
// get reader map
Map<String, Integer> readersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_READERS);
// update the readers map
if (readers != null && readers.size() != 0)
{
// get reader map
Map<String, Integer> readersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_READERS);
// set the readers property (this will in turn apply the aspect if required)
nodeService.setProperty(nodeRef, PROP_READERS, (Serializable)addToMap(readersMap, readers));
}
// set the readers property (this will in turn apply the aspect if required)
nodeService.setProperty(nodeRef, PROP_READERS, (Serializable)addToMap(readersMap, readers));
}
// update the writers map
if (writers != null && writers.size() != 0)
{
// get writer map
Map<String, Integer> writersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_WRITERS);
// update the writers map
if (writers != null && writers.size() != 0)
// set the writers property (this will in turn apply the aspect if required)
nodeService.setProperty(nodeRef, PROP_WRITERS, (Serializable)addToMap(writersMap, writers));
}
// apply the readers to any renditions of the content
if (recordService.isRecord(nodeRef) == true)
{
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, RenditionModel.ASSOC_RENDITION, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef assoc : assocs)
{
// get writer map
Map<String, Integer> writersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_WRITERS);
// set the writers property (this will in turn apply the aspect if required)
nodeService.setProperty(nodeRef, PROP_WRITERS, (Serializable)addToMap(writersMap, writers));
}
// apply the readers to any renditions of the content
if (recordService.isRecord(nodeRef) == true)
{
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, RenditionModel.ASSOC_RENDITION, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef assoc : assocs)
{
NodeRef child = assoc.getChildRef();
addExtendedSecurity(child, readers, writers, false);
}
}
if (applyToParents == true)
{
// apply the extended readers up the file plan primary hierarchy
NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef();
if (parent != null &&
recordsManagementService.isFilePlanComponent(parent) == true)
{
addExtendedSecurity(parent, readers, null);
addExtendedSecurity(parent, writers, null);
}
NodeRef child = assoc.getChildRef();
addExtendedSecurityImpl(child, readers, writers, false);
}
}
// add to the extended security roles
addExtendedSecurityRoles(nodeRef, readers, writers);
if (applyToParents == true)
{
// apply the extended readers up the file plan primary hierarchy
NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef();
if (parent != null &&
recordsManagementService.isFilePlanComponent(parent) == true)
{
addExtendedSecurityImpl(parent, readers, null, applyToParents);
addExtendedSecurityImpl(parent, writers, null, applyToParents);
}
}
}
/**
*
* @param nodeRef
* @param readers
* @param writers
*/
private void addExtendedSecurityRoles(NodeRef nodeRef, Set<String> readers, Set<String> writers)
{
NodeRef filePlan = filePlanService.getFilePlan(nodeRef);
addExtendedSecurityRolesImpl(filePlan, readers, PROP_EXTENDED_READER_ROLE, FilePlanRoleService.ROLE_EXTENDED_READERS);
addExtendedSecurityRolesImpl(filePlan, writers, PROP_EXTENDED_WRITER_ROLE, FilePlanRoleService.ROLE_EXTENDED_WRITERS);
}
/**
*
* @param filePlan
* @param authorities
* @param propertyName
* @param roleName
*/
@SuppressWarnings("unchecked")
private void addExtendedSecurityRolesImpl(NodeRef filePlan, Set<String> authorities, QName propertyName, String roleName)
{
if (authorities != null)
{
// get the reference count
Map<String, Integer> referenceCountMap = (Map<String, Integer>)nodeService.getProperty(filePlan, propertyName);
for (String authority : authorities)
{
if (authority.equals(PermissionService.ALL_AUTHORITIES) == false)
{
if (referenceCountMap == null ||
referenceCountMap.containsKey(authority) == false)
{
// add the authority to the role
filePlanRoleService.assignRoleToAuthority(filePlan, roleName, authority);
}
}
}
// update the reference count
nodeService.setProperty(filePlan, propertyName, (Serializable)addToMap(referenceCountMap, authorities));
}
}
@SuppressWarnings("unused")
private void removeExtendedSecurityRoles(NodeRef nodeRef, Set<String> readers, Set<String> writers)
{
NodeRef filePlan = filePlanService.getFilePlan(nodeRef);
removeExtendedSecurityRolesImpl(filePlan, readers, PROP_EXTENDED_READER_ROLE, FilePlanRoleService.ROLE_EXTENDED_READERS);
removeExtendedSecurityRolesImpl(filePlan, writers, PROP_EXTENDED_WRITER_ROLE, FilePlanRoleService.ROLE_EXTENDED_WRITERS);
}
@SuppressWarnings("unchecked")
private void removeExtendedSecurityRolesImpl(NodeRef filePlan, Set<String> authorities, QName propertyName, String roleName)
{
if (authorities != null)
{
// get the reference count
Map<String, Integer> referenceCountMap = (Map<String, Integer>)nodeService.getProperty(filePlan, propertyName);
for (String authority : authorities)
{
if (authority.equals(PermissionService.ALL_AUTHORITIES) == false)
{
if (referenceCountMap == null)
{
// remove the authority from the role
filePlanRoleService.unassignRoleFromAuthority(filePlan, roleName, authority);
}
else
{
Integer count = referenceCountMap.get(authority);
if (count == null || count == 1)
{
// remove the authority from the role
filePlanRoleService.unassignRoleFromAuthority(filePlan, roleName, authority);
}
}
}
}
// update the reference count
nodeService.setProperty(filePlan, propertyName, (Serializable)removeFromMap(referenceCountMap, authorities));
}
}
/**
@@ -227,16 +359,19 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
for (String key : keys)
{
if (map.containsKey(key) == true)
if (key.equals(PermissionService.ALL_AUTHORITIES) == false)
{
// increment reference count
Integer count = map.get(key);
map.put(key, Integer.valueOf(count.intValue()+1));
}
else
{
// add key with initial count
map.put(key, Integer.valueOf(1));
if (map.containsKey(key) == true)
{
// increment reference count
Integer count = map.get(key);
map.put(key, Integer.valueOf(count.intValue()+1));
}
else
{
// add key with initial count
map.put(key, Integer.valueOf(1));
}
}
}
@@ -314,18 +449,21 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
// remove the keys
for (String key : keys)
{
Integer count = map.get(key);
if (count != null)
if (key.equals(PermissionService.ALL_AUTHORITIES) == false)
{
if (count == 1)
Integer count = map.get(key);
if (count != null)
{
// remove entry all together if the reference count is now 0
map.remove(key);
}
else
{
// decrement the reference count by 1
map.put(key, Integer.valueOf(count.intValue()-1));
if (count == 1)
{
// remove entry all together if the reference count is now 0
map.remove(key);
}
else
{
// decrement the reference count by 1
map.put(key, Integer.valueOf(count.intValue()-1));
}
}
}
}

View File

@@ -37,12 +37,15 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* File plan permission service.
*
* @author Roy Wetherall
* @since 2.1
*/
@@ -80,6 +83,10 @@ public class FilePlanPermissionServiceImpl implements FilePlanPermissionService,
NodeServicePolicies.OnCreateNodePolicy.QNAME,
TYPE_RECORD_FOLDER,
new JavaBehaviour(this, "onCreateRecordFolder", NotificationFrequency.TRANSACTION_COMMIT));
policyComponent.bindClassBehaviour(
NodeServicePolicies.OnAddAspectPolicy.QNAME,
ASPECT_RECORD,
new JavaBehaviour(this, "onAddRecord", NotificationFrequency.TRANSACTION_COMMIT));
}
/**
@@ -176,7 +183,9 @@ public class FilePlanPermissionServiceImpl implements FilePlanPermissionService,
*/
public void onCreateRecordFolder(ChildAssociationRef childAssocRef)
{
final NodeRef folderNodeRef = childAssocRef.getChildRef();
final NodeRef folderNodeRef = childAssocRef.getChildRef();
// initialise the permissions
setUpPermissions(folderNodeRef);
// Pull any permissions found on the parent (ie the record category)
@@ -212,6 +221,53 @@ public class FilePlanPermissionServiceImpl implements FilePlanPermissionService,
}, AuthenticationUtil.getSystemUserName());
}
}
/**
* Sets ups records permission when aspect is added.
*
* @see NodeServicePolicies.OnAddAspectPolicy#onAddAspect(NodeRef, QName)
*
* @param record
* @param aspectTypeQName
*/
public void onAddRecord(final NodeRef record, final QName aspectTypeQName)
{
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork()
{
if (nodeService.exists(record) == true && nodeService.hasAspect(record, aspectTypeQName) == true)
{
NodeRef recordFolder = nodeService.getPrimaryParent(record).getParentRef();
setUpPermissions(record);
Set<AccessPermission> perms = permissionService.getAllSetPermissions(recordFolder);
for (AccessPermission perm : perms)
{
if (ExtendedReaderDynamicAuthority.EXTENDED_READER.equals(perm.getAuthority()) == false &&
ExtendedWriterDynamicAuthority.EXTENDED_WRITER.equals(perm.getAuthority()) == false)
{
AccessStatus accessStatus = perm.getAccessStatus();
boolean allow = false;
if (AccessStatus.ALLOWED.equals(accessStatus) == true)
{
allow = true;
}
permissionService.setPermission(
record,
perm.getAuthority(),
perm.getPermission(),
allow);
}
}
}
return null;
}
}, AuthenticationUtil.getSystemUserName());
}
/**
*
@@ -255,16 +311,13 @@ public class FilePlanPermissionServiceImpl implements FilePlanPermissionService,
{
setPermissionDown(nodeRef, authority, permission);
}
else if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true)
else if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true ||
recordsManagementService.isRecordFolder(nodeRef) == true ||
recordsManagementService.isRecord(nodeRef) == true)
{
setReadPermissionUp(nodeRef, authority);
setPermissionDown(nodeRef, authority, permission);
}
else if (recordsManagementService.isRecordFolder(nodeRef) == true)
{
setReadPermissionUp(nodeRef, authority);
setPermissionImpl(nodeRef, authority, permission);
}
else
{
if (logger.isWarnEnabled() == true)
@@ -281,8 +334,8 @@ public class FilePlanPermissionServiceImpl implements FilePlanPermissionService,
/**
* Helper method to set the read permission up the hierarchy
*
* @param nodeRef
* @param authority
* @param nodeRef node reference
* @param authority authority
*/
private void setReadPermissionUp(NodeRef nodeRef, String authority)
{
@@ -298,21 +351,23 @@ public class FilePlanPermissionServiceImpl implements FilePlanPermissionService,
/**
* Helper method to set the permission down the hierarchy
*
* @param nodeRef
* @param authority
* @param permission
* @param nodeRef node reference
* @param authority authority
* @param permission permission
*/
private void setPermissionDown(NodeRef nodeRef, String authority, String permission)
{
setPermissionImpl(nodeRef, authority, permission);
if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true)
if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true ||
recordsManagementService.isRecordFolder(nodeRef) == true)
{
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef assoc : assocs)
{
NodeRef child = assoc.getChildRef();
if (recordsManagementService.isRecordsManagementContainer(child) == true ||
recordsManagementService.isRecordFolder(child) == true)
recordsManagementService.isRecordFolder(child) == true ||
recordsManagementService.isRecord(child) == true)
{
setPermissionDown(child, authority, permission);
}
@@ -350,14 +405,16 @@ public class FilePlanPermissionServiceImpl implements FilePlanPermissionService,
// Delete permission on this node
permissionService.deletePermission(nodeRef, authority, permission);
if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true)
if (recordsManagementService.isRecordsManagementContainer(nodeRef) == true ||
recordsManagementService.isRecordFolder(nodeRef) == true)
{
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef assoc : assocs)
{
NodeRef child = assoc.getChildRef();
if (recordsManagementService.isRecordsManagementContainer(child) == true ||
recordsManagementService.isRecordFolder(child) == true)
recordsManagementService.isRecordFolder(child) == true ||
recordsManagementService.isRecord(child) == true)
{
deletePermission(child, authority, permission);
}

View File

@@ -25,7 +25,9 @@ import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.GUID;
/**
* Records management security service test.
@@ -67,8 +69,25 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
moveRecordFolder = rmService.createRecordFolder(moveRecordCategory, "moveRecordFolder");
}
private String createTestUser()
{
return doTestInTransaction(new Test<String>()
{
public String run()
{
String userName = GUID.generate();
createPerson(userName);
return userName;
}
}, AuthenticationUtil.getSystemUserName());
}
public void testExtendedSecurity()
{
final String monkey = createTestUser();
final String elephant = createTestUser();
final String snake = createTestUser();
doTestInTransaction(new Test<Void>()
{
public Void run()
@@ -79,16 +98,17 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
assertFalse(extendedSecurityService.hasExtendedSecurity(record));
assertNull(extendedSecurityService.getExtendedReaders(record));
assertNull(extendedSecurityService.getExtendedWriters(record));
Set<String> extendedReaders = new HashSet<String>(2);
extendedReaders.add("monkey");
extendedReaders.add("elephant");
extendedReaders.add(monkey);
extendedReaders.add(elephant);
extendedSecurityService.addExtendedSecurity(record, extendedReaders, null);
Map<String, Integer> testMap = new HashMap<String, Integer>(2);
testMap.put("monkey", Integer.valueOf(1));
testMap.put("elephant", Integer.valueOf(1));
testMap.put(monkey, Integer.valueOf(1));
testMap.put(elephant, Integer.valueOf(1));
checkExtendedReaders(filePlan, testMap);
checkExtendedReaders(rmContainer, testMap);
@@ -96,19 +116,19 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
checkExtendedReaders(record, testMap);
Set<String> extendedReadersToo = new HashSet<String>(2);
extendedReadersToo.add("monkey");
extendedReadersToo.add("snake");
extendedReadersToo.add(monkey);
extendedReadersToo.add(snake);
extendedSecurityService.addExtendedSecurity(recordToo, extendedReadersToo, null);
Map<String, Integer> testMapToo = new HashMap<String, Integer>(2);
testMapToo.put("monkey", Integer.valueOf(1));
testMapToo.put("snake", Integer.valueOf(1));
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));
testMapThree.put(monkey, Integer.valueOf(2));
testMapThree.put(elephant, Integer.valueOf(1));
testMapThree.put(snake, Integer.valueOf(1));
checkExtendedReaders(filePlan, testMapThree);
checkExtendedReaders(rmContainer, testMapThree);
@@ -118,14 +138,14 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
// test remove (with no parent inheritance)
Set<String> removeMap1 = new HashSet<String>(2);
removeMap1.add("elephant");
removeMap1.add("monkey");
removeMap1.add(elephant);
removeMap1.add(monkey);
extendedSecurityService.removeExtendedSecurity(rmFolder, removeMap1, null, false);
Map<String, Integer> testMapFour = new HashMap<String, Integer>(2);
testMapFour.put("monkey", Integer.valueOf(1));
testMapFour.put("snake", Integer.valueOf(1));
testMapFour.put(monkey, Integer.valueOf(1));
testMapFour.put(snake, Integer.valueOf(1));
checkExtendedReaders(filePlan, testMapThree);
checkExtendedReaders(rmContainer, testMapThree);
@@ -135,13 +155,13 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
// test remove (apply to parents)
Set<String> removeMap2 = new HashSet<String>(1);
removeMap2.add("snake");
removeMap2.add(snake);
extendedSecurityService.removeExtendedSecurity(recordToo, removeMap2, null, true);
testMapThree.remove("snake");
testMapFour.remove("snake");
testMapToo.remove("snake");
testMapThree.remove(snake);
testMapFour.remove(snake);
testMapToo.remove(snake);
checkExtendedReaders(filePlan, testMapThree);
checkExtendedReaders(rmContainer, testMapThree);
@@ -155,14 +175,17 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
public void testMove()
{
final String monkey = createTestUser();
final String elephant = createTestUser();
doTestInTransaction(new Test<Void>()
{
Map<String, Integer> testMap = new HashMap<String, Integer>(2);
public Void run() throws Exception
{
testMap.put("monkey", Integer.valueOf(1));
testMap.put("elephant", Integer.valueOf(1));
testMap.put(monkey, Integer.valueOf(1));
testMap.put(elephant, Integer.valueOf(1));
assertFalse(extendedSecurityService.hasExtendedSecurity(filePlan));
assertFalse(extendedSecurityService.hasExtendedSecurity(rmContainer));
@@ -174,8 +197,8 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
assertNull(extendedSecurityService.getExtendedReaders(record));
Set<String> extendedReaders = new HashSet<String>(2);
extendedReaders.add("monkey");
extendedReaders.add("elephant");
extendedReaders.add(monkey);
extendedReaders.add(elephant);
extendedSecurityService.addExtendedSecurity(record, extendedReaders, null);

View File

@@ -19,6 +19,7 @@
package org.alfresco.module.org_alfresco_module_rm.test.service;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -27,8 +28,11 @@ 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.dod5015.DOD5015Model;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.role.Role;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
@@ -36,6 +40,7 @@ import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
@@ -188,6 +193,86 @@ public class RecordServiceImplTest extends BaseRMTestCase
}
});
}
public void testExtendedWriters() throws Exception
{
final ExtendedReaderDynamicAuthority readerDy = (ExtendedReaderDynamicAuthority)applicationContext.getBean("extendedReaderDynamicAuthority");
final ExtendedWriterDynamicAuthority writerDy = (ExtendedWriterDynamicAuthority)applicationContext.getBean("extendedWriterDynamicAuthority");
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
assertNull(extendedSecurityService.getExtendedReaders(recordOne));
assertNull(extendedSecurityService.getExtendedWriters(recordOne));
assertFalse(readerDy.hasAuthority(recordOne, dmCollaborator));
assertFalse(writerDy.hasAuthority(recordOne, dmCollaborator));
assertFalse(readerDy.hasAuthority(filePlan, dmCollaborator));
assertFalse(writerDy.hasAuthority(filePlan, dmCollaborator));
return null;
}
}, dmCollaborator);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(recordOne, RMPermissionModel.READ_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(recordOne, RMPermissionModel.FILING));
assertFalse(readerDy.hasAuthority(recordOne, dmCollaborator));
assertFalse(writerDy.hasAuthority(recordOne, dmCollaborator));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(filePlan, RMPermissionModel.EDIT_NON_RECORD_METADATA));
assertFalse(readerDy.hasAuthority(filePlan, dmCollaborator));
assertFalse(writerDy.hasAuthority(filePlan, dmCollaborator));
return null;
}
}, dmCollaborator);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
Set<String> writers = new HashSet<String>(1);
writers.add(dmCollaborator);
extendedSecurityService.addExtendedSecurity(recordOne, null, writers);
assertNull(extendedSecurityService.getExtendedReaders(recordOne));
assertFalse(extendedSecurityService.getExtendedWriters(recordOne).isEmpty());
return null;
}
});
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(recordOne, RMPermissionModel.READ_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(recordOne, RMPermissionModel.FILING));
assertFalse(readerDy.hasAuthority(recordOne, dmCollaborator));
assertTrue(writerDy.hasAuthority(recordOne, dmCollaborator));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan, RMPermissionModel.EDIT_NON_RECORD_METADATA));
return null;
}
}, dmCollaborator);
}
/**
* @see RecordService#createRecord(org.alfresco.service.cmr.repository.NodeRef,
@@ -240,6 +325,8 @@ public class RecordServiceImplTest extends BaseRMTestCase
AccessStatus.DENIED, // record category
AccessStatus.DENIED, // record folder
AccessStatus.ALLOWED); // doc/record
permissionReport();
assertEquals(AccessStatus.ALLOWED, dmPermissionService.hasPermission(filePlan,
RMPermissionModel.VIEW_RECORDS));
@@ -266,9 +353,9 @@ public class RecordServiceImplTest extends BaseRMTestCase
// ****
// Capability Tests
// ****
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan,
RMPermissionModel.VIEW_RECORDS));
RMPermissionModel.VIEW_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan,
RMPermissionModel.EDIT_NON_RECORD_METADATA));
@@ -307,7 +394,7 @@ public class RecordServiceImplTest extends BaseRMTestCase
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan,
RMPermissionModel.VIEW_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan,
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(filePlan,
RMPermissionModel.EDIT_NON_RECORD_METADATA));
Capability filling = capabilityService.getCapability("FileRecords");
@@ -323,6 +410,40 @@ public class RecordServiceImplTest extends BaseRMTestCase
}
}, dmConsumer);
}
private void permissionReport()
{
Set<String> writers = extendedSecurityService.getExtendedWriters(dmDocument);
for (String writer : writers)
{
System.out.println("writer: " + writer);
}
System.out.println("Users assigned to extended writers role:");
Set<String> assignedUsers = filePlanRoleService.getUsersAssignedToRole(filePlan, FilePlanRoleService.ROLE_EXTENDED_WRITERS);
for (String assignedUser : assignedUsers)
{
System.out.println(" ... " + assignedUser);
}
PermissionService ps = (PermissionService)applicationContext.getBean("permissionService");
Set<AccessPermission> perms = ps.getAllSetPermissions(filePlan);
for (AccessPermission perm : perms)
{
if (perm.getPermission().contains(RMPermissionModel.EDIT_NON_RECORD_METADATA))
{
System.out.println(" ... " + perm.getAuthority() + " - " + perm.getPermission() + " - " + perm.getAccessStatus().toString());
}
}
for (AccessPermission perm : perms)
{
if (perm.getPermission().contains(RMPermissionModel.VIEW_RECORDS))
{
System.out.println(" ... " + perm.getAuthority() + " - " + perm.getPermission() + " - " + perm.getAccessStatus().toString());
}
}
}
public void testCreateRecordNoLink() throws Exception
{
@@ -565,6 +686,8 @@ public class RecordServiceImplTest extends BaseRMTestCase
@Override
public void runImpl() throws Exception
{
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(recordOne, RMPermissionModel.READ_RECORDS));
assertFalse(recordService.isPropertyEditable(recordOne, PROP_ORIGINATING_ORGANIZATION));
assertFalse(recordService.isPropertyEditable(recordOne, PROP_DESCRIPTION));
assertFalse(recordService.isPropertyEditable(recordDeclaredOne, PROP_ORIGINATING_ORGANIZATION));
@@ -674,24 +797,6 @@ public class RecordServiceImplTest extends BaseRMTestCase
}
public abstract class CommitPropertyFailTest extends Test<Void>
{
@Override
public Void run() throws Exception
{
// TODO Auto-generated method stub
return null;
}
@Override
public void test(Void result) throws Exception
{
// TODO Auto-generated method stub
super.test(result);
}
}
private void cantEditProperty(final NodeRef nodeRef, final QName property, String user) throws Exception
{
boolean failure = false;