REPO-558, REPO-557: Update Permissions For Node

- Merged changes from branch 5.2.N-NODEPERMS-REST-API
   - Added tests for update node permissions

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@133021 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Raluca Munteanu
2016-11-22 11:55:08 +00:00
parent 6fb6732eb2
commit 5b10029042
6 changed files with 784 additions and 58 deletions

View File

@@ -25,7 +25,19 @@
*/
package org.alfresco.rest.api;
import org.alfresco.rest.api.model.*;
import java.io.InputStream;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.rest.api.model.AssocChild;
import org.alfresco.rest.api.model.AssocTarget;
import org.alfresco.rest.api.model.Document;
import org.alfresco.rest.api.model.Folder;
import org.alfresco.rest.api.model.LockInfo;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.UserInfo;
import org.alfresco.rest.framework.resource.content.BasicContentInfo;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
@@ -35,12 +47,6 @@ import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
import org.springframework.extensions.webscripts.servlet.FormData;
import java.io.InputStream;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* File Folder (Nodes) API
*
@@ -323,6 +329,7 @@ public interface Nodes
String OP_CREATE = "create";
String OP_DELETE = "delete";
String OP_UPDATE = "update";
String OP_UPDATE_PERMISSIONS = "updatePermissions";
String PARAM_RELATIVE_PATH = "relativePath";
String PARAM_PERMANENT = "permanent";
@@ -333,6 +340,7 @@ public interface Nodes
String PARAM_INCLUDE_ISLINK = "isLink";
String PARAM_INCLUDE_ISLOCKED = "isLocked";
String PARAM_INCLUDE_ALLOWABLEOPERATIONS = "allowableOperations";
String PARAM_INCLUDE_PERMISSIONS = "permissions";
String PARAM_INCLUDE_ASSOCIATION = "association";

View File

@@ -86,6 +86,7 @@ import org.alfresco.rest.api.model.Document;
import org.alfresco.rest.api.model.Folder;
import org.alfresco.rest.api.model.LockInfo;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.NodePermissions;
import org.alfresco.rest.api.model.PathInfo;
import org.alfresco.rest.api.model.PathInfo.ElementInfo;
import org.alfresco.rest.api.model.QuickShareLink;
@@ -143,6 +144,7 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.Path.Element;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.OwnableService;
@@ -917,6 +919,8 @@ public class NodesImpl implements Nodes
mapPermsToOps.put(PermissionService.DELETE, OP_DELETE);
mapPermsToOps.put(PermissionService.ADD_CHILDREN, OP_CREATE);
mapPermsToOps.put(PermissionService.WRITE, OP_UPDATE);
mapPermsToOps.put(PermissionService.CHANGE_PERMISSIONS, OP_UPDATE_PERMISSIONS);
List<String> allowableOperations = new ArrayList<>(3);
for (Entry<String, String> kv : mapPermsToOps.entrySet())
@@ -943,6 +947,39 @@ public class NodesImpl implements Nodes
node.setAllowableOperations((allowableOperations.size() > 0 )? allowableOperations : null);
}
if (includeParam.contains(PARAM_INCLUDE_PERMISSIONS))
{
Boolean inherit = permissionService.getInheritParentPermissions(nodeRef);
List<NodePermissions.NodePermission> inheritedPerms = new ArrayList<>(5);
List<NodePermissions.NodePermission> setDirectlyPerms = new ArrayList<>(5);
Set<String> settablePerms = null;
try
{
for (AccessPermission accessPerm : permissionService.getAllSetPermissions(nodeRef))
{
NodePermissions.NodePermission nodePerm = new NodePermissions.NodePermission(accessPerm.getAuthority(), accessPerm.getPermission(), accessPerm.getAccessStatus().toString());
if (accessPerm.isSetDirectly())
{
setDirectlyPerms.add(nodePerm);
} else
{
inheritedPerms.add(nodePerm);
}
}
settablePerms = permissionService.getSettablePermissions(nodeRef);
}
catch (AccessDeniedException ade)
{
// ignore - ie. denied access to retrieve permissions, eg. non-admin on root (Company Home)
}
NodePermissions nodePerms = new NodePermissions(inherit, inheritedPerms, setDirectlyPerms, settablePerms);
node.setPermissions(nodePerms);
}
if (includeParam.contains(PARAM_INCLUDE_ASSOCIATION))
{
// Ugh ... can we optimise this and return the actual assoc directly (via FileFolderService/GetChildrenCQ) ?
@@ -2145,6 +2182,113 @@ public class NodesImpl implements Nodes
props.put(ContentModel.PROP_NAME, name);
}
NodePermissions nodePerms = nodeInfo.getPermissions();
if (nodePerms != null)
{
// Cannot set inherited permissions, only direct (locally set) permissions can be set
if ((nodePerms.getInherited() != null) && (nodePerms.getInherited().size() > 0))
{
throw new InvalidArgumentException("Cannot set *inherited* permissions on this node");
}
// Check inherit from parent value and if it's changed set the new value
if (nodePerms.isInheritanceEnabled() != null)
{
if (nodePerms.isInheritanceEnabled() != permissionService.getInheritParentPermissions(nodeRef))
{
permissionService.setInheritParentPermissions(nodeRef, nodePerms.isInheritanceEnabled());
}
}
// set direct permissions
if ((nodePerms.getLocallySet() != null))
{
// list of all directly set permissions
Set<AccessPermission> directPerms = new HashSet<>(5);
for (AccessPermission accessPerm : permissionService.getAllSetPermissions(nodeRef))
{
if (accessPerm.isSetDirectly())
{
directPerms.add(accessPerm);
}
}
//
// replace (or clear) set of direct permissions
//
// TODO cleanup the way we replace permissions (ie. add, update and delete)
// check if same permission is sent more than once
if (hasDuplicatePermissions(nodePerms.getLocallySet()))
{
throw new InvalidArgumentException("Duplicate node permissions, there is more than one permission with the same authority and name!");
}
for (NodePermissions.NodePermission nodePerm : nodePerms.getLocallySet())
{
String permName = nodePerm.getName();
String authorityId = nodePerm.getAuthorityId();
AccessStatus accessStatus = AccessStatus.ALLOWED;
if (nodePerm.getAccessStatus() != null)
{
accessStatus = AccessStatus.valueOf(nodePerm.getAccessStatus());
}
if ((authorityId == null) ||
((! authorityId.equals(PermissionService.ALL_AUTHORITIES) && (! authorityService.authorityExists(authorityId)))))
{
throw new InvalidArgumentException("Cannot set permissions on this node - unknown authority: "+authorityId);
}
AccessPermission existing = null;
boolean addPerm = true;
boolean updatePerm = false;
// If the permission already exists but with different access status it will be updated
for (AccessPermission accessPerm : directPerms)
{
if (accessPerm.getAuthority().equals(authorityId) && accessPerm.getPermission().equals(permName))
{
existing = accessPerm;
addPerm = false;
if (accessPerm.getAccessStatus() != accessStatus)
{
updatePerm = true;
}
break;
}
}
if (existing != null)
{
// ignore existing permissions
directPerms.remove(existing);
}
if (addPerm || updatePerm)
{
try
{
permissionService.setPermission(nodeRef, authorityId, permName, (accessStatus == AccessStatus.ALLOWED));
}
catch (UnsupportedOperationException e)
{
throw new InvalidArgumentException("Cannot set permissions on this node - unknown access level: " + permName);
}
}
}
// remove any remaining direct perms
for (AccessPermission accessPerm : directPerms)
{
permissionService.deletePermission(nodeRef, accessPerm.getAuthority(), accessPerm.getPermission());
}
}
}
String nodeType = nodeInfo.getNodeType();
if ((nodeType != null) && (! nodeType.isEmpty()))
{
@@ -3104,6 +3248,26 @@ public class NodesImpl implements Nodes
return getFolderOrDocument(nodeId, parameters);
}
/**
* Checks if same permission is sent more than once
* @param locallySetPermissions
* @return
*/
private boolean hasDuplicatePermissions(List<NodePermissions.NodePermission> locallySetPermissions)
{
boolean duplicate = false;
if (locallySetPermissions != null)
{
HashSet<NodePermissions.NodePermission> temp = new HashSet<NodePermissions.NodePermission>(locallySetPermissions.size());
for (NodePermissions.NodePermission permission : locallySetPermissions)
{
temp.add(permission);
}
duplicate = (locallySetPermissions.size() != temp.size());
}
return duplicate;
}
/**
* @author Jamal Kaabi-Mofrad
*/

View File

@@ -91,6 +91,7 @@ public class Node implements Comparable<Node>
protected Map<String, Object> properties;
protected List<String> allowableOperations;
protected NodePermissions nodePermissions;
//optional SearchEntry (only ever returned from a search)
protected SearchEntry search = null;
@@ -336,6 +337,16 @@ public class Node implements Comparable<Node>
this.allowableOperations = allowableOperations;
}
public NodePermissions getPermissions()
{
return nodePermissions;
}
public void setPermissions(NodePermissions nodePermissions)
{
this.nodePermissions = nodePermissions;
}
public List<AssocTarget> getTargets()
{
return targets;

View File

@@ -0,0 +1,170 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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/>.
* #L%
*/
package org.alfresco.rest.api.model;
import java.util.List;
import java.util.Set;
import org.alfresco.service.cmr.security.AccessStatus;
/**
* Representation of Node Permissions
*
* @author janv
*/
public class NodePermissions
{
private Boolean inherit;
private List<NodePermission> inherited;
private List<NodePermission> locallySet;
private Set<String> settable;
public NodePermissions()
{
}
public NodePermissions(Boolean inherit,
List<NodePermission> inherited,
List<NodePermission> locallySet,
Set<String> settable)
{
this.inherit = inherit;
this.inherited = inherited;
this.locallySet = locallySet;
this.settable = settable;
}
public Boolean isInheritanceEnabled()
{
return inherit;
}
public void setInheritanceEnabled(boolean inherit)
{
this.inherit = inherit;
}
public List<NodePermission> getInherited()
{
return inherited;
}
public List<NodePermission> getLocallySet()
{
return locallySet;
}
public void setLocallySet(List<NodePermission> directPermissions)
{
this.locallySet = directPermissions;
}
public Set<String> getSettable()
{
return settable;
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(120);
sb.append("PathInfo [inheritanceEnabled=").append(inherit)
.append(", inherited=").append(getInherited())
.append(", locallySet=").append(getLocallySet())
.append(", settable=").append(getSettable())
.append(']');
return sb.toString();
}
public static class NodePermission
{
private String authorityId;
private String name;
private String accessStatus;
public NodePermission()
{
}
public NodePermission(String authorityId, String name, String accessStatus)
{
this.authorityId = authorityId;
this.name = name;
this.accessStatus = accessStatus != null ? accessStatus : AccessStatus.ALLOWED.toString();
}
public String getName()
{
return name;
}
public String getAuthorityId()
{
return authorityId;
}
public String getAccessStatus()
{
return accessStatus;
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(250);
sb.append("NodePermission [authorityId=").append(authorityId)
.append(", name=").append(name)
.append(", accessStatus=").append(accessStatus)
.append(']');
return sb.toString();
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
NodePermission that = (NodePermission) o;
if (!authorityId.equals(that.authorityId))
return false;
return name.equals(that.name);
}
@Override
public int hashCode()
{
int result = authorityId.hashCode();
result = 31 * result + name.hashCode();
return result;
}
}
}