This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch 4_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/4_1_X by this push:
     new 4367f4345c [SYNCOPE-1983] Requiring admin approval for self changes 
beyond attributes (#1452)
4367f4345c is described below

commit 4367f4345cb298eb0b327f037ca0807b5b84ac76
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Mon Jul 13 16:47:05 2026 +0200

    [SYNCOPE-1983] Requiring admin approval for self changes beyond attributes 
(#1452)
---
 .../apache/syncope/common/lib/request/UserCR.java  |  11 +
 .../apache/syncope/common/lib/request/UserUR.java  |  11 +
 .../apache/syncope/core/logic/UserSelfLogic.java   |  11 +-
 .../workflow/java/DefaultUserWorkflowAdapter.java  |  14 +
 .../src/main/resources/userWorkflow.bpmn20.xml     | 655 ++++++++++++++++++---
 fit/core-reference/pom.xml                         |   2 +-
 .../src/main/resources/core-wildfly.properties     |   2 +-
 .../src/main/resources/userWorkflow.bpmn20.xml     |   4 +-
 .../apache/syncope/fit/core/UserIssuesITCase.java  |   3 +
 .../apache/syncope/fit/core/UserSelfITCase.java    |  83 +++
 src/main/asciidoc/images/userWorkflow.png          | Bin 28208 -> 115721 bytes
 .../configuration/configurationparameters.adoc     |   6 +-
 12 files changed, 699 insertions(+), 103 deletions(-)

diff --git 
a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/request/UserCR.java
 
b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/request/UserCR.java
index 837f65403a..0fe8dae439 100644
--- 
a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/request/UserCR.java
+++ 
b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/request/UserCR.java
@@ -217,6 +217,17 @@ public class UserCR extends AnyCR implements 
GroupableRelatableTO {
         return linkedAccounts;
     }
 
+    @JsonIgnore
+    public boolean requiresApproval() {
+        return getUManager() != null
+                || getGManager() != null
+                || !getResources().isEmpty()
+                || !getRelationships().isEmpty()
+                || !memberships.isEmpty()
+                || !roles.isEmpty()
+                || !linkedAccounts.isEmpty();
+    }
+
     @Override
     public int hashCode() {
         return new HashCodeBuilder().
diff --git 
a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/request/UserUR.java
 
b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/request/UserUR.java
index 8d6a4eacb9..7e33b9dad3 100644
--- 
a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/request/UserUR.java
+++ 
b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/request/UserUR.java
@@ -195,6 +195,17 @@ public class UserUR extends AnyUR {
         return isEmptyNotConsideringPassword() && password == null;
     }
 
+    @JsonIgnore
+    public boolean requiresApproval() {
+        return getUManager() != null
+                || getGManager() != null
+                || !getResources().isEmpty()
+                || !getRelationships().isEmpty()
+                || !memberships.isEmpty()
+                || !roles.isEmpty()
+                || !linkedAccounts.isEmpty();
+    }
+
     @Override
     public int hashCode() {
         return new HashCodeBuilder().
diff --git 
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserSelfLogic.java
 
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserSelfLogic.java
index 8a95f9e4a3..5f474b1136 100644
--- 
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserSelfLogic.java
+++ 
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserSelfLogic.java
@@ -129,17 +129,16 @@ public class UserSelfLogic extends AbstractUserLogic {
             + "and not(hasRole('" + IdRepoEntitlement.MUST_CHANGE_PASSWORD + 
"'))")
     @Transactional(readOnly = true)
     public Self read() {
-        UserTO authenticatedUser = binder.getAuthenticatedUserTO();
+        UserTO authenticated = binder.getAuthenticatedUserTO();
 
         return new Self(
-                authenticatedUser,
+                authenticated,
                 POJOHelper.serialize(AuthContextUtils.getAuthorizations()),
-                POJOHelper.serialize(delegationDAO.findValidDelegating(
-                        authenticatedUser.getKey(), OffsetDateTime.now())));
+                
POJOHelper.serialize(delegationDAO.findValidDelegating(authenticated.getKey(), 
OffsetDateTime.now())));
     }
 
     @PreAuthorize("hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
-    public ProvisioningResult<UserTO> create(final UserCR createReq, final 
boolean nullPriorityAsync) {
+    public ProvisioningResult<UserTO> create(final UserCR userCR, final 
boolean nullPriorityAsync) {
         if (!confParamOps.get(
                 AuthContextUtils.getDomain(), 
StandardConfParams.SELF_REGISTRATION_ALLOWED, false, boolean.class)) {
 
@@ -148,7 +147,7 @@ public class UserSelfLogic extends AbstractUserLogic {
             throw sce;
         }
 
-        return doCreate(createReq, true, nullPriorityAsync);
+        return doCreate(userCR, true, nullPriorityAsync);
     }
 
     @PreAuthorize("isAuthenticated() "
diff --git 
a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
 
b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
index d7c0cae668..3083fb5423 100644
--- 
a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
+++ 
b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
@@ -80,6 +80,16 @@ public class DefaultUserWorkflowAdapter extends 
AbstractUserWorkflowAdapter {
         this.notificationManager = notificationManager;
     }
 
+    protected void throwApprovalRequired(final String executor, final boolean 
condition) {
+        if (!securityProperties.getAdminUser().equals(executor)
+                && confParamOps.get(
+                        AuthContextUtils.getDomain(), 
"default.workflow.requires.approval", true, boolean.class)
+                && condition) {
+
+            throw new WorkflowException(new 
UnsupportedOperationException("This operation requires approval"));
+        }
+    }
+
     @Override
     protected UserWorkflowResult<Pair<String, Boolean>> doCreate(
             final UserCR userCR,
@@ -88,6 +98,8 @@ public class DefaultUserWorkflowAdapter extends 
AbstractUserWorkflowAdapter {
             final String creator,
             final String context) {
 
+        throwApprovalRequired(creator, userCR.requiresApproval());
+
         User user = entityFactory.newEntity(User.class);
         dataBinder.create(user, userCR);
 
@@ -148,6 +160,8 @@ public class DefaultUserWorkflowAdapter extends 
AbstractUserWorkflowAdapter {
     protected UserWorkflowResult<Pair<UserUR, Boolean>> doUpdate(
             final User user, final UserUR userUR, final String updater, final 
String context) {
 
+        throwApprovalRequired(updater, userUR.requiresApproval());
+
         UserWorkflowResult.PropagationInfo propInfo = dataBinder.update(user, 
userUR);
 
         metadata(user, updater, context);
diff --git 
a/ext/flowable/flowable-bpmn/src/main/resources/userWorkflow.bpmn20.xml 
b/ext/flowable/flowable-bpmn/src/main/resources/userWorkflow.bpmn20.xml
index 8325733f9b..1f414259bf 100644
--- a/ext/flowable/flowable-bpmn/src/main/resources/userWorkflow.bpmn20.xml
+++ b/ext/flowable/flowable-bpmn/src/main/resources/userWorkflow.bpmn20.xml
@@ -31,14 +31,76 @@ under the License.
     <startEvent id="theStart"/>
     <sequenceFlow id="flow1" sourceRef="theStart" targetRef="create"/>
     <serviceTask id="create" name="Create" 
flowable:delegateExpression="${create}"/>
-    <sequenceFlow id="flow2" sourceRef="create" targetRef="activate"/>
-    <scriptTask id="activate" name="Activate" scriptFormat="groovy" 
flowable:autoStoreVariables="false">
-      <script><![CDATA[execution.setVariable("propagateEnable", 
Boolean.TRUE);]]></script>
+    <sequenceFlow id="flow2" sourceRef="create" targetRef="createGW"/>
+    <exclusiveGateway id="createGW" default="create2Activate"/>
+    <userTask id="createApproval" name="Create approval" 
flowable:formKey="createApproval">
+      <extensionElements>
+        <flowable:formProperty id="username" name="Username" type="string" 
expression="${userTO.username}" writable="false"/>
+        <flowable:formProperty id="approveCreate" name="Approve?" 
type="boolean" variable="approveCreate" required="true"/>
+        <flowable:formProperty id="rejectReason" name="Reason for rejecting" 
type="string" variable="rejectReason"/>
+      </extensionElements>
+    </userTask>
+    <scriptTask id="CreateApprovalEvaluation" name="Create approval 
evaluation" scriptFormat="groovy" flowable:autoStoreVariables="false">
+      <script><![CDATA[
+try {
+  if (approveCreate){
+    execution.setVariable("task", 'approve');
+  } else {
+    execution.setVariable("task", 'reject');
+  }
+} catch(Exception ae) {
+  try {
+    if (task != 'delete') {
+      execution.setVariable("task", null);
+    }
+  } catch(Exception te) {
+    execution.setVariable("task", null);
+  }
+} finally {
+  execution.removeVariable("approveCreate");
+  execution.removeVariable("rejectReason");
+}]]></script>
     </scriptTask>
-    <sequenceFlow id="flow3" sourceRef="activate" targetRef="active"/>
+    <exclusiveGateway id="createApprovalGW" 
default="sid-76B82B68-099D-4729-B8CF-D028386FE900"/>
+    <exclusiveGateway id="enableGW"/>
+    <sequenceFlow id="enableGW2Activate" sourceRef="enableGW" 
targetRef="activate">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${enabled == 
null}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="enableGW2Active" sourceRef="enableGW" targetRef="active">
+      <conditionExpression 
xsi:type="tFormalExpression"><![CDATA[${enabled}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="enableGW2Suspended" sourceRef="enableGW" 
targetRef="suspend">
+      <conditionExpression 
xsi:type="tFormalExpression"><![CDATA[${!enabled}]]></conditionExpression>
+    </sequenceFlow>
+    <serviceTask id="activate" name="Activate" 
flowable:delegateExpression="${autoActivate}"/>
+    <sequenceFlow id="flow4" sourceRef="activate" targetRef="active"/>
+    <serviceTask id="generateToken" name="Generate token" 
flowable:delegateExpression="${generateToken}"/>
+    <sequenceFlow id="flow5" sourceRef="generateToken" targetRef="created"/>
+    <userTask id="created" name="Created"/>
+    <sequenceFlow id="flow6" sourceRef="created" targetRef="optinGW"/>
+    <exclusiveGateway id="optinGW"/>
+    <sequenceFlow id="created2Activate" sourceRef="optinGW" 
targetRef="removeToken">
+      <conditionExpression 
xsi:type="tFormalExpression"><![CDATA[${user.checkToken(token)}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="created2Created" sourceRef="optinGW" targetRef="created">
+      <conditionExpression 
xsi:type="tFormalExpression"><![CDATA[${!user.checkToken(token)}]]></conditionExpression>
+    </sequenceFlow>
+    <scriptTask id="removeToken" name="Remove Token and Activate" 
scriptFormat="groovy" flowable:autoStoreVariables="false">
+      <script><![CDATA[
+        user.removeToken()
+      ]]></script>
+    </scriptTask>
+    <sequenceFlow id="flow7" sourceRef="removeToken" targetRef="active"/>
     <userTask id="active" name="Active"/>
     <sequenceFlow id="flow8" sourceRef="active" targetRef="activeGw"/>
     <exclusiveGateway id="activeGw"/>
+    <sequenceFlow id="active2UpdateApproval" sourceRef="activeGw" 
targetRef="updateApproval">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${wfExecutor 
== user.getUsername() and task == 'update' 
+        and userUR.requiresApproval()}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="active2DeleteApproval" sourceRef="activeGw" 
targetRef="deleteApproval">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${wfExecutor 
== user.getUsername() and task == 'delete'}]]></conditionExpression>
+    </sequenceFlow>
     <sequenceFlow id="active2Update" sourceRef="activeGw" targetRef="update">
       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'update'}]]></conditionExpression>
     </sequenceFlow>
@@ -54,13 +116,58 @@ under the License.
     <sequenceFlow id="active2ConfirmPasswordReset" sourceRef="activeGw" 
targetRef="checkToken4ConfirmPasswordReset">
       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'confirmPasswordReset'}]]></conditionExpression>
     </sequenceFlow>
+    <userTask id="updateApproval" name="Update approval" 
flowable:formKey="updateApproval">
+      <extensionElements>
+        <flowable:formProperty id="username" name="Username" type="string" 
expression="${userTO.username}" writable="false"/>
+        <flowable:formProperty id="approveUpdate" name="Approve?" 
type="boolean" variable="approveUpdate" required="true"/>
+        <flowable:formProperty id="rejectReason" name="Reason for rejecting" 
type="string" variable="rejectReason"/>
+      </extensionElements>
+    </userTask>
+    <scriptTask id="UpdateApprovalEvaluation" name="Update approval 
evaluation" scriptFormat="groovy" flowable:autoStoreVariables="false">
+      <script><![CDATA[
+try {
+  if (approveUpdate){
+    execution.setVariable("task", 'approve');
+  } else {
+    execution.setVariable("task", 'reject');
+  }
+} catch(Exception ae) {
+  try {
+    if (task != 'delete') {
+      execution.setVariable("task", null);
+    }
+  } catch(Exception te) {
+    execution.setVariable("task", null);
+  }
+} finally {
+  execution.removeVariable("approveUpdate");
+  execution.removeVariable("rejectReason");
+}]]></script>
+    </scriptTask>
+    <exclusiveGateway id="updateApprovalGW" 
default="sid-E58BBC2D-8831-4CF2-A798-14B258FE569B"/>
+    <sequenceFlow id="sid-E58BBC2D-8831-4CF2-A798-14B258FE569B" 
sourceRef="updateApprovalGW" targetRef="updateApproval"/>
+    <sequenceFlow id="updateApprovalGW2Update" sourceRef="updateApprovalGW" 
targetRef="update">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'approve'}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="updateApprovalGW2Reject" sourceRef="updateApprovalGW" 
targetRef="rejectUpdate">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'reject'}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="sid-B5FFEBCA-1FBF-457F-BC55-39FD387188B2" 
sourceRef="updateApprovalGW" targetRef="delete">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'delete'}]]></conditionExpression>
+    </sequenceFlow>
+    <scriptTask id="rejectUpdate" name="Reject update" scriptFormat="groovy" 
flowable:autoStoreVariables="false">
+      <script><![CDATA[
+        execution.setVariable("propByResource", null);
+      ]]></script>
+    </scriptTask>
+    <sequenceFlow id="flow8ter" sourceRef="rejectUpdate" targetRef="active"/>
     <serviceTask id="update" name="Update" 
flowable:delegateExpression="${update}"/>
-    <sequenceFlow id="sid-EA22026A-25F0-4ED0-AB6E-9CE9CE74623C" 
sourceRef="update" targetRef="active"/>
+    <sequenceFlow id="flow9" sourceRef="update" targetRef="active"/>
     <serviceTask id="suspend" name="Suspend" 
flowable:delegateExpression="${suspend}"/>
     <sequenceFlow id="flow10" sourceRef="suspend" targetRef="suspended"/>
     <userTask id="suspended" name="Suspended"/>
     <sequenceFlow id="flow11" sourceRef="suspended" targetRef="suspendedGw"/>
-    <exclusiveGateway id="suspendedGw"/>
+    <exclusiveGateway id="suspendedGw" 
default="sid-26ACDEC4-8BE2-4E70-BB63-36B6375B7EEC"/>
     <sequenceFlow id="suspended2Reactivate" sourceRef="suspendedGw" 
targetRef="reactivate">
       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'reactivate'}]]></conditionExpression>
     </sequenceFlow>
@@ -69,160 +176,524 @@ under the License.
     </sequenceFlow>
     <serviceTask id="reactivate" name="Reactivate" 
flowable:delegateExpression="${reactivate}"/>
     <sequenceFlow id="flow12" sourceRef="reactivate" targetRef="active"/>
-    <serviceTask id="generateToken4PasswordReset" name="Generate Token" 
flowable:delegateExpression="${generateToken}"/>
-    <sequenceFlow id="sid-7F78CE07-A7A1-467F-BB4B-40FB234AEFF7" 
sourceRef="generateToken4PasswordReset" 
targetRef="notify4RequestPasswordReset"/>
+    <scriptTask id="reject" name="Reject" scriptFormat="groovy" 
flowable:autoStoreVariables="false">
+      <script><![CDATA[
+        execution.removeVariable("userTO");
+        execution.removeVariable("encryptedPwd");
+        execution.removeVariable("propByResource");
+      ]]></script>
+    </scriptTask>
+    <userTask id="rejected" name="Rejected"/>
+    <sequenceFlow id="flow14" sourceRef="rejected" targetRef="rejectedGw"/>
+    <exclusiveGateway id="rejectedGw"/>
+    <sequenceFlow id="rejected2Delete" sourceRef="rejectedGw" 
targetRef="delete">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'delete'}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="rejected2Rejected" sourceRef="rejectedGw" 
targetRef="rejected">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${empty 
task}]]></conditionExpression>
+    </sequenceFlow>
+    <userTask id="deleteApproval" name="Delete approval" 
flowable:formKey="deleteApproval">
+      <extensionElements>
+        <flowable:formProperty id="username" name="Username" type="string" 
expression="${userTO.username}" writable="false"/>
+        <flowable:formProperty id="approveDelete" name="Approve?" 
type="boolean" variable="approveDelete" required="true"/>
+        <flowable:formProperty id="rejectReason" name="Reason for rejecting" 
type="string" variable="rejectReason"/>
+      </extensionElements>
+    </userTask>
+    <sequenceFlow id="flow14bis" sourceRef="deleteApproval" 
targetRef="deleteApprovalGW"/>
+    <exclusiveGateway id="deleteApprovalGW"/>
+    <sequenceFlow id="deleteApprovalGW2Delete" sourceRef="deleteApprovalGW" 
targetRef="delete">
+      <conditionExpression 
xsi:type="tFormalExpression"><![CDATA[${approve}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="deleteApprovalGW2Reject" sourceRef="deleteApprovalGW" 
targetRef="rejectDelete">
+      <conditionExpression 
xsi:type="tFormalExpression"><![CDATA[${!approve}]]></conditionExpression>
+    </sequenceFlow>
+    <scriptTask id="rejectDelete" name="Reject delete" scriptFormat="groovy" 
flowable:autoStoreVariables="false">
+      <script><![CDATA[
+        execution.setVariable("propByResource", null);
+      ]]></script>
+    </scriptTask>
+    <sequenceFlow id="flow14ter" sourceRef="rejectDelete" targetRef="active"/>
+    <serviceTask id="generateToken4PasswordReset" name="Generate token" 
flowable:delegateExpression="${generateToken}"/>
+    <sequenceFlow id="flow15" sourceRef="generateToken4PasswordReset" 
targetRef="notify4RequestPasswordReset"/>
     <serviceTask id="notify4RequestPasswordReset" name="Notification" 
flowable:delegateExpression="${notify}"/>
-    <sequenceFlow id="sid-CF9ACA40-7750-47C3-A508-7250D24D4F1F" 
sourceRef="notify4RequestPasswordReset" targetRef="active"/>
+    <sequenceFlow id="flow16" sourceRef="notify4RequestPasswordReset" 
targetRef="active"/>
     <serviceTask id="checkToken4ConfirmPasswordReset" name="Check token, 
remove and update password" flowable:delegateExpression="${passwordReset}"/>
-    <sequenceFlow id="sid-3E9FE01D-CC60-4A95-B356-CA0DC000FAD6" 
sourceRef="checkToken4ConfirmPasswordReset" 
targetRef="notify4ConfirmPasswordReset"/>
+    <sequenceFlow id="flow17" sourceRef="checkToken4ConfirmPasswordReset" 
targetRef="notify4ConfirmPasswordReset"/>
     <serviceTask id="notify4ConfirmPasswordReset" name="Notification" 
flowable:delegateExpression="${notify}"/>
-    <sequenceFlow id="sid-A37806A7-6B7B-48A2-BB37-DAE640231144" 
sourceRef="notify4ConfirmPasswordReset" targetRef="active"/>
+    <sequenceFlow id="flow18" sourceRef="notify4ConfirmPasswordReset" 
targetRef="active"/>
     <serviceTask id="delete" name="Delete" 
flowable:delegateExpression="${delete}"/>
     <sequenceFlow id="flow99" sourceRef="delete" targetRef="theEnd"/>
     <endEvent id="theEnd"/>
+    <serviceTask id="updateWhilePendingCreateApproval" name="Update" 
flowable:delegateExpression="${update}"/>
+    <sequenceFlow id="sid-76B82B68-099D-4729-B8CF-D028386FE900" 
sourceRef="createApprovalGW" targetRef="createApproval"/>
+    <sequenceFlow id="sid-B2EEC511-2924-4A95-B0B8-E35DA268DD58" 
sourceRef="createApprovalGW" targetRef="rejectedGw">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'delete'}]]></conditionExpression>
+    </sequenceFlow>
+    <exclusiveGateway id="sid-8CFA3152-19AA-4878-AD2C-96B63F6E98C7" 
default="flow3"/>
+    <sequenceFlow id="flow13" sourceRef="reject" targetRef="rejected"/>
+    <sequenceFlow id="createApprovalGW2EnableGW" sourceRef="createApprovalGW" 
targetRef="enableGW">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'approve'}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="createApproval2Reject" sourceRef="createApprovalGW" 
targetRef="reject">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'reject'}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="create2Activate" sourceRef="createGW" 
targetRef="enableGW"/>
+    <sequenceFlow id="flow3" 
sourceRef="sid-8CFA3152-19AA-4878-AD2C-96B63F6E98C7" 
targetRef="CreateApprovalEvaluation"/>
+    <sequenceFlow id="sid-56E7041A-748A-4C71-ABF3-7DCA0BEC8991" 
sourceRef="CreateApprovalEvaluation" targetRef="createApprovalGW"/>
+    <sequenceFlow id="createAsAnonymous2Approval" sourceRef="createGW" 
targetRef="createApproval">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${wfExecutor 
== 'anonymous' and userCR.requiresApproval()}]]></conditionExpression>
+    </sequenceFlow>
+    <serviceTask id="updateWhilePendingUpdateApproval" name="Update" 
flowable:delegateExpression="${update}"/>
+    <exclusiveGateway id="sid-4C9C9117-26DB-4326-A12B-EEDA42EADF07" 
default="sid-12E29B94-C369-45C1-BCEF-C165AFDA525A"/>
+    <sequenceFlow id="sid-930DADF1-C361-43DD-A240-582F21DEB9B6" 
sourceRef="createApproval" 
targetRef="sid-8CFA3152-19AA-4878-AD2C-96B63F6E98C7"/>
+    <sequenceFlow id="sid-A2BDF803-688C-4A4D-9D33-6D859C029245" 
sourceRef="updateApproval" 
targetRef="sid-4C9C9117-26DB-4326-A12B-EEDA42EADF07"/>
+    <sequenceFlow id="sid-66CDB1C4-7C2F-4BAE-9834-84CF0CF52BF3" 
sourceRef="sid-4C9C9117-26DB-4326-A12B-EEDA42EADF07" 
targetRef="updateWhilePendingUpdateApproval">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'update'}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="sid-C9FA59AF-4F39-489E-B424-5C06B15AE317" 
sourceRef="sid-8CFA3152-19AA-4878-AD2C-96B63F6E98C7" 
targetRef="updateWhilePendingCreateApproval">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 
'update'}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow id="sid-F746E78F-F59B-4842-9D88-C9C79474FC06" 
sourceRef="updateWhilePendingCreateApproval" targetRef="createApproval"/>
+    <sequenceFlow id="sid-1D0DA593-85D7-412B-8DA3-79DC0CE00E1D" 
sourceRef="updateWhilePendingUpdateApproval" targetRef="updateApproval"/>
+    <sequenceFlow id="sid-12E29B94-C369-45C1-BCEF-C165AFDA525A" 
sourceRef="sid-4C9C9117-26DB-4326-A12B-EEDA42EADF07" 
targetRef="UpdateApprovalEvaluation"/>
+    <sequenceFlow id="sid-53FA7F29-CE60-4AE6-921D-AF7331CDB19F" 
sourceRef="UpdateApprovalEvaluation" targetRef="updateApprovalGW"/>
+    <sequenceFlow id="sid-26ACDEC4-8BE2-4E70-BB63-36B6375B7EEC" 
sourceRef="suspendedGw" targetRef="suspended"/>
   </process>
   <bpmndi:BPMNDiagram id="BPMNDiagram_userWorkflow">
     <bpmndi:BPMNPlane bpmnElement="userWorkflow" id="BPMNPlane_userWorkflow">
       <bpmndi:BPMNShape bpmnElement="theStart" id="BPMNShape_theStart">
-        <omgdc:Bounds height="30.0" width="30.0" x="540.0" y="521.0"/>
+        <omgdc:Bounds height="30.0" width="30.0" x="333.0" y="252.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="create" id="BPMNShape_create">
-        <omgdc:Bounds height="60.0" width="100.0" x="620.0" y="509.0"/>
+        <omgdc:Bounds height="60.0" width="100.0" x="300.0" y="323.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="createGW" id="BPMNShape_createGW">
+        <omgdc:Bounds height="40.0" width="40.0" x="330.0" y="507.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="createApproval" 
id="BPMNShape_createApproval">
+        <omgdc:Bounds height="60.0" width="100.0" x="420.0" y="560.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="CreateApprovalEvaluation" 
id="BPMNShape_CreateApprovalEvaluation">
+        <omgdc:Bounds height="80.0" width="100.0" x="477.5" y="765.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="createApprovalGW" 
id="BPMNShape_createApprovalGW">
+        <omgdc:Bounds height="40.0" width="40.0" x="570.0" y="570.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="enableGW" id="BPMNShape_enableGW">
+        <omgdc:Bounds height="40.0" width="40.0" x="690.0" y="429.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="activate" id="BPMNShape_activate">
-        <omgdc:Bounds height="80.0" width="100.0" x="828.0" y="500.0"/>
+        <omgdc:Bounds height="60.0" width="100.0" x="810.0" y="610.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="generateToken" 
id="BPMNShape_generateToken">
+        <omgdc:Bounds height="60.0" width="100.0" x="810.0" y="213.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="created" id="BPMNShape_created">
+        <omgdc:Bounds height="60.0" width="100.0" x="952.0" y="213.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="optinGW" id="BPMNShape_optinGW">
+        <omgdc:Bounds height="40.0" width="40.0" x="1102.0" y="223.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="removeToken" id="BPMNShape_removeToken">
+        <omgdc:Bounds height="60.0" width="100.0" x="1180.0" y="213.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="active" id="BPMNShape_active">
-        <omgdc:Bounds height="60.0" width="100.0" x="1030.0" y="511.0"/>
+        <omgdc:Bounds height="60.0" width="100.0" x="1130.0" y="511.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="activeGw" id="BPMNShape_activeGw">
-        <omgdc:Bounds height="40.0" width="40.0" x="1400.0" y="520.0"/>
+        <omgdc:Bounds height="40.0" width="40.0" x="1500.0" y="520.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="updateApproval" 
id="BPMNShape_updateApproval">
+        <omgdc:Bounds height="60.0" width="100.0" x="1605.0" y="740.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="UpdateApprovalEvaluation" 
id="BPMNShape_UpdateApprovalEvaluation">
+        <omgdc:Bounds height="80.0" width="100.0" x="1740.0" y="855.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="updateApprovalGW" 
id="BPMNShape_updateApprovalGW">
+        <omgdc:Bounds height="40.0" width="40.0" x="1770.0" y="750.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="rejectUpdate" id="BPMNShape_rejectUpdate">
+        <omgdc:Bounds height="60.0" width="100.0" x="1890.0" y="840.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="update" id="BPMNShape_update">
-        <omgdc:Bounds height="60.0" width="100.0" x="1370.0" y="615.0"/>
+        <omgdc:Bounds height="60.0" width="100.0" x="1890.0" y="700.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="suspend" id="BPMNShape_suspend">
-        <omgdc:Bounds height="60.0" width="100.0" x="1490.0" y="370.0"/>
+        <omgdc:Bounds height="60.0" width="100.0" x="1590.0" y="100.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="suspended" id="BPMNShape_suspended">
-        <omgdc:Bounds height="60.0" width="100.0" x="1640.0" y="370.0"/>
+        <omgdc:Bounds height="60.0" width="100.0" x="1740.0" y="120.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="suspendedGw" id="BPMNShape_suspendedGw">
-        <omgdc:Bounds height="40.0" width="40.0" x="1820.0" y="380.0"/>
+        <omgdc:Bounds height="40.0" width="40.0" x="1920.0" y="180.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="reactivate" id="BPMNShape_reactivate">
-        <omgdc:Bounds height="60.0" width="100.0" x="1940.0" y="290.0"/>
+        <omgdc:Bounds height="60.0" width="100.0" x="2040.0" y="110.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="reject" id="BPMNShape_reject">
+        <omgdc:Bounds height="60.0" width="100.0" x="660.0" y="659.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="rejected" id="BPMNShape_rejected">
+        <omgdc:Bounds height="60.0" width="100.0" x="810.0" y="770.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="rejectedGw" id="BPMNShape_rejectedGw">
+        <omgdc:Bounds height="40.0" width="40.0" x="990.0" y="780.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="deleteApproval" 
id="BPMNShape_deleteApproval">
+        <omgdc:Bounds height="60.0" width="100.0" x="1590.0" y="280.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="deleteApprovalGW" 
id="BPMNShape_deleteApprovalGW">
+        <omgdc:Bounds height="40.0" width="40.0" x="1770.0" y="300.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="rejectDelete" id="BPMNShape_rejectDelete">
+        <omgdc:Bounds height="60.0" width="100.0" x="1890.0" y="240.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="generateToken4PasswordReset" 
id="BPMNShape_generateToken4PasswordReset">
-        <omgdc:Bounds height="81.0" width="121.0" x="1515.0" y="604.0"/>
+        <omgdc:Bounds height="59.0" width="100.0" x="1643.0" y="452.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="notify4RequestPasswordReset" 
id="BPMNShape_notify4RequestPasswordReset">
-        <omgdc:Bounds height="81.0" width="121.0" x="1515.0" y="750.0"/>
+        <omgdc:Bounds height="60.0" width="100.0" x="1848.0" y="452.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="checkToken4ConfirmPasswordReset" 
id="BPMNShape_checkToken4ConfirmPasswordReset">
-        <omgdc:Bounds height="81.0" width="121.0" x="1725.0" y="664.0"/>
+        <omgdc:Bounds height="60.0" width="100.0" x="1643.0" y="561.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="notify4ConfirmPasswordReset" 
id="BPMNShape_notify4ConfirmPasswordReset">
-        <omgdc:Bounds height="81.0" width="121.0" x="1725.0" y="810.0"/>
+        <omgdc:Bounds height="60.0" width="100.0" x="1848.0" y="561.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="delete" id="BPMNShape_delete">
-        <omgdc:Bounds height="60.0" width="100.0" x="1940.0" y="438.0"/>
+        <omgdc:Bounds height="60.0" width="100.0" x="2220.0" y="358.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="theEnd" id="BPMNShape_theEnd">
-        <omgdc:Bounds height="28.0" width="28.0" x="2080.0" y="451.0"/>
+        <omgdc:Bounds height="28.0" width="28.0" x="2358.0" y="374.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="updateWhilePendingCreateApproval" 
id="BPMNShape_updateWhilePendingCreateApproval">
+        <omgdc:Bounds height="60.0" width="100.0" x="362.5" y="770.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="sid-8CFA3152-19AA-4878-AD2C-96B63F6E98C7" 
id="BPMNShape_sid-8CFA3152-19AA-4878-AD2C-96B63F6E98C7">
+        <omgdc:Bounds height="40.0" width="40.0" x="450.0" y="660.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="updateWhilePendingUpdateApproval" 
id="BPMNShape_updateWhilePendingUpdateApproval">
+        <omgdc:Bounds height="60.0" width="100.0" x="1455.0" y="865.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="sid-4C9C9117-26DB-4326-A12B-EEDA42EADF07" 
id="BPMNShape_sid-4C9C9117-26DB-4326-A12B-EEDA42EADF07">
+        <omgdc:Bounds height="40.0" width="40.0" x="1635.0" y="875.0"/>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNEdge bpmnElement="active2Update" id="BPMNEdge_active2Update">
-        <omgdi:waypoint x="1420.0" y="559.9405090390104"/>
-        <omgdi:waypoint x="1420.0" y="615.0"/>
+        <omgdi:waypoint x="1539.9223684210267" y="540.0"/>
+        <omgdi:waypoint x="1556.0" y="540.0"/>
+        <omgdi:waypoint x="1556.0" y="730.0"/>
+        <omgdi:waypoint x="1889.999999999701" y="730.0"/>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge bpmnElement="suspended2Delete" 
id="BPMNEdge_suspended2Delete">
-        <omgdi:waypoint x="1859.9433544303797" y="400.0"/>
-        <omgdi:waypoint x="1990.0" y="400.0"/>
-        <omgdi:waypoint x="1990.0" y="438.0"/>
+      <bpmndi:BPMNEdge bpmnElement="sid-1D0DA593-85D7-412B-8DA3-79DC0CE00E1D" 
id="BPMNEdge_sid-1D0DA593-85D7-412B-8DA3-79DC0CE00E1D">
+        <omgdi:waypoint x="1540.94" y="865.0"/>
+        <omgdi:waypoint x="1619.0" y="799.9499999999999"/>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge bpmnElement="active2ConfirmPasswordReset" 
id="BPMNEdge_active2ConfirmPasswordReset">
-        <omgdi:waypoint x="1439.947267871352" y="540.0"/>
-        <omgdi:waypoint x="1785.0" y="540.0"/>
-        <omgdi:waypoint x="1785.3768996960487" y="664.0"/>
+        <omgdi:waypoint x="1539.9442374350085" y="540.0"/>
+        <omgdi:waypoint x="1693.0" y="540.0"/>
+        <omgdi:waypoint x="1693.0" y="561.0"/>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge bpmnElement="sid-EA22026A-25F0-4ED0-AB6E-9CE9CE74623C" 
id="BPMNEdge_sid-EA22026A-25F0-4ED0-AB6E-9CE9CE74623C">
-        <omgdi:waypoint x="1370.0" y="645.0"/>
-        <omgdi:waypoint x="1080.0" y="645.0"/>
-        <omgdi:waypoint x="1080.0" y="570.95"/>
+      <bpmndi:BPMNEdge bpmnElement="sid-76B82B68-099D-4729-B8CF-D028386FE900" 
id="BPMNEdge_sid-76B82B68-099D-4729-B8CF-D028386FE900">
+        <omgdi:waypoint x="570.0" y="590.0"/>
+        <omgdi:waypoint x="519.9499999997392" y="590.0"/>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge bpmnElement="suspended2Reactivate" 
id="BPMNEdge_suspended2Reactivate">
-        <omgdi:waypoint x="1859.9339371980675" y="400.0"/>
-        <omgdi:waypoint x="1902.0" y="400.0"/>
-        <omgdi:waypoint x="1902.0" y="320.0"/>
-        <omgdi:waypoint x="1939.9999999999768" y="320.0"/>
+      <bpmndi:BPMNEdge bpmnElement="sid-930DADF1-C361-43DD-A240-582F21DEB9B6" 
id="BPMNEdge_sid-930DADF1-C361-43DD-A240-582F21DEB9B6">
+        <omgdi:waypoint x="470.0" y="619.9499999999999"/>
+        <omgdi:waypoint x="470.0" y="660.0"/>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge bpmnElement="active2Delete" id="BPMNEdge_active2Delete">
-        <omgdi:waypoint x="1439.9482503069637" y="540.0"/>
-        <omgdi:waypoint x="1990.0" y="540.0"/>
-        <omgdi:waypoint x="1990.0" y="497.95"/>
+      <bpmndi:BPMNEdge bpmnElement="rejected2Rejected" 
id="BPMNEdge_rejected2Rejected">
+        <omgdi:waypoint x="990.0" y="800.0"/>
+        <omgdi:waypoint x="909.9499999999135" y="800.0"/>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge bpmnElement="sid-7F78CE07-A7A1-467F-BB4B-40FB234AEFF7" 
id="BPMNEdge_sid-7F78CE07-A7A1-467F-BB4B-40FB234AEFF7">
-        <omgdi:waypoint x="1575.5" y="684.9499999999999"/>
-        <omgdi:waypoint x="1575.5" y="750.0"/>
+      <bpmndi:BPMNEdge bpmnElement="sid-56E7041A-748A-4C71-ABF3-7DCA0BEC8991" 
id="BPMNEdge_sid-56E7041A-748A-4C71-ABF3-7DCA0BEC8991">
+        <omgdi:waypoint x="577.4499999999488" y="805.0"/>
+        <omgdi:waypoint x="590.0" y="805.0"/>
+        <omgdi:waypoint x="590.0" y="609.9046184271755"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="active2Delete" id="BPMNEdge_active2Delete">
+        <omgdi:waypoint x="1539.9189252336448" y="540.0"/>
+        <omgdi:waypoint x="1552.0" y="540.0"/>
+        <omgdi:waypoint x="1552.0" y="680.0"/>
+        <omgdi:waypoint x="2174.0" y="680.0"/>
+        <omgdi:waypoint x="2260.1369863013697" y="417.95"/>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
-        <omgdi:waypoint x="569.9448521215137" y="536.3898700596537"/>
-        <omgdi:waypoint x="620.0" y="537.6956521739131"/>
+        <omgdi:waypoint x="348.3475822648328" y="281.94584310464063"/>
+        <omgdi:waypoint x="349.30232558139534" y="323.0"/>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
-        <omgdi:waypoint x="719.9499999999825" y="539.2401442307691"/>
-        <omgdi:waypoint x="827.9999999999945" y="539.7596153846154"/>
+        <omgdi:waypoint x="350.0" y="382.95"/>
+        <omgdi:waypoint x="350.0" y="507.0"/>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
-        <omgdi:waypoint x="927.9499999999819" y="540.2472772277227"/>
-        <omgdi:waypoint x="1029.9999999999911" y="540.7524752475248"/>
+        <omgdi:waypoint x="489.93253064798597" y="680.0"/>
+        <omgdi:waypoint x="527.0" y="680.0"/>
+        <omgdi:waypoint x="527.34" y="765.0"/>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge bpmnElement="active2RequestPasswordReset" 
id="BPMNEdge_active2RequestPasswordReset">
-        <omgdi:waypoint x="1439.943568665287" y="540.0"/>
-        <omgdi:waypoint x="1575.0" y="540.0"/>
-        <omgdi:waypoint x="1575.3062200956938" y="604.0"/>
+      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
+        <omgdi:waypoint x="909.9499999998994" y="640.0"/>
+        <omgdi:waypoint x="922.0" y="640.0"/>
+        <omgdi:waypoint x="1059.0" y="640.0"/>
+        <omgdi:waypoint x="1143.3333333333333" y="570.95"/>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge bpmnElement="sid-3E9FE01D-CC60-4A95-B356-CA0DC000FAD6" 
id="BPMNEdge_sid-3E9FE01D-CC60-4A95-B356-CA0DC000FAD6">
-        <omgdi:waypoint x="1785.5" y="744.9499999999999"/>
-        <omgdi:waypoint x="1785.5" y="810.0"/>
+      <bpmndi:BPMNEdge bpmnElement="updateApprovalGW2Update" 
id="BPMNEdge_updateApprovalGW2Update">
+        <omgdi:waypoint x="1809.9339371980675" y="770.0"/>
+        <omgdi:waypoint x="1852.0" y="770.0"/>
+        <omgdi:waypoint x="1852.0" y="730.0"/>
+        <omgdi:waypoint x="1890.0" y="730.0"/>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10">
-        <omgdi:waypoint x="1589.95" y="400.0"/>
-        <omgdi:waypoint x="1640.0" y="400.0"/>
+      <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
+        <omgdi:waypoint x="909.9499999999393" y="243.0"/>
+        <omgdi:waypoint x="952.0" y="243.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
+        <omgdi:waypoint x="1002.0" y="272.95"/>
+        <omgdi:waypoint x="1002.0" y="310.0"/>
+        <omgdi:waypoint x="1122.0" y="310.0"/>
+        <omgdi:waypoint x="1122.0" y="262.9148355754858"/>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge bpmnElement="sid-CF9ACA40-7750-47C3-A508-7250D24D4F1F" 
id="BPMNEdge_sid-CF9ACA40-7750-47C3-A508-7250D24D4F1F">
-        <omgdi:waypoint x="1514.9999999999554" y="790.438950554995"/>
-        <omgdi:waypoint x="1080.0" y="790.0"/>
-        <omgdi:waypoint x="1080.0" y="570.95"/>
+      <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
+        <omgdi:waypoint x="1224.96644295302" y="272.95"/>
+        <omgdi:waypoint x="1185.025167785235" y="511.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-66CDB1C4-7C2F-4BAE-9834-84CF0CF52BF3" 
id="BPMNEdge_sid-66CDB1C4-7C2F-4BAE-9834-84CF0CF52BF3">
+        <omgdi:waypoint x="1635.0" y="895.0"/>
+        <omgdi:waypoint x="1554.95" y="895.0"/>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
-        <omgdi:waypoint x="1129.9499999999914" y="540.8529411764707"/>
-        <omgdi:waypoint x="1400.0586510263724" y="540.058504398827"/>
+        <omgdi:waypoint x="1229.9499999999914" y="540.8529411764707"/>
+        <omgdi:waypoint x="1500.0586510263724" y="540.058504398827"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="active2Suspend" 
id="BPMNEdge_active2Suspend">
+        <omgdi:waypoint x="1539.9189252336448" y="540.0"/>
+        <omgdi:waypoint x="1552.0" y="540.0"/>
+        <omgdi:waypoint x="1552.0" y="130.0"/>
+        <omgdi:waypoint x="1589.9999999999768" y="130.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9">
+        <omgdi:waypoint x="1989.95" y="730.0"/>
+        <omgdi:waypoint x="2037.0" y="730.0"/>
+        <omgdi:waypoint x="2037.0" y="971.0"/>
+        <omgdi:waypoint x="1334.0" y="971.0"/>
+        <omgdi:waypoint x="1180.0" y="844.0"/>
+        <omgdi:waypoint x="1180.0" y="570.95"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="active2UpdateApproval" 
id="BPMNEdge_active2UpdateApproval">
+        <omgdi:waypoint x="1539.9207478005092" y="540.0"/>
+        <omgdi:waypoint x="1554.0" y="540.0"/>
+        <omgdi:waypoint x="1554.0" y="770.0"/>
+        <omgdi:waypoint x="1605.0" y="770.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-B5FFEBCA-1FBF-457F-BC55-39FD387188B2" 
id="BPMNEdge_sid-B5FFEBCA-1FBF-457F-BC55-39FD387188B2">
+        <omgdi:waypoint x="1790.0" y="789.9304794520548"/>
+        <omgdi:waypoint x="1790.0" y="821.0"/>
+        <omgdi:waypoint x="2270.0" y="821.0"/>
+        <omgdi:waypoint x="2270.0" y="417.95"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="deleteApprovalGW2Delete" 
id="BPMNEdge_deleteApprovalGW2Delete">
+        <omgdi:waypoint x="1809.9339371980677" y="320.0"/>
+        <omgdi:waypoint x="1852.0" y="320.0"/>
+        <omgdi:waypoint x="1852.0" y="388.0"/>
+        <omgdi:waypoint x="2220.0" y="388.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="createAsAnonymous2Approval" 
id="BPMNEdge_createAsAnonymous2Approval">
+        <omgdi:waypoint x="369.91892523364487" y="527.0"/>
+        <omgdi:waypoint x="382.0" y="527.0"/>
+        <omgdi:waypoint x="382.0" y="590.0"/>
+        <omgdi:waypoint x="420.0" y="590.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="createApproval2Reject" 
id="BPMNEdge_createApproval2Reject">
+        <omgdi:waypoint x="609.9189252336447" y="590.0"/>
+        <omgdi:waypoint x="622.0" y="590.0"/>
+        <omgdi:waypoint x="622.0" y="689.0"/>
+        <omgdi:waypoint x="660.0" y="689.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-53FA7F29-CE60-4AE6-921D-AF7331CDB19F" 
id="BPMNEdge_sid-53FA7F29-CE60-4AE6-921D-AF7331CDB19F">
+        <omgdi:waypoint x="1790.0" y="855.0"/>
+        <omgdi:waypoint x="1790.0" y="789.9079463570856"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="rejected2Delete" 
id="BPMNEdge_rejected2Delete">
+        <omgdi:waypoint x="1029.9339371980675" y="800.0"/>
+        <omgdi:waypoint x="1072.0" y="800.0"/>
+        <omgdi:waypoint x="1323.0" y="1000.0"/>
+        <omgdi:waypoint x="2270.0" y="1000.0"/>
+        <omgdi:waypoint x="2270.0" y="417.95"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-F746E78F-F59B-4842-9D88-C9C79474FC06" 
id="BPMNEdge_sid-F746E78F-F59B-4842-9D88-C9C79474FC06">
+        <omgdi:waypoint x="400.83333333333337" y="770.0"/>
+        <omgdi:waypoint x="367.0" y="683.0"/>
+        <omgdi:waypoint x="436.7741935483871" y="619.9499999999999"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="enableGW2Active" 
id="BPMNEdge_enableGW2Active">
+        <omgdi:waypoint x="729.9433984115534" y="449.0"/>
+        <omgdi:waypoint x="861.0" y="449.0"/>
+        <omgdi:waypoint x="861.0" y="541.0"/>
+        <omgdi:waypoint x="1130.0" y="541.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="flow14ter" id="BPMNEdge_flow14ter">
+        <omgdi:waypoint x="1889.9999999999998" y="260.7451923076923"/>
+        <omgdi:waypoint x="1524.0" y="193.0"/>
+        <omgdi:waypoint x="1209.6057471264367" y="511.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-26ACDEC4-8BE2-4E70-BB63-36B6375B7EEC" 
id="BPMNEdge_sid-26ACDEC4-8BE2-4E70-BB63-36B6375B7EEC">
+        <omgdi:waypoint x="1940.0" y="180.0"/>
+        <omgdi:waypoint x="1940.0" y="135.0"/>
+        <omgdi:waypoint x="1839.95" y="135.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="suspended2Delete" 
id="BPMNEdge_suspended2Delete">
+        <omgdi:waypoint x="1959.9469781884277" y="200.0"/>
+        <omgdi:waypoint x="2270.0" y="200.0"/>
+        <omgdi:waypoint x="2270.0" y="358.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="deleteApprovalGW2Reject" 
id="BPMNEdge_deleteApprovalGW2Reject">
+        <omgdi:waypoint x="1809.9339371980677" y="320.0"/>
+        <omgdi:waypoint x="1852.0" y="320.0"/>
+        <omgdi:waypoint x="1852.0" y="270.0"/>
+        <omgdi:waypoint x="1889.9999999999768" y="270.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="createApprovalGW2EnableGW" 
id="BPMNEdge_createApprovalGW2EnableGW">
+        <omgdi:waypoint x="609.9189252336447" y="590.0"/>
+        <omgdi:waypoint x="622.0" y="590.0"/>
+        <omgdi:waypoint x="622.0" y="449.0"/>
+        <omgdi:waypoint x="690.0" y="449.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="created2Created" 
id="BPMNEdge_created2Created">
+        <omgdi:waypoint x="1102.0" y="243.0"/>
+        <omgdi:waypoint x="1051.95" y="243.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="suspended2Reactivate" 
id="BPMNEdge_suspended2Reactivate">
+        <omgdi:waypoint x="1959.9339371980413" y="200.0"/>
+        <omgdi:waypoint x="2002.0" y="200.0"/>
+        <omgdi:waypoint x="2002.0" y="140.0"/>
+        <omgdi:waypoint x="2039.999999999977" y="140.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="active2DeleteApproval" 
id="BPMNEdge_active2DeleteApproval">
+        <omgdi:waypoint x="1539.9207478005092" y="540.0"/>
+        <omgdi:waypoint x="1554.0" y="540.0"/>
+        <omgdi:waypoint x="1554.0" y="310.0"/>
+        <omgdi:waypoint x="1590.0" y="310.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="flow17" id="BPMNEdge_flow17">
+        <omgdi:waypoint x="1742.95" y="591.0"/>
+        <omgdi:waypoint x="1848.0" y="591.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="flow18" id="BPMNEdge_flow18">
+        <omgdi:waypoint x="1847.9999999999998" y="619.3716000000001"/>
+        <omgdi:waypoint x="1773.0" y="662.0"/>
+        <omgdi:waypoint x="1229.9499999999998" y="551.1921585160202"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-A2BDF803-688C-4A4D-9D33-6D859C029245" 
id="BPMNEdge_sid-A2BDF803-688C-4A4D-9D33-6D859C029245">
+        <omgdi:waypoint x="1655.0" y="799.9499999999999"/>
+        <omgdi:waypoint x="1655.0" y="875.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="flow13" id="BPMNEdge_flow13">
+        <omgdi:waypoint x="759.9499999998994" y="689.0"/>
+        <omgdi:waypoint x="772.0" y="689.0"/>
+        <omgdi:waypoint x="772.0" y="800.0"/>
+        <omgdi:waypoint x="810.0" y="800.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="flow14" id="BPMNEdge_flow14">
+        <omgdi:waypoint x="860.0" y="770.0"/>
+        <omgdi:waypoint x="860.0" y="732.0"/>
+        <omgdi:waypoint x="1010.0" y="732.0"/>
+        <omgdi:waypoint x="1010.0" y="780.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="flow15" id="BPMNEdge_flow15">
+        <omgdi:waypoint x="1742.95" y="481.62182926829274"/>
+        <omgdi:waypoint x="1847.9999999999989" y="481.8780487804878"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-B2EEC511-2924-4A95-B0B8-E35DA268DD58" 
id="BPMNEdge_sid-B2EEC511-2924-4A95-B0B8-E35DA268DD58">
+        <omgdi:waypoint x="590.0" y="609.9462931995539"/>
+        <omgdi:waypoint x="590.0" y="859.0"/>
+        <omgdi:waypoint x="1010.0" y="859.0"/>
+        <omgdi:waypoint x="1010.0" y="819.9168505942274"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="updateApprovalGW2Reject" 
id="BPMNEdge_updateApprovalGW2Reject">
+        <omgdi:waypoint x="1809.9339371980675" y="770.0"/>
+        <omgdi:waypoint x="1852.0" y="770.0"/>
+        <omgdi:waypoint x="1852.0" y="870.0"/>
+        <omgdi:waypoint x="1890.0" y="870.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="flow16" id="BPMNEdge_flow16">
+        <omgdi:waypoint x="1848.0" y="458.94174757281553"/>
+        <omgdi:waypoint x="1692.0" y="387.0"/>
+        <omgdi:waypoint x="1229.9499999999998" y="525.9609375"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-C9FA59AF-4F39-489E-B424-5C06B15AE317" 
id="BPMNEdge_sid-C9FA59AF-4F39-489E-B424-5C06B15AE317">
+        <omgdi:waypoint x="450.0" y="680.0"/>
+        <omgdi:waypoint x="412.0" y="680.0"/>
+        <omgdi:waypoint x="412.375" y="770.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="flow14bis" id="BPMNEdge_flow14bis">
+        <omgdi:waypoint x="1689.949999999984" y="310.0"/>
+        <omgdi:waypoint x="1702.0" y="310.0"/>
+        <omgdi:waypoint x="1702.0" y="320.0"/>
+        <omgdi:waypoint x="1770.0" y="320.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="created2Activate" 
id="BPMNEdge_created2Activate">
+        <omgdi:waypoint x="1141.9407724328892" y="243.0"/>
+        <omgdi:waypoint x="1180.0" y="243.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-12E29B94-C369-45C1-BCEF-C165AFDA525A" 
id="BPMNEdge_sid-12E29B94-C369-45C1-BCEF-C165AFDA525A">
+        <omgdi:waypoint x="1674.9426165798702" y="895.0"/>
+        <omgdi:waypoint x="1739.9999999997615" y="895.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-E58BBC2D-8831-4CF2-A798-14B258FE569B" 
id="BPMNEdge_sid-E58BBC2D-8831-4CF2-A798-14B258FE569B">
+        <omgdi:waypoint x="1770.0" y="770.0"/>
+        <omgdi:waypoint x="1704.95" y="770.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="enableGW2Activate" 
id="BPMNEdge_enableGW2Activate">
+        <omgdi:waypoint x="729.9339371980061" y="449.0"/>
+        <omgdi:waypoint x="772.0" y="449.0"/>
+        <omgdi:waypoint x="772.0" y="640.0"/>
+        <omgdi:waypoint x="810.0" y="640.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="enableGW2Suspended" 
id="BPMNEdge_enableGW2Suspended">
+        <omgdi:waypoint x="729.9339371980061" y="449.0"/>
+        <omgdi:waypoint x="772.0" y="449.0"/>
+        <omgdi:waypoint x="772.0" y="130.0"/>
+        <omgdi:waypoint x="1590.0" y="130.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="create2Activate" 
id="BPMNEdge_create2Activate">
+        <omgdi:waypoint x="369.91892523364487" y="527.0"/>
+        <omgdi:waypoint x="382.0" y="527.0"/>
+        <omgdi:waypoint x="382.0" y="449.0"/>
+        <omgdi:waypoint x="690.0" y="449.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="active2RequestPasswordReset" 
id="BPMNEdge_active2RequestPasswordReset">
+        <omgdi:waypoint x="1539.9442374350085" y="540.0"/>
+        <omgdi:waypoint x="1693.0" y="540.0"/>
+        <omgdi:waypoint x="1693.0" y="510.95"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10">
+        <omgdi:waypoint x="1689.95" y="130.0"/>
+        <omgdi:waypoint x="1702.0" y="130.0"/>
+        <omgdi:waypoint x="1702.0" y="150.0"/>
+        <omgdi:waypoint x="1739.9999999999768" y="150.0"/>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11">
-        <omgdi:waypoint x="1739.95" y="400.0"/>
-        <omgdi:waypoint x="1820.0" y="400.0"/>
+        <omgdi:waypoint x="1839.95" y="165.0"/>
+        <omgdi:waypoint x="1879.0" y="165.0"/>
+        <omgdi:waypoint x="1879.0" y="200.0"/>
+        <omgdi:waypoint x="1920.0" y="200.0"/>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge bpmnElement="flow99" id="BPMNEdge_flow99">
-        <omgdi:waypoint x="2039.9499999999982" y="466.5576923076923"/>
-        <omgdi:waypoint x="2080.005704870052" y="465.4022398573087"/>
-      </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge bpmnElement="active2Suspend" 
id="BPMNEdge_active2Suspend">
-        <omgdi:waypoint x="1439.9416944213153" y="540.0"/>
-        <omgdi:waypoint x="1540.0" y="540.0"/>
-        <omgdi:waypoint x="1540.0" y="429.95"/>
+        <omgdi:waypoint x="2319.9499999999875" y="388.0"/>
+        <omgdi:waypoint x="2358.0" y="388.0"/>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge bpmnElement="flow12" id="BPMNEdge_flow12">
-        <omgdi:waypoint x="1990.0" y="290.0"/>
-        <omgdi:waypoint x="1990.0" y="261.0"/>
-        <omgdi:waypoint x="1080.0" y="261.0"/>
-        <omgdi:waypoint x="1080.0" y="511.0"/>
+        <omgdi:waypoint x="2040.0" y="129.51612903225808"/>
+        <omgdi:waypoint x="2028.0" y="127.0"/>
+        <omgdi:waypoint x="1478.0" y="40.0"/>
+        <omgdi:waypoint x="1197.8145708582833" y="511.0"/>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge bpmnElement="sid-A37806A7-6B7B-48A2-BB37-DAE640231144" 
id="BPMNEdge_sid-A37806A7-6B7B-48A2-BB37-DAE640231144">
-        <omgdi:waypoint x="1724.9999999998677" y="850.4571226080794"/>
-        <omgdi:waypoint x="1080.0" y="850.0"/>
-        <omgdi:waypoint x="1080.0" y="570.95"/>
+      <bpmndi:BPMNEdge bpmnElement="flow8ter" id="BPMNEdge_flow8ter">
+        <omgdi:waypoint x="1940.0" y="899.9499999999999"/>
+        <omgdi:waypoint x="1940.0" y="948.0"/>
+        <omgdi:waypoint x="1339.0" y="948.0"/>
+        <omgdi:waypoint x="1214.0" y="837.0"/>
+        <omgdi:waypoint x="1183.4402027027027" y="570.95"/>
       </bpmndi:BPMNEdge>
     </bpmndi:BPMNPlane>
   </bpmndi:BPMNDiagram>
-</definitions>
\ No newline at end of file
+</definitions>
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index d2d91adc55..1be5c9a51e 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -1393,7 +1393,7 @@ under the License.
             <inherited>true</inherited>
             <configuration>
               <container>
-                <containerId>wildfly39x</containerId>
+                <containerId>wildfly40x</containerId>
                 <zipUrlInstaller>
                   
<url>https://github.com/wildfly/wildfly/releases/download/${wildfly.version}/wildfly-${wildfly.version}.zip</url>
                   
<downloadDir>${settings.localRepository}/org/codehaus/cargo/cargo-container-archives</downloadDir>
diff --git a/fit/core-reference/src/main/resources/core-wildfly.properties 
b/fit/core-reference/src/main/resources/core-wildfly.properties
index f8c3e31e9b..3e227ff177 100644
--- a/fit/core-reference/src/main/resources/core-wildfly.properties
+++ b/fit/core-reference/src/main/resources/core-wildfly.properties
@@ -14,7 +14,7 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-persistence.metaDataFactory=jpa(URLs=vfs:${project.build.directory}/cargo/configurations/wildfly39x/deployments/syncope.war/WEB-INF/lib/syncope-core-persistence-jpa-${syncope.version}.jar;
 
vfs:${project.build.directory}/cargo/configurations/wildfly39x/deployments/syncope.war/WEB-INF/lib/syncope-core-self-keymaster-starter-${syncope.version}.jar,
 Resources=##orm##)
+persistence.metaDataFactory=jpa(URLs=vfs:${project.build.directory}/cargo/configurations/wildfly40x/deployments/syncope.war/WEB-INF/lib/syncope-core-persistence-jpa-${syncope.version}.jar;
 
vfs:${project.build.directory}/cargo/configurations/wildfly40x/deployments/syncope.war/WEB-INF/lib/syncope-core-self-keymaster-starter-${syncope.version}.jar,
 Resources=##orm##)
 
 
javadocPaths=/WEB-INF/lib/syncope-common-idrepo-rest-api-${syncope.version}-javadoc.jar,\
 /WEB-INF/lib/syncope-common-idm-rest-api-${syncope.version}-javadoc.jar,\
diff --git a/fit/core-reference/src/main/resources/userWorkflow.bpmn20.xml 
b/fit/core-reference/src/main/resources/userWorkflow.bpmn20.xml
index 68ea2217a2..697f175951 100644
--- a/fit/core-reference/src/main/resources/userWorkflow.bpmn20.xml
+++ b/fit/core-reference/src/main/resources/userWorkflow.bpmn20.xml
@@ -26,7 +26,7 @@ under the License.
              typeLanguage="http://www.w3.org/2001/XMLSchema"; 
              expressionLanguage="http://www.w3.org/1999/XPath"; 
              targetNamespace="http://www.flowable.org/processdef";>
- 
+
   <process id="userWorkflow" name="User Workflow" isExecutable="true">
     <startEvent id="theStart"/>
     <sequenceFlow id="flow1" sourceRef="theStart" targetRef="create"/>
@@ -99,7 +99,7 @@ try {
     <exclusiveGateway id="activeGw"/>
     <sequenceFlow id="active2UpdateApproval" sourceRef="activeGw" 
targetRef="updateApproval">
       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${wfExecutor 
== user.getUsername() and task == 'update' 
-        and (!userUR.getMemberships().isEmpty())}]]></conditionExpression>
+        and userUR.requiresApproval()}]]></conditionExpression>
     </sequenceFlow>
     <sequenceFlow id="active2DeleteApproval" sourceRef="activeGw" 
targetRef="deleteApproval">
       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${wfExecutor 
== user.getUsername() and task == 'delete'}]]></conditionExpression>
diff --git 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
index 4ee88229e6..a90327a0bf 100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
@@ -27,6 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 import static org.junit.jupiter.api.Assumptions.assumeFalse;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 import jakarta.ws.rs.HttpMethod;
@@ -1550,6 +1551,8 @@ public class UserIssuesITCase extends AbstractITCase {
 
     @Test
     public void issueSYNCOPE1793() {
+        assumeTrue(IS_FLOWABLE_ENABLED);
+
         RoleTO role = new RoleTO();
         role.setKey("syncope1793" + getUUIDString());
         role.getRealms().add(SyncopeConstants.ROOT_REALM);
diff --git 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
index ee4981bfa2..538cd23579 100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
@@ -807,4 +807,87 @@ public class UserSelfITCase extends AbstractITCase {
         UserTO userTO = ADMIN_CLIENT.self().user();
         assertEquals(ADMIN_UNAME, userTO.getUsername());
     }
+
+    @Test
+    public void issueSYNCOPE1983Default() {
+        assumeFalse(IS_FLOWABLE_ENABLED);
+
+        // 1. create
+        UserCR userCR = 
UserITCase.getUniqueSample("[email protected]");
+        userCR.getRoles().add("User manager");
+
+        SyncopeClientException e = assertThrows(
+                SyncopeClientException.class,
+                () -> 
ANONYMOUS_CLIENT.getService(UserSelfService.class).create(userCR));
+        assertEquals(ClientExceptionType.Workflow, e.getType());
+
+        // remove roles so self registration can proceed
+        userCR.getRoles().clear();
+
+        UserTO user = ANONYMOUS_CLIENT.getService(UserSelfService.class).
+                create(userCR).
+                readEntity(new GenericType<ProvisioningResult<UserTO>>() {
+                }).getEntity();
+        assertNotNull(user);
+
+        // 2. update
+        UserUR userUR = new UserUR.Builder(user.getKey()).
+                username(new 
StringReplacePatchItem.Builder().value(user.getUsername() + 
getUUIDString()).build()).
+                role(new StringPatchItem.Builder().value("User 
manager").build()).
+                build();
+
+        SyncopeClient authClient = CLIENT_FACTORY.create(user.getUsername(), 
"password123");
+        e = assertThrows(
+                SyncopeClientException.class,
+                () -> 
authClient.getService(UserSelfService.class).update(userUR));
+        assertEquals(ClientExceptionType.Workflow, e.getType());
+
+        // remove roles so update can proceed
+        userUR.getRoles().clear();
+
+        user = authClient.getService(UserSelfService.class).
+                update(userUR).
+                readEntity(new GenericType<ProvisioningResult<UserTO>>() {
+                }).getEntity();
+        assertNotNull(user);
+    }
+
+    @Test
+    public void issueSYNCOPE1983Flowable() {
+        assumeTrue(IS_FLOWABLE_ENABLED);
+
+        // 1. create
+        UserCR userCR = 
UserITCase.getUniqueSample("[email protected]");
+        userCR.getRoles().add("User manager");
+
+        UserTO user = ANONYMOUS_CLIENT.getService(UserSelfService.class).
+                create(userCR).
+                readEntity(new GenericType<ProvisioningResult<UserTO>>() {
+                }).getEntity();
+        assertNotNull(user);
+        assertEquals("createApproval", user.getStatus());
+
+        // approve
+        UserRequestForm form = USER_REQUEST_SERVICE.listForms(
+                new 
UserRequestQuery.Builder().user(user.getKey()).build()).getResult().getFirst();
+        form = USER_REQUEST_SERVICE.claimForm(form.getTaskId());
+        
form.getProperty("approveCreate").get().setValue(Boolean.TRUE.toString());
+        user = USER_REQUEST_SERVICE.submitForm(form).readEntity(new 
GenericType<ProvisioningResult<UserTO>>() {
+        }).getEntity();
+        assertNotNull(user);
+        assertEquals("active", user.getStatus());
+
+        // 2. update
+        UserUR userUR = new UserUR.Builder(user.getKey()).
+                username(new 
StringReplacePatchItem.Builder().value(user.getUsername() + 
getUUIDString()).build()).
+                role(new StringPatchItem.Builder().value("User 
manager").build()).
+                build();
+
+        SyncopeClient authClient = CLIENT_FACTORY.create(user.getUsername(), 
"password123");
+        user = authClient.getService(UserSelfService.class).
+                update(userUR).
+                readEntity(new GenericType<ProvisioningResult<UserTO>>() {
+                }).getEntity();
+        assertEquals("updateApproval", user.getStatus());
+    }
 }
diff --git a/src/main/asciidoc/images/userWorkflow.png 
b/src/main/asciidoc/images/userWorkflow.png
index 04c63722c4..a522f38dce 100644
Binary files a/src/main/asciidoc/images/userWorkflow.png and 
b/src/main/asciidoc/images/userWorkflow.png differ
diff --git 
a/src/main/asciidoc/reference-guide/configuration/configurationparameters.adoc 
b/src/main/asciidoc/reference-guide/configuration/configurationparameters.adoc
index e55ba970f4..e5625a62bb 100644
--- 
a/src/main/asciidoc/reference-guide/configuration/configurationparameters.adoc
+++ 
b/src/main/asciidoc/reference-guide/configuration/configurationparameters.adoc
@@ -76,7 +76,11 @@ or to completely disable connector connection testing.
 [NOTE]
 ====
 This parameter is useful to avoid waiting for the default resource timeout, by 
setting a shorter value; 
-or to completely disable resource connection testing.
+or to completely disable resource connection testing;
 ====
 
+* `default.workflow.requires.approval` - when using the default 
<<workflow,user workflow adapter>> (e.g. not
+<<flowable-user-workflow-adapter,Flowable>>), this option controls whether an 
exception shall be raised when any
+requested change requires admin approval.
+
 Besides this default set, new configuration parameters can be defined to 
support <<customization,custom>> code.

Reply via email to