This is an automated email from the ASF dual-hosted git repository.
pefernan pushed a commit to branch main
in repository
https://gitbox.apache.org/repos/asf/incubator-kie-kogito-runtimes.git
The following commit(s) were added to refs/heads/main by this push:
new 0c347c5b4e incubator-kie-issues#1837: Ensure
`DefaultUserTasksLifeCycle` checks the user Identity calculating the
`allowedTransitions` (#3848)
0c347c5b4e is described below
commit 0c347c5b4e0c176c303f6899df4c8c857140aa3a
Author: Pere Fernández <[email protected]>
AuthorDate: Thu Feb 20 09:23:27 2025 +0100
incubator-kie-issues#1837: Ensure `DefaultUserTasksLifeCycle` checks the
user Identity calculating the `allowedTransitions` (#3848)
* incubator-kie-issues#1837: Ensure DefaultUserTasksLifeCycle checks the
user Identity calculating the allowedTransitions
* Removed unnecessary outputs modification
---
.../usertask/lifecycle/UserTaskLifeCycle.java | 2 +-
.../kogito/usertask/impl/UserTaskServiceImpl.java | 2 +-
.../impl/lifecycle/DefaultUserTaskLifeCycle.java | 5 +-
.../jbpm/userTask/jpa/it/UserTaskLifeCycleIT.java | 94 ++++++++++++++++++++++
.../jbpm/userTask/jpa/it/UserTaskLifeCycleIT.java | 94 ++++++++++++++++++++++
5 files changed, 193 insertions(+), 4 deletions(-)
diff --git
a/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskLifeCycle.java
b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskLifeCycle.java
index 9fbe1cdcc2..16d62b304a 100644
---
a/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskLifeCycle.java
+++
b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskLifeCycle.java
@@ -51,6 +51,6 @@ public interface UserTaskLifeCycle {
UserTaskTransitionToken newAbortTransitionToken(UserTaskInstance
userTaskInstance, Map<String, Object> data);
- List<UserTaskTransition> allowedTransitions(UserTaskInstance ut);
+ List<UserTaskTransition> allowedTransitions(UserTaskInstance ut,
IdentityProvider identity);
}
diff --git
a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/UserTaskServiceImpl.java
b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/UserTaskServiceImpl.java
index 3f1009245e..f2148e5d63 100644
---
a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/UserTaskServiceImpl.java
+++
b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/UserTaskServiceImpl.java
@@ -98,7 +98,7 @@ public class UserTaskServiceImpl implements UserTaskService {
}
UserTaskInstance ut = userTaskInstance.get();
UserTaskLifeCycle userTaskLifeCycle =
application.config().get(UserTaskConfig.class).userTaskLifeCycle();
- List<UserTaskTransition> transitions =
userTaskLifeCycle.allowedTransitions(ut);
+ List<UserTaskTransition> transitions =
userTaskLifeCycle.allowedTransitions(ut, identity);
return toUserTaskTransitionView(transitions);
}
diff --git
a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/DefaultUserTaskLifeCycle.java
b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/DefaultUserTaskLifeCycle.java
index 986de80780..b237ca7850 100644
---
a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/DefaultUserTaskLifeCycle.java
+++
b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/lifecycle/DefaultUserTaskLifeCycle.java
@@ -87,7 +87,8 @@ public class DefaultUserTaskLifeCycle implements
UserTaskLifeCycle {
}
@Override
- public List<UserTaskTransition> allowedTransitions(UserTaskInstance
userTaskInstance) {
+ public List<UserTaskTransition> allowedTransitions(UserTaskInstance
userTaskInstance, IdentityProvider identity) {
+ checkPermission(userTaskInstance, identity);
return transitions.stream().filter(t ->
t.source().equals(userTaskInstance.getStatus())).toList();
}
@@ -258,7 +259,7 @@ public class DefaultUserTaskLifeCycle implements
UserTaskLifeCycle {
}
}
- throw new UserTaskInstanceNotAuthorizedException("user " + user + "
with roles " + roles + " not autorized to perform an operation on user task " +
userTaskInstance.getId());
+ throw new UserTaskInstanceNotAuthorizedException("user " + user + "
with roles " + roles + " not authorized to perform an operation on user task "
+ userTaskInstance.getId());
}
}
diff --git
a/quarkus/integration-tests/integration-tests-quarkus-usertasks/src/test/java/org/jbpm/userTask/jpa/it/UserTaskLifeCycleIT.java
b/quarkus/integration-tests/integration-tests-quarkus-usertasks/src/test/java/org/jbpm/userTask/jpa/it/UserTaskLifeCycleIT.java
index b2c7b29e11..7ad7745a39 100644
---
a/quarkus/integration-tests/integration-tests-quarkus-usertasks/src/test/java/org/jbpm/userTask/jpa/it/UserTaskLifeCycleIT.java
+++
b/quarkus/integration-tests/integration-tests-quarkus-usertasks/src/test/java/org/jbpm/userTask/jpa/it/UserTaskLifeCycleIT.java
@@ -19,19 +19,24 @@
package org.jbpm.userTask.jpa.it;
+import java.util.List;
import java.util.Map;
import org.acme.travels.Address;
import org.acme.travels.Traveller;
import org.junit.jupiter.api.Test;
import org.kie.kogito.testcontainers.quarkus.PostgreSqlQuarkusTestResource;
+import org.kie.kogito.usertask.impl.lifecycle.DefaultUserTaskLifeCycle;
+import org.kie.kogito.usertask.lifecycle.UserTaskState;
import org.kie.kogito.usertask.model.TransitionInfo;
+import org.kie.kogito.usertask.view.UserTaskTransitionView;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusIntegrationTest;
import io.restassured.http.ContentType;
import static io.restassured.RestAssured.given;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.*;
@QuarkusIntegrationTest
@@ -189,4 +194,93 @@ public class UserTaskLifeCycleIT extends BaseUserTaskIT {
.then()
.statusCode(404);
}
+
+ @Test
+ public void testUserTaskAllowedTransitions() {
+ Traveller traveller = new Traveller("John", "Doe",
"[email protected]", "American", new Address("main street", "Boston",
"10005", "US"));
+
+ String processId = startProcessInstance(traveller);
+
+ String taskId = given().contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "manager")
+ .queryParam("group", "department-managers")
+ .get(USER_TASKS_ENDPOINT)
+ .then()
+ .statusCode(200)
+ .body("$.size()", is(1))
+ .extract()
+ .path("[0].id");
+
+ List<UserTaskTransitionView> transitions =
given().contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "manager")
+ .queryParam("group", "managers")
+ .get(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(200)
+ .extract()
+ .jsonPath().getList(".", UserTaskTransitionView.class);
+
+ assertThat(transitions)
+ .hasSize(5)
+ .satisfiesExactlyInAnyOrder(transition ->
matchTransitionView(transition, DefaultUserTaskLifeCycle.RELEASE,
DefaultUserTaskLifeCycle.RESERVED, DefaultUserTaskLifeCycle.ACTIVE),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.COMPLETE, DefaultUserTaskLifeCycle.RESERVED,
DefaultUserTaskLifeCycle.COMPLETED),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.REASSIGN, DefaultUserTaskLifeCycle.RESERVED,
DefaultUserTaskLifeCycle.ACTIVE),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.FAIL, DefaultUserTaskLifeCycle.RESERVED,
DefaultUserTaskLifeCycle.ERROR),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.SKIP, DefaultUserTaskLifeCycle.RESERVED,
DefaultUserTaskLifeCycle.OBSOLETE));
+
+ given()
+ .contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "john")
+ .queryParam("group", "it")
+ .get(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(500);
+
+ given()
+ .contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "manager")
+ .queryParam("group", "managers")
+ .body(new TransitionInfo("release", Map.of()))
+ .post(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(200)
+ .body("id", equalTo(taskId))
+ .body("status.name", equalTo("Ready"))
+ .body("status.terminate", nullValue());
+
+ transitions = given().contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "manager")
+ .queryParam("group", "managers")
+ .get(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(200)
+ .extract()
+ .jsonPath().getList(".", UserTaskTransitionView.class);
+
+ assertThat(transitions)
+ .hasSize(4)
+ .satisfiesExactlyInAnyOrder(transition ->
matchTransitionView(transition, DefaultUserTaskLifeCycle.CLAIM,
DefaultUserTaskLifeCycle.ACTIVE, DefaultUserTaskLifeCycle.RESERVED),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.REASSIGN, DefaultUserTaskLifeCycle.ACTIVE,
DefaultUserTaskLifeCycle.ACTIVE),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.FAIL, DefaultUserTaskLifeCycle.ACTIVE,
DefaultUserTaskLifeCycle.ERROR),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.SKIP, DefaultUserTaskLifeCycle.ACTIVE,
DefaultUserTaskLifeCycle.OBSOLETE));
+
+ given()
+ .accept(ContentType.JSON)
+ .when()
+ .delete("/{processId}/{id}", PROCESS_ID, processId)
+ .then()
+ .statusCode(200);
+ }
+
+ private void matchTransitionView(UserTaskTransitionView transition, String
expectedId, UserTaskState expectedSource, UserTaskState expectedTarget) {
+ assertThat(transition)
+ .hasFieldOrPropertyWithValue("transitionId", expectedId)
+ .hasFieldOrPropertyWithValue("source", expectedSource)
+ .hasFieldOrPropertyWithValue("target", expectedTarget);
+ }
}
diff --git
a/springboot/integration-tests/integration-tests-springboot-usertasks-it/src/test/java/org/jbpm/userTask/jpa/it/UserTaskLifeCycleIT.java
b/springboot/integration-tests/integration-tests-springboot-usertasks-it/src/test/java/org/jbpm/userTask/jpa/it/UserTaskLifeCycleIT.java
index 0f04acf956..2b9621626c 100644
---
a/springboot/integration-tests/integration-tests-springboot-usertasks-it/src/test/java/org/jbpm/userTask/jpa/it/UserTaskLifeCycleIT.java
+++
b/springboot/integration-tests/integration-tests-springboot-usertasks-it/src/test/java/org/jbpm/userTask/jpa/it/UserTaskLifeCycleIT.java
@@ -19,6 +19,7 @@
package org.jbpm.userTask.jpa.it;
+import java.util.List;
import java.util.Map;
import org.acme.travels.Address;
@@ -26,13 +27,17 @@ import org.acme.travels.Traveller;
import org.junit.jupiter.api.Test;
import org.kie.kogito.it.KogitoSpringbootApplication;
import
org.kie.kogito.testcontainers.springboot.PostgreSqlSpringBootTestResource;
+import org.kie.kogito.usertask.impl.lifecycle.DefaultUserTaskLifeCycle;
+import org.kie.kogito.usertask.lifecycle.UserTaskState;
import org.kie.kogito.usertask.model.TransitionInfo;
+import org.kie.kogito.usertask.view.UserTaskTransitionView;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import io.restassured.http.ContentType;
import static io.restassured.RestAssured.given;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.*;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = KogitoSpringbootApplication.class)
@@ -193,4 +198,93 @@ public class UserTaskLifeCycleIT extends BaseUserTaskIT {
.then()
.statusCode(404);
}
+
+ @Test
+ public void testUserTaskAllowedTransitions() {
+ Traveller traveller = new Traveller("John", "Doe",
"[email protected]", "American", new Address("main street", "Boston",
"10005", "US"));
+
+ String processId = startProcessInstance(traveller);
+
+ String taskId = given().contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "manager")
+ .queryParam("group", "department-managers")
+ .get(USER_TASKS_ENDPOINT)
+ .then()
+ .statusCode(200)
+ .body("$.size()", is(1))
+ .extract()
+ .path("[0].id");
+
+ List<UserTaskTransitionView> transitions =
given().contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "manager")
+ .queryParam("group", "managers")
+ .get(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(200)
+ .extract()
+ .jsonPath().getList(".", UserTaskTransitionView.class);
+
+ assertThat(transitions)
+ .hasSize(5)
+ .satisfiesExactlyInAnyOrder(transition ->
matchTransitionView(transition, DefaultUserTaskLifeCycle.RELEASE,
DefaultUserTaskLifeCycle.RESERVED, DefaultUserTaskLifeCycle.ACTIVE),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.COMPLETE, DefaultUserTaskLifeCycle.RESERVED,
DefaultUserTaskLifeCycle.COMPLETED),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.REASSIGN, DefaultUserTaskLifeCycle.RESERVED,
DefaultUserTaskLifeCycle.ACTIVE),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.FAIL, DefaultUserTaskLifeCycle.RESERVED,
DefaultUserTaskLifeCycle.ERROR),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.SKIP, DefaultUserTaskLifeCycle.RESERVED,
DefaultUserTaskLifeCycle.OBSOLETE));
+
+ given()
+ .contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "john")
+ .queryParam("group", "it")
+ .get(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(500);
+
+ given()
+ .contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "manager")
+ .queryParam("group", "managers")
+ .body(new TransitionInfo("release", Map.of()))
+ .post(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(200)
+ .body("id", equalTo(taskId))
+ .body("status.name", equalTo("Ready"))
+ .body("status.terminate", nullValue());
+
+ transitions = given().contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "manager")
+ .queryParam("group", "managers")
+ .get(USER_TASKS_INSTANCE_TRANSITION_ENDPOINT, taskId)
+ .then()
+ .statusCode(200)
+ .extract()
+ .jsonPath().getList(".", UserTaskTransitionView.class);
+
+ assertThat(transitions)
+ .hasSize(4)
+ .satisfiesExactlyInAnyOrder(transition ->
matchTransitionView(transition, DefaultUserTaskLifeCycle.CLAIM,
DefaultUserTaskLifeCycle.ACTIVE, DefaultUserTaskLifeCycle.RESERVED),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.REASSIGN, DefaultUserTaskLifeCycle.ACTIVE,
DefaultUserTaskLifeCycle.ACTIVE),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.FAIL, DefaultUserTaskLifeCycle.ACTIVE,
DefaultUserTaskLifeCycle.ERROR),
+ transition -> matchTransitionView(transition,
DefaultUserTaskLifeCycle.SKIP, DefaultUserTaskLifeCycle.ACTIVE,
DefaultUserTaskLifeCycle.OBSOLETE));
+
+ given()
+ .accept(ContentType.JSON)
+ .when()
+ .delete("/{processId}/{id}", PROCESS_ID, processId)
+ .then()
+ .statusCode(200);
+ }
+
+ private void matchTransitionView(UserTaskTransitionView transition, String
expectedId, UserTaskState expectedSource, UserTaskState expectedTarget) {
+ assertThat(transition)
+ .hasFieldOrPropertyWithValue("transitionId", expectedId)
+ .hasFieldOrPropertyWithValue("source", expectedSource)
+ .hasFieldOrPropertyWithValue("target", expectedTarget);
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]