//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//
=== Workflow

Workflow manages the internal identity lifecycle by defining statuses and transitions that every user, group or any
object in Apache Syncope will traverse. A workflow instance is started once identities get created, and shut down when
they are removed.

Workflow is triggered during the <<provisioning,provisioning>> process as the first step in creating, updating or deleting
identities into the internal storage.

[[workflow-adapters]]
[NOTE]
.Workflow Adapters
====
The workflow features are defined by the workflow adapter interfaces:

ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java[UserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/tree/2_0_X/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java[UserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/GroupWorkflowAdapter.java[GroupWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/tree/2_0_X/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/GroupWorkflowAdapter.java[GroupWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/AnyObjectWorkflowAdapter.java[AnyObjectWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/tree/2_0_X/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/AnyObjectWorkflowAdapter.java[AnyObjectWorkflowAdapter^]
endif::[]

Default implementations are available:

ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/tree/2_0_X/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java[DefaultGroupWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/tree/2_0_X/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java[DefaultGroupWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java[DefaultAnyObjectWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/tree/2_0_X/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java[DefaultAnyObjectWorkflowAdapter^]
endif::[]

Custom adapters can be provided by implementing the related interfaces, also as bridges towards third-party tools as 
https://camunda.org/[Camunda^] or http://jbpm.jboss.org/[jBPM^].
====

[[which-user-worflow-adapter]]
[TIP]
.Which workflow adapter for users?
====
. Do you need <<approval,approval>> management? <<activiti-user-workflow-adapter,Activiti>> or
<<flowable-user-workflow-adapter,Flowable>>
. If approval management is not needed, do you want to customize the internal user processing, or attach custom logic
to it? Provide a Java class with your customizations, extending
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/tree/2_0_X/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
. No approval nor customizations needed? Stick with
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/tree/2_0_X/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
====

==== Activiti User Workflow Adapter

An advanced adapter is provided for Users, based on http://www.activiti.org/[Activiti BPM^], one of reference open
source http://www.bpmn.org/[BPMN 2.0^] implementations.

The
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java[ActivitiUserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/tree/2_0_X/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java[ActivitiUserWorkflowAdapter^]
endif::[]
is bootstrapped from
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-activiti/src/main/resources/userWorkflow.bpmn20.xml[userWorkflow.bpmn20.xml^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/tree/2_0_X/core/workflow-activiti/src/main/resources/userWorkflow.bpmn20.xml[userWorkflow.bpmn20.xml^]
endif::[]
and presents several advantages and more features, if compared to the default user adapter:

. Besides mandatory statuses, which are modeled as BPMN `userTask` instances, more can be freely added
at runtime, provided that adequate transitions and conditions are also inserted; more details about available BPMN
constructs are available in the http://www.activiti.org/userguide/index.html#bpmnConstructs[Activiti User Guide^]. +
Additional statuses and transitions allow the internal processes of Apache Syncope to better adapt to suit organizational flows.
. Custom logic can be injected into the workflow process by providing BPMN `serviceTask` instances.
. http://www.activiti.org/userguide/index.html#forms[Activiti forms^] are used for implementing <<approval,approval>>.
. The http://www.activiti.org/userguide/index.html#activitiModeler[Activiti Modeler^] can be enabled in the
<<admin-console,admin console>>, thus allowing web-based graphical modeling of the workflow definition.

[.text-center]
image::userWorkflow.png[title="Default Activiti user workflow",alt="Default Activiti user workflow"] 

===== Approval

Every transition in the Activiti user workflow definition can be subjected to approval.

The underlying idea is that some kind of self-modifications (group memberships, external resource assignments, ...)
might not be allowed to 'plain' Users, as there could be conditions which require management approval.
Managers could also be asked to complete the information provided before the requested operation is finished.

In order to define an approval form, a dedicated BPMN `userTask` needs to be defined, following the rules established
for http://www.activiti.org/userguide/index.html#forms[Activiti forms^].

[NOTE]
.What is required for administrators to manage approval?
====
The following conditions must be met, for an User `U` to act as administrator for approval:

. `U` must own the following <<entitlements,entitlements>>, for all the required realms:
.. `WORKFLOW_FORM_CLAIM`
.. `WORKFLOW_FORM_LIST`
.. `WORKFLOW_FORM_READ`
.. `WORKFLOW_FORM_SUBMIT`
.. `USER_READ`
. The BPMN `userTask` must either indicate `U` among `candidateUsers` or at least one of the groups assigned to `U`
among `candidateGroups`, as required by
http://www.activiti.org/userguide/index.html#bpmnUserTaskUserAssignmentExtension[Activiti's task assignment rules^]

The special super-user `admin` is entitled to manage all approvals, even those not specifying any
`candidateUsers` or `candidateGroups`.
====

[[sample-selfreg-approval]]
.Approving self-registration
====
The snippet below shows how to define an approval form in XML; the same operation can be performed via the
http://www.activiti.org/userguide/index.html#activitiModeler[Activiti Modeler^].

[source,xml]
----
<userTask id="createApproval" name="Create approval"
          activiti:candidateGroups="managingDirector" activiti:formKey="createApproval"> // <1>
  <extensionElements>
    <activiti:formProperty id="username" name="Username" type="string"
                           expression="${user.username}" writable="false"/> // <2>
    <activiti:formProperty id="approve" name="Approve?" type="boolean"
                           variable="approve" required="true"/> // <3>
    <activiti:formProperty id="rejectReason" name="Reason for rejecting" type="string"
                           variable="rejectReason"/>
  </extensionElements>
</userTask>
----
<1> `formKey` and `id` must be unique across the workflow definition, `name` is displayed by the admin console;
`candidateGroups` and `candidateUsers` might be defined, even both, to indicate which Groups or Users should be
managing these approvals; if none are specified, only `admin` is entitled to manage such approval
<2> `expression` will be evaluated against the current requesting `user` (as workflow variable) and related properties;
read-only form input can be defined by setting `writable="false"`
<3> exporting approval inputs into workflow variables is possible via the `variable` attribute; required form input can
be defined by setting `required="true"`
====

Once the form is defined, any modification subject to that approval will be manageable via the admin console, according to
the following flow (the actual operations on the admin console for the sample above are reported <<console-approval,below>>):

. administrator A sees the new approval notifications +
. administrator A claims the approval and is then allowed to manage it
. administrator A reviews the updated user, with ongoing modification applied (no actual modification performed yet)
. administrator A can approve or reject such modification

===== Identity Recertification

Recertification, also referred to as Attestation, is the process of periodically reviewing all the identities and
granted accesses, within a given organization.

[TIP]
====
Recertification is the traditional and most effective countermeasure against __privilege creep__, that is the
retention of accounts during time even when the user change his role, or even his job. 

Recertification is a good practice, recommended and often required by international or organizational standards.
====

Typically, every entity within an Identity Manager needs to be periodically recertified:

* *Identities*: Is the user still valid for the organization?
* *Accounts*: Is the user still using this account?
* *Group Memberships / Entitlements*: Does the user require this functionality?

A basic <<tasks-custom,custom task>> implementing identity recertification is provided with the
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/IdentityRecertification.java[IdentityRecertification^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/tree/2_0_X/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/IdentityRecertification.java[IdentityRecertification^]
endif::[]
class, which can be used as base to implement more complex recertification processes.

Essentially, this task goes through all the available users and checks whether they were already recertified in the
past `identity.recertification.day.interval` days - see <<configuration-parameters, below>> for details; when needed,
it triggers a specific <<approval,approval>>.

The delegated administrator for approving recertifications can be configured by modifying the
"Recertification Request" task in the workflow definition.

.Certifiers are members of the `managingDirector` group
====
[source,xml]
----
<userTask id="recertificationRequest" name="Recertification Request"
          activiti:formKey="recertify"
          activiti:candidateGroups="managingDirector">
----
====

.Certifier is the manager defined in the user's `lastRecertificator` attribute
====
[source,xml]
----
<userTask id="recertificationRequest" name="Recertification Request"
          activiti:formKey="recertify"
          activiti:candidateUser="${user.lastRecertificator}">
----
====

==== Flowable User Workflow Adapter

Starting with Apache Syncope 2.0.3, another advanced adapter is provided for Users, based on
http://www.flowable.org/[Flowable^], one of reference open source http://www.bpmn.org/[BPMN 2.0^] implementations.

Since Flowable was https://blog.flowable.org/2016/10/12/flowable-and-activiti-what-the-fork/[forked from Activiti BPM^],
everything stated <<activiti-user-workflow-adapter,above>> about Activiti BPM can be applied.
