RM-582: A user can edit record meta-data if they have write permissions.

* all users that had 'write' permissions on a document when it becomes a record continue to have 'file' on that record.
* these users also have EditMetadata capability
* this include the owner of the document at the time it was made a record
* extended 'read' permissions for created records continues to work in the same way
* added an extended permission service with additional method to get the writers of a node .. configured and implemented as an extension to the core and held in the RM AMP (could be moved down at a later stage if appropriate)
* patches updated
* unit tests updated (and fixed)
* content model updated to more generic 'ExtendedSecurity' aspect with writers property
* service generalised as an ExtendedSecurityService with appropriate method changes
* mandatory parameter no longer mandatory in create-record action .. fixes issues seen in unit tests and UI

NOTE:  due to the nature of this change any db's created on an earlier 2.1 dev build will need to be reset .. going from 2.0.1 onwards will, however, be fine.



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@46270 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2013-02-06 04:53:35 +00:00
parent bc4f45f7c7
commit 66d9075500
23 changed files with 667 additions and 435 deletions

View File

@@ -239,9 +239,10 @@ public class RecordsManagementServiceImpl extends ServiceBaseImpl
ExtendedSecurityService extendedSecurityService = serviceRegistry.getExtendedSecurityService();
NodeRef parent = childAssocRef.getParentRef();
Set<String> readers = extendedSecurityService.getExtendedReaders(parent);
Set<String> writers = extendedSecurityService.getExtendedWriters(parent);
if (readers != null && readers.size() != 0)
{
extendedSecurityService.setExtendedReaders(thumbnail, readers, false);
extendedSecurityService.addExtendedSecurity(thumbnail, readers, writers, false);
}
}

View File

@@ -143,8 +143,13 @@ public class CreateRecordAction extends ActionExecuterAbstractBase
}
}
// indicate whether the record should be hidden or not
boolean hideRecord = ((Boolean)action.getParameterValue(PARAM_HIDE_RECORD)).booleanValue();
// indicate whether the record should be hidden or not (default not)
boolean hideRecord = false;
Boolean hideRecordValue = ((Boolean)action.getParameterValue(PARAM_HIDE_RECORD));
if (hideRecordValue != null)
{
hideRecord = hideRecordValue.booleanValue();
}
// create record from existing document
recordService.createRecord(filePlan, actionedUponNodeRef, !hideRecord);
@@ -159,7 +164,7 @@ public class CreateRecordAction extends ActionExecuterAbstractBase
{
// NOTE: commented out for now so that it doesn't appear in the UI ... enable later when multi-file plan support is added
//params.add(new ParameterDefinitionImpl(PARAM_FILE_PLAN, DataTypeDefinition.NODE_REF, false, getParamDisplayLabel(PARAM_FILE_PLAN)));
params.add(new ParameterDefinitionImpl(PARAM_HIDE_RECORD, DataTypeDefinition.BOOLEAN, true, getParamDisplayLabel(PARAM_HIDE_RECORD)));
params.add(new ParameterDefinitionImpl(PARAM_HIDE_RECORD, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_HIDE_RECORD)));
}
}

View File

@@ -93,17 +93,6 @@ public abstract class AbstractCapability extends RMSecurityCommon
capabilityService.registerCapability(this);
}
/**
* Registers an action
*
* @param action
*/
// public void registerAction(RecordsManagementAction action)
// {
// this.actions.add(action);
// this.actionNames.add(action.getName());
// }
/**
* @param name capability name
*/
@@ -205,37 +194,6 @@ public abstract class AbstractCapability extends RMSecurityCommon
}
}
/**
*
* @param nodeRef
* @return
*/
// public int checkActionConditionsIfPresent(NodeRef nodeRef)
// {
// String prefix = "checkActionConditionsIfPresent" + getName();
// int result = getTransactionCache(prefix, nodeRef);
// if (result != NOSET_VALUE)
// {
// return result;
// }
//
// if (actions.size() > 0)
// {
// for (RecordsManagementAction action : actions)
// {
// if (action.isExecutable(nodeRef, null))
// {
// return setTransactionCache(prefix, nodeRef, AccessDecisionVoter.ACCESS_GRANTED);
// }
// }
// return setTransactionCache(prefix, nodeRef, AccessDecisionVoter.ACCESS_DENIED);
// }
// else
// {
// return setTransactionCache(prefix, nodeRef, AccessDecisionVoter.ACCESS_GRANTED);
// }
// }
/**
* @see org.alfresco.module.org_alfresco_module_rm.capability.Capability#hasPermission(org.alfresco.service.cmr.repository.NodeRef)
*/
@@ -265,10 +223,6 @@ public abstract class AbstractCapability extends RMSecurityCommon
{
result = AccessDecisionVoter.ACCESS_DENIED;
}
// else if (checkActionConditionsIfPresent(nodeRef) == AccessDecisionVoter.ACCESS_DENIED)
// {
// result = AccessDecisionVoter.ACCESS_DENIED;
// }
else
{
result = hasPermissionImpl(nodeRef);
@@ -296,22 +250,6 @@ public abstract class AbstractCapability extends RMSecurityCommon
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.capability.Capability#getActionNames()
*/
// public List<String> getActionNames()
// {
// return actionNames;
// }
/**
* @see org.alfresco.module.org_alfresco_module_rm.capability.Capability#getActions()
*/
// public List<RecordsManagementAction> getActions()
// {
// return actions;
// }
/**
* @see org.alfresco.module.org_alfresco_module_rm.capability.Capability#getGroup()
*/

View File

@@ -169,7 +169,7 @@ public class DeclarativeCapability extends AbstractCapability
for (String permission : permissions)
{
if (permissionService.hasPermission(filePlan, permission) != AccessStatus.ALLOWED)
if (permissionService.hasPermission(filePlan, permission) != AccessStatus.ALLOWED)
{
result = false;
break;

View File

@@ -29,6 +29,7 @@ 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.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -159,6 +160,7 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
permissionService.setInheritParentPermissions(container, false);
permissionService.setPermission(container, allRoles, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(container, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(container, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
// TODO set the admin users to have filing permissions on the unfiled container!!!
// TODO we will need to be able to get a list of the admin roles from the service

View File

@@ -227,9 +227,10 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel
public static final QName ASPECT_LOADED_DATA_SET_ID = QName.createQName(RM_URI, "loadedDataSetId");
public static final QName PROP_LOADED_DATA_SET_IDS = QName.createQName(RM_URI, "loadedDataSetIds");
// Extended readers aspect
public static final QName ASPECT_EXTENDED_READERS = QName.createQName(RM_URI, "extendedReaders");
// Extended security aspect
public static final QName ASPECT_EXTENDED_SECURITY = QName.createQName(RM_URI, "extendedSecurity");
public static final QName PROP_READERS = QName.createQName(RM_URI, "readers");
public static final QName PROP_WRITERS = QName.createQName(RM_URI, "writers");
// Originating details of a record
public static final QName ASPECT_RECORD_ORIGINATING_DETAILS = QName.createQName(RM_URI, "recordOriginatingDetails");

View File

@@ -26,6 +26,7 @@ import org.alfresco.module.org_alfresco_module_rm.dod5015.DOD5015Model;
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.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService;
import org.alfresco.repo.module.AbstractModuleComponent;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -117,7 +118,11 @@ public class RMv21InPlacePatch extends AbstractModuleComponent
// set permissions
filePlanPermissionService.setPermission(filePlan, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS);
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_RECORD_METADATA, true);
// create unfiled container
filePlanService.createUnfiledContainer(filePlan);

View File

@@ -21,6 +21,7 @@ package org.alfresco.module.org_alfresco_module_rm.record;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -46,12 +47,14 @@ import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.security.permissions.impl.ExtendedPermissionService;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
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.AccessStatus;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ParameterCheck;
@@ -83,7 +86,7 @@ public class RecordServiceImpl implements RecordService,
private DictionaryService dictionaryService;
/** Permission service */
private PermissionService permissionService;
private ExtendedPermissionService permissionService;
/** Extended security service */
private ExtendedSecurityService extendedSecurityService;
@@ -102,6 +105,9 @@ public class RecordServiceImpl implements RecordService,
/** Policy component */
private PolicyComponent policyComponent;
/** Ownable service */
private OwnableService ownableService;
/** List of available record meta-data aspects */
private Set<QName> recordMetaDataAspects;
@@ -145,7 +151,7 @@ public class RecordServiceImpl implements RecordService,
/**
* @param permissionService permission service
*/
public void setPermissionService(PermissionService permissionService)
public void setPermissionService(ExtendedPermissionService permissionService)
{
this.permissionService = permissionService;
}
@@ -198,6 +204,14 @@ public class RecordServiceImpl implements RecordService,
this.policyComponent = policyComponent;
}
/**
* @param ownableService ownable service
*/
public void setOwnableService(OwnableService ownableService)
{
this.ownableService = ownableService;
}
/**
* Init method
*/
@@ -323,6 +337,13 @@ public class RecordServiceImpl implements RecordService,
// get the documents readers
Long aclId = nodeService.getNodeAclId(nodeRef);
Set<String> readers = permissionService.getReaders(aclId);
Set<String> writers = permissionService.getWriters(aclId);
// add the current owner to the list of extended writers
String owner = ownableService.getOwner(nodeRef);
// remove the owner
ownableService.setOwner(nodeRef, OwnableService.NO_OWNER);
// get the documents primary parent assoc
ChildAssociationRef parentAssoc = nodeService.getPrimaryParent(nodeRef);
@@ -345,8 +366,9 @@ public class RecordServiceImpl implements RecordService,
// maintain the original primary location
nodeService.addChild(parentAssoc.getParentRef(), nodeRef, parentAssoc.getTypeQName(), parentAssoc.getQName());
// set the readers
extendedSecurityService.setExtendedReaders(nodeRef, readers);
// set the extended security
extendedSecurityService.addExtendedSecurity(nodeRef, readers, writers);
extendedSecurityService.addExtendedSecurity(nodeRef, null, Collections.singleton(owner));
}
return null;
@@ -417,7 +439,7 @@ public class RecordServiceImpl implements RecordService,
// check whether this item is already an item or not
if (isRecord(record) == false)
{
// make the item a record
// make the item a recor
makeRecord(record);
}
@@ -483,7 +505,7 @@ public class RecordServiceImpl implements RecordService,
// remove the extended security from the node
// this prevents the users from continuing to see the record in searchs and other linked locations
extendedSecurityService.removeAllExtendedReaders(nodeRef);
extendedSecurityService.removeAllExtendedSecurity(nodeRef);
return null;
}
@@ -534,7 +556,7 @@ public class RecordServiceImpl implements RecordService,
nodeService.moveNode(nodeRef, originatingLocation, ContentModel.ASSOC_CONTAINS, parentAssoc.getQName());
// remove all extended readers
extendedSecurityService.removeAllExtendedReaders(nodeRef);
extendedSecurityService.removeAllExtendedSecurity(nodeRef);
// save the information about the rejection details
Map<QName, Serializable> aspectProperties = new HashMap<QName, Serializable>(3);

View File

@@ -32,6 +32,7 @@ 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.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
@@ -176,8 +177,12 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService,
permissionService.setInheritParentPermissions(rmRootNode, false);
permissionService.setPermission(rmRootNode, allRoles, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(rmRootNode, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.VIEW_RECORDS, true);
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_RECORD_METADATA, true);
// Create the unfiled record container
return filePlanService.createUnfiledContainer(rmRootNode);
}

View File

@@ -20,16 +20,7 @@ package org.alfresco.module.org_alfresco_module_rm.security;
import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.security.permissions.DynamicAuthority;
import org.alfresco.repo.security.permissions.PermissionReference;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* Extended readers dynamic authority implementation.
@@ -37,73 +28,11 @@ import org.springframework.context.ApplicationContextAware;
* @author Roy Wetherall
* @since 2.1
*/
public class ExtendedReaderDynamicAuthority implements DynamicAuthority,
RecordsManagementModel,
ApplicationContextAware
public class ExtendedReaderDynamicAuthority extends ExtendedSecurityBaseDynamicAuthority
{
/** Extended reader role */
public static final String EXTENDED_READER = "ROLE_EXTENDED_READER";
/** Authority service */
private AuthorityService authorityService;
/** Extended security service */
private ExtendedSecurityService extendedSecurityService;
/** Node service */
private NodeService nodeService;
/** Application context */
private 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
/**
* @return authority service
*/
private AuthorityService getAuthorityService()
{
if (authorityService == null)
{
authorityService = (AuthorityService)applicationContext.getBean("authorityService");
}
return authorityService;
}
/**
* @return extended security service
*/
public ExtendedSecurityService getExtendedSecurityService()
{
if (extendedSecurityService == null)
{
extendedSecurityService = (ExtendedSecurityService)applicationContext.getBean("extendedSecurityService");
}
return extendedSecurityService;
}
/**
* @return node service
*/
public NodeService getNodeService()
{
if (nodeService == null)
{
nodeService = (NodeService)applicationContext.getBean("nodeService");
}
return nodeService;
}
/**
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
/**
* @see org.alfresco.repo.security.permissions.DynamicAuthority#getAuthority()
*/
@@ -114,61 +43,10 @@ public class ExtendedReaderDynamicAuthority implements DynamicAuthority,
}
/**
* @see org.alfresco.repo.security.permissions.DynamicAuthority#hasAuthority(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityBaseDynamicAuthority#getAuthorites(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
public boolean hasAuthority(NodeRef nodeRef, String userName)
protected Set<String> getAuthorites(NodeRef nodeRef)
{
boolean result = false;
if (getNodeService().hasAspect(nodeRef, ASPECT_EXTENDED_READERS) == true)
{
Set<String> readers = getExtendedSecurityService().getExtendedReaders(nodeRef);
if (readers != null)
{
for (String reader : readers)
{
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);
if (contained.isEmpty() == false &&
contained.contains(userName) == true)
{
result = true;
break;
}
}
else
{
// presume we have a user
if (reader.equals(userName) == true)
{
result = true;
break;
}
}
}
}
}
return result;
}
/**
* @see org.alfresco.repo.security.permissions.DynamicAuthority#requiredFor()
*/
@Override
public Set<PermissionReference> requiredFor()
{
// TODO ... should we set something here? ReadRecord?
return null;
}
return getExtendedSecurityService().getExtendedReaders(nodeRef);
}
}

View File

@@ -0,0 +1,171 @@
/*
* Copyright (C) 2005-2012 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 java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.security.permissions.DynamicAuthority;
import org.alfresco.repo.security.permissions.PermissionReference;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* Extended readers dynamic authority implementation.
*
* @author Roy Wetherall
* @since 2.1
*/
public abstract class ExtendedSecurityBaseDynamicAuthority implements DynamicAuthority,
RecordsManagementModel,
ApplicationContextAware
{
/** Authority service */
private AuthorityService authorityService;
/** Extended security service */
private ExtendedSecurityService extendedSecurityService;
/** Node service */
private NodeService nodeService;
/** Application context */
private 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
/**
* @return authority service
*/
protected AuthorityService getAuthorityService()
{
if (authorityService == null)
{
authorityService = (AuthorityService)applicationContext.getBean("authorityService");
}
return authorityService;
}
/**
* @return extended security service
*/
protected ExtendedSecurityService getExtendedSecurityService()
{
if (extendedSecurityService == null)
{
extendedSecurityService = (ExtendedSecurityService)applicationContext.getBean("extendedSecurityService");
}
return extendedSecurityService;
}
/**
* @return node service
*/
protected NodeService getNodeService()
{
if (nodeService == null)
{
nodeService = (NodeService)applicationContext.getBean("nodeService");
}
return nodeService;
}
/**
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
/**
* Gets a list of the authorities from the extended security aspect that this dynamic
* authority is checking against.
*
* @param nodeRef
* @return
*/
protected abstract Set<String> getAuthorites(NodeRef nodeRef);
/**
* @see org.alfresco.repo.security.permissions.DynamicAuthority#hasAuthority(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
*/
@Override
public boolean hasAuthority(NodeRef nodeRef, String userName)
{
boolean result = false;
if (getNodeService().hasAspect(nodeRef, ASPECT_EXTENDED_SECURITY) == true)
{
Set<String> authorities = getAuthorites(nodeRef);
if (authorities != null)
{
for (String authority : authorities)
{
if ("GROUP_EVERYONE".equals(authority) == true)
{
// 'eveyone' is there so break
result = true;
break;
}
else if (authority.startsWith("GROUP_") == true)
{
// check group to see if the user is contained
Set<String> contained = getAuthorityService().getContainedAuthorities(AuthorityType.USER, authority, false);
if (contained.isEmpty() == false &&
contained.contains(userName) == true)
{
result = true;
break;
}
}
else
{
// presume we have a user
if (authority.equals(userName) == true)
{
result = true;
break;
}
}
}
}
}
return result;
}
/**
* Base implementation
*
* @see org.alfresco.repo.security.permissions.DynamicAuthority#requiredFor()
*/
@Override
public Set<PermissionReference> requiredFor()
{
return null;
}
}

View File

@@ -30,13 +30,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
*/
public interface ExtendedSecurityService
{
/**
* Indicates whether the node has any extended readers set or not.
*
* @param nodeRef node reference
* @return boolean true if the node has extended readers set, false otherwise
*/
boolean hasExtendedReaders(NodeRef nodeRef);
boolean hasExtendedSecurity(NodeRef nodeRef);
/**
* Gets the set authorities that are extended readers for the given node.
@@ -47,63 +41,22 @@ public interface ExtendedSecurityService
Set<String> getExtendedReaders(NodeRef nodeRef);
/**
* Set the authorities that are extended readers on the node. Applies extended readers to
* file plan parent hierarchy.
*
* @param nodeRef node reference
* @param readers extended readers
* @param nodeRef
* @return
*/
void setExtendedReaders(NodeRef nodeRef, Set<String> readers);
Set<String> getExtendedWriters(NodeRef nodeRef);
void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers);
/**
* Set the authorities that have extended reading permissions on the node.
* <p>
* Optionally applies the extended readers to the file plan hierarchy.
*
* @param nodeRef node reference
* @param readers extended readers
* @param applyToParents true if applied to file plan hierarchy, false otherwise
*/
void setExtendedReaders(NodeRef nodeRef, Set<String> readers, boolean applyToParents);
void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents);
/**
* Removes the given authorities from the extended readers set for this node.
* <p>
* Applies to file plan hierarchy.
*
* @param nodeRef node reference
* @param readers extended readers
*/
void removeExtendedReaders(NodeRef nodeRef, Set<String> readers);
void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers);
/**
* Removes the given authorities from the extended readers set for this node.
* <p>
* Optionally applies the removal to the file plan hierarchy.
*
* @param nodeRef node reference
* @param readers extended readers
* @param applyToParents true if applied to the file plan hierarchy, false otherwise
*/
void removeExtendedReaders(NodeRef nodeRef, Set<String> readers, boolean applyToParents);
void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents);
/**
* Removes all extended readers from this node.
* <p>
* Applies removal to the file plan hierarchy.
*
* @param nodeRef node reference
*/
void removeAllExtendedReaders(NodeRef nodeRef);
void removeAllExtendedSecurity(NodeRef nodeRef);
/**
* Removes all extended readers from this node.
* <p>
* Optionally applies the removal to the file plan hierarchy.
*
* @param nodeRef node reference
* @param applyToParents true if applied to the file plan hierarchy, false otherwise
*/
void removeAllExtendedReaders(NodeRef nodeRef, boolean applyToParents);
void removeAllExtendedSecurity(NodeRef nodeRef, boolean applyToParents);
}

View File

@@ -28,6 +28,7 @@ import org.alfresco.model.RenditionModel;
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.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
@@ -36,7 +37,6 @@ 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.repository.NodeService;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.ParameterCheck;
@@ -46,16 +46,14 @@ import org.alfresco.util.ParameterCheck;
* @author Roy Wetherall
* @since 2.1
*/
public class ExtendedSecurityServiceImpl implements ExtendedSecurityService,
public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
implements ExtendedSecurityService,
RecordsManagementModel,
NodeServicePolicies.OnMoveNodePolicy
{
/** Policy component */
private PolicyComponent policyComponent;
/** Node service */
private NodeService nodeService;
/** Records management service */
private RecordsManagementService recordsManagementService;
@@ -86,14 +84,6 @@ public class ExtendedSecurityServiceImpl implements ExtendedSecurityService,
this.recordsManagementService = recordsManagementService;
}
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Init method
*/
@@ -101,23 +91,16 @@ public class ExtendedSecurityServiceImpl implements ExtendedSecurityService,
{
policyComponent.bindClassBehaviour(
NodeServicePolicies.OnMoveNodePolicy.QNAME,
ASPECT_EXTENDED_READERS,
ASPECT_EXTENDED_SECURITY,
new JavaBehaviour(this, "onMoveNode", NotificationFrequency.TRANSACTION_COMMIT));
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#hasExtendedReaders(org.alfresco.service.cmr.repository.NodeRef)
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#hasExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
public boolean hasExtendedReaders(NodeRef nodeRef)
public boolean hasExtendedSecurity(NodeRef nodeRef)
{
boolean result = false;
Set<String> extendedReaders = getExtendedReaders(nodeRef);
if (extendedReaders != null && extendedReaders.size() != 0)
{
result = true;
}
return result;
return nodeService.hasAspect(nodeRef, ASPECT_EXTENDED_SECURITY);
}
/**
@@ -137,61 +120,72 @@ public class ExtendedSecurityServiceImpl implements ExtendedSecurityService,
return result;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#setExtendedReaders(org.alfresco.service.cmr.repository.NodeRef, java.util.Set)
*/
@Override
public void setExtendedReaders(NodeRef nodeRef, Set<String> readers)
{
setExtendedReaders(nodeRef, readers, true);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#setExtendedReaders(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, boolean)
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#getExtendedWriters(org.alfresco.service.cmr.repository.NodeRef)
*/
@SuppressWarnings("unchecked")
@Override
public void setExtendedReaders(NodeRef nodeRef, java.util.Set<String> readers, boolean applyToParents)
{
public Set<String> getExtendedWriters(NodeRef nodeRef)
{
Set<String> result = null;
Map<String, Integer> map = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_WRITERS);
if (map != null)
{
result = map.keySet();
}
return result;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#addExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set)
*/
@Override
public void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers)
{
addExtendedSecurity(nodeRef, readers, writers, true);
}
/**
* @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)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
ParameterCheck.mandatory("readers", readers);
ParameterCheck.mandatory("applyToParents", applyToParents);
if (nodeRef != null && readers.isEmpty() == false)
if (nodeRef != null)
{
// add the aspect if missing
if (nodeService.hasAspect(nodeRef, ASPECT_EXTENDED_READERS) == false)
if (nodeService.hasAspect(nodeRef, ASPECT_EXTENDED_SECURITY) == false)
{
nodeService.addAspect(nodeRef, ASPECT_EXTENDED_READERS, null);
nodeService.addAspect(nodeRef, ASPECT_EXTENDED_SECURITY, null);
}
// get reader map
Map<String, Integer> readersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_READERS);
if (readersMap == null)
// update the readers map
if (readers != null && readers.size() != 0)
{
// create reader map
readersMap = new HashMap<String, Integer>(7);
// 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));
}
for (String reader : readers)
// update the writers map
if (writers != null && writers.size() != 0)
{
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));
}
// 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));
}
// set the readers property (this will in turn apply the aspect if required)
nodeService.setProperty(nodeRef, PROP_READERS, (Serializable)readersMap);
// apply the readers to any renditions of the content
if (recordService.isRecord(nodeRef) == true)
{
@@ -199,41 +193,69 @@ public class ExtendedSecurityServiceImpl implements ExtendedSecurityService,
for (ChildAssociationRef assoc : assocs)
{
NodeRef child = assoc.getChildRef();
setExtendedReaders(child, readers, false);
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)
{
setExtendedReaders(parent, readers);
addExtendedSecurity(parent, readers, null);
addExtendedSecurity(parent, writers, null);
}
}
}
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#removeExtendedReaders(org.alfresco.service.cmr.repository.NodeRef, java.util.Set)
*
* @param map
* @param keys
* @return
*/
@Override
public void removeExtendedReaders(NodeRef nodeRef, Set<String> readers)
private Map<String, Integer> addToMap(Map<String, Integer> map, Set<String> keys)
{
removeExtendedReaders(nodeRef, readers, true);
if (map == null)
{
// create map
map = new HashMap<String, Integer>(7);
}
for (String key : keys)
{
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));
}
}
return map;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#removeExtendedReaders(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, boolean)
*/
@Override
public void removeExtendedReaders(NodeRef nodeRef, Set<String> readers, boolean applyToParents)
public void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers)
{
if (hasExtendedReaders(nodeRef) == true)
removeExtendedSecurity(nodeRef, readers, writers, true);
}
@Override
public void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String>writers, boolean applyToParents)
{
if (hasExtendedSecurity(nodeRef) == true)
{
removeExtendedReadersImpl(nodeRef, readers);
removeExtendedSecurityImpl(nodeRef, readers, writers);
// remove the readers from any renditions of the content
if (recordService.isRecord(nodeRef) == true)
@@ -242,7 +264,7 @@ public class ExtendedSecurityServiceImpl implements ExtendedSecurityService,
for (ChildAssociationRef assoc : assocs)
{
NodeRef child = assoc.getChildRef();
removeExtendedReadersImpl(child, readers);
removeExtendedSecurityImpl(child, readers, writers);
}
}
@@ -253,80 +275,83 @@ public class ExtendedSecurityServiceImpl implements ExtendedSecurityService,
if (parent != null &&
recordsManagementService.isFilePlanComponent(parent) == true)
{
removeExtendedReaders(parent, readers, applyToParents);
removeExtendedSecurity(parent, readers, null, applyToParents);
removeExtendedSecurity(parent, writers, null, applyToParents);
}
}
}
}
/**
* Removes a set of readers from a node reference.
* Removes a set of readers and writers from a node reference.
* <p>
* Removes the aspect and resets the property to null if all readers are removed.
* Removes the aspect and resets the property to null if all readers and writers are removed.
*
* @param nodeRef node reference
* @param readers {@link Set} of readers
* @param writers {@link Set} of writers
*/
@SuppressWarnings("unchecked")
private void removeExtendedReadersImpl(NodeRef nodeRef, Set<String> readers)
private void removeExtendedSecurityImpl(NodeRef nodeRef, Set<String> readers, Set<String> writers)
{
Map<String, Integer> readersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_READERS);
nodeService.setProperty(nodeRef, PROP_READERS, (Serializable)removeFromMap(readersMap, readers));
// remove the readers
for (String reader : readers)
Map<String, Integer> writersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_WRITERS);
nodeService.setProperty(nodeRef, PROP_WRITERS, (Serializable)removeFromMap(writersMap, writers));
if (readersMap == null && writersMap == null)
{
Integer readerCount = readersMap.get(reader);
if (readerCount != null)
// remove the aspect
nodeService.removeAspect(nodeRef, ASPECT_EXTENDED_SECURITY);
}
}
private Map<String, Integer> removeFromMap(Map<String, Integer> map, Set<String> keys)
{
if (map != null && keys != null && keys.size() != 0)
{
// remove the keys
for (String key : keys)
{
if (readerCount == 1)
Integer count = map.get(key);
if (count != null)
{
// remove entry all together if the reference count is now 0
readersMap.remove(reader);
}
else
{
// decrement the reference count by 1
readersMap.put(reader, Integer.valueOf(readerCount.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));
}
}
}
}
// reset the map to null if now empty
if (readersMap.isEmpty() == true)
if (map != null && map.isEmpty() == true)
{
readersMap = null;
map = null;
}
// set the property and remove the aspect if appropriate
nodeService.setProperty(nodeRef, PROP_READERS, (Serializable)readersMap);
if (readersMap == null)
{
nodeService.removeAspect(nodeRef, ASPECT_EXTENDED_READERS);
}
return map;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#removeAllExtendedReaders(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
public void removeAllExtendedReaders(NodeRef nodeRef)
public void removeAllExtendedSecurity(NodeRef nodeRef)
{
removeAllExtendedReaders(nodeRef, true);
removeAllExtendedSecurity(nodeRef, true);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#removeAllExtendedReaders(org.alfresco.service.cmr.repository.NodeRef, boolean)
*/
@Override
public void removeAllExtendedReaders(NodeRef nodeRef, boolean applyToParents)
public void removeAllExtendedSecurity(NodeRef nodeRef, boolean applyToParents)
{
if (hasExtendedReaders(nodeRef) == true)
if (hasExtendedSecurity(nodeRef) == true)
{
Set<String> readers = getExtendedReaders(nodeRef);
if (readers != null && readers.isEmpty() == false)
{
removeExtendedReaders(nodeRef, readers);
}
removeExtendedSecurity(nodeRef, getExtendedReaders(nodeRef), getExtendedWriters(nodeRef));
}
}
@@ -346,11 +371,10 @@ public class ExtendedSecurityServiceImpl implements ExtendedSecurityService,
NodeRef oldParent = origAssoc.getParentRef();
Set<String> readers = getExtendedReaders(record);
if (readers != null && readers.size() != 0)
{
setExtendedReaders(newParent, readers);
removeExtendedReaders(oldParent, readers);
}
Set<String> writers = getExtendedWriters(record);
addExtendedSecurity(newParent, readers, writers);
removeExtendedSecurity(oldParent, readers, writers);
return null;
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2005-2012 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 java.util.Set;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Extended writers dynamic authority implementation.
*
* @author Roy Wetherall
* @since 2.1
*/
public class ExtendedWriterDynamicAuthority extends ExtendedSecurityBaseDynamicAuthority
{
/** Extended writer role */
public static final String EXTENDED_WRITER = "ROLE_EXTENDED_WRITER";
/**
* @see org.alfresco.repo.security.permissions.DynamicAuthority#getAuthority()
*/
@Override
public String getAuthority()
{
return EXTENDED_WRITER;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityBaseDynamicAuthority#getAuthorites(org.alfresco.service.cmr.repository.NodeRef)
*/
protected Set<String> getAuthorites(NodeRef nodeRef)
{
return getExtendedSecurityService().getExtendedWriters(nodeRef);
}
}

View File

@@ -171,14 +171,15 @@ public class FilePlanPermissionServiceImpl implements FilePlanPermissionService,
final NodeRef catNodeRef = childAssocRef.getParentRef();
if (nodeService.exists(catNodeRef) == true)
{
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork()
{
Set<AccessPermission> perms = permissionService.getAllSetPermissions(catNodeRef);
for (AccessPermission perm : perms)
{
if (ExtendedReaderDynamicAuthority.EXTENDED_READER.equals(perm.getAuthority()) == false)
if (ExtendedReaderDynamicAuthority.EXTENDED_READER.equals(perm.getAuthority()) == false &&
ExtendedWriterDynamicAuthority.EXTENDED_WRITER.equals(perm.getAuthority()) == false)
{
AccessStatus accessStatus = perm.getAccessStatus();
boolean allow = false;
@@ -217,6 +218,7 @@ public class FilePlanPermissionServiceImpl implements FilePlanPermissionService,
// set extended reader permissions
permissionService.setPermission(nodeRef, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(nodeRef, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
return null;
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2005-2012 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.repo.security.permissions.impl;
import java.util.Set;
import org.alfresco.service.cmr.security.PermissionService;
/**
* Extended Permission Service Interface used in RM.
*
* @author Roy Wetherall
* @since 2.1
*/
public interface ExtendedPermissionService extends PermissionService
{
public Set<String> getWriters(Long aclId);
}

View File

@@ -18,14 +18,18 @@
*/
package org.alfresco.repo.security.permissions.impl;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.security.permissions.AccessControlEntry;
import org.alfresco.repo.security.permissions.AccessControlList;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.util.PropertyCheck;
import org.springframework.context.ApplicationEvent;
/**
* Extends the core permission service implementation allowing the consideration of the read records
@@ -36,7 +40,31 @@ import org.alfresco.service.cmr.security.PermissionService;
* @author Roy Wetherall
*/
public class RMPermissionServiceImpl extends PermissionServiceImpl
implements ExtendedPermissionService
{
protected SimpleCache<Serializable, Set<String>> writersCache;
@Override
public void setAnyDenyDenies(boolean anyDenyDenies)
{
super.setAnyDenyDenies(anyDenyDenies);
writersCache.clear();
}
/**
* @param writersCache the writersCache to set
*/
public void setWritersCache(SimpleCache<Serializable, Set<String>> writersCache)
{
this.writersCache = writersCache;
}
@Override
protected void onBootstrap(ApplicationEvent event)
{
super.onBootstrap(event);
PropertyCheck.mandatory(this, "writersCache", writersCache);
}
/**
* Builds the set of authorities who can read the given ACL. No caching is done here.
@@ -103,5 +131,44 @@ public class RMPermissionServiceImpl extends PermissionServiceImpl
}
return denied;
}
/**
* @see org.alfresco.repo.security.permissions.impl.ExtendedPermissionService#getWriters(java.lang.Long)
*/
public Set<String> getWriters(Long aclId)
{
AccessControlList acl = aclDaoComponent.getAccessControlList(aclId);
if (acl == null)
{
return Collections.emptySet();
}
Set<String> aclWriters = writersCache.get((Serializable)acl.getProperties());
if (aclWriters != null)
{
return aclWriters;
}
HashSet<String> assigned = new HashSet<String>();
HashSet<String> readers = new HashSet<String>();
for (AccessControlEntry ace : acl.getEntries())
{
assigned.add(ace.getAuthority());
}
for (String authority : assigned)
{
UnconditionalAclTest test = new UnconditionalAclTest(getPermissionReference(PermissionService.WRITE));
if (test.evaluate(authority, aclId))
{
readers.add(authority);
}
}
aclWriters = Collections.unmodifiableSet(readers);
writersCache.put((Serializable)acl.getProperties(), aclWriters);
return aclWriters;
}
}