diff --git a/config/alfresco/public-rest-context.xml b/config/alfresco/public-rest-context.xml index 09c096ca83..cfb4536abc 100644 --- a/config/alfresco/public-rest-context.xml +++ b/config/alfresco/public-rest-context.xml @@ -142,6 +142,7 @@ + @@ -781,26 +782,20 @@ - - - - - - + + - - - - + - - - - + + + + + @@ -1201,4 +1196,90 @@ + + + + + + + org.alfresco.service.cmr.repository.NodeService + + + + + + + + + + + + + + + + + + + + + + + + + + org.alfresco.service.cmr.repository.NodeService.getStores=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.createStore=ACL_METHOD.ROLE_ADMINISTRATOR + org.alfresco.service.cmr.repository.NodeService.exists=ACL_ALLOW + org.alfresco.service.cmr.repository.NodeService.getNodeStatus=ACL_NODE.0.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getNodeRef=AFTER_ACL_NODE.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getAllRootNodes=ACL_NODE.0.sys:base.ReadProperties,AFTER_ACL_NODE.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getRootNode=ACL_NODE.0.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.createNode=ACL_NODE.0.sys:base.CreateChildren + org.alfresco.service.cmr.repository.NodeService.moveNode=ACL_NODE.0.sys:base.DeleteNode,ACL_NODE.1.sys:base.CreateChildren + org.alfresco.service.cmr.repository.NodeService.setChildAssociationIndex=ACL_PARENT.0.sys:base.WriteProperties + org.alfresco.service.cmr.repository.NodeService.getType=ACL_ALLOW + org.alfresco.service.cmr.repository.NodeService.setType=ACL_NODE.0.sys:base.WriteProperties + org.alfresco.service.cmr.repository.NodeService.addAspect=ACL_NODE.0.sys:base.WriteProperties,ACL_ITEM.0.cm:ownable.TakeOwnership + org.alfresco.service.cmr.repository.NodeService.removeAspect=ACL_NODE.0.sys:base.WriteProperties + org.alfresco.service.cmr.repository.NodeService.hasAspect=ACL_NODE.0.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getAspects=ACL_NODE.0.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.deleteNode=ACL_NODE.0.sys:base.DeleteNode + org.alfresco.service.cmr.repository.NodeService.addChild=ACL_NODE.0.sys:base.CreateChildren,ACL_NODE.1.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.removeChild=ACL_NODE.0.sys:base.DeleteChildren,ACL_PRI_CHILD_ASSOC_ON_CHILD.0.1.sys:base.DeleteNode + org.alfresco.service.cmr.repository.NodeService.removeChildAssociation=ACL_PARENT.0.sys:base.DeleteChildren,ACL_PRI_CHILD_ASSOC_ON_CHILD.0.sys:base.DeleteNode + org.alfresco.service.cmr.repository.NodeService.removeSeconaryChildAssociation=ACL_PARENT.0.sys:base.DeleteChildren + org.alfresco.service.cmr.repository.NodeService.removeSecondaryChildAssociation=ACL_PARENT.0.sys:base.DeleteChildren + org.alfresco.service.cmr.repository.NodeService.getProperties=ACL_NODE.0.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getProperty=ACL_NODE.0.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.setProperties=ACL_NODE.0.sys:base.WriteProperties,ACL_ITEM.0.cm:ownable.TakeOwnership + org.alfresco.service.cmr.repository.NodeService.addProperties=ACL_NODE.0.sys:base.WriteProperties,ACL_ITEM.0.cm:ownable.TakeOwnership + org.alfresco.service.cmr.repository.NodeService.setProperty=ACL_NODE.0.sys:base.WriteProperties,ACL_ITEM.0.cm:ownable.TakeOwnership + org.alfresco.service.cmr.repository.NodeService.removeProperty=ACL_NODE.0.sys:base.WriteProperties + org.alfresco.service.cmr.repository.NodeService.getParentAssocs=ACL_NODE.0.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getChildAssocs=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getChildByName=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getChildAssocsByPropertyValue=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getChildrenByName=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getPrimaryParent=ACL_NODE.0.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.createAssociation=ACL_NODE.0.sys:base.WriteProperties,ACL_NODE.1.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.removeAssociation=ACL_NODE.0.sys:base.DeleteNode,ACL_NODE.1.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.setAssociations=ACL_NODE.0.sys:base.WriteProperties,ACL_NODE.2.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getTargetAssocs=ACL_NODE.0.sys:base.ReadProperties,AFTER_ACL_NODE.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getSourceAssocs=ACL_NODE.0.sys:base.ReadProperties,AFTER_ACL_PARENT.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getAssoc=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getPath=ACL_NODE.0.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getPaths=ACL_NODE.0.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.getStoreArchiveNode=ACL_NODE.0.sys:base.Read + org.alfresco.service.cmr.repository.NodeService.restoreNode=ACL_NODE.0.sys:base.DeleteNode,ACL_NODE.1.sys:base.CreateChildren + org.alfresco.service.cmr.repository.NodeService.getChildAssocsWithoutParentAssocsOfType=ACL_NODE.0.sys:base.ReadProperties,AFTER_ACL_NODE.sys:base.ReadProperties + org.alfresco.service.cmr.repository.NodeService.countChildAssocs=ACL_NODE.0.sys:base.ReadChildren + org.alfresco.service.cmr.repository.NodeService.*=ACL_DENY + + + + diff --git a/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java b/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java index a54247ed39..9a4571b18a 100644 --- a/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java +++ b/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java @@ -82,13 +82,19 @@ public class AbstractNodeRelation implements InitializingBean this.sr = sr; } + // Introduces permissions for Node Assoc (see public-rest-context.xml) + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + @Override public void afterPropertiesSet() { PropertyCheck.mandatory(this, "serviceRegistry", sr); ParameterCheck.mandatory("nodes", this.nodes); - this.nodeService = sr.getNodeService(); + //this.nodeService = sr.getNodeService(); this.namespaceService = sr.getNamespaceService(); this.dictionaryService = sr.getDictionaryService(); } diff --git a/source/test-java/org/alfresco/rest/api/tests/NodeAssociationsApiTest.java b/source/test-java/org/alfresco/rest/api/tests/NodeAssociationsApiTest.java index 9ec6c2e45d..f7626957eb 100644 --- a/source/test-java/org/alfresco/rest/api/tests/NodeAssociationsApiTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/NodeAssociationsApiTest.java @@ -18,17 +18,26 @@ */ package org.alfresco.rest.api.tests; +import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.rest.api.Nodes; import org.alfresco.rest.api.model.AssocChild; import org.alfresco.rest.api.model.AssocTarget; +import org.alfresco.rest.api.nodes.NodesEntityResource; import org.alfresco.rest.api.tests.client.HttpResponse; import org.alfresco.rest.api.tests.client.PublicApiClient.Paging; +import org.alfresco.rest.api.tests.client.RequestContext; import org.alfresco.rest.api.tests.client.data.Association; import org.alfresco.rest.api.tests.client.data.Node; +import org.alfresco.rest.api.tests.util.JacksonUtil; import org.alfresco.rest.api.tests.util.RestApiUtil; +import org.alfresco.rest.framework.jacksonextensions.JacksonHelper; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.security.MutableAuthenticationService; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PersonService; import org.junit.After; import org.junit.Before; @@ -97,14 +106,17 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest private List users = new ArrayList<>(); protected MutableAuthenticationService authenticationService; + protected PermissionService permissionService; protected PersonService personService; private final String RUNID = System.currentTimeMillis()+""; + @Before public void setup() throws Exception { authenticationService = applicationContext.getBean("authenticationService", MutableAuthenticationService.class); + permissionService = applicationContext.getBean("permissionService", PermissionService.class); personService = applicationContext.getBean("personService", PersonService.class); // note: createUser currently relies on repoService @@ -447,6 +459,140 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest } } + @Test + public void testNodePeerAssocsPermissions() throws Exception + { + // as user 1 + + String sharedFolderNodeId = getSharedNodeId(user1); + String sfId = createFolder(user1, sharedFolderNodeId, "shared folder "+RUNID).getId(); + + String u1myNodeId = getMyNodeId(user1); + String u1f1Id = createFolder(user1, u1myNodeId, "f1").getId(); + + // create content node + Node n = new Node(); + n.setName("o1"); + n.setNodeType(TYPE_CM_CONTENT); + n.setAspectNames(Arrays.asList(ASPECT_CM_REFERENCING, ASPECT_CM_PARTABLE)); + HttpResponse response = post(getNodeChildrenUrl(u1f1Id), user1, toJsonAsStringNonNull(n), 201); + String u1o1Id = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class).getId(); + + // as user 2 + + String u2myNodeId = getMyNodeId(user2); + String u2f1Id = createFolder(user2, u2myNodeId, "f1").getId(); + + // create content node + n = new Node(); + n.setName("o1"); + n.setNodeType(TYPE_CM_CONTENT); + n.setAspectNames(Arrays.asList(ASPECT_CM_REFERENCING, ASPECT_CM_PARTABLE)); + response = post(getNodeChildrenUrl(u2f1Id), user2, toJsonAsStringNonNull(n), 201); + String u2o1Id = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class).getId(); + + try + { + Paging paging = getPaging(0, 100); + + // empty lists - before + + response = getAll(getNodeTargetsUrl(u1f1Id), user1, paging, null, 200); + List nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + assertEquals(0, nodes.size()); + + response = getAll(getNodeTargetsUrl(u2f1Id), user2, paging, null, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + assertEquals(0, nodes.size()); + + // Create some assocs + + AssocTarget tgt = new AssocTarget(u1o1Id, ASSOC_TYPE_CM_REFERENCES); + post(getNodeTargetsUrl(u1f1Id), user1, toJsonAsStringNonNull(tgt), 201); + + tgt = new AssocTarget(u2o1Id, ASSOC_TYPE_CM_REFERENCES); + post(getNodeTargetsUrl(u2f1Id), user2, toJsonAsStringNonNull(tgt), 201); + + response = getAll(getNodeTargetsUrl(u1f1Id), user1, paging, null, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + assertEquals(1, nodes.size()); + + response = getAll(getNodeTargetsUrl(u2f1Id), user2, paging, null, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + assertEquals(1, nodes.size()); + + // -ve tests + { + // source/target not readable + + // list + getAll(getNodeTargetsUrl(u1f1Id), user2, paging, null, 403); + getAll(getNodeSourcesUrl(u1o1Id), user2, paging, null, 403); + + // create + tgt = new AssocTarget(u2o1Id, ASSOC_TYPE_CM_REFERENCES); + post(getNodeTargetsUrl(u1f1Id), user1, toJsonAsStringNonNull(tgt), 403); + + tgt = new AssocTarget(u1o1Id, ASSOC_TYPE_CM_REFERENCES); + post(getNodeTargetsUrl(u2f1Id), user1, toJsonAsStringNonNull(tgt), 403); + + // remove + delete(getNodeTargetsUrl(u1f1Id), user2, u2o1Id, null, 403); + delete(getNodeTargetsUrl(u2f1Id), user2, u1o1Id, null, 404); + } + + + // Test listing targets with permissions applied + + // update permission + // TODO refactor with remote permission api calls (use v0 until we have v1 ?) + AuthenticationUtil.setFullyAuthenticatedUser(user1); + permissionService.setPermission(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, sfId), user2, PermissionService.EDITOR, true); + + // TODO improve - admin-related tests + publicApiClient.setRequestContext(new RequestContext("-default-", "admin", "admin")); + response = publicApiClient.get(getScope(), "nodes/"+sfId+"/targets", null, null, null, createParams(paging, null)); + checkStatus(200, response.getStatusCode()); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + assertEquals(0, nodes.size()); + + // user 1 + tgt = new AssocTarget(u1o1Id, ASSOC_TYPE_CM_REFERENCES); + post(getNodeTargetsUrl(sfId), user1, toJsonAsStringNonNull(tgt), 201); + + // user 2 + tgt = new AssocTarget(u2o1Id, ASSOC_TYPE_CM_REFERENCES); + post(getNodeTargetsUrl(sfId), user2, toJsonAsStringNonNull(tgt), 201); + + // TODO improve - admin-related tests + publicApiClient.setRequestContext(new RequestContext("-default-", "admin", "admin")); + response = publicApiClient.get(getScope(), "nodes/"+sfId+"/targets", null, null, null, createParams(paging, null)); + checkStatus(200, response.getStatusCode()); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + assertEquals(2, nodes.size()); + + response = getAll(getNodeTargetsUrl(sfId), user1, paging, null, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + assertEquals(1, nodes.size()); + assertEquals(u1o1Id, nodes.get(0).getId()); + + response = getAll(getNodeTargetsUrl(sfId), user2, paging, null, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + assertEquals(1, nodes.size()); + assertEquals(u2o1Id, nodes.get(0).getId()); + + // TODO test listing sources with permissions applied + } + finally + { + // some cleanup + Map params = Collections.singletonMap("permanent", "true"); + delete(URL_NODES, user1, u1f1Id, params, 204); + delete(URL_NODES, user2, u2f1Id, params, 204); + delete(URL_NODES, user1, sfId, params, 204); + } + } + /** * Tests basic api to manage (add, list, remove) node secondary child associations (ie. parent node -> child node) *