mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
RM-600: A user with the "EditDocumentMetaData" capability can only edit the properties of the records content.
* record service extended with isPropertyEditable method .. indicates, based on the capabilities of the current user and the nature of the property, whether it can be edited * the record service monitors record aspect property updates and throws ModelExceptions if a user tries to update a record or non-record property if they don't have the appropriate capability * form filter updated to protect record properties the current user may not be able to edit * unit tests So what does this all mean? It means we can control the write permissions of individual properties on a record based on capabilities. In this case we slice the capability to edit a record in two .. you can either edit the content properties (ie the normal meta-data) or the record properties .. or both of course! git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@49041 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -30,6 +30,7 @@ import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase;
|
||||
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
@@ -59,7 +60,7 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase
|
||||
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@Override
|
||||
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
|
||||
protected void executeImpl(final Action action, final NodeRef actionedUponNodeRef)
|
||||
{
|
||||
if (recordService.isRecord(actionedUponNodeRef) == true)
|
||||
{
|
||||
@@ -75,8 +76,16 @@ public class DeclareRecordAction extends RMActionExecuterAbstractBase
|
||||
declaredProps.put(PROP_DECLARED_BY, AuthenticationUtil.getRunAsUser());
|
||||
this.nodeService.addAspect(actionedUponNodeRef, ASPECT_DECLARED_RECORD, declaredProps);
|
||||
|
||||
// remove all owner related rights
|
||||
this.ownableService.setOwner(actionedUponNodeRef, OwnableService.NO_OWNER);
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
// remove all owner related rights
|
||||
ownableService.setOwner(actionedUponNodeRef, OwnableService.NO_OWNER);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 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.capability.impl;
|
||||
|
||||
import net.sf.acegisecurity.vote.AccessDecisionVoter;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.capability.declarative.DeclarativeCapability;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.security.OwnableService;
|
||||
|
||||
/**
|
||||
* Edit capability, checks the permission and whether the current user is the owner of the
|
||||
* object.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class EditCapability extends DeclarativeCapability
|
||||
{
|
||||
private OwnableService ownableService;
|
||||
|
||||
private OwnableService getOwnableService()
|
||||
{
|
||||
if (ownableService == null)
|
||||
{
|
||||
ownableService = (OwnableService)applicationContext.getBean("OwnableService");
|
||||
}
|
||||
return ownableService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.capability.declarative.DeclarativeCapability#evaluate(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public int evaluate(final NodeRef nodeRef)
|
||||
{
|
||||
// The default state is not knowing anything
|
||||
int result = AccessDecisionVoter.ACCESS_ABSTAIN;
|
||||
|
||||
// Check we are dealing with a file plan component
|
||||
if (rmService.isFilePlanComponent(nodeRef) == true)
|
||||
{
|
||||
// Now the default state is denied
|
||||
result = AccessDecisionVoter.ACCESS_DENIED;
|
||||
|
||||
// Check the kind of the object, the permissions and the conditions
|
||||
if (checkKinds(nodeRef) == true && checkConditions(nodeRef) == true)
|
||||
{
|
||||
if (checkPermissions(nodeRef) == true)
|
||||
{
|
||||
result = AccessDecisionVoter.ACCESS_GRANTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = AuthenticationUtil.runAs(new RunAsWork<Integer>()
|
||||
{
|
||||
@Override
|
||||
public Integer doWork() throws Exception
|
||||
{
|
||||
Integer result = Integer.valueOf(AccessDecisionVoter.ACCESS_DENIED);
|
||||
|
||||
// Since we know this is undeclared if you are the owner then you should be able to
|
||||
// edit the records meta-data (otherwise how can it be declared by the user?)
|
||||
if (getOwnableService().hasOwner(nodeRef) == true)
|
||||
{
|
||||
String user = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
if (user != null &&
|
||||
getOwnableService().getOwner(nodeRef).equals(user) == true)
|
||||
{
|
||||
result = Integer.valueOf(AccessDecisionVoter.ACCESS_GRANTED);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}, AuthenticationUtil.getSystemUserName()).intValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -38,6 +38,7 @@ import org.alfresco.repo.forms.Form;
|
||||
import org.alfresco.repo.forms.PropertyFieldDefinition;
|
||||
import org.alfresco.repo.forms.processor.node.FieldUtils;
|
||||
import org.alfresco.repo.forms.processor.node.FormFieldConstants;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
@@ -91,9 +92,10 @@ public class RecordsManagementNodeFormFilter extends RecordsManagementFormFilter
|
||||
this.dispositionService = dispositionService;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* @see org.alfresco.repo.forms.processor.Filter#afterGenerate(java.lang.Object, java.util.List, java.util.List, org.alfresco.repo.forms.Form, java.util.Map)
|
||||
*/
|
||||
@Override
|
||||
public void afterGenerate(
|
||||
NodeRef nodeRef,
|
||||
List<String> fields,
|
||||
@@ -118,6 +120,9 @@ public class RecordsManagementNodeFormFilter extends RecordsManagementFormFilter
|
||||
// add the supplemental marking list property
|
||||
forceSupplementalMarkingListProperty(form, nodeRef);
|
||||
|
||||
// protect uneditable properties
|
||||
protectRecordProperties(form, nodeRef);
|
||||
|
||||
// if the record is the result of an email we need to 'protect' some fields
|
||||
if (this.nodeService.hasAspect(nodeRef, ImapModel.ASPECT_IMAP_CONTENT))
|
||||
{
|
||||
@@ -147,6 +152,11 @@ public class RecordsManagementNodeFormFilter extends RecordsManagementFormFilter
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param form
|
||||
* @param nodeRef
|
||||
*/
|
||||
protected void addCustomPropertyFieldsToGroup(Form form, NodeRef nodeRef)
|
||||
{
|
||||
Set<QName> customisables = rmAdminService.getCustomisable(nodeRef);
|
||||
@@ -165,6 +175,11 @@ public class RecordsManagementNodeFormFilter extends RecordsManagementFormFilter
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param form
|
||||
* @param nodeRef
|
||||
*/
|
||||
protected void addRecordMetadataPropertyFieldsToGroup(Form form, NodeRef nodeRef)
|
||||
{
|
||||
Set<QName> aspects = recordService.getRecordMetaDataAspects();
|
||||
@@ -210,7 +225,11 @@ public class RecordsManagementNodeFormFilter extends RecordsManagementFormFilter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param form
|
||||
* @param nodeRef
|
||||
*/
|
||||
protected void addTransientProperties(Form form, NodeRef nodeRef)
|
||||
{
|
||||
if (recordService.isRecord(nodeRef) == true)
|
||||
@@ -239,6 +258,13 @@ public class RecordsManagementNodeFormFilter extends RecordsManagementFormFilter
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param form
|
||||
* @param name
|
||||
* @param type
|
||||
* @param value
|
||||
*/
|
||||
protected void addTransientPropertyField(Form form, String name, QName type, Object value)
|
||||
{
|
||||
String dataKeyName = FormFieldConstants.PROP_DATA_PREFIX + name;
|
||||
@@ -251,6 +277,47 @@ public class RecordsManagementNodeFormFilter extends RecordsManagementFormFilter
|
||||
form.addData(dataKeyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param form
|
||||
* @param nodeRef
|
||||
*/
|
||||
protected void protectRecordProperties(Form form, NodeRef nodeRef)
|
||||
{
|
||||
List<FieldDefinition> fieldDefs = form.getFieldDefinitions();
|
||||
for (FieldDefinition fieldDef : fieldDefs)
|
||||
{
|
||||
if (fieldDef.isProtectedField() == false)
|
||||
{
|
||||
String name = fieldDef.getName();
|
||||
String prefixName = null;
|
||||
if ("size".equals(name) || "mimetype".equals(name) || "encoding".equals(name))
|
||||
{
|
||||
prefixName = "cm:content";
|
||||
}
|
||||
else
|
||||
{
|
||||
prefixName = fieldDef.getName();
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled() == true)
|
||||
{
|
||||
logger.debug("Checking property " + prefixName + " is editable by user " + AuthenticationUtil.getFullyAuthenticatedUser());
|
||||
}
|
||||
|
||||
QName qname = QName.createQName(prefixName, namespaceService);
|
||||
if (recordService.isPropertyEditable(nodeRef, qname) == false)
|
||||
{
|
||||
if (logger.isDebugEnabled() == true)
|
||||
{
|
||||
logger.debug(" ... protected property");
|
||||
}
|
||||
fieldDef.setProtectedField(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks all the fields that contain data extracted from an email
|
||||
* as protected fields.
|
||||
|
@@ -128,7 +128,7 @@ public class RecordContainerType implements RecordsManagementModel,
|
||||
@Override
|
||||
public void onCreateChildAssociation(final ChildAssociationRef childAssocRef, boolean isNewNode)
|
||||
{
|
||||
filePlanAuthenticationService.runAsRmAdmin(new RunAsWork<Void>()
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
|
@@ -45,44 +45,69 @@ public abstract class ProtectedModelArtifact
|
||||
/** Set of capabilities */
|
||||
private Set<Capability> capabilities;
|
||||
|
||||
/** Capability names */
|
||||
private Set<String> capabilityNames;
|
||||
|
||||
/**
|
||||
* @param namespaceService namespace service
|
||||
*/
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param modelSecurityService model security service
|
||||
*/
|
||||
public void setModelSecurityService(ModelSecurityService modelSecurityService)
|
||||
{
|
||||
this.modelSecurityService = modelSecurityService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
modelSecurityService.register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name artifact name (in cm:content form)
|
||||
*/
|
||||
public void setName(String name)
|
||||
{
|
||||
QName qname = QName.createQName(name, namespaceService);
|
||||
this.name = qname;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return artifact QName
|
||||
*/
|
||||
public QName getQName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param capabilities capabilities
|
||||
*/
|
||||
public void setCapabilities(Set<Capability> capabilities)
|
||||
{
|
||||
this.capabilities = capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return capabilities
|
||||
*/
|
||||
public Set<Capability> getCapabilities()
|
||||
{
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return capability names
|
||||
*/
|
||||
public Set<String> getCapilityNames()
|
||||
{
|
||||
if (capabilityNames == null && capabilities != null)
|
||||
|
@@ -96,4 +96,13 @@ public interface RecordService
|
||||
* @param reason The reason for rejection
|
||||
*/
|
||||
void rejectRecord(NodeRef nodeRef, String reason);
|
||||
|
||||
/**
|
||||
* Indicates whether a property of a record is editable for the current user or not.
|
||||
*
|
||||
* @param record record
|
||||
* @param property property
|
||||
* @return boolean true if editable, false otherwise.
|
||||
*/
|
||||
boolean isPropertyEditable(NodeRef record, QName property);
|
||||
}
|
||||
|
@@ -31,11 +31,16 @@ 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.CapabilityService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule;
|
||||
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService;
|
||||
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.identifier.IdentifierService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementCustomModel;
|
||||
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.security.ExtendedSecurityService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordServiceImpl;
|
||||
@@ -48,31 +53,80 @@ 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.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
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.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.OwnableService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.EqualsHelper;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* Record service implementation
|
||||
* Record service implementation.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
* @since 2.1
|
||||
*/
|
||||
public class RecordServiceImpl implements RecordService,
|
||||
RecordsManagementModel,
|
||||
RecordsManagementCustomModel,
|
||||
NodeServicePolicies.OnCreateChildAssociationPolicy,
|
||||
NodeServicePolicies.OnUpdatePropertiesPolicy,
|
||||
ApplicationContextAware
|
||||
{
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(RecordServiceImpl.class);
|
||||
|
||||
/** Always edit property array */
|
||||
private static final QName[] ALWAYS_EDIT_PROPERTIES = new QName[]
|
||||
{
|
||||
ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA
|
||||
};
|
||||
|
||||
private static final String[] ALWAYS_EDIT_URIS = new String[]
|
||||
{
|
||||
NamespaceService.SECURITY_MODEL_1_0_URI,
|
||||
NamespaceService.SYSTEM_MODEL_1_0_URI,
|
||||
NamespaceService.WORKFLOW_MODEL_1_0_URI,
|
||||
NamespaceService.APP_MODEL_1_0_URI,
|
||||
NamespaceService.DATALIST_MODEL_1_0_URI,
|
||||
NamespaceService.DICTIONARY_MODEL_1_0_URI,
|
||||
NamespaceService.BPM_MODEL_1_0_URI,
|
||||
NamespaceService.RENDITION_MODEL_1_0_URI
|
||||
};
|
||||
|
||||
private static final String[] RECORD_MODEL_URIS = new String[]
|
||||
{
|
||||
RM_URI,
|
||||
RM_CUSTOM_URI,
|
||||
DOD5015Model.DOD_URI
|
||||
};
|
||||
|
||||
private static final String[] NON_RECORD_MODEL_URIS = new String[]
|
||||
{
|
||||
NamespaceService.AUDIO_MODEL_1_0_URI,
|
||||
NamespaceService.CONTENT_MODEL_1_0_URI,
|
||||
NamespaceService.EMAILSERVER_MODEL_URI,
|
||||
NamespaceService.EXIF_MODEL_1_0_URI,
|
||||
NamespaceService.FORUMS_MODEL_1_0_URI,
|
||||
NamespaceService.LINKS_MODEL_1_0_URI,
|
||||
NamespaceService.REPOSITORY_VIEW_1_0_URI
|
||||
|
||||
};
|
||||
|
||||
/** Application context */
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@@ -108,15 +162,22 @@ public class RecordServiceImpl implements RecordService,
|
||||
|
||||
/** Ownable service */
|
||||
private OwnableService ownableService;
|
||||
|
||||
/** Capability service */
|
||||
private CapabilityService capabilityService;
|
||||
|
||||
/** List of available record meta-data aspects */
|
||||
private Set<QName> recordMetaDataAspects;
|
||||
private Set<QName> recordMetaDataAspects;
|
||||
|
||||
/** Behaviours */
|
||||
private JavaBehaviour onCreateChildAssociation = new JavaBehaviour(
|
||||
this,
|
||||
"onCreateChildAssociation",
|
||||
NotificationFrequency.FIRST_EVENT);
|
||||
private JavaBehaviour onUpdateProperties = new JavaBehaviour(
|
||||
this,
|
||||
"onUpdateProperties",
|
||||
NotificationFrequency.EVERY_EVENT);
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
|
||||
@@ -211,6 +272,14 @@ public class RecordServiceImpl implements RecordService,
|
||||
{
|
||||
this.ownableService = ownableService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param capabilityService capability service
|
||||
*/
|
||||
public void setCapabilityService(CapabilityService capabilityService)
|
||||
{
|
||||
this.capabilityService = capabilityService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method
|
||||
@@ -222,6 +291,10 @@ public class RecordServiceImpl implements RecordService,
|
||||
TYPE_RECORD_FOLDER,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
onCreateChildAssociation);
|
||||
policyComponent.bindClassBehaviour(
|
||||
NodeServicePolicies.OnUpdatePropertiesPolicy.QNAME,
|
||||
ASPECT_RECORD,
|
||||
onUpdateProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,6 +312,56 @@ public class RecordServiceImpl implements RecordService,
|
||||
file(nodeRef);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the user only updates record properties that they have permission to.
|
||||
*
|
||||
* @see org.alfresco.repo.node.NodeServicePolicies.OnUpdatePropertiesPolicy#onUpdateProperties(org.alfresco.service.cmr.repository.NodeRef, java.util.Map, java.util.Map)
|
||||
*/
|
||||
@Override
|
||||
public void onUpdateProperties(final NodeRef nodeRef, final Map<QName, Serializable> before, final Map<QName, Serializable> after)
|
||||
{
|
||||
onUpdateProperties.disable();
|
||||
try
|
||||
{
|
||||
if (AuthenticationUtil.getFullyAuthenticatedUser() != null &&
|
||||
AuthenticationUtil.isRunAsUserTheSystemUser() == false &&
|
||||
nodeService.exists(nodeRef) == true)
|
||||
{
|
||||
if (isRecord(nodeRef) == true)
|
||||
{
|
||||
for (QName property : after.keySet())
|
||||
{
|
||||
Serializable beforeValue = null;
|
||||
if (before != null)
|
||||
{
|
||||
beforeValue = before.get(property);
|
||||
}
|
||||
|
||||
Serializable afterValue = null;
|
||||
if (after != null)
|
||||
{
|
||||
afterValue = after.get(property);
|
||||
}
|
||||
|
||||
if (EqualsHelper.nullSafeEquals(beforeValue, afterValue) == false &&
|
||||
isPropertyEditable(nodeRef, property) == false)
|
||||
{
|
||||
// the user can't edit the record property
|
||||
throw new ModelAccessDeniedException(
|
||||
"The user " + AuthenticationUtil.getFullyAuthenticatedUser() +
|
||||
" does not have the permission to edit the record property " + property.toString() +
|
||||
" on the node " + nodeRef.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
onUpdateProperties.enable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#getRecordMetaDataAspects()
|
||||
@@ -579,4 +702,120 @@ public class RecordServiceImpl implements RecordService,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#isPropertyEditable(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
|
||||
*/
|
||||
@Override
|
||||
public boolean isPropertyEditable(NodeRef record, QName property)
|
||||
{
|
||||
ParameterCheck.mandatory("record", record);
|
||||
ParameterCheck.mandatory("property", property);
|
||||
|
||||
if (isRecord(record) == false)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Can not check if the property " + property.toString() + " is editable, because node reference is not a record.");
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled() == true)
|
||||
{
|
||||
logger.debug("Checking whether property " + property.toString() + " is editable for user " + AuthenticationUtil.getRunAsUser());
|
||||
}
|
||||
|
||||
boolean result = alwaysEditProperty(property);
|
||||
if (result == false)
|
||||
{
|
||||
boolean allowRecordEdit = false;
|
||||
boolean allowNonRecordEdit = false;
|
||||
|
||||
AccessStatus accessNonRecord = capabilityService.getCapabilityAccessState(record, RMPermissionModel.EDIT_NON_RECORD_METADATA);
|
||||
AccessStatus accessDeclaredRecord = capabilityService.getCapabilityAccessState(record, RMPermissionModel.EDIT_DECLARED_RECORD_METADATA);
|
||||
AccessStatus accessRecord = capabilityService.getCapabilityAccessState(record, RMPermissionModel.EDIT_RECORD_METADATA);
|
||||
|
||||
if (AccessStatus.ALLOWED.equals(accessNonRecord) == true)
|
||||
{
|
||||
allowNonRecordEdit = true;
|
||||
}
|
||||
|
||||
if (AccessStatus.ALLOWED.equals(accessRecord) == true ||
|
||||
AccessStatus.ALLOWED.equals(accessDeclaredRecord) == true)
|
||||
{
|
||||
allowRecordEdit = true;
|
||||
}
|
||||
|
||||
if (allowNonRecordEdit == true && allowRecordEdit == true)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else if (allowNonRecordEdit == true && allowRecordEdit == false)
|
||||
{
|
||||
// can only edit non record properties
|
||||
if (isRecordMetadata(property) == false)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
else if (allowNonRecordEdit == false && allowRecordEdit == true)
|
||||
{
|
||||
// can only edit record properties
|
||||
if (isRecordMetadata(property) == true)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
// otherwise we can't edit any properties so just return the empty set
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isRecordMetadata(QName property)
|
||||
{
|
||||
boolean result = ArrayUtils.contains(RECORD_MODEL_URIS, property.getNamespaceURI());
|
||||
|
||||
if (result == false && ArrayUtils.contains(NON_RECORD_MODEL_URIS, property.getNamespaceURI()) == false)
|
||||
{
|
||||
PropertyDefinition def = dictionaryService.getProperty(property);
|
||||
if (def != null)
|
||||
{
|
||||
ClassDefinition parent = def.getContainerClass();
|
||||
if (parent != null && parent.isAspect() == true)
|
||||
{
|
||||
result = getRecordMetaDataAspects().contains(parent.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the property should always be allowed to be edited or not.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
private boolean alwaysEditProperty(QName property)
|
||||
{
|
||||
return (ArrayUtils.contains(ALWAYS_EDIT_URIS, property.getNamespaceURI()) ||
|
||||
ArrayUtils.contains(ALWAYS_EDIT_PROPERTIES, property) ||
|
||||
isProtectedProperty(property));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to determine whether a property is protected at a dictionary definition
|
||||
* level.
|
||||
*
|
||||
* @param property property qualified name
|
||||
* @return booelan true if protected, false otherwise
|
||||
*/
|
||||
private boolean isProtectedProperty(QName property)
|
||||
{
|
||||
boolean result = false;
|
||||
PropertyDefinition def = dictionaryService.getProperty(property);
|
||||
if (def != null)
|
||||
{
|
||||
result = def.isProtected();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,8 @@ import java.util.Map;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase;
|
||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.security.FilePlanAuthenticationService;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -43,14 +45,29 @@ import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
*/
|
||||
public class BroadcastVitalRecordDefinitionAction extends RMActionExecuterAbstractBase
|
||||
{
|
||||
private FilePlanAuthenticationService filePlanAuthenticationService;
|
||||
|
||||
public void setFilePlanAuthenticationService(FilePlanAuthenticationService filePlanAuthenticationService)
|
||||
{
|
||||
this.filePlanAuthenticationService = filePlanAuthenticationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action,
|
||||
* org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@Override
|
||||
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
|
||||
protected void executeImpl(Action action, final NodeRef actionedUponNodeRef)
|
||||
{
|
||||
this.propagateChangeToChildrenOf(actionedUponNodeRef);
|
||||
filePlanAuthenticationService.runAsRmAdmin(new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
propagateChangeToChildrenOf(actionedUponNodeRef);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user