Merged HEAD (5.2) to 5.2.N (5.2.1)

126540 jkaabimofrad: Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2)
      123376 jvonka: Nodes (FileFolder) API - extra delete check (hence also move) for special system folders, currently Company Home, Sites and Data Dictionary - even for an admin
      RA-770, RA-642, RA-806


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@126885 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ancuta Morarasu
2016-05-11 12:04:32 +00:00
parent e23ea22d56
commit 728b8739da
2 changed files with 210 additions and 26 deletions

View File

@@ -40,6 +40,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import org.alfresco.model.ApplicationModel;
import org.alfresco.model.ContentModel;
@@ -55,6 +56,9 @@ import org.alfresco.repo.policy.BehaviourFilter;
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.site.SiteModel;
import org.alfresco.repo.site.SiteServiceInternal;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.version.VersionModel;
import org.alfresco.rest.antlr.WhereClauseParser;
import org.alfresco.rest.api.Nodes;
@@ -166,6 +170,7 @@ public class NodesImpl implements Nodes
private PersonService personService;
private OwnableService ownableService;
private AuthorityService authorityService;
private SiteServiceInternal siteServiceInternal;
private BehaviourFilter behaviourFilter;
@@ -179,6 +184,8 @@ public class NodesImpl implements Nodes
// ignore types/aspects
private Set<QName> ignoreQNames;
private ConcurrentHashMap<String,NodeRef> ddCache = new ConcurrentHashMap<String, NodeRef>();
private Set<String> nonAttachContentTypes = Collections.emptySet(); // pre-configured whitelist, eg. images & pdf
public void setNonAttachContentTypes(Set<String> nonAttachWhiteList)
@@ -807,13 +814,19 @@ public class NodesImpl implements Nodes
String perm = kv.getKey();
String op = kv.getValue();
// special case: do not return "create" for file
if (! (perm.equals(PermissionService.ADD_CHILDREN) && type.equals(Type.DOCUMENT)))
if (perm.equals(PermissionService.ADD_CHILDREN) && type.equals(Type.DOCUMENT))
{
if (permissionService.hasPermission(nodeRef, perm) == AccessStatus.ALLOWED)
{
allowableOperations.add(op);
}
// special case: do not return "create" (as an allowable op) for file/content types
continue;
}
else if (perm.equals(PermissionService.DELETE) && (isSpecialNodeDoNotDelete(nodeRef, nodeTypeQName)))
{
// special case: do not return "delete" (as an allowable op) for specific system nodes
continue;
}
else if (permissionService.hasPermission(nodeRef, perm) == AccessStatus.ALLOWED)
{
allowableOperations.add(op);
}
}
@@ -1226,7 +1239,12 @@ public class NodesImpl implements Nodes
@Override
public void deleteNode(String nodeId, Parameters parameters)
{
NodeRef nodeRef = validateNode(nodeId);
NodeRef nodeRef = validateOrLookupNode(nodeId, null);
if (isSpecialNodeDoNotDelete(nodeRef, getNodeType(nodeRef)))
{
throw new PermissionDeniedException("Cannot delete: " + nodeId);
}
// default false (if not provided)
boolean permanentDelete = Boolean.valueOf(parameters.getParameter(PARAM_PERMANENT));
@@ -1390,6 +1408,47 @@ public class NodesImpl implements Nodes
}
}
// special case: additional delete validation (pending common lower-level service support)
// for blacklist of system nodes that should not be deleted, eg. Company Home, Sites, Data Dictionary
private boolean isSpecialNodeDoNotDelete(NodeRef nodeRef, QName type)
{
// Check for Company Home, Sites and Data Dictionary (note: must be tenant-aware)
if (nodeRef.equals(repositoryHelper.getCompanyHome()))
{
return true;
}
else if (type.equals(SiteModel.TYPE_SITES))
{
// note: alternatively, we could inject SiteServiceInternal and use getSitesRoot (or indirectly via node locator)
return true;
}
else
{
String tenantDomain = TenantUtil.getCurrentDomain();
NodeRef ddNodeRef = ddCache.get(tenantDomain);
if (ddNodeRef == null)
{
List<ChildAssociationRef> ddAssocs = nodeService.getChildAssocs(
repositoryHelper.getCompanyHome(),
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "dictionary"));
if (ddAssocs.size() == 1)
{
ddNodeRef = ddAssocs.get(0).getChildRef();
ddCache.put(tenantDomain, ddNodeRef);
}
}
if (nodeRef.equals(ddNodeRef))
{
return true;
}
}
return false;
}
@Override
public Node updateNode(String nodeId, Node nodeInfo, Parameters parameters)
{
@@ -1565,10 +1624,17 @@ public class NodesImpl implements Nodes
{
if (isCopy)
{
// copy
return fileFolderService.copy(nodeRef, parentNodeRef, name);
}
else
{
// move
if ((! nodeRef.equals(parentNodeRef)) && isSpecialNodeDoNotDelete(nodeRef, getNodeType(nodeRef)))
{
throw new PermissionDeniedException("Cannot move: "+nodeRef.getId());
}
// updating "parentId" means moving primary parent !
// note: in the future (as and when we support secondary parent/child assocs) we may also
// wish to select which parent to "move from" (in case where the node resides in multiple locations)