diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/claim/ClaimTaskAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/claim/ClaimTaskAccTest.java index 65996ed8ee..0b5058c9a7 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/claim/ClaimTaskAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/claim/ClaimTaskAccTest.java @@ -8,15 +8,21 @@ import static pro.taskana.testapi.DefaultTestEntities.defaultTestWorkbasket; import java.time.Instant; +import java.util.List; +import java.util.stream.Stream; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.api.function.ThrowingConsumer; import pro.taskana.TaskanaConfiguration; import pro.taskana.classification.api.ClassificationService; import pro.taskana.classification.api.models.ClassificationSummary; +import pro.taskana.common.internal.util.Triplet; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.exceptions.InvalidOwnerException; @@ -46,6 +52,9 @@ class ClaimTaskAccTest { ClassificationSummary defaultClassificationSummary; WorkbasketSummary defaultWorkbasketSummary; ObjectReference defaultObjectReference; + WorkbasketSummary wbWithoutEditTasks; + WorkbasketSummary wbWithoutReadTasks; + WorkbasketSummary wbWithoutRead; @WithAccessId(user = "businessadmin") @BeforeAll @@ -53,6 +62,9 @@ void setup() throws Exception { defaultClassificationSummary = defaultTestClassification().buildAndStoreAsSummary(classificationService); defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutEditTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutReadTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutRead = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); WorkbasketAccessItemBuilder.newWorkbasketAccessItem() .workbasketId(defaultWorkbasketSummary.getId()) @@ -60,6 +72,34 @@ void setup() throws Exception { .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutEditTasks.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutReadTasks.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutRead.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -240,28 +280,49 @@ void should_ForceClaimTask_When_InReviewByAnotherUser() throws Exception { assertThat(claimedTask.getOwner()).isEqualTo("user-1-2"); } - @WithAccessId(user = "user-taskrouter") - @Test - void should_ThrowNotAuthorizedException_When_UserHasNoReadPermissionAndTaskIsReady() + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_ThrowException_When_ForceClaimingTaskWithMissingPermission() throws Exception { - Task task = - TaskBuilder.newTask() - .state(TaskState.READY) - .classificationSummary(defaultClassificationSummary) - .workbasketSummary(defaultWorkbasketSummary) - .primaryObjRef(defaultObjectReference) - .buildAndStore(taskService, "user-1-2"); - - ThrowingCallable call = () -> taskService.claim(task.getId()); - - NotAuthorizedOnWorkbasketException e = - catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); - assertThat(e.getCurrentUserId()).isEqualTo("user-taskrouter"); - assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasketSummary.getId()); - assertThat(e.getRequiredPermissions()) - .containsExactlyInAnyOrder(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); - - ; + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testClaimTask = + t -> { + String anyUserName = "TestUser28"; + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.CLAIMED) + .owner(anyUserName) + .buildAndStore(taskService, "admin"); + + ThrowingCallable call = () -> taskService.forceClaim(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testClaimTask); } @WithAccessId(user = "user-taskrouter") @@ -370,6 +431,51 @@ void should_ThrowException_When_CancelClaimingATaskInReviewByAnotherUser() throw assertThat(e.getTaskId()).isEqualTo(claimedTask.getId()); } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_ThrowException_When_CancelClaimingTaskWithMissingPermission() + throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testCancelClaimTask = + t -> { + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.CLAIMED) + .owner("user-1-2") + .buildAndStore(taskService, "admin"); + + task.setNote("Test Note"); + ThrowingCallable call = () -> taskService.cancelClaim(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testCancelClaimTask); + } + @WithAccessId(user = "user-1-2") @Test void should_ForceCancelClaim_When_TaskClaimedByAnotherUser() throws Exception { @@ -414,6 +520,51 @@ void should_ForceCancelClaimTask_When_InReviewByAnotherUser() throws Exception { assertThat(unclaimedTask.getOwner()).isNull(); } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_ThrowException_When_ForceCancelClaimingTaskWithMissingPermission() + throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testCancelClaimTask = + t -> { + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.CLAIMED) + .owner("user-1-2") + .buildAndStore(taskService, "admin"); + + task.setNote("Test Note"); + ThrowingCallable call = () -> taskService.forceCancelClaim(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testCancelClaimTask); + } + @WithAccessId(user = "user-1-2") @Test void should_ClaimTask_When_OwnerOfReadyForReviewTaskIsSet() throws Exception { @@ -452,6 +603,51 @@ void should_ClaimTask_When_OwnerOfReadyTaskIsSet() throws Exception { assertThat(taskClaimed.getOwner()).isEqualTo("user-1-2"); } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_ThrowException_When_ClaimingTaskWithMissingPermission() + throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testClaimTask = + t -> { + String anyUserName = "TestUser28"; + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.READY) + .owner(anyUserName) + .buildAndStore(taskService, "admin"); + + ThrowingCallable call = () -> taskService.claim(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testClaimTask); + } + @Nested @TestInstance(Lifecycle.PER_CLASS) class WithAdditionalUserInfoEnabled implements TaskanaConfigurationModifier { diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/claim/SetOwnerAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/claim/SetOwnerAccTest.java index 65d6f0a586..818e334f6b 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/claim/SetOwnerAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/claim/SetOwnerAccTest.java @@ -57,6 +57,7 @@ void setup() throws Exception { .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskAccTest.java index 2bcfa54965..d02b569440 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskAccTest.java @@ -11,10 +11,14 @@ import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.List; +import java.util.stream.Stream; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.function.ThrowingConsumer; import pro.taskana.TaskanaConfiguration; import pro.taskana.classification.api.ClassificationService; import pro.taskana.classification.api.models.ClassificationSummary; @@ -24,6 +28,7 @@ import pro.taskana.common.api.exceptions.TaskanaException; import pro.taskana.common.api.security.CurrentUserContext; import pro.taskana.common.internal.util.EnumUtil; +import pro.taskana.common.internal.util.Triplet; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.exceptions.InvalidOwnerException; @@ -58,6 +63,9 @@ class CompleteTaskAccTest implements TaskanaConfigurationModifier { ClassificationSummary defaultClassificationSummary; WorkbasketSummary defaultWorkbasketSummary; ObjectReference defaultObjectReference; + WorkbasketSummary wbWithoutEditTasks; + WorkbasketSummary wbWithoutReadTasks; + WorkbasketSummary wbWithoutRead; @Override public TaskanaConfiguration.Builder modify(TaskanaConfiguration.Builder builder) { @@ -71,12 +79,43 @@ void setup(ClassificationService classificationService, WorkbasketService workba defaultClassificationSummary = defaultTestClassification().buildAndStoreAsSummary(classificationService); defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutEditTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutReadTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutRead = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); WorkbasketAccessItemBuilder.newWorkbasketAccessItem() .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-1") .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutEditTasks.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutReadTasks.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutRead.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -193,6 +232,52 @@ void should_ForceCompleteTask_When_TaskIsReadyForReview() throws Exception { assertTaskIsComplete(before, completedTask); } + @WithAccessId(user = "user-1-1") + @TestFactory + Stream should_ThrowException_When_ForceCompleteTaskWithMissingPermission() + throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testCompleteTask = + t -> { + String anyUserName = "TestUser28"; + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.READY_FOR_REVIEW) + .owner(anyUserName) + .buildAndStore(taskService, "admin"); + + ThrowingCallable call = () -> taskService.forceCompleteTask(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-1"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testCompleteTask); + } + @WithAccessId(user = "user-1-1") @Test void should_ThrowException_When_CompletingNonExistingTask() { @@ -688,6 +773,50 @@ void should_OnlyClaimTasksWhichAreNotClaimed_When_BulkForceCompletingTasks() thr assertTaskIsComplete(beforeBulkComplete, completedTask2); } + @WithAccessId(user = "user-1-1") + @TestFactory + Stream should_ThrowException_When_CompleteTaskWithMissingPermission() + throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testCompleteTask = + t -> { + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.CLAIMED) + .claimed(Instant.now()) + .owner("user-1-1") + .buildAndStore(taskService, "admin"); + + ThrowingCallable call = () -> taskService.completeTask(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactly(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-1"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testCompleteTask); + } + private void assertTaskIsComplete(Instant before, Task completedTask) { assertThat(completedTask).isNotNull(); assertThat(completedTask.getState()).isEqualTo(TaskState.COMPLETED); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskWithSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskWithSpiAccTest.java index 03fccdd96f..864b78f255 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskWithSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskWithSpiAccTest.java @@ -55,6 +55,7 @@ void setup(ClassificationService classificationService, WorkbasketService workba .accessId("user-1-1") .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplAccTest.java index 01b493b186..706df1847a 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplAccTest.java @@ -215,19 +215,15 @@ void should_OnlyReturnTasksFromCorrectWorkbaskets_When_UserHasNoPermissionToOneW void should_ReturnEmptyList_When_WorkbasketOfTaskHasNoReadTasksPerm() { List list = taskService.createTaskQuery().idIn(taskSummary3.getId()).list(); - assertThat(list.isEmpty()); + assertThat(list).isEmpty(); } @WithAccessId(user = "user-1-1") @Test void should_ThrowException_When_QueryByWorkbasketThatHasOpenReadButNoReadTasksPermission() { - assertThatThrownBy( - () -> - taskService - .createTaskQuery() - .workbasketIdIn(wbWithoutReadTasksPerm.getId()) - .list()) - .isInstanceOf(NotAuthorizedToQueryWorkbasketException.class); + ThrowingCallable call = + () -> taskService.createTaskQuery().workbasketIdIn(wbWithoutReadTasksPerm.getId()).list(); + assertThatThrownBy(call).isInstanceOf(NotAuthorizedToQueryWorkbasketException.class); } @WithAccessId(user = "user-1-1") @@ -261,17 +257,17 @@ void should_OnlyReturnTaskFromWorkbasketWithoutOpenPerm_When_OthersHasNoReadOrRe @WithAccessId(user = "user-1-1") @Test void should_ThrowException_When_QueryByWbIdAndWorkbasketHasReadTasksButNoReadPerm() { - assertThatThrownBy( - () -> taskService.createTaskQuery().workbasketIdIn(wbWithoutReadPerm.getId()).list()) - .isInstanceOf(NotAuthorizedToQueryWorkbasketException.class); + ThrowingCallable call = + () -> taskService.createTaskQuery().workbasketIdIn(wbWithoutReadPerm.getId()).list(); + assertThatThrownBy(call).isInstanceOf(NotAuthorizedToQueryWorkbasketException.class); } @WithAccessId(user = "user-1-1") @Test void should_ThrowException_When_QueryByWbIdAndWorkbasketHasReadAndReadTasksButNoOpenPerm() { - assertThatThrownBy( - () -> taskService.createTaskQuery().workbasketIdIn(wbWithoutOpenPerm.getId()).list()) - .isInstanceOf(NotAuthorizedToQueryWorkbasketException.class); + ThrowingCallable call = + () -> taskService.createTaskQuery().workbasketIdIn(wbWithoutOpenPerm.getId()).list(); + assertThatThrownBy(call).isInstanceOf(NotAuthorizedToQueryWorkbasketException.class); } } @@ -803,9 +799,7 @@ void setup() throws Exception { taskInWorkbasket(wb) .completed(Instant.parse("2020-02-01T00:00:00Z")) .buildAndStoreAsSummary(taskService); - taskInWorkbasket(wb) - .completed(null) - .buildAndStoreAsSummary(taskService); + taskInWorkbasket(wb).completed(null).buildAndStoreAsSummary(taskService); } @WithAccessId(user = "user-1-1") diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplGroupByAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplGroupByAccTest.java index 6c3c842ecc..34432c9cbf 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplGroupByAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplGroupByAccTest.java @@ -125,30 +125,6 @@ void setup() throws Exception { taskInWorkbasket(createWorkbasketWithPermission()).buildAndStore(taskService); } - private TaskBuilder taskInWorkbasket(WorkbasketSummary wb) { - return TaskBuilder.newTask() - .classificationSummary(defaultClassificationSummary) - .primaryObjRef(defaultTestObjectReference().build()) - .workbasketSummary(wb); - } - - private WorkbasketSummary createWorkbasketWithPermission() throws Exception { - WorkbasketSummary workbasketSummary = - defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService, "businessadmin"); - persistPermission(workbasketSummary); - return workbasketSummary; - } - - private void persistPermission(WorkbasketSummary workbasketSummary) throws Exception { - WorkbasketAccessItemBuilder.newWorkbasketAccessItem() - .workbasketId(workbasketSummary.getId()) - .accessId(currentUserContext.getUserid()) - .permission(WorkbasketPermission.OPEN) - .permission(WorkbasketPermission.READ) - .permission(WorkbasketPermission.APPEND) - .buildAndStore(workbasketService, "businessadmin"); - } - @WithAccessId(user = "user-1-1") @Test void should_GroupByPor_When_OrderingByName() { @@ -331,4 +307,29 @@ void should_Count_When_GroupingBySor() { .count(); assertThat(numberOfTasks).isEqualTo(1); } + + private TaskBuilder taskInWorkbasket(WorkbasketSummary wb) { + return TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .primaryObjRef(defaultTestObjectReference().build()) + .workbasketSummary(wb); + } + + private WorkbasketSummary createWorkbasketWithPermission() throws Exception { + WorkbasketSummary workbasketSummary = + defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService, "businessadmin"); + persistPermission(workbasketSummary); + return workbasketSummary; + } + + private void persistPermission(WorkbasketSummary workbasketSummary) throws Exception { + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(workbasketSummary.getId()) + .accessId(currentUserContext.getUserid()) + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService, "businessadmin"); + } } diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithAfterSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithAfterSpiAccTest.java index 973181f938..c2135fec32 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithAfterSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithAfterSpiAccTest.java @@ -61,6 +61,7 @@ void setup(ClassificationService classificationService, WorkbasketService workba .accessId("user-1-1") .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .permission(WorkbasketPermission.TRANSFER) .buildAndStore(workbasketService); @@ -70,6 +71,7 @@ void setup(ClassificationService classificationService, WorkbasketService workba .accessId("user-1-1") .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithBeforeSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithBeforeSpiAccTest.java index 77911eb565..b1b0a32d6e 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithBeforeSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithBeforeSpiAccTest.java @@ -58,6 +58,7 @@ void setup(ClassificationService classificationService, WorkbasketService workba .accessId("user-1-1") .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .permission(WorkbasketPermission.TRANSFER) .buildAndStore(workbasketService); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithAfterSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithAfterSpiAccTest.java index 94ebf4931f..a9cd02faa2 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithAfterSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithAfterSpiAccTest.java @@ -62,6 +62,7 @@ void setup(ClassificationService classificationService, WorkbasketService workba .accessId("user-1-1") .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .permission(WorkbasketPermission.TRANSFER) .buildAndStore(workbasketService); @@ -71,6 +72,7 @@ void setup(ClassificationService classificationService, WorkbasketService workba .accessId("user-1-1") .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithBeforeSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithBeforeSpiAccTest.java index aac442e86d..16886dd109 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithBeforeSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithBeforeSpiAccTest.java @@ -59,6 +59,7 @@ void setup(ClassificationService classificationService, WorkbasketService workba .accessId("user-1-1") .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .permission(WorkbasketPermission.TRANSFER) .buildAndStore(workbasketService); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityAccTest.java index b01646c350..d5136e77c9 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityAccTest.java @@ -54,6 +54,7 @@ void setup() throws Exception { .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityWithSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityWithSpiAccTest.java index 9d798005c4..2cf2f6629d 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityWithSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityWithSpiAccTest.java @@ -75,6 +75,7 @@ void setup() throws Exception { .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskAccTest.java index 94b1bb03c5..ee6c57cec7 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskAccTest.java @@ -38,14 +38,17 @@ import pro.taskana.common.api.exceptions.ConcurrencyException; import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.internal.util.Pair; +import pro.taskana.common.internal.util.Triplet; import pro.taskana.task.api.TaskCustomField; import pro.taskana.task.api.TaskService; +import pro.taskana.task.api.TaskState; import pro.taskana.task.api.exceptions.TaskNotFoundException; import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; import pro.taskana.task.api.models.TaskSummary; import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.internal.models.TaskImpl; +import pro.taskana.testapi.DefaultTestEntities; import pro.taskana.testapi.TaskanaConfigurationModifier; import pro.taskana.testapi.TaskanaInject; import pro.taskana.testapi.TaskanaIntegrationTest; @@ -71,6 +74,9 @@ public class UpdateTaskAccTest { ClassificationSummary defaultClassificationSummary; WorkbasketSummary defaultWorkbasketSummary; ObjectReference defaultObjectReference; + WorkbasketSummary wbWithoutEditTasks; + WorkbasketSummary wbWithoutReadTasks; + WorkbasketSummary wbWithoutRead; @WithAccessId(user = "businessadmin") @BeforeAll @@ -80,12 +86,44 @@ void setup() throws Exception { .serviceLevel("P1D") .buildAndStoreAsSummary(classificationService); defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutEditTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutReadTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutRead = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); WorkbasketAccessItemBuilder.newWorkbasketAccessItem() .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-2") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutEditTasks.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutReadTasks.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutRead.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -248,7 +286,8 @@ void should_ThrowException_When_UserIsNotAuthorized() throws Exception { catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); assertThat(e.getCurrentUserId()).isEqualTo("user-taskrouter"); assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasketSummary.getId()); - assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); } @WithAccessId(user = "user-1-2") @@ -446,6 +485,42 @@ void should_UpdateNoTasks_When_UpdateTasksWithUnmatchedObjectReferenceWasCalled( assertThat(taskIds).isEmpty(); } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_UpdateNoTasksWithPor_When_UserHasMissingPermission() throws Exception { + List> list = + List.of( + Pair.of("With Missing Read Permission", wbWithoutRead), + Pair.of("With Missing ReadTasks Permission", wbWithoutReadTasks), + Pair.of("With Missing EditTasks Permission", wbWithoutEditTasks)); + ThrowingConsumer> testUpdateTask = + t -> { + ObjectReference objectReference = + ObjectReferenceBuilder.newObjectReference() + .company("00") + .system("PASystem") + .systemInstance("00") + .type("VNR") + .value("22334455") + .build(); + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getRight()) + .primaryObjRef(objectReference) + .buildAndStore(taskService, "admin"); + Map customProperties = new HashMap<>(); + customProperties.put(CUSTOM_7, "This is modifiedValue 7"); + customProperties.put(CUSTOM_14, null); + customProperties.put(CUSTOM_3, "This is modifiedValue 3"); + customProperties.put(CUSTOM_16, "This is modifiedValue 16"); + + List taskIds = taskService.updateTasks(objectReference, customProperties); + + assertThat(taskIds).isEmpty(); + }; + return DynamicTest.stream(list.iterator(), Pair::getLeft, testUpdateTask); + } + @WithAccessId(user = "user-1-2") @Test void should_UpdateTasks_When_MatchingPrimaryObjectReferenceWasChanged() throws Exception { @@ -523,6 +598,36 @@ void should_UpdateTaskCustomAttributes_When_UpdateTasksIsCalled() throws Excepti } } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_UpdateNoTasksWithTaskId_When_UserHasMissingPermission() + throws Exception { + List> list = + List.of( + Pair.of("With Missing Read Permission", wbWithoutRead), + Pair.of("With Missing ReadTasks Permission", wbWithoutReadTasks), + Pair.of("With Missing EditTasks Permission", wbWithoutEditTasks)); + ThrowingConsumer> testUpdateTask = + t -> { + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getRight()) + .primaryObjRef(defaultObjectReference) + .buildAndStore(taskService, "admin"); + Map customProperties = new HashMap<>(); + customProperties.put(CUSTOM_7, "This is modifiedValue 7"); + customProperties.put(CUSTOM_14, null); + customProperties.put(CUSTOM_3, "This is modifiedValue 3"); + customProperties.put(CUSTOM_16, "This is modifiedValue 16"); + + List taskIds = taskService.updateTasks(List.of(task.getId()), customProperties); + + assertThat(taskIds).isEmpty(); + }; + return DynamicTest.stream(list.iterator(), Pair::getLeft, testUpdateTask); + } + @WithAccessId(user = "user-1-2") @Test void should_UpdateCallbackInfo() throws Exception { @@ -560,6 +665,51 @@ void should_UpdateRetrieved_When_UpdateTaskIsCalled() throws Exception { assertThat(retrievedUpdatedTask).extracting(TaskSummary::getReceived).isEqualTo(retrievedTime); } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_ThrowException_When_MissingOneOfThePermissions() throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testUpdateTask = + t -> { + String anyUserName = "TestUser28"; + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.READY) + .owner(anyUserName) + .buildAndStore(taskService, "admin"); + + task.setNote("Test Note"); + ThrowingCallable call = () -> taskService.updateTask(task); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testUpdateTask); + } + private ObjectReferenceImpl createObjectReference( String company, String system, String systemInstance, String type, String value) { ObjectReferenceImpl objectReference = new ObjectReferenceImpl(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskWithSorAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskWithSorAccTest.java index 400fce4ede..78567c8ca1 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskWithSorAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskWithSorAccTest.java @@ -47,6 +47,7 @@ void setup() throws Exception { .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/workbasket/get/GetWorkbasketAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/workbasket/get/GetWorkbasketAccTest.java index 8462b98d2b..b1a07b0c52 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/workbasket/get/GetWorkbasketAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/workbasket/get/GetWorkbasketAccTest.java @@ -36,7 +36,7 @@ import pro.taskana.workbasket.api.models.WorkbasketSummary; @TaskanaIntegrationTest -public class GetWorkbasketAccTest { +class GetWorkbasketAccTest { @TaskanaInject ClassificationService classificationService; @TaskanaInject WorkbasketService workbasketService; ClassificationSummary defaultClassificationSummary; @@ -103,11 +103,12 @@ void should_ReturnWorkbasketPermissions_When_IdIsValidAndUserHasPermissions() { List permissions = workbasketService.getPermissionsForWorkbasket(defaultWorkbasketSummary.getId()); - assertThat(permissions).hasSize(4); - assertThat(permissions.contains(WorkbasketPermission.READ)).isTrue(); - assertThat(permissions.contains(WorkbasketPermission.OPEN)).isTrue(); - assertThat(permissions.contains(WorkbasketPermission.TRANSFER)).isTrue(); - assertThat(permissions.contains(WorkbasketPermission.APPEND)).isTrue(); + assertThat(permissions) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, + WorkbasketPermission.APPEND, + WorkbasketPermission.TRANSFER, + WorkbasketPermission.OPEN); } @WithAccessId(user = "user-1-1") @@ -166,7 +167,7 @@ void should_ThrowException_When_TryingToGetByIdWithoutPermissions() { catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasketSummary.getId()); - assertThat(e.getCurrentUserId()).isEqualTo(null); + assertThat(e.getCurrentUserId()).isNull(); assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); } @@ -179,7 +180,7 @@ void should_ThrowException_When_TryingToGetByKeyAndDomainWithoutPermissions() { assertThat(e.getWorkbasketKey()).isEqualTo("USER-1-2"); assertThat(e.getDomain()).isEqualTo("DOMAIN_A"); - assertThat(e.getCurrentUserId()).isEqualTo(null); + assertThat(e.getCurrentUserId()).isNull(); assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java index b7eaf07b3b..0c51e9b956 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java @@ -233,9 +233,7 @@ Task cancelClaim(String taskId) * WorkbasketPermission#READ} for the {@linkplain Workbasket} the {@linkplain Task} is in */ Task forceCancelClaim(String taskId) - throws TaskNotFoundException, - NotAuthorizedOnWorkbasketException, - InvalidTaskStateException; + throws TaskNotFoundException, NotAuthorizedOnWorkbasketException, InvalidTaskStateException; /** * Request review for an existing {@linkplain Task} that is in {@linkplain TaskState#CLAIMED}. @@ -643,7 +641,8 @@ Task updateTask(Task task) /** * Updates specified {@linkplain TaskCustomField TaskCustomFields} of {@linkplain Task Tasks} - * associated with the given {@linkplain Task#getPrimaryObjRef() primaryObjRef}. + * associated with the given {@linkplain Task#getPrimaryObjRef() primaryObjRef}. Tasks in + * Workbaskets without EDITTASKS permission will be ignored and not updated. * * @param selectionCriteria the {@linkplain Task#getPrimaryObjRef() primaryObjRef} of the * searched-for {@linkplain Task Tasks}. diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java index c8562fe4e1..e2359e5f86 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java @@ -514,6 +514,12 @@ public Task updateTask(Task task) TaskImpl oldTaskImpl = (TaskImpl) getTask(newTaskImpl.getId()); checkConcurrencyAndSetModified(newTaskImpl, oldTaskImpl); + if (!checkEditTasksPerm(oldTaskImpl)) { + throw new NotAuthorizedOnWorkbasketException( + taskanaEngine.getEngine().getCurrentUserContext().getUserid(), + oldTaskImpl.getWorkbasketSummary().getId(), + WorkbasketPermission.EDITTASKS); + } attachmentHandler.insertAndDeleteAttachmentsOnTaskUpdate(newTaskImpl, oldTaskImpl); objectReferenceHandler.insertAndDeleteObjectReferencesOnTaskUpdate(newTaskImpl, oldTaskImpl); @@ -586,11 +592,18 @@ public void forceDeleteTask(String taskId) } @Override - public Optional selectAndClaim(TaskQuery taskQuery) { + public Optional selectAndClaim(TaskQuery taskQuery) + throws NotAuthorizedOnWorkbasketException { ((TaskQueryImpl) taskQuery).selectAndClaimEquals(true); - return taskanaEngine.executeInDatabaseConnection( - () -> - Optional.ofNullable(taskQuery.single()).map(TaskSummary::getId).map(wrap(this::claim))); + try { + return taskanaEngine.executeInDatabaseConnection( + () -> + Optional.ofNullable(taskQuery.single()) + .map(TaskSummary::getId) + .map(wrap(this::claim))); + } catch (Exception e) { + return Optional.empty(); + } } @Override @@ -666,9 +679,17 @@ public List updateTasks( // use query in order to find only those tasks that are visible to the current user List taskSummaries = getTasksToChange(selectionCriteria); + List tasksWithPermissions = new ArrayList<>(); + for (TaskSummary taskSummary : taskSummaries) { + if (checkEditTasksPerm(taskSummary)) { + tasksWithPermissions.add(taskSummary); + } + } + List changedTasks = new ArrayList<>(); - if (!taskSummaries.isEmpty()) { - changedTasks = taskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList()); + if (!tasksWithPermissions.isEmpty()) { + changedTasks = + tasksWithPermissions.stream().map(TaskSummary::getId).collect(Collectors.toList()); taskMapper.updateTasks(changedTasks, updated, fieldSelector); if (LOGGER.isDebugEnabled()) { LOGGER.debug("updateTasks() updated the following tasks: {} ", changedTasks); @@ -700,9 +721,17 @@ public List updateTasks( // use query in order to find only those tasks that are visible to the current user List taskSummaries = getTasksToChange(taskIds); + List tasksWithPermissions = new ArrayList<>(); + for (TaskSummary taskSummary : taskSummaries) { + if (checkEditTasksPerm(taskSummary)) { + tasksWithPermissions.add(taskSummary); + } + } + List changedTasks = new ArrayList<>(); - if (!taskSummaries.isEmpty()) { - changedTasks = taskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList()); + if (!tasksWithPermissions.isEmpty()) { + changedTasks = + tasksWithPermissions.stream().map(TaskSummary::getId).collect(Collectors.toList()); taskMapper.updateTasks(changedTasks, updatedTask, fieldSelector); if (LOGGER.isDebugEnabled()) { LOGGER.debug("updateTasks() updated the following tasks: {} ", changedTasks); @@ -1388,7 +1417,7 @@ private static void completeActionsOnTask(TaskSummaryImpl task, String userId, I } private void checkPreconditionsForClaimTask(TaskSummary task, boolean forced) - throws InvalidOwnerException, InvalidTaskStateException { + throws InvalidOwnerException, InvalidTaskStateException, NotAuthorizedOnWorkbasketException { TaskState state = task.getState(); if (state.isEndState()) { throw new InvalidTaskStateException( @@ -1401,6 +1430,12 @@ private void checkPreconditionsForClaimTask(TaskSummary task, boolean forced) && !task.getOwner().equals(userId)) { throw new InvalidOwnerException(userId, task.getId()); } + if (!checkEditTasksPerm(task)) { + throw new NotAuthorizedOnWorkbasketException( + taskanaEngine.getEngine().getCurrentUserContext().getUserid(), + task.getWorkbasketSummary().getId(), + WorkbasketPermission.EDITTASKS); + } } private static boolean taskIsNotClaimed(TaskSummary task) { @@ -1419,7 +1454,7 @@ private static void checkIfTaskIsTerminatedOrCancelled(TaskSummary task) } private void checkPreconditionsForCompleteTask(TaskSummary task) - throws InvalidOwnerException, InvalidTaskStateException { + throws InvalidOwnerException, InvalidTaskStateException, NotAuthorizedOnWorkbasketException { if (taskIsNotClaimed(task)) { throw new InvalidTaskStateException( task.getId(), task.getState(), TaskState.CLAIMED, TaskState.IN_REVIEW); @@ -1432,6 +1467,12 @@ private void checkPreconditionsForCompleteTask(TaskSummary task) throw new InvalidOwnerException( taskanaEngine.getEngine().getCurrentUserContext().getUserid(), task.getId()); } + if (!checkEditTasksPerm(task)) { + throw new NotAuthorizedOnWorkbasketException( + taskanaEngine.getEngine().getCurrentUserContext().getUserid(), + task.getWorkbasketSummary().getId(), + WorkbasketPermission.EDITTASKS); + } } private Task cancelClaim(String taskId, boolean forceUnclaim) @@ -1446,6 +1487,12 @@ private Task cancelClaim(String taskId, boolean forceUnclaim) TaskImpl oldTask = duplicateTaskExactly(task); TaskState state = task.getState(); + if (!checkEditTasksPerm(task)) { + throw new NotAuthorizedOnWorkbasketException( + taskanaEngine.getEngine().getCurrentUserContext().getUserid(), + task.getWorkbasketSummary().getId(), + WorkbasketPermission.EDITTASKS); + } if (state.isEndState()) { throw new InvalidTaskStateException( taskId, state, EnumUtil.allValuesExceptFor(TaskState.END_STATES)); @@ -2091,4 +2138,16 @@ private TaskImpl duplicateTaskExactly(TaskImpl task) { oldTask.setSecondaryObjectReferences(task.getSecondaryObjectReferences()); return oldTask; } + + private boolean checkEditTasksPerm(TaskSummary task) { + WorkbasketQueryImpl query = (WorkbasketQueryImpl) workbasketService.createWorkbasketQuery(); + String workbasketId = task.getWorkbasketSummary().getId(); + WorkbasketSummary workbasket = + query.idIn(workbasketId).callerHasPermissions(WorkbasketPermission.EDITTASKS).single(); + if (workbasket == null) { + return false; + } else { + return true; + } + } } diff --git a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryMapper.java b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryMapper.java index 156eb1d3ae..4e1500e414 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryMapper.java @@ -18,13 +18,13 @@ public interface WorkbasketQueryMapper { + " " + "" + "" - + "LEFT OUTER JOIN (select WORKBASKET_ID as WID, MAX(PERM_READ) as MAX_READ, MAX(PERM_READTASKS) as MAX_READTASKS, MAX(PERM_OPEN) as MAX_OPEN, " + + "LEFT OUTER JOIN (select WORKBASKET_ID as WID, MAX(PERM_READ) as MAX_READ, MAX(PERM_READTASKS) as MAX_READTASKS, MAX(PERM_EDITTASKS) as MAX_EDITTASKS, MAX(PERM_OPEN) as MAX_OPEN, " + "MAX(PERM_APPEND) as MAX_APPEND, MAX(PERM_TRANSFER) as MAX_TRANSFER, MAX(PERM_DISTRIBUTE) as MAX_DISTRIBUTE, MAX(PERM_CUSTOM_1) as MAX_CUSTOM_1, MAX(PERM_CUSTOM_2) as MAX_CUSTOM_2, " + "MAX(PERM_CUSTOM_3) as MAX_CUSTOM_3, MAX(PERM_CUSTOM_4) as MAX_CUSTOM_4, MAX(PERM_CUSTOM_5) as MAX_CUSTOM_5, MAX(PERM_CUSTOM_6) as MAX_CUSTOM_6, MAX(PERM_CUSTOM_7) as MAX_CUSTOM_7, " + "MAX(PERM_CUSTOM_8) as MAX_CUSTOM_8, MAX(PERM_CUSTOM_9) as MAX_CUSTOM_9, MAX(PERM_CUSTOM_10) as MAX_CUSTOM_10, MAX(PERM_CUSTOM_11) as MAX_CUSTOM_11, MAX(PERM_CUSTOM_12) as MAX_CUSTOM_12 " + "" + "" - + "LEFT OUTER JOIN (select WORKBASKET_ID as WID, MAX(PERM_READ::int) as MAX_READ, MAX(PERM_READTASKS::int) as MAX_READTASKS, MAX(PERM_OPEN::int) as MAX_OPEN, " + + "LEFT OUTER JOIN (select WORKBASKET_ID as WID, MAX(PERM_READ::int) as MAX_READ, MAX(PERM_READTASKS::int) as MAX_READTASKS, MAX(PERM_EDITTASKS::int) as MAX_EDITTASKS, MAX(PERM_OPEN::int) as MAX_OPEN, " + "MAX(PERM_APPEND::int) as MAX_APPEND, MAX(PERM_TRANSFER::int) as MAX_TRANSFER, MAX(PERM_DISTRIBUTE::int) as MAX_DISTRIBUTE, MAX(PERM_CUSTOM_1::int) as MAX_CUSTOM_1, MAX(PERM_CUSTOM_2::int) as MAX_CUSTOM_2, " + "MAX(PERM_CUSTOM_3::int) as MAX_CUSTOM_3, MAX(PERM_CUSTOM_4::int) as MAX_CUSTOM_4, MAX(PERM_CUSTOM_5::int) as MAX_CUSTOM_5, MAX(PERM_CUSTOM_6::int) as MAX_CUSTOM_6, MAX(PERM_CUSTOM_7::int) as MAX_CUSTOM_7, " + "MAX(PERM_CUSTOM_8::int) as MAX_CUSTOM_8, MAX(PERM_CUSTOM_9::int) as MAX_CUSTOM_9, MAX(PERM_CUSTOM_10::int) as MAX_CUSTOM_10, MAX(PERM_CUSTOM_11::int) as MAX_CUSTOM_11, MAX(PERM_CUSTOM_12::int) as MAX_CUSTOM_12 " @@ -75,6 +75,7 @@ public interface WorkbasketQueryMapper { + "" + "a.MAX_READ " + "a.MAX_READTASKS " + + "a.MAX_EDITTASKS " + "a.MAX_OPEN " + "a.MAX_APPEND" + "a.MAX_TRANSFER" @@ -119,7 +120,7 @@ public interface WorkbasketQueryMapper { @Select( "