diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/RouteModelDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/RouteModelDao.java index 6f5f6736..af640875 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/RouteModelDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/RouteModelDao.java @@ -6,6 +6,7 @@ import com.sismics.docs.core.dao.criteria.RouteModelCriteria; import com.sismics.docs.core.dao.dto.RouteModelDto; import com.sismics.docs.core.model.jpa.RouteModel; import com.sismics.docs.core.util.AuditLogUtil; +import com.sismics.docs.core.util.SecurityUtil; import com.sismics.docs.core.util.jpa.QueryParam; import com.sismics.docs.core.util.jpa.QueryUtil; import com.sismics.docs.core.util.jpa.SortCriteria; @@ -124,6 +125,12 @@ public class RouteModelDao { sb.append(" from T_ROUTE_MODEL rm "); // Add search criterias + if (criteria.getTargetIdList() != null && !SecurityUtil.skipAclCheck(criteria.getTargetIdList())) { + sb.append(" left join T_ACL a on a.ACL_TARGETID_C in (:targetIdList) and a.ACL_SOURCEID_C = rm.RTM_ID_C and a.ACL_PERM_C = 'READ' and a.ACL_DELETEDATE_D is null "); + criteriaList.add("a.ACL_ID_C is not null"); + parameterMap.put("targetIdList", criteria.getTargetIdList()); + } + criteriaList.add("rm.RTM_DELETEDATE_D is null"); if (!criteriaList.isEmpty()) { diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/criteria/RouteModelCriteria.java b/docs-core/src/main/java/com/sismics/docs/core/dao/criteria/RouteModelCriteria.java index 97223183..47bf1f06 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/criteria/RouteModelCriteria.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/criteria/RouteModelCriteria.java @@ -1,10 +1,25 @@ package com.sismics.docs.core.dao.criteria; +import java.util.List; + /** * Route model criteria. * * @author bgamard */ public class RouteModelCriteria { + /** + * ACL target ID list. + */ + private List targetIdList; + + public List getTargetIdList() { + return targetIdList; + } + + public RouteModelCriteria setTargetIdList(List targetIdList) { + this.targetIdList = targetIdList; + return this; + } } diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/criteria/TagCriteria.java b/docs-core/src/main/java/com/sismics/docs/core/dao/criteria/TagCriteria.java index a4f2ad33..e3ccbaad 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/criteria/TagCriteria.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/criteria/TagCriteria.java @@ -23,11 +23,6 @@ public class TagCriteria { */ private String documentId; - /** - * Tag name. - */ - private String name; - public String getId() { return id; } diff --git a/docs-core/src/main/resources/db/update/dbupdate-015-0.sql b/docs-core/src/main/resources/db/update/dbupdate-015-0.sql index fe67f85a..44435efe 100644 --- a/docs-core/src/main/resources/db/update/dbupdate-015-0.sql +++ b/docs-core/src/main/resources/db/update/dbupdate-015-0.sql @@ -7,5 +7,7 @@ alter table T_ROUTE_STEP add constraint FK_RTP_IDROUTE_C foreign key (RTP_IDROUT alter table T_ROUTE_STEP add constraint FK_RTP_IDVALIDATORUSER_C foreign key (RTP_IDVALIDATORUSER_C) references T_USER (USE_ID_C) on delete restrict on update restrict; insert into T_ROUTE_MODEL (RTM_ID_C, RTM_NAME_C, RTM_STEPS_C, RTM_CREATEDATE_D) values ('default-document-review', 'Document review', '[{"type":"VALIDATE","target":{"name":"administrators","type":"GROUP"},"name":"Check the document''s metadata"},{"type":"VALIDATE","target":{"name":"administrators","type":"GROUP"},"name":"Add relevant files to the document"},{"type":"APPROVE","target":{"name":"administrators","type":"GROUP"},"name":"Approve the document"}]', now()); +insert into T_ACL (ACL_ID_C, ACL_PERM_C, ACL_SOURCEID_C, ACL_TARGETID_C) values ('acl-admin-default-route-read', 'READ', 'default-document-review', 'administrators'); +insert into T_ACL (ACL_ID_C, ACL_PERM_C, ACL_SOURCEID_C, ACL_TARGETID_C) values ('acl-admin-default-route-write', 'WRITE', 'default-document-review', 'administrators'); update T_CONFIG set CFG_VALUE_C = '15' where CFG_ID_C = 'DB_VERSION'; diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java index 2214e408..35a7cf69 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java @@ -1,16 +1,14 @@ package com.sismics.docs.rest.resource; import com.google.common.collect.Lists; -import com.sismics.docs.core.constant.AclTargetType; -import com.sismics.docs.core.constant.ActionType; -import com.sismics.docs.core.constant.RouteStepTransition; -import com.sismics.docs.core.constant.RouteStepType; +import com.sismics.docs.core.constant.*; +import com.sismics.docs.core.dao.AclDao; import com.sismics.docs.core.dao.GroupDao; import com.sismics.docs.core.dao.RouteModelDao; -import com.sismics.docs.core.dao.TagDao; import com.sismics.docs.core.dao.UserDao; import com.sismics.docs.core.dao.criteria.RouteModelCriteria; import com.sismics.docs.core.dao.dto.RouteModelDto; +import com.sismics.docs.core.model.jpa.Acl; import com.sismics.docs.core.model.jpa.Group; import com.sismics.docs.core.model.jpa.RouteModel; import com.sismics.docs.core.model.jpa.User; @@ -19,6 +17,7 @@ import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.docs.rest.constant.BaseFunction; import com.sismics.rest.exception.ClientException; import com.sismics.rest.exception.ForbiddenClientException; +import com.sismics.rest.util.AclUtil; import com.sismics.rest.util.ValidationUtil; import javax.json.*; @@ -64,7 +63,7 @@ public class RouteModelResource extends BaseResource { SortCriteria sortCriteria = new SortCriteria(sortColumn, asc); RouteModelDao routeModelDao = new RouteModelDao(); - List routeModelDtoList = routeModelDao.findByCriteria(new RouteModelCriteria(), sortCriteria); + List routeModelDtoList = routeModelDao.findByCriteria(new RouteModelCriteria().setTargetIdList(getTargetIdList(null)), sortCriteria); for (RouteModelDto routeModelDto : routeModelDtoList) { routeModels.add(Json.createObjectBuilder() .add("id", routeModelDto.getId()) @@ -111,6 +110,23 @@ public class RouteModelResource extends BaseResource { .setName(name) .setSteps(steps), principal.getId()); + // Create read ACL + AclDao aclDao = new AclDao(); + Acl acl = new Acl(); + acl.setPerm(PermType.READ); + acl.setType(AclType.USER); + acl.setSourceId(id); + acl.setTargetId(principal.getId()); + aclDao.create(acl, principal.getId()); + + // Create write ACL + acl = new Acl(); + acl.setPerm(PermType.WRITE); + acl.setType(AclType.USER); + acl.setSourceId(id); + acl.setTargetId(principal.getId()); + aclDao.create(acl, principal.getId()); + // Always return OK JsonObjectBuilder response = Json.createObjectBuilder() .add("id", id); @@ -125,7 +141,6 @@ public class RouteModelResource extends BaseResource { private void validateRouteModelSteps(String steps) { UserDao userDao = new UserDao(); GroupDao groupDao = new GroupDao(); - TagDao tagDao = new TagDao(); try (JsonReader reader = Json.createReader(new StringReader(steps))) { JsonArray stepsJson = reader.readArray(); @@ -374,6 +389,9 @@ public class RouteModelResource extends BaseResource { .add("create_date", routeModel.getCreateDate().getTime()) .add("steps", routeModel.getSteps()); + // Add ACL + AclUtil.addAcls(response, id, getTargetIdList(null)); + return Response.ok().entity(response.build()).build(); } } diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteResource.java index e5aa515d..57b66b91 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteResource.java @@ -70,6 +70,11 @@ public class RouteResource extends BaseResource { throw new NotFoundException(); } + // Check permission on this route model + if (!aclDao.checkPermission(routeModelId, PermType.READ, getTargetIdList(null))) { + throw new ForbiddenClientException(); + } + // Avoid creating 2 running routes on the same document RouteStepDao routeStepDao = new RouteStepDao(); if (routeStepDao.getCurrentStep(documentId) != null) { diff --git a/docs-web/src/main/webapp/src/app/docs/controller/settings/SettingsWorkflowEdit.js b/docs-web/src/main/webapp/src/app/docs/controller/settings/SettingsWorkflowEdit.js index 21b50447..a4a4dfa1 100644 --- a/docs-web/src/main/webapp/src/app/docs/controller/settings/SettingsWorkflowEdit.js +++ b/docs-web/src/main/webapp/src/app/docs/controller/settings/SettingsWorkflowEdit.js @@ -59,26 +59,6 @@ angular.module('docs').controller('SettingsWorkflowEdit', function($scope, $dial return $stateParams.id; }; - /** - * In edit mode, load the current workflow. - */ - if ($scope.isEdit()) { - Restangular.one('routemodel', $stateParams.id).get().then(function (data) { - $scope.workflow = data; - $scope.workflow.steps = JSON.parse(data.steps); - _.each($scope.workflow.steps, function (step) { - if (!step.transitions) { - // Patch for old route models - $scope.updateTransitions(step); - } - }); - }); - } else { - $scope.workflow = { - steps: [] - } - } - /** * Update the current workflow. */ @@ -188,4 +168,25 @@ angular.module('docs').controller('SettingsWorkflowEdit', function($scope, $dial Restangular.one('tag/list').get().then(function(data) { $scope.tags = data.tags; }); + + /** + * In edit mode, load the current workflow. + */ + if ($scope.isEdit()) { + Restangular.one('routemodel', $stateParams.id).get().then(function (data) { + $scope.workflow = data; + $scope.workflow.steps = JSON.parse(data.steps); + _.each($scope.workflow.steps, function (step) { + if (!step.transitions) { + // Patch for old route models + $scope.updateTransitions(step); + } + }); + }); + } else { + $scope.workflow = { + steps: [] + }; + $scope.addStep(); + } }); \ No newline at end of file diff --git a/docs-web/src/main/webapp/src/locale/en.json b/docs-web/src/main/webapp/src/locale/en.json index e20d7514..b27ebd68 100644 --- a/docs-web/src/main/webapp/src/locale/en.json +++ b/docs-web/src/main/webapp/src/locale/en.json @@ -311,7 +311,8 @@ "target_help": "Approve: Accept or reject the review
Validate: Review and continue the workflow", "add_step": "Add a workflow step", "actions": "What happens after?", - "remove_action": "Remove action" + "remove_action": "Remove action", + "acl_info": "Only users and groups defined here will be able to start this workflow on a document" } }, "security": { diff --git a/docs-web/src/main/webapp/src/partial/docs/settings.workflow.edit.html b/docs-web/src/main/webapp/src/partial/docs/settings.workflow.edit.html index dfdfeeef..1cc03eca 100644 --- a/docs-web/src/main/webapp/src/partial/docs/settings.workflow.edit.html +++ b/docs-web/src/main/webapp/src/partial/docs/settings.workflow.edit.html @@ -136,6 +136,16 @@ +
+
+

+ +
+
+