From cee8cc5346bb18ca6840ea626e63046d716844ad Mon Sep 17 00:00:00 2001 From: Alan Davis Date: Sat, 31 Jan 2015 09:35:20 +0000 Subject: [PATCH] Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.0/Cloud) 85943: Merged V4.2-BUG-FIX (4.2.4) to HEAD-BUG-FIX (5.0/Cloud) 85883: Merged DEV to V4.2-BUG-FIX (4.2.4) 85645 : MNT-12382 : No access to process items of (unclaimed) pooled group task via Activiti REST API if user being member of assigned candidate group is not in administrators group - Add unit test 85718 : MNT-12382 : No access to process items of (unclaimed) pooled group task via Activiti REST API if user being member of assigned candidate group is not in administrators group - Add check for unclaimed process - Add unit test 85771 : MNT-12382 : No access to process items of (unclaimed) pooled group task via Activiti REST API if user being member of assigned candidate group is not in administrators group - Added check for membership in the assigned group for unclaimed pooled workflow git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@94521 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../workflow/api/impl/WorkflowRestImpl.java | 29 ++++- .../api/tests/ProcessWorkflowApiTest.java | 114 ++++++++++++++++++ 2 files changed, 142 insertions(+), 1 deletion(-) diff --git a/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java index 90eca637eb..6599457398 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java @@ -17,6 +17,7 @@ import org.activiti.engine.ProcessEngine; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.history.HistoricTaskInstanceQuery; import org.activiti.engine.history.HistoricVariableInstance; +import org.activiti.engine.task.Task; import org.alfresco.model.ContentModel; import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -50,6 +51,7 @@ 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.AuthorityService; +import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.apache.commons.beanutils.ConversionException; @@ -493,13 +495,26 @@ public class WorkflowRestImpl return variableInstances; } - if (authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser())) + String username = AuthenticationUtil.getRunAsUser(); + if (authorityService.isAdminAuthority(username)) { // Admin is allowed to read all processes in the current tenant return variableInstances; } else { + // MNT-12382 check for membership in the assigned group + ActivitiScriptNode group = (ActivitiScriptNode) variableMap.get("bpm_groupAssignee"); + if (group != null) + { + // check that the process is unclaimed + Task task = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processId).singleResult(); + if ((task != null) && (task.getAssignee() == null) && isUserInGroup(username, group.getNodeRef())) + { + return variableInstances; + } + } + // If non-admin user, involvement in the task is required (either owner, assignee or externally involved). HistoricTaskInstanceQuery query = activitiProcessEngine.getHistoryService() .createHistoricTaskInstanceQuery() @@ -550,4 +565,16 @@ public class WorkflowRestImpl { this.activitiWorkflowEngine = activitiWorkflowEngine; } + + private boolean isUserInGroup(String username, NodeRef group) + { + // Get the group name + String groupName = (String) nodeService.getProperty(group, ContentModel.PROP_AUTHORITY_NAME); + + // Get all group members + Set groupMembers = authorityService.getContainedAuthorities(AuthorityType.USER, groupName, false); + + // Check if the user is a group member. + return (groupMembers != null) && groupMembers.contains(username); + } } diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java index 4845efbdcb..ff398a221e 100644 --- a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java +++ b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java @@ -24,24 +24,33 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import org.activiti.engine.TaskService; import org.activiti.engine.history.HistoricProcessInstance; import org.activiti.engine.task.Task; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.tenant.TenantUtil; import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork; +import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.workflow.activiti.ActivitiScriptNode; +import org.alfresco.rest.api.tests.PersonInfo; import org.alfresco.rest.api.tests.RepoService.TestNetwork; +import org.alfresco.rest.api.tests.RepoService.TestPerson; +import org.alfresco.rest.api.tests.RepoService.TestSite; import org.alfresco.rest.api.tests.client.HttpResponse; import org.alfresco.rest.api.tests.client.PublicApiClient.ListResponse; import org.alfresco.rest.api.tests.client.PublicApiException; import org.alfresco.rest.api.tests.client.RequestContext; import org.alfresco.rest.api.tests.client.data.Document; +import org.alfresco.rest.api.tests.client.data.MemberOfSite; +import org.alfresco.rest.api.tests.client.data.SiteRole; import org.alfresco.rest.workflow.api.model.ProcessInfo; import org.alfresco.rest.workflow.api.model.Variable; import org.alfresco.rest.workflow.api.tests.WorkflowApiClient.ProcessesClient; @@ -49,6 +58,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.test_category.OwnJVMTestsCategory; import org.alfresco.util.ISO8601DateFormat; +import org.alfresco.util.Pair; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.junit.experimental.categories.Category; @@ -1285,6 +1295,110 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi } } + @Test + public void testMNT12382() throws Exception + { + currentNetwork = getTestFixture().getRandomNetwork(); + TestPerson initiator = currentNetwork.getPeople().get(0); + RequestContext requestContext = new RequestContext(currentNetwork.getId(), initiator.getId()); + publicApiClient.setRequestContext(requestContext); + ProcessInfo processInfo = startReviewPooledProcess(requestContext); + + final List persons = transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback>() + { + @SuppressWarnings("synthetic-access") + public List execute() throws Throwable + { + ArrayList persons = new ArrayList(); + persons.add(currentNetwork.createUser(new PersonInfo("Maxim0", "Bobyleu0", "maxim0.bobyleu0", "password", null, "skype", "location", "telephone", "mob", "instant", "google"))); + persons.add(currentNetwork.createUser(new PersonInfo("Maxim1", "Bobyleu1", "maxim1.bobyleu1", "password", null, "skype", "location", "telephone", "mob", "instant", "google"))); + persons.add(currentNetwork.createUser(new PersonInfo("Maxim2", "Bobyleu2", "maxim2.bobyleu2", "password", null, "skype", "location", "telephone", "mob", "instant", "google"))); + return persons; + } + }, false, true); + + final MemberOfSite memberOfSite = currentNetwork.getSiteMemberships(initiator.getId()).get(0); + + // startReviewPooledProcess() uses initiator's site id and role name for construct bpm_groupAssignee, thus we need appropriate things for created users + transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + TenantUtil.runAsUserTenant(new TenantRunAsWork() + { + @Override + public Void doWork() throws Exception + { + TestSite initiatorSite = (TestSite) memberOfSite.getSite(); + initiatorSite.inviteToSite(persons.get(0).getId(), memberOfSite.getRole()); + initiatorSite.inviteToSite(persons.get(1).getId(), memberOfSite.getRole()); + // this user wouldn't be in group + initiatorSite.inviteToSite(persons.get(2).getId(), SiteRole.SiteConsumer == memberOfSite.getRole() ? SiteRole.SiteCollaborator : SiteRole.SiteConsumer); + return null; + } + }, AuthenticationUtil.getAdminUserName(), currentNetwork.getId()); + + return null; + } + }, false, true); + + String processId = processInfo.getId(); + + // getting process items by workflow initiator + ProcessesClient processesClient = publicApiClient.processesClient(); + JSONObject initiatorItems = processesClient.findProcessItems(processId); + + // getting unclaimed process items by user in group + requestContext = new RequestContext(currentNetwork.getId(), persons.get(0).getId()); + publicApiClient.setRequestContext(requestContext); + JSONObject items1 = processesClient.findProcessItems(processId); + assertEquals(initiatorItems.toJSONString(), items1.toJSONString()); + + // getting unclaimed process items by user not in group + requestContext = new RequestContext(currentNetwork.getId(), persons.get(2).getId()); + publicApiClient.setRequestContext(requestContext); + try + { + JSONObject items2 = processesClient.findProcessItems(processId); + fail("User not from group should not see items."); + } + catch (PublicApiException e) + { + // expected + assertEquals(403, e.getHttpResponse().getStatusCode()); + } + + // claim task + TaskService taskService = activitiProcessEngine.getTaskService(); + Task task = taskService.createTaskQuery().processInstanceId(processId).singleResult(); + TestPerson assignee = persons.get(1); + taskService.setAssignee(task.getId(), assignee.getId()); + + // getting claimed process items by assignee + requestContext = new RequestContext(currentNetwork.getId(), assignee.getId()); + publicApiClient.setRequestContext(requestContext); + JSONObject items3 = processesClient.findProcessItems(processId); + assertEquals(initiatorItems.toJSONString(), items3.toJSONString()); + + // getting claimed process items by user in group + requestContext = new RequestContext(currentNetwork.getId(), persons.get(0).getId()); + publicApiClient.setRequestContext(requestContext); + try + { + JSONObject items4 = processesClient.findProcessItems(processId); + fail("User from group should not see items for claimed task by another user."); + } + catch (PublicApiException e) + { + // expected + assertEquals(403, e.getHttpResponse().getStatusCode()); + } + finally + { + cleanupProcessInstance(processId); + } + } + @Test public void testGetProcessItems() throws Exception {