chap-workflow.xml revision 49da166d507312f800a326215fea42407ce9bc25
<?xml version="1.0" encoding="UTF-8"?>
<!--
! CCPL HEADER START
!
! This work is licensed under the Creative Commons
! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
! To view a copy of this license, visit
! http://creativecommons.org/licenses/by-nc-nd/3.0/
! or send a letter to Creative Commons, 444 Castro Street,
! Suite 900, Mountain View, California, 94041, USA.
!
! You can also obtain a copy of the license at
! legal/CC-BY-NC-ND.txt.
! See the License for the specific language governing permissions
! and limitations under the License.
!
! If applicable, add the following below this CCPL HEADER, with the fields
! enclosed by brackets "[]" replaced with your own identifying information:
! Portions Copyright [yyyy] [name of copyright owner]
!
! CCPL HEADER END
!
! Copyright 2011-2014 ForgeRock AS
!
-->
<chapter xml:id='chap-workflow'
xmlns='http://docbook.org/ns/docbook'
version='5.0' xml:lang='en'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:schemaLocation='http://docbook.org/ns/docbook
http://docbook.org/xml/5.0/xsd/docbook.xsd'
xmlns:xlink='http://www.w3.org/1999/xlink'>
<title>Integrating Business Processes and Workflows</title>
<indexterm>
<primary>Workflow</primary>
</indexterm>
<indexterm>
<primary>Business processes</primary>
</indexterm>
<para>Key to any identity management solution is the ability to provide
workflow-driven provisioning activities, whether for self-service actions
such as requests for entitlements, roles or resources, running sunrise or
sunset processes, handling approvals with escalations, or performing
maintenance.</para>
<para>OpenIDM provides an embedded workflow and business process engine
based on Activiti and the Business Process Model and Notation (BPMN) 2.0
standard.</para>
<para>More information about Activiti and the Activiti project can be found
at <link xlink:href="http://www.activiti.org" xlink:show="new" />.</para>
<section xml:id="about-bmpm-2-activiti">
<title>BPMN 2.0 and the Activiti Tools</title>
<para>Business Process Model and Notation 2.0 is the result of consensus
among Business Process Management (BPM) system vendors. The <link
xlink:href="http://omg.org/" xlink:show="new">Object Management Group</link>
(OMG) has developed and maintained the <link xlink:show="new"
xlink:href="http://www.omg.org/spec/BPMN/">BPMN</link> standard since
2004.</para>
<para>The first version of the BPMN specification focused only on graphical
notation, and quickly became popular with the business analyst audience.
BPMN 1.x defines how constructs such as human tasks, executable scripts, and
automated decisions are visualized in a vendor-neutral, standard way. The
second version of BPMN extends that focus to include execution semantics,
and a common exchange format. Thus, BPMN 2.0 process definition models
can be exchanged not only between different graphical editors, but can also
be executed as is on any BPMN 2.0-compliant engine, such as the engine
embedded in OpenIDM.</para>
<para>Using BPMN 2.0, you can add artifacts describing workflow and business
process behavior to OpenIDM for provisioning and other purposes. For example,
you can craft the actual artifacts defining business processes and workflow
in a text editor, or using a special Eclipse plugin. The Eclipse plugin
provides visual design capabilities, simplifying packaging and deployment of
the artifact to OpenIDM. See the <link
xlink:href="http://docs.codehaus.org/display/ACT/Activiti+BPMN+2.0+Eclipse+Plugin"
xlink:show="new">Activiti BPMN 2.0 Eclipse Plugin</link> documentation for
instructions on installing Activiti Eclipse BPMN 2.0 Designer.</para>
<para>Also, read the Activiti <citetitle>User Guide</citetitle> section
covering <link xlink:href="http://www.activiti.org/userguide/#bpmnConstructs"
xlink:show="new"><citetitle>BPMN 2.0 Constructs</citetitle></link>, which
describes in detail the graphical notations and XML representations for
events, flows, gateways, tasks, and process constructs.</para>
<para>
With the latest version of Activiti, JavaScript tasks can be added to
workflow definitions. However, OpenIDM functions cannot be called from a
JavaScript task in a workflow. Therefore, you can use JavaScript for
non-OpenIDM workflow tasks, but you must use the
<literal>activiti:expression</literal> construct to call OpenIDM functions.
</para>
</section>
<section xml:id="setting-up-activiti">
<title>Setting Up Activiti Integration With OpenIDM</title>
<para>
OpenIDM embeds an Activiti Process Engine that is started in the OpenIDM OSGi
container.
</para>
<para>
After OpenIDM has been installed (as described in the
<link xlink:href="install-guide#chap-install"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Installation
Guide</citetitle></link>), start OpenIDM, and run the
<command>scr list</command> command at the console to check that the workflow
bundle is active.
</para>
<screen>-> OpenIDM ready
<userinput>scr list</userinput>
Id State Name
...
[ 39] [active ] org.forgerock.openidm.workflow
...</screen>
<para>
OpenIDM reads workflow definitions from the
<literal>/path/to/openidm/workflow</literal> directory. To test workflow
integration, at least one workflow definition must exist in this directory.
</para>
<para>
A sample workflow (<filename>example.bpmn20.xml</filename>) is provided in
the <literal>/path/to/openidm/samples/misc</literal> directory. Copy this
workflow to the <literal>/path/to/openidm/workflow</literal> directory to
test the workflow integration.
</para>
<screen>$ cd /path/to/openidm
$ cp samples/misc/example.bpmn20.xml workflow/</screen>
<para>
Verify the workflow integration by using the REST API. The following
REST call lists the defined workflows:
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processdefinition?_queryId=query-all-ids"
</userinput></screen>
<para>
The sample workflow definition that you copied in the previous step is named
<literal>osgiProcess</literal>. The result of the preceding REST call
therefore includes output similar to the following:
</para>
<screen><computeroutput>{
...
"result":[
{
...
"key": "osgiProcess",
...
"name":"Osgi process",
...
"_id":"osgiProcess:1:3",
...
}
]
}</computeroutput></screen>
<para>
The <literal>osgiProcess</literal> workflow calls OpenIDM, queries the
available workflow definitions from Activiti, then prints the list of
workflow definitions to the OpenIDM logs. Invoke the <literal>osgiProcess
</literal> workflow with the following REST call:
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
--data '{"_key":"osgiProcess"}' \
"https://localhost:8443/openidm/workflow/processinstance?_action=create"</userinput></screen>
<para>
The workflow prints the list of workflow definitions to the OpenIDM console.
With the default sample, you should see something like this on the console:
</para>
<screen><computeroutput>
script task using resolver: [
pagedResultsCookie:null,
remainingPagedResults:-1,
result:[
[
tenantId:,
candidateStarterGroupIdExpressions:[],
candidateStarterUserIdExpressions:[],
participantProcess:null,
processDiagramResourceName:null,
historyLevel:null,
hasStartFormKey:false,
laneSets:[],
version:1, _id:osgiProcess:1:3,
description:null,
name:Osgi process,
executionListeners:[:],
key:osgiProcess,
resourceName:OSGI-INF/activiti/example.bpmn20.xml,
ioSpecification:null,
taskDefinitions:null,
suspensionState:1,
deploymentId:1,
properties:[:],
startFormHandler:null,
suspended:false,
variables:null,
_rev:1,
revisionNext:2,
category:Examples,
eventSupport:[:],
graphicalNotationDefined:false
]
]
]
script task using expression resolver: [
pagedResultsCookie:null,
remainingPagedResults:-1,
result:[
[
tenantId:,
candidateStarterGroupIdExpressions:[],
...
]</computeroutput></screen>
<section xml:id="configuring-activiti-engine">
<title>Configuring the Activiti Engine</title>
<para>
The OpenIDM Activiti module is configured in a file named
<filename>conf/workflow.json</filename>. If this file is absent from the
configuration, the workflow module is unavailable for use. In the default
OpenIDM installation, the <filename>workflow.json</filename> file has the
following basic configuration:
</para>
<programlisting language="javascript">
{
"enabled" : true
}
</programlisting>
<para>
You can disable the workflow module by setting the
<literal>"enabled"</literal> property to <literal>false</literal>.
</para>
<para>
There are several additional configuration properties for the Activiti
module. A sample <filename>workflow.json</filename> file that includes all
configurable properties, is provided in <literal>samples/misc</literal>. To
configure an Activiti engine beyond the default configuration, edit this
sample file and copy it to the <literal>/path/to/openidm/conf</literal>
directory.
</para>
<para>
The sample <literal>workflow.json</literal> file contains the following
configuration:
</para>
<programlisting language="javascript">
{
"enabled" : true,
"location" : "remote",
"engine" : {
"url" : "http://localhost:9090/openidm-workflow-remote-${docTargetVersion}",
"username" : "youractivitiuser",
"password" : "youractivitipassword"
},
"mail" : {
"host" : "yourserver.smtp.com",
"port" : 587,
"username" : "yourusername",
"password" : "yourpassword",
"starttls" : true
},
"history" : "audit"
}
</programlisting>
<itemizedlist>
<para>
These fields have the following meaning:
</para>
<listitem>
<para>
<literal>enabled</literal>. Indicates whether the Activiti module is
enabled for use. Possible values are <literal>true</literal> or
<literal>false</literal>. The default value is <literal>true</literal>.
</para>
</listitem>
<listitem>
<para>
<literal>mail</literal>. Specifies the details of the mail server that
Activiti will use to send email notifications. By default, Activiti uses
the mail server <literal>localhost:25</literal>. To specify a different
mail server, enter the details of the mail server here.
</para>
<itemizedlist>
<listitem>
<para>
<literal>host</literal>. The host of the mail server.
</para>
</listitem>
<listitem>
<para>
<literal>port</literal>. The port number of the mail server.
</para>
</listitem>
<listitem>
<para>
<literal>username</literal>. The user name of the account that connects
to the mail server.
</para>
</listitem>
<listitem>
<para>
<literal>password</literal>. The password for the user specified above.
</para>
</listitem>
<listitem>
<para>
<literal>startTLS</literal>. Whether startTLS should be used to secure
the connection.
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
<literal>history</literal>. Determines the history level that should be
used for the Activiti engine. For more information, see
<link linkend="activiti-history-level">Configuring the Activiti History
Level</link>.
</para>
</listitem>
</itemizedlist>
<section xml:id="activiti-history-level">
<title>Configuring the Activiti History Level</title>
<para>
The Activiti history level determines how much historical information is
retained when workflows are executed. You can configure the history level
by setting the <literal>history</literal> property in the
<literal>workflow.json</literal> file, for example:
</para>
<programlisting>"history" : "audit"</programlisting>
<itemizedlist>
<para>
The following history levels can be configured:
</para>
<listitem>
<para>
<literal>none</literal>. No history archiving is done. This level results
in the best performance for workflow execution, but no historical
information is available.
</para>
</listitem>
<listitem>
<para>
<literal>activity</literal>. Archives all process instances and activity
instances. No details are archived.
</para>
</listitem>
<listitem>
<para>
<literal>audit</literal>. This is the default level. All process
instances, activity instances and submitted form properties are archived
so that all user interaction through forms is traceable and can be
audited.
</para>
</listitem>
<listitem>
<para>
<literal>full</literal>. This is the highest level of history archiving
and has the greatest performance impact. This history level stores all
the information that is stored for the <literal>audit</literal> level, as
well as any process variable updates.
</para>
</listitem>
</itemizedlist>
</section>
</section>
<section xml:id="defining-activiti-workflows">
<title>Defining Activiti Workflows</title>
<para>
The following section outlines the process to follow when you create an
Activiti workflow for OpenIDM. Before you start creating workflows, you must
configure the Activiti engine, as described in <link
linkend="configuring-activiti-engine">Configuring the Activiti Engine</link>.
</para>
<procedure>
<step>
<para>
Define your workflow in a text file, either using an editor, such as
Activiti Eclipse BPMN 2.0 Designer, or a simple text editor.
</para>
</step>
<step>
<para>
Package the workflow definition file as a <literal>.bar</literal> file
(Business Archive File). If you are using Eclipse to define the workflow, a
<literal>.bar</literal> file is created when you select "Create deployment
artifacts". A <literal>.bar</literal> file is essentially the same as a
<literal>.zip</literal> file, but with the <literal>.bar</literal>
extension.
</para>
</step>
<step>
<para>
Copy the <literal>.bar</literal> file to the
<literal>openidm/workflow</literal> directory.
</para>
</step>
<step>
<para>
Invoke the workflow using a script (in <literal>openidm/script/</literal>)
or directly using the REST interface. For more information, see <link
linkend="invoking-activiti-workflows">Invoking Activiti Workflows</link>.
</para>
<para>
You can also schedule the workflow to be invoked repeatedly, or at a future
time. For more information, see the <link
xlink:href="integrators-guide#appendix-scheduling"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Scheduler
Reference</citetitle></link>.
</para>
</step>
<!--TODO Add a new section that specifically describes scheduling workflows -->
</procedure>
</section>
<section xml:id="invoking-activiti-workflows">
<title>Invoking Activiti Workflows</title>
<para>
You can invoke workflows and business processes from any trigger point within
OpenIDM, including reacting to situations discovered during reconciliation.
Workflows can be invoked from script files, using the
<literal>openidm.create()</literal> function, or directly from the REST
interface.
</para>
<para>
The following sample script extract shows how to invoke a workflow from a
script file:
</para>
<programlisting language="javascript">
/*
* Calling 'myWorkflow' workflow
*/
var params = {
"_key": "myWorkflow"
};
openidm.create('workflow/processinstance', null, params);
</programlisting>
<para>
The <literal>null</literal> in this example indicates that you do not want to
specify an ID as part of the create call. For more information, see the
<link xlink:show="new" xlink:href="integrators-guide#function-create"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Function
Reference</citetitle></link>.
</para>
<para>
You can invoke the same workflow from the REST interface by sending the
following REST call to OpenIDM:
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
--data '{"_key":"myWorkflow"}' \
"https://localhost:8443/openidm/workflow/processinstance?_action=create"</userinput>
</screen>
<itemizedlist>
<para>
There are two ways in which you can specify the workflow definition that is
used when a new workflow instance is started.
</para>
<listitem>
<para>
<literal>_key</literal> specifies the <literal>id</literal> attribute of
the workflow process definition, for example:
</para>
<programlisting language="javascript">
&lt;process id="sendNotificationProcess" name="Send Notification Process"&gt;
</programlisting>
<para>
If there is more than one workflow definition with the same
<literal>_key</literal> parameter, the latest deployed version of the
workflow definition is invoked.
</para>
</listitem>
<listitem>
<para>
<literal>_processDefinitionId</literal> specifies the ID that is generated
by the Activiti Process Engine when a workflow definition is deployed, for
example:
</para>
<programlisting language="javascript">
"sendNotificationProcess:1:104";
</programlisting>
<para>
You can obtain the <literal>processDefinitionId</literal> by querying the
available workflows, for example:
</para>
<programlisting language="javascript">
{
"result": [
{
"name": "Process Start Auto Generated Task Auto Generated",
"_id": "ProcessSAGTAG:1:728"
},
{
"name": "Process Start Auto Generated Task Empty",
"_id": "ProcessSAGTE:1:725"
},
...
</programlisting>
<para>
If you specify a <literal>_key</literal> and a
<literal>_processDefinitionId</literal>, the
<literal>_processDefinitionId</literal> is used because it is more precise.
</para>
</listitem>
</itemizedlist>
<para>
You can use the optional <literal>_businessKey</literal> parameter to add
specific business logic information to the workflow when it is invoked. For
example, the following workflow invocation assigns the workflow a business
key of <literal>"newOrder"</literal>. This business key can later be used to
query "newOrder" processes.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
--data '{"_key":"myWorkflow", "_businessKey":"newOrder"}' \
"https://localhost:8443/openidm/workflow/processinstance?_action=create"</userinput></screen>
</section>
<section xml:id="querying-activiti-workflows">
<title>Querying Activiti Workflows</title>
<para>
The Activiti implementation supports filtered queries that enable you to
query the running process instances and tasks, based on specific query
parameters. To perform a filtered query send a GET request to the
<literal>workflow/processinstance</literal> context path, including the query
in the URL.
</para>
<para>
For example, the following query returns all process instances
with the business key <literal>"newOrder"</literal>, as invoked in the
previous example.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processinstance?_queryId=filtered-query&amp;processInstanceBusinessKey=newOrder"</userinput>
</screen>
<para>
Any Activiti properties can be queried using the same notation, for example,
<literal>processDefinitionId=managedUserApproval:1:6405</literal>. The query
syntax applies to all queries with <literal>_queryId=filtered-query</literal>.
The following query returns all process instances that were started by the
user <literal>openidm-admin</literal>:
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processinstance?_queryId=filtered-query&amp;startUserId=openidm-admin"</userinput>
</screen>
<para>
You can also query process instances based on the value of any process
instance variable, by prefixing the variable name with
<literal>var-</literal>. For example:
</para>
<screen>var-processvariablename=processvariablevalue</screen>
</section>
</section>
<section xml:id="activiti-custom-templates">
<title>Using Custom Templates for Activiti Workflows</title>
<para>
The embedded Activiti engine is integrated with the default user interface.
For simple workflows, you can use the standard Activiti form properties, and
have the UI render the corresponding generic forms automatically. If you
require a more complex form template, (including input validation,
rich input field types, complex CSS, and so forth) you must define a custom
form template.
</para>
<itemizedlist>
<para>
There are two ways in which you can define custom form templates for your
workflows:
</para>
<listitem>
<para>
Create an HTML template, and refer to that template in the workflow
definition.
</para>
<para>
This is the recommended method of creating custom form templates. To refer
to the HTML template in the workflow definition, use the
<literal>activiti:formKey</literal> attribute, for example
<literal>activiti:formKey="nUCStartForm.xhtml"</literal>.
</para>
<para>The HTML file must be deployed as part of the workflow definition.
Create a .zip file that contains the HTML template and the workflow
definition file. Rename the .zip file with a .bar extension.
</para>
<para>
For a sample workflow that uses external, referenced form templates, see
<literal>samples/usecase/workflow/newUserCreate.bpmn20.xml</literal>. The
HTML templates, and the corresponding .bar file are included in that
directory.
</para>
</listitem>
<listitem>
<para>
Use an embedded template within the workflow definition.
</para>
<para>
This method is not ideal, because the HTML code must be escaped, and is
difficult to read, edit, or maintain, as a result. Also, sections of HTML
code will most likely need to be duplicated if your workflow includes
multiple task stages. However, you might want to use this method if your
form is small, not too complex and you do not want to bother with creating
a separate HTML file and .bar deployment.
</para>
</listitem>
</itemizedlist>
</section>
<section xml:id="workflows-REST">
<title>Managing Workflows Over the REST Interface</title>
<para>
In addition to the queries described previously, the following examples show
the context paths that are exposed for managing workflows over the REST
interface. The example output is based on the sample workflow that is
provided in <literal>openidm/samples/sample9</literal>.
</para>
<bridgehead>openidm/workflow/processdefinition</bridgehead>
<itemizedlist>
<listitem>
<para>
List the available workflow definitions:
</para>
<screen><?dbfo pgwide="1"?><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processdefinition?_queryId=query-all-ids"</userinput>
<computeroutput>
{
"result" : [ {
"tenantId" : "",
"candidateStarterGroupIdExpressions" : [ ],
"candidateStarterUserIdExpressions" : [ ],
"participantProcess" : null,
"processDiagramResourceName" : null,
"historyLevel" : null,
"hasStartFormKey" : false,
"laneSets" : [ ],
"version" : 1,
"_id" : "managedUserApproval:1:3",
"description" : null,
"name" : "Managed User Approval Workflow",
"executionListeners" : { },
"key" : "managedUserApproval",
"resourceName" : "OSGI-INF/activiti/managedUserApproval.bpmn20.xml",
"ioSpecification" : null,
"taskDefinitions" : null,
"suspensionState" : 1,
"deploymentId" : "1",
"properties" : { },
"startFormHandler" : null,
"suspended" : false,
"variables" : null,
"_rev" : 1,
"revisionNext" : 2,
"category" : "Examples",
"eventSupport" : { },
"graphicalNotationDefined" : false
} ],
"resultCount" : 1,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
} </computeroutput>
</screen>
</listitem>
<listitem>
<para>
List the workflow definitions, based on certain filter criteria:
</para>
<screen><?dbfo pgwide="1"?><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processdefinition?_queryId=filtered-query&amp;category=Examples"
</userinput>
<computeroutput>
{
"result": [
{
...
"name": "Managed User Approval Workflow",
"_id": "managedUserApproval:1:3",
...
"category" : "Examples",
...
}
]
}</computeroutput>
</screen>
</listitem>
</itemizedlist>
<bridgehead>openidm/workflow/processdefinition/{id}</bridgehead>
<itemizedlist>
<listitem>
<para>
Obtain detailed information for a process definition, based on the ID. You
can determine the ID by querying all the available process definitions, as
described in the first example in this section.
</para>
<screen><?dbfo pgwide="1"?><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processdefinition/managedUserApproval:1:3"
</userinput>
<computeroutput>
{
"tenantId" : "",
"candidateStarterGroupIdExpressions" : [ ],
"candidateStarterUserIdExpressions" : [ ],
"participantProcess" : null,
"processDiagramResourceName" : null,
"historyLevel" : null,
"hasStartFormKey" : false,
"laneSets" : [ ],
"version" : 1,
"formProperties" : [ ],
"_id" : "managedUserApproval:1:3",
"description" : null,
"name" : "Managed User Approval Workflow",
"executionListeners" : {
"end" : [ { } ]
},
"key" : "managedUserApproval",
"resourceName" : "OSGI-INF/activiti/managedUserApproval.bpmn20.xml",
"ioSpecification" : null,
"taskDefinitions" : {
"evaluateRequest" : {
"assigneeExpression" : {
"expressionText" : "openidm-admin"
},
"candidateGroupIdExpressions" : [ ],
"candidateUserIdExpressions" : [ ],
"categoryExpression" : null,
"descriptionExpression" : null,
"dueDateExpression" : null,
"key" : "evaluateRequest",
"nameExpression" : {
"expressionText" : "Evaluate request"
},
"ownerExpression" : null,
"priorityExpression" : null,
"taskFormHandler" : {
"deploymentId" : "1",
"formKey" : null,
"formPropertyHandlers" : [ {
"defaultExpression" : null,
"id" : "requesterName",
"name" : "Requester's name",
"readable" : true,
"required" : false,
"type" : null,
"variableExpression" : {
"expressionText" : "${sourceId}"
},
"variableName" : null,
"writable" : false
}, {
"defaultExpression" : null,
"id" : "requestApproved",
"name" : "Do you approve the request?",
"readable" : true,
"required" : true,
"type" : {
"name" : "enum",
"values" : {
"true" : "Yes",
"false" : "No"
}
},
"variableExpression" : null,
"variableName" : null,
"writable" : true
} ]
},
"taskListeners" : {
"assignment" : [ { } ],
"create" : [ { } ]
}
}
},
"suspensionState" : 1,
"deploymentId" : "1",
"properties" : {
"documentation" : null
},
"startFormHandler" : {
"deploymentId" : "1",
"formKey" : null,
"formPropertyHandlers" : [ ]
},
"suspended" : false,
"variables" : { },
"_rev" : 2,
"revisionNext" : 3,
"category" : "Examples",
"eventSupport" : { },
"graphicalNotationDefined" : false
} </computeroutput>
</screen>
</listitem>
<listitem>
<para>
Delete a workflow process definition, based on its ID. Note that you
cannot delete a process definition if there are currently running
instances of that process definition.
</para>
<para>
OpenIDM picks up workflow definitions from the files located in the
<filename>/path/to/openidm/workflow</filename> directory. If you delete the
workflow definition (<filename>.xml</filename> file) from this directory,
the OSGI bundle is deleted. However, deleting this file does not remove the
workflow definition from the Activiti engine. You must therefore delete the
definition over REST, as shown in the following example.
</para>
<para>
Note that, although there is only one representation of a workflow
definition in the file system, there might be several versions of the same
definition in Activiti. If you want to delete redundant process
definitions, delete the definition over REST, <emphasis>making sure that
you do not delete the latest version</emphasis>.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "If-Match: *" \
--request DELETE \
"https://localhost:8443/openidm/workflow/processdefinition/managedUserApproval:1:3"</userinput>
</screen>
<para>
The delete request returns the contents of the deleted workflow definition.
</para>
</listitem>
</itemizedlist>
<bridgehead>openidm/workflow/processinstance</bridgehead>
<itemizedlist>
<listitem>
<para>
Start a workflow process instance. For example:
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--data '{"_key":"managedUserApproval"}' \
--request POST \
"https://localhost:8443/openidm/workflow/processinstance?_action=create"</userinput>
<computeroutput>
{
"_id" : "4",
"processInstanceId" : "4",
"status" : "suspended",
"businessKey" : null,
"processDefinitionId" : "managedUserApproval:1:3"
}</computeroutput>
</screen>
</listitem>
<listitem>
<para>
Obtain the list of running workflows (process instances). The query returns
a list of IDs. For example:
</para>
<screen><?dbfo pgwide="1"?><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processinstance?_queryId=query-all-ids"
</userinput>
<computeroutput>
{
"result" : [ {
"tenantId" : "",
"businessKey" : null,
"queryVariables" : null,
"durationInMillis" : null,
"processVariables" : { },
"endTime" : null,
"superProcessInstanceId" : null,
"startActivityId" : "start",
"startTime" : "2014-04-25T09:54:30.035+02:00",
"startUserId" : "openidm-admin",
"_id" : "4",
"endActivityId" : null,
"processInstanceId" : "4",
"processDefinitionId" : "managedUserApproval:1:3",
"deleteReason" : null
} ],
"resultCount" : 1,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}</computeroutput>
</screen>
</listitem>
<listitem>
<para>
Obtain the list of running workflows based on specific filter criteria.
</para>
<screen><?dbfo pgwide="1"?><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processinstance?_queryId=filtered-query&amp;businessKey=myBusinessKey"</userinput>
</screen>
</listitem>
</itemizedlist>
<bridgehead>openidm/workflow/processinstance/{id}</bridgehead>
<itemizedlist>
<listitem>
<para>
Obtain the details of the specified process instance. For example:
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processinstance/4"
</userinput>
<computeroutput>{
"tenantId" : "",
"businessKey" : null,
"queryVariables" : null,
"durationInMillis" : null,
"processVariables" : { },
"endTime" : null,
"superProcessInstanceId" : null,
"startActivityId" : "start",
"startTime" : "2014-05-12T20:56:25.415+02:00",
"startUserId" : "openidm-admin",
"_id" : "4",
"endActivityId" : null,
"processInstanceId" : "4",
"processDefinitionId" : "managedUserApproval:1:3",
"deleteReason" : null
}</computeroutput>
</screen>
</listitem>
<listitem>
<para>
Stop the specified process instance. For example:
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request DELETE \
"https://localhost:8443/openidm/workflow/processinstance/4"</userinput>
<computeroutput>{
"deleteReason": null,
"processDefinitionId": "managedUserApproval:1:3",
"processInstanceId": "4",
"endActivityId": null,
"_id": "4",
"startUserId": "openidm-admin",
"startTime": "2014-06-18T10:33:40.955+02:00",
"tenantId": "",
"businessKey": null,
"queryVariables": null,
"durationInMillis": null,
"processVariables": {},
"endTime": null,
"superProcessInstanceId": null,
"startActivityId": "start"
}</computeroutput></screen>
<para>
The delete request returns the contents of the deleted process instance.
</para>
</listitem>
</itemizedlist>
<bridgehead>openidm/workflow/processdefinition/{id}/taskdefinition</bridgehead>
<itemizedlist>
<listitem>
<para>
Query the list of tasks defined for a specific process definition. For
example:
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processdefinition/managedUserApproval:1:3/taskdefinition?_queryId=query-all-ids"</userinput>
<computeroutput>
{
"result" : [ {
"taskCandidateGroup" : [ ],
"ownerExpression" : null,
"assignee" : {
"expressionText" : "openidm-admin"
},
"categoryExpression" : null,
"taskListeners" : {
"assignment" : [ { } ],
"create" : [ { } ]
},
"formProperties" : {
"deploymentId" : "1",
"formKey" : null,
"formPropertyHandlers" : [ {
"_id" : "requesterName",
"defaultExpression" : null,
"name" : "Requester's name",
"readable" : true,
"required" : false,
"type" : null,
"variableExpression" : {
"expressionText" : "${sourceId}"
},
"variableName" : null,
"writable" : false
}, {
"_id" : "requestApproved",
"defaultExpression" : null,
"name" : "Do you approve the request?",
"readable" : true,
"required" : true,
"type" : {
"name" : "enum",
"values" : {
"true" : "Yes",
"false" : "No"
}
},
"variableExpression" : null,
"variableName" : null,
"writable" : true
} ]
},
"taskCandidateUser" : [ ],
"formResourceKey" : null,
"_id" : "evaluateRequest",
"priority" : null,
"descriptionExpression" : null,
"name" : {
"expressionText" : "Evaluate request"
},
"dueDate" : null
} ],
"resultCount" : 1,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
} </computeroutput>
</screen>
</listitem>
<listitem>
<para>
Query a task definition based on the process definition ID and the task
name (<literal>taskDefinitionKey</literal>). For example:
</para>
<screen width="105"><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/processdefinition/managedUserApproval:1:3/taskdefinition/evaluateRequest"
</userinput>
<computeroutput>{
"taskCandidateGroup" : [ ],
"ownerExpression" : null,
"formProperties" : {
"deploymentId" : "1",
"formKey" : null,
"formPropertyHandlers" : [ {
"_id" : "requesterName",
"defaultExpression" : null,
"name" : "Requester's name",
"readable" : true,
"required" : false,
"type" : null,
"variableExpression" : {
"expressionText" : "${sourceId}"
},
"variableName" : null,
"writable" : false
}, {
"_id" : "requestApproved",
"defaultExpression" : null,
"name" : "Do you approve the request?",
"readable" : true,
"required" : true,
"type" : {
"name" : "enum",
"values" : {
"true" : "Yes",
"false" : "No"
}
},
"variableExpression" : null,
"variableName" : null,
"writable" : true
} ]
},
"taskCandidateUser" : [ ],
"_id" : "evaluateRequest",
"priority" : null,
"name" : {
"expressionText" : "Evaluate request"
},
"descriptionExpression" : null,
"categoryExpression" : null,
"assignee" : {
"expressionText" : "openidm-admin"
},
"taskListeners" : {
"assignment" : [ { } ],
"create" : [ { } ]
},
"dueDate" : null
}</computeroutput>
</screen>
</listitem>
</itemizedlist>
<bridgehead>openidm/workflow/taskinstance</bridgehead>
<itemizedlist>
<listitem>
<para>
Query all running task instances. For example:
</para>
<screen><?dbfo pgwide="1"?><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/taskinstance?_queryId=query-all-ids"
</userinput>
<computeroutput>{
"result" : [ {
"tenantId" : "",
"createTime" : "2014-05-12T21:17:10.054+02:00",
"executionId" : "10",
"delegationStateString" : null,
"processVariables" : { },
"_id" : "15",
"processInstanceId" : "10",
"description" : null,
"priority" : 50,
"name" : "Evaluate request",
"dueDate" : null,
"parentTaskId" : null,
"processDefinitionId" : "managedUserApproval:1:3",
"taskLocalVariables" : { },
"suspensionState" : 1,
"assignee" : "openidm-admin",
"cachedElContext" : null,
"queryVariables" : null,
"activityInstanceVariables" : { },
"deleted" : false,
"suspended" : false,
"_rev" : 1,
"revisionNext" : 2,
"category" : null,
"taskDefinitionKey" : "evaluateRequest",
"owner" : null,
"eventName" : null,
"delegationState" : null
} ],
"resultCount" : 1,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}</computeroutput>
</screen>
</listitem>
<listitem>
<para>
Query task instances based on candidate users or candidate groups. For
example:
</para>
<screen><?dbfo pgwide="1"?><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/taskinstance?_queryId=filtered-query&amp;taskCandidateUser=manager1"
</userinput>
</screen>
<para>
or
</para>
<screen><?dbfo pgwide="1"?><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/taskinstance?_queryId=filtered-query&amp;taskCandidateGroup=management"
</userinput>
</screen>
<para>
Note that you can include both users and groups in the same query.
</para>
</listitem>
</itemizedlist>
<bridgehead>openidm/workflow/taskinstance/{id}</bridgehead>
<itemizedlist>
<listitem>
<para>
Obtain detailed information for a running task, based on the task ID. For
example:
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/workflow/taskinstance/15"
</userinput>
<computeroutput>{
"dueDate": null,
"processDefinitionId": "managedUserApproval:1:3",
"owner": null,
"taskDefinitionKey": "evaluateRequest",
"name": "Evaluate request",
...</computeroutput>
</screen>
</listitem>
<listitem>
<para>
Update task-related data stored in the Activiti workflow engine. For
example:
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "If-Match : *" \
--request PUT \
--data '{"description":"Evaluate the new managed user request"}' \
"https://localhost:8443/openidm/workflow/taskinstance/15" </userinput>
</screen>
</listitem>
<listitem>
<para>
Complete the specified task. The variables required by the task are
provided in the request body. For example:
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
--data '{"requestApproved":"true"}' \
"https://localhost:8443/openidm/workflow/taskinstance/15?_action=complete"</userinput></screen>
</listitem>
<listitem>
<para>
Claim the specified task. A user who claims a task has that task inserted
into his list of pending tasks. The ID of the user who claims the task is
provided in the request body. For example:
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
--data '{"userId":"manager1"}' \
"https://localhost:8443/openidm/workflow/taskinstance/15?_action=claim"</userinput></screen>
</listitem>
</itemizedlist>
</section>
<section xml:id="sample-activiti-workflows">
<title>Example Activiti Workflows With OpenIDM</title>
<para>
This section describes two example workflows - an email notification
workflow, and a workflow that demonstrates provisioning, using the
browser-based user interface.
</para>
<section xml:id="example-activiti-email-notification-flow">
<title>Example Email Notification Workflow</title>
<para>
This example uses the Activiti Eclipse BPMN 2.0 Designer to set up an email
notification business process. The example relies on an SMTP server
listening on <literal>localhost</literal>, port 25.
</para>
<variablelist>
<para>
The example sets up a workflow that can accept parameters used to specify
the sender and recipient of the mail.
</para>
<varlistentry>
<term><literal>${fromSender}</literal></term>
<listitem>
<para>
Specifies the sender
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>${toEmail}</literal></term>
<listitem>
<para>
Specifies the recipient
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Create a new BPMN2 diagram in Eclipse, then drag and drop components to
create the workflow. This simple example uses a
<literal>StartEvent</literal>, <literal>MailTask</literal>, and
<literal>EndEvent</literal>.
</para>
<mediaobject xml:id="figure-bpmn-email-notification">
<alt>Email notification process</alt>
<imageobject>
<imagedata fileref="images/bpmn-email-notification.png" format="PNG" />
</imageobject>
<textobject>
<para>The email notification workflow has a start event, mail task, and
end event.</para>
</textobject>
</mediaobject>
<para>
When you have created the workflow definition, edit the generated XML
source code, adding the <literal>&lt;extensionElements&gt;</literal> to
the <literal>&lt;serviceTask&gt;</literal> tag, as follows.
</para>
<programlisting language="xml">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;definitions
xmlns=&quot;http://www.omg.org/spec/BPMN/20100524/MODEL&quot;
xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xmlns:activiti=&quot;http://activiti.org/bpmn&quot;
xmlns:bpmndi=&quot;http://www.omg.org/spec/BPMN/20100524/DI&quot;
xmlns:omgdc=&quot;http://www.omg.org/spec/DD/20100524/DC&quot;
xmlns:omgdi=&quot;http://www.omg.org/spec/DD/20100524/DI&quot;
typeLanguage=&quot;http://www.w3.org/2001/XMLSchema&quot;
expressionLanguage=&quot;http://www.w3.org/1999/XPath&quot;
targetNamespace=&quot;http://www.activiti.org/test&quot;&gt;
&lt;process id=&quot;EmailNotification&quot; name=&quot;emailNotification&quot;&gt;
&lt;documentation&gt;Simple Email Notification Task&lt;/documentation&gt;
&lt;startEvent id=&quot;startevent1&quot; name=&quot;Start&quot;&gt;&lt;/startEvent&gt;
&lt;sequenceFlow id=&quot;flow1&quot; name=&quot;&quot; sourceRef=&quot;startevent1&quot;
targetRef=&quot;mailtask1&quot;&gt;&lt;/sequenceFlow&gt;
&lt;endEvent id=&quot;endevent1&quot; name=&quot;End&quot;&gt;&lt;/endEvent&gt;
&lt;sequenceFlow id=&quot;flow2&quot; name=&quot;&quot; sourceRef=&quot;mailtask1&quot;
targetRef=&quot;endevent1&quot;&gt;&lt;/sequenceFlow&gt;
&lt;serviceTask id=&quot;mailtask1&quot; name=&quot;Email Notification&quot;
activiti:type=&quot;mail&quot;&gt;
&lt;extensionElements&gt;
&lt;activiti:field name=&quot;to&quot; expression=&quot;${toEmail}&quot;
&gt;&lt;/activiti:field&gt;
&lt;activiti:field name=&quot;from&quot; expression=&quot;${fromSender}&quot;
&gt;&lt;/activiti:field&gt;
&lt;activiti:field name=&quot;subject&quot; expression=&quot;Simple Email Notification&quot;
&gt;&lt;/activiti:field&gt;
&lt;activiti:field name=&quot;text&quot;&gt;
&lt;activiti:expression&gt;&lt;![CDATA[Here is a simple Email Notification
from ${fromSender}.]]&gt;&lt;/activiti:expression&gt;
&lt;/activiti:field&gt;
&lt;/extensionElements&gt;
&lt;/serviceTask&gt;
&lt;/process&gt;
&lt;bpmndi:BPMNDiagram id=&quot;BPMNDiagram_EmailNotification&quot;&gt;
&lt;bpmndi:BPMNPlane bpmnElement=&quot;EmailNotification&quot;
id=&quot;BPMNPlane_EmailNotification&quot;&gt;
&lt;bpmndi:BPMNShape bpmnElement=&quot;startevent1&quot; id=&quot;BPMNShape_startevent1&quot;&gt;
&lt;omgdc:Bounds height=&quot;35&quot; width=&quot;35&quot; x=&quot;170&quot; y=&quot;250&quot;&gt;&lt;/omgdc:Bounds&gt;
&lt;/bpmndi:BPMNShape&gt;
&lt;bpmndi:BPMNShape bpmnElement=&quot;endevent1&quot; id=&quot;BPMNShape_endevent1&quot;&gt;
&lt;omgdc:Bounds height=&quot;35&quot; width=&quot;35&quot; x=&quot;410&quot; y=&quot;250&quot;&gt;&lt;/omgdc:Bounds&gt;
&lt;/bpmndi:BPMNShape&gt;
&lt;bpmndi:BPMNShape bpmnElement=&quot;mailtask1&quot; id=&quot;BPMNShape_mailtask1&quot;&gt;
&lt;omgdc:Bounds height=&quot;55&quot; width=&quot;105&quot; x=&quot;250&quot; y=&quot;240&quot;&gt;&lt;/omgdc:Bounds&gt;
&lt;/bpmndi:BPMNShape&gt;
&lt;bpmndi:BPMNEdge bpmnElement=&quot;flow1&quot; id=&quot;BPMNEdge_flow1&quot;&gt;
&lt;omgdi:waypoint x=&quot;205&quot; y=&quot;267&quot;&gt;&lt;/omgdi:waypoint&gt;
&lt;omgdi:waypoint x=&quot;250&quot; y=&quot;267&quot;&gt;&lt;/omgdi:waypoint&gt;
&lt;/bpmndi:BPMNEdge&gt;
&lt;bpmndi:BPMNEdge bpmnElement=&quot;flow2&quot; id=&quot;BPMNEdge_flow2&quot;&gt;
&lt;omgdi:waypoint x=&quot;355&quot; y=&quot;267&quot;&gt;&lt;/omgdi:waypoint&gt;
&lt;omgdi:waypoint x=&quot;410&quot; y=&quot;267&quot;&gt;&lt;/omgdi:waypoint&gt;
&lt;/bpmndi:BPMNEdge&gt;
&lt;/bpmndi:BPMNPlane&gt;
&lt;/bpmndi:BPMNDiagram&gt;
&lt;/definitions&gt;</programlisting>
<para>
Save the workflow definition as a <literal>bpmn20.xml</literal> file
(<filename>email-notification.bpmn20.xml</filename>) in the
<filename>openidm/workflow</filename> directory.
</para>
<para>
After you have deployed the workflow, create a script named
<filename>openidm/script/triggerEmailNotification.js</filename>. The script
invokes the workflow.
</para>
<programlisting language="javascript">
/*
* Calling 'EmailNotification' workflow
*/
var params = {
"_key" : "EmailNotification",
"fromSender" : "noreply@openidm",
"toEmail" : "jdoe@example.com"
};
openidm.action('workflow/processinstance', {"_action" : "createProcessInstance"}, params);
</programlisting>
<para>
You can also invoke the workflow over the REST interface with the following
REST command:
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--data '{
"_key":"EmailNotification",
"fromSender":"noreply@openidm",
"toEmail":"jdoe@example.com"
}' \
--request POST \
"https://localhost:8443/openidm/workflow/processinstance?_action=create"</userinput></screen>
<para>
To schedule the workflow to be invoked regularly, create a schedule
configuration object named
<filename>openidm/conf/schedule-EmailNotification.json</filename>. The
following schedule invokes the workflow once per minute.
</para>
<programlisting language="javascript">
{
"enabled" : true,
"type" : "cron",
"schedule" : "0 0/1 * * * ?",
"invokeService" : "script",
"invokeContext" : {
"script" : {
"type" : "text/javascript",
"file" : "script/triggerEmailNotification.js"
},
}
}
</programlisting>
</section>
<section xml:id="example-provisioning-workflow">
<title>Sample Workflow - Provisioning User Accounts</title>
<para>
This example, provided in <filename>openidm/samples/workflow</filename>,
uses workflows to provision user accounts. The example demonstrates the use
of the browser-based user interface to manage workflows.
</para>
<section xml:id="provisioning-sample-overview">
<title>Overview of the Sample</title>
<para>
The sample starts with a reconciliation process that loads user accounts
from an XML file into the managed users repository. The reconciliation
creates two users, with UIDs <literal>user1</literal> and
<literal>manager1</literal>. Both users have the same password
(<literal>Welcome1</literal>).
</para>
<para>
The sample adds two new business roles to the configuration -
<literal>employee</literal> (assigned to <literal>user1</literal>) and
<literal>manager</literal> (assigned to <literal>manager1</literal>).
</para>
<para>
As part of the provisioning, employees are required to initiate a
"Contract Onboarding" process. This process is a request to add a
contractor to the managed users repository, with an option to include the
contractor in the original data source (the XML file).
</para>
<para>
When the employee has completed the required form, the request is sent to
the manager for approval. Any user with the role
<literal>"manager"</literal> can claim the approval task. If the request is
approved, the user is created in the managed users repository. If a request
was made to add the user to the original data source (the XML file) this is
done in a subsequent step.
</para>
<para>
The workflow uses embedded templates to build a more sophisticated input
form. The form is validated with the server-side policy rules, described
in <link xlink:href="integrators-guide#chap-policies"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Using
Policies to Validate Data</citetitle></link>.
</para>
</section>
<section xml:id="provisioning-sample-running">
<title>Running the Sample</title>
<procedure>
<step>
<para>
Start OpenIDM with the configuration for the workflow sample.
</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/workflow</screen>
</step>
<step>
<para>
Run reconciliation over the REST interface.
</para>
<screen><?dbfo pgwide="1"?>$ curl \
--cacert self-signed.crt \
--header "Content-Type: application/json" \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemXmlfileAccounts_managedUser"</screen>
<para>
Successful reconciliation returns an "_id" object, such as the following:
</para>
<screen>{"_id":"aea493f5-29ee-423d-b4b1-10449c60886c","state":"ACTIVE"}</screen>
<para>
The two users are added to the repository. You can test this with the
following REST query, which shows the two users,
<literal>manager1</literal> and <literal>user1</literal>.
</para>
<screen><?dbfo pgwide="1"?><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user/?_queryId=query-all-ids"
</userinput>
<computeroutput>{
"result" : [ {
"_id" : "manager1",
"_rev" : "0"
}, {
"_id" : "user1",
"_rev" : "0"
} ],
"resultCount" : 2,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}</computeroutput>
</screen>
</step>
<step>
<para>
Log into the user interface as <literal>user1</literal>, with password
<literal>Welcome1</literal>. For information about logging in to the user
interface, see <link xlink:href="integrators-guide#ui-overview"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Overview of
the Default User Interface</citetitle></link>.
</para>
</step>
<step>
<para>
Under "Processes" click "Contractor onboarding process".
</para>
<mediaobject>
<alt>User interface - processes</alt>
<imageobject>
<imagedata fileref="images/ui-processes.png" format="PNG" />
</imageobject>
</mediaobject>
</step>
<step>
<para>
Complete the details of the new user, then click Start.
</para>
<mediaobject>
<alt>Contractor onboarding process form</alt>
<imageobject>
<imagedata fileref="images/ui-workflow.png" format="PNG" />
</imageobject>
</mediaobject>
</step>
<step>
<para>
Log out of the UI.
</para>
</step>
<step>
<para>
Log into the UI as <literal>manager1</literal>, with password
<literal>Welcome1</literal>.
</para>
</step>
<step>
<para>
Under "Tasks that are in my group's queue" click "Contractor Approval".
</para>
<mediaobject>
<alt>Contractor approval</alt>
<imageobject>
<imagedata fileref="images/ui-contractor-approval.png" format="PNG" />
</imageobject>
</mediaobject>
</step>
<step>
<para>
From the drop-down list, select "Assign to me".
</para>
<para>
Note that the "Contractor Approval" task has now moved under "My tasks".
</para>
</step>
<step>
<para>
Under "My tasks" click "Contractor Approval".
</para>
<mediaobject>
<alt>My tasks</alt>
<imageobject>
<imagedata fileref="images/ui-my-tasks.png" format="PNG" />
</imageobject>
</mediaobject>
</step>
<step>
<para>
Under Actions, click Details.
</para>
<para>
The form containing the details of the contractor is displayed.
</para>
</step>
<step>
<para>
At the bottom of the form, select a decision from the drop-down list
(either "Accept" or "Reject"), then click Complete.
</para>
<mediaobject>
<alt>Accept new user account</alt>
<imageobject>
<imagedata fileref="images/ui-workflow-complete.png" format="PNG" />
</imageobject>
</mediaobject>
<para>
When you Accept the new contractor details, the user account is created
in the repository. You can check the new account by running the following
REST command:
</para>
<screen><?dbfo pgwide="1"?><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user/?_queryId=query-all-ids"
</userinput>
<computeroutput>
{
"result" : [ {
"_id" : "manager1",
"_rev" : "0"
}, {
"_id" : "user1",
"_rev" : "0"
}, {
"_id" : "96a9513b-7896-4d22-83cc-6b35a709f0a8",
"_rev" : "0"
} ],
"resultCount" : 3,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}</computeroutput></screen>
<para>
Display the details of the new user, by running a REST query on the user
ID, as follows:
</para>
<screen><?dbfo pgwide="1"?><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user/96a9513b-7896-4d22-83cc-6b35a709f0a8"
</userinput>
<computeroutput>
{
"_id" : "96a9513b-7896-4d22-83cc-6b35a709f0a8",
"_rev" : "1",
"startDate" : "05/13/2014",
"manager" : "user1",
"passwordAttempts" : "0",
"department" : "Finance",
"address2" : "",
"endDate" : "06/13/2014",
"givenName" : "John",
"effectiveRoles" : [ "openidm-authorized" ],
"city" : "",
"lastPasswordSet" : "",
"postalCode" : "",
"description" : "Accountant",
"accountStatus" : "active",
"userName" : "johnb",
"stateProvince" : "",
"jobTitle" : "Contract Accountant",
"mail" : "johnb@example.com",
"sn" : "Brand",
"provisionToXML" : "1",
"lastPasswordAttempt" : "Tue May 13 2014 09:56:49 GMT+0200 (SAST)",
"country" : "",
"telephoneNumber" : "8934794578",
"roles" : [ "openidm-authorized" ],
"effectiveAssignments" : { },
"postalAddress" : ""
}</computeroutput></screen>
<para>
You can now log into the UI as the new user (with the details that you
specified in Step 5). Under "Notifications" you will see a welcome
message indicating the working dates of the new user. If you log in as
<literal>user1</literal> you are notified of the result of the manager's
decision.
</para>
<para>
If you specified that the new user should be added to the original data
source, you will see that the account was added to the XML file:
</para>
<screen><userinput>$ cd /path/to/openidm
$ cat samples/workflow/data/xmlConnectorData.xml </userinput>
<computeroutput>...
&lt;ri:__ACCOUNT__&gt;
&lt;icf:__DESCRIPTION__&gt;Accountant&lt;/icf:__DESCRIPTION__&gt;
&lt;ri:roles&gt;openidm-authorized&lt;/ri:roles&gt;
&lt;ri:mobileTelephoneNumber&gt;8934794578&lt;/ri:mobileTelephoneNumber&gt;
&lt;ri:firstname&gt;John&lt;/ri:firstname&gt;
&lt;ri:manager&gt;user1&lt;/ri:manager&gt;
&lt;ri:startDate&gt;05/13/2014&lt;/ri:startDate&gt;
&lt;ri:jobTitle&gt;Contract Accountant&lt;/ri:jobTitle&gt;
&lt;icf:__UID__&gt;67b6bb5f-5457-4ac6-bb49-5d98f2b1f3f8&lt;/icf:__UID__&gt;
&lt;icf:__NAME__&gt;johnb&lt;/icf:__NAME__&gt;
&lt;ri:email&gt;johnb@example.com&lt;/ri:email&gt;
&lt;icf:__PASSWORD__&gt;Welcome1&lt;/icf:__PASSWORD__&gt;
&lt;ri:department&gt;Finance&lt;/ri:department&gt;
&lt;ri:endDate&gt;06/13/2014&lt;/ri:endDate&gt;
&lt;ri:lastname&gt;Brand&lt;/ri:lastname&gt;
&lt;/ri:__ACCOUNT__&gt;
... </computeroutput>
</screen>
<para>
If you declined the approval request, the user will not be created in
either data source.
</para>
</step>
</procedure>
<para>
You can see the details of the workflow definition in
<filename>samples/workflow/workflow/contractorOnboarding.bpmn20.xml</filename>.
</para>
</section>
</section>
</section>
<section xml:id="workflow-use-cases">
<title>Workflow Use Cases</title>
<para>
This section describes a number of sample workflows, that demonstrate typical
use cases for OpenIDM. The use cases, provided in
<filename>/path/to/openidm/samples/usecase</filename>, work together to
provide a complete business story, with the same set of sample data. Each of
the use cases is integrated with the default UI.
</para>
<para>
These use cases use OrientDB as a repository by default. Alternative
repository configuration files are provided in
<filename>/path/to/openidm/samples/usecase/db</filename>. If you want to use
one of these alternative repositories, remove the
<filename>repo.orientdb.json</filename> file from the <literal>conf/</literal>
directory of the use case you are testing (for example,
<filename>samples/usecase/usecase1/conf/repo.orientdb.json</filename>) and
copy the appropriate JDBC repository configuration file
(<filename>repo.jdbc.json</filename>) into that <literal>conf/</literal>
directory. For more information on using an alternative repository, see
<link xlink:show="new" xlink:href="install-guide#chap-repository"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Installing a
Repository For Production</citetitle></link> in the <citetitle>Installation
Guide</citetitle>.
</para>
<para>
The use cases can be run independently, but rely on the data set that is
imported during use case 1 - so you <emphasis>must</emphasis> run use case 1
before running any of the other use cases.
</para>
<para>
The use cases assume an initial data set of twenty "ordinary" managed users
in OpenIDM (user.0 - user.19). The users are divided as follows:
</para>
<informaltable><?dbfo pgwide="1"?>
<tgroup cols="5">
<colspec colname="c1" colwidth="2*"/>
<colspec colname="c2" colwidth="2*"/>
<colspec colname="c3" colwidth="1*"/>
<colspec colname="c4" colwidth="2*"/>
<colspec colname="c5" colwidth="1*"/>
<thead>
<row>
<entry>Users</entry>
<entry>Department</entry>
<entry>Manager</entry>
<entry>Employees</entry>
<entry>Contractors</entry>
</row>
</thead>
<tbody>
<row>
<entry>user.0-user.4</entry>
<entry>Human Resources</entry>
<entry>user.0</entry>
<entry>user.0-user.3</entry>
<entry>user.4</entry>
</row>
<row>
<entry>user.5-user.9</entry>
<entry>Production Planning</entry>
<entry>user.5</entry>
<entry>user.5-user.8</entry>
<entry>user.9</entry>
</row>
<row>
<entry>user.10-user.14</entry>
<entry>Sales &amp; Distribution</entry>
<entry>user.10</entry>
<entry>user.10-user.13</entry>
<entry>user.14</entry>
</row>
<row>
<entry>user.15-user.19</entry>
<entry>Treasury &amp; Payments</entry>
<entry>user.15</entry>
<entry>user.15-user.18</entry>
<entry>user.19</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<itemizedlist>
<para>
In addition, the following "special" users are defined:
</para>
<listitem>
<para>
<literal>hradmin</literal> - represents the human interaction of the HR
department
</para>
</listitem>
<listitem>
<para>
<literal>systemadmin</literal> - represents the human interaction of the
populated systems (Business and Project)
</para>
</listitem>
<listitem>
<para>
<literal>superadmin</literal> - represents the manager of the managers
</para>
</listitem>
</itemizedlist>
<para>
Note that the <command>curl</command> commands in this section use the secure
port for OpenIDM (8443) and assume a self-signed certificate named
<literal>self-signed.crt</literal>, located in the directory from which the
command is launched. For instructions on using the self-signed certificate
that is generated when OpenIDM first starts up, see
<link xlink:show="new" xlink:href="integrators-guide#rest-over-https"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Restrict REST
Access to the HTTPS Port</citetitle></link>.
</para>
<section xml:id="use-case-1">
<title>Use Case 1 - Initial Reconciliation</title>
<para>
This use case assumes an OpenDJ server and populates the managed user
repository with users from OpenDJ.
</para>
<itemizedlist>
<para>
To prepare the sample:
</para>
<listitem>
<para>
Download and install OpenDJ, as described in <link xlink:show="new"
xlink:href="http://docs.forgerock.org/en/opendj/2.6.0/install-guide/index.html#chap-install-gui">Installing
OpenDJ With the QuickSetup Wizard</link>.
</para>
<para>
This sample assumes that OpenDJ is listening on port 1389, the standard
LDAP port for users who cannot use privileged ports.
</para>
</listitem>
<listitem>
<para>
During the install, import the user data from the LDIF file
<filename>/path/to/openidm/samples/usecase/data/hr_data.ldif</filename>.
</para>
</listitem>
<listitem>
<para>
The use case assumes a user with DN <literal>cn=Directory Manager</literal>
and password <literal>password</literal> who will bind to the directory
server.
</para>
</listitem>
</itemizedlist>
<para>
The OpenDJ server now contains the users required for all the workflow use
cases.
</para>
<procedure>
<step>
<para>
Start OpenIDM with the configuration for use case 1.
</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/usecase/usecase1
</screen>
</step>
<step>
<para>
Run reconciliation to populate the managed user repository with the users
from the OpenDJ server.
</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=systemHRAccounts_managedUser"
</screen>
</step>
<step>
<para>
Query the managed users that were created by the reconciliation process.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user?_queryId=query-all-ids"
</userinput>
<computeroutput>{
"result" : [ {
"_id" : "user.5",
"_rev" : "0"
}, {
"_id" : "user.10",
"_rev" : "0"
}, {
"_id" : "user.1",
"_rev" : "0"
},
...
{
"_id" : "hradmin",
"_rev" : "0"
}, {
"_id" : "systemadmin",
"_rev" : "0"
}, {
"_id" : "superadmin",
"_rev" : "0"
} ],
"resultCount" : 23,
"pagedResultsCookie" : null,
"remainingPagedResults" : -1
}</computeroutput>
</screen>
<para>
23 users will have been created by the reconciliation process. The default
password of all the newly created users is <literal>Passw0rd</literal>.
</para>
</step>
<step>
<para>
Shut down OpenIDM before you proceed with the next use case.
</para>
<screen>$ cd /path/to/openidm
$ /shutdown.sh
</screen>
</step>
</procedure>
</section>
<section xml:id="use-case-2">
<title>Use Case 2 - New User Onboarding</title>
<para>
This use case demonstrates a new user onboarding process. The process can be
initiated by any of the users created in the previous reconciliation
process. In this example, we use <literal>user.1</literal> to initiate the
process. <literal>user.1</literal> captures the details of a new user, and
then submits the new user entry for approval by the prospective manager of
that new user.
</para>
<para>
The use case includes three separate workflows - onboarding (creation of the
new user), sunrise (commencement of the new user work period) and sunset
(termination of the user contract).
</para>
<para>
The use case also demonstrates email notification with the optional
configuration of an external email service. If you want to use email
notification, you must configure the external email service, as described in
<xref linkend="configure-email-notification" />, before you start the
workflow.
</para>
<para>
The use case works with the OpenIDM UI, accessible at the following URL by
default: <literal>https://localhost:8443/openidmui/</literal>.
</para>
<procedure xml:id="initiate-onboarding">
<title>Initiating the Onboarding Workflow</title>
<step>
<para>
Start OpenIDM with the configuration for use case 2.
</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/usecase/usecase2
</screen>
</step>
<step>
<para>
Log into the UI as <literal>user.1</literal> with password
<literal>Passw0rd</literal>.
</para>
<mediaobject>
<alt>Log into the UI</alt>
<imageobject>
<imagedata fileref="images/login-user1.png" format="PNG" />
</imageobject>
</mediaobject>
</step>
<step>
<para>
In this use case, the processes associated with the new user onboarding
workflow are visible to any user who logs into the UI.
</para>
<mediaobject>
<alt>Processes available to user.1</alt>
<imageobject>
<imagedata fileref="images/processes-user1.png" format="PNG" />
</imageobject>
</mediaobject>
<para>
Click on the User Onboarding Process and complete the fields for a sample
new user. Complete at least all mandatory fields.
</para>
<para>
<emphasis>Department</emphasis>. Specifies one of four departments to
which the new user will belong (Human Resources, Production Planning,
Sales &amp; Distribution, or Treasury &amp; Payments). The value you
select here determines the "manager" of the new user, to which the request
will be sent for approval. (See the previous table of users for a list of
the managers of the various departments.)
</para>
<para>
<emphasis>User Type</emphasis>. Governs user access to specific accounts.
If the User Type is "Employee", the new user will have access to an
account named "Business". This access is represented as an attribute of
the managed user entry in the OpenIDM repository, as follows:
<literal>accounts : ["Business"]</literal>. If the User Type is
"Contractor", the new user will have no accounts associated with its
managed user representation in OpenIDM.
</para>
<para>
<emphasis>Send Email Notification</emphasis>. Indicates whether an email
should be sent to alert the manager of the new required approval. The
email details used here are defined when you configure email notification,
as described in <xref linkend="configure-email-notification" />. If you
select not to send an email notification, the notification is simply added
to the OpenIDM repository, and appears when the manager logs into the UI.
</para>
</step>
<step>
<para>
Click Start to initiate the onboarding workflow.
</para>
<para>
This action sends the new user request to the corresponding "management"
users (the department manager, as well as the
<literal>superadmin</literal> user, who is an overall manager).
</para>
</step>
<step>
<para>
Log out of the UI, and log back in as the management user of the
department that you selected when you completed the new user form. For
example, if you selected "Human Resources", log in as
<literal>user.0</literal>, which simulates the management user for the HR
department. All users have the password <literal>Passw0rd</literal>.
</para>
<para>
Notice that this user now has an Onboarding Approval task in the queue of
tasks assigned to his group.
</para>
<mediaobject>
<alt>Approval task in group queue</alt>
<imageobject>
<imagedata fileref="images/approval-task.png" format="PNG" />
</imageobject>
</mediaobject>
</step>
<step>
<para>
Click on the Onboarding Approval task and select "Assign to Me".
</para>
<para>
This action "claims" the task for <literal>user.0</literal>, removes it
from the group queue, and places it in the list of pending tasks for
<literal>user.0</literal>.
</para>
</step>
<step>
<para>
Click on the Onboarding Approval task under the My Tasks list and click
Details.
</para>
<para>
The complete new user request is displayed for the manager's approval. As
the manager, you can add any information that was missing from the
original request.
</para>
<para>
In addition, you can specify the following information for the new user.
</para>
<itemizedlist>
<listitem>
<para>
<emphasis>Start Date</emphasis>. Completing this field results in the
user being created, with a <literal>"startDate"</literal> added to that
user's managed user entry. The status of the user is
<literal>inactive</literal>. This field is optional, and is used by
the task scanner to trigger the Sunrise workflow.
</para>
</listitem>
<listitem>
<para>
<emphasis>End Date</emphasis>. Completing this field results in the user
being created, with an <literal>"endDate"</literal> added to that user's
managed user entry. The field is optional, and is used by the task
scanner to trigger the Sunset workflow.
</para>
</listitem>
<listitem>
<para>
<emphasis>Manager</emphasis>. Selecting "Yes" here adds a
<literal>"title"</literal> property, with a value of
<literal>"manager"</literal>, to the new managed user entry.
</para>
</listitem>
<listitem>
<para>
<emphasis>Decision</emphasis>. Selecting "Reject" here terminates the
workflow and sends a notification to the user who initiated the
workflow. Selecting "Accept" creates the managed user entry in OpenIDM.
The password of the new user is <literal>Passw0rd</literal>.
</para>
<para>
Two notifications are created when the request is accepted - one for the
user who initiated the workflow, and one for the newly created user.
The notifications are visible in the UI after login. If you selected
email notification, one email is sent to the user defined when you
configured email notification, as described in
<xref linkend="configure-email-notification" />.
</para>
</listitem>
</itemizedlist>
</step>
<step>
<para>
At the bottom of the form, there is an option either to Requeue the
request or to Complete it. Click Complete.
</para>
<para>
If you click Requeue here, the task is removed from the list of My Tasks
for that user, and returned to the list of tasks pending for that group.
The task can then be claimed by any member of that group.
</para>
<para>
When the new user request has been approved, the user is created in the
OpenIDM repository. If you did not include a Start Date in the manager
approval, you should now be able to log into the UI with the details of
the new user. If you included a Start Date, you need to complete the
sunrise workflow before the user account is active (which will enable you
to log in as this user).
</para>
</step>
</procedure>
<procedure xml:id="configure-email-notification">
<title>Configuring Email Notification</title>
<para>
This step is optional, and required only if you want to use email
notification with this workflow.
</para>
<step>
<para>
Edit the settings in the file
<filename>/path/to/openidm/samples/usecase/usecase2/conf/external.email.json</filename>
to match the settings of your mail server. For example:
</para>
<screen><userinput>$ cd /path/to/openidm
$ more samples/usecase/usecase2/conf/external.email.json
</userinput>
<computeroutput>{
"host" : "smtp.gmail.com",
"port" : "587",
"username" : "my-username"
"password" : "my-password",
"mail.smtp.auth" : "true",
"mail.smtp.starttls.enable" : "true"
}</computeroutput></screen>
</step>
<step>
<para>
Change the notification email parameters in the workflow definition file.
To edit the workflow definition file:
</para>
<orderedlist>
<listitem>
<para>
Copy the workflow archive (<literal>.bar</literal>) file
(<filename>samples/usecase/usecase2/workflow/newUserCreate.bar</filename>)
to a temporary location.
</para>
</listitem>
<listitem>
<para>
Unzip the temporary workflow <literal>.bar</literal> file. This step
extracts the workflow definition file
(<filename>newUserCreate.bpmn20.xml</filename>) and two xhtml templates
required by the workflow.
</para>
<screen><userinput>$ unzip newUserCreate.bar</userinput>
<computeroutput>Archive: newUserCreate.bar
inflating: nUCDecideApprovalForm.xhtml
inflating: nUCStartForm.xhtml
inflating: newUserCreate.bpmn20.xml</computeroutput></screen>
</listitem>
<listitem>
<para>
Edit the extracted workflow definition file
(<filename>newUserCreate.bpmn20.xml</filename>). The email parameters
are towards the end of this file:
</para>
<screen><userinput>$ cd /path/to/openidm/samples/usecase/usecase2/workflow
$ grep emailParams newUserCreate.bpmn20.xml</userinput>
<computeroutput>emailParams = [from : 'usecasetest@forgerock.com', to : 'notification@example.com',
...</computeroutput></screen>
<para>
Change the <literal>from</literal> and <literal>to</literal> parameters
to reflect valid email addresses.
</para>
</listitem>
<listitem>
<para>
Zip up the amended workflow definition file, and the xhtml templates
into a workflow <literal>.bar</literal> file.
</para>
<screen><userinput>$ zip newUserCreate.bar newUserCreate.bpmn20.xml nUCDecideApprovalForm.xhtml nUCStartForm.xhtml</userinput>
<computeroutput>updating: nUCDecideApprovalForm.xhtml (deflated 82%)
updating: nUCStartForm.xhtml (deflated 82%)
updating: newUserCreate.bpmn20.xml (deflated 85%)</computeroutput></screen>
</listitem>
<listitem>
<para>
Copy the new <literal>.bar</literal> file to the workflow directory,
overwriting the existing <literal>.bar</literal> file.
</para>
<screen><userinput>$ cp /tmp/newUserCreate.bar /path/to/openidm/samples/usecase/usecase2/workflow</userinput></screen>
</listitem>
</orderedlist>
</step>
</procedure>
<procedure xml:id="initiate-sunrise">
<title>Initiating the Sunrise Workflow</title>
<para>
If a sunrise date is specified for the new user, the user is created in
the repository, with an <literal>inactive</literal> account status.
</para>
<step>
<para>
To trigger the sunrise workflow (which activates the account), enable the
sunrise task scanning schedule. The schedule is disabled by default.
</para>
<para>
Modify the schedule configuration file
(<filename>samples/usecase/usecase2/conf/schedule-taskscan_sunrise.json</filename>),
setting the <literal>"enabled"</literal> property to <literal>true</literal>.
</para>
<screen><userinput>$ cd /path/to/openidm
$ grep "enabled" samples/usecase/usecase2/conf/schedule-taskscan_sunrise.json</userinput>
<computeroutput>"enabled" : true,</computeroutput></screen>
<para>
The scan runs every minute, and checks the repository for users that have
a sunrise date that is anything up to one day after the current date.
When the scan is triggered, it locates the newly created user and starts
the sunrise workflow on this user. The workflow takes the following
actions:
</para>
<itemizedlist>
<listitem>
<para>
Changes the account status of the user to <literal>active</literal>.
</para>
</listitem>
<listitem>
<para>
Generates a notification for the new user, which is visible when the
user logs into the UI.
</para>
</listitem>
</itemizedlist>
<mediaobject>
<alt>Notifications for newly activated user</alt>
<imageobject>
<imagedata fileref="images/workflow-notifications.png" format="PNG" />
</imageobject>
</mediaobject>
</step>
</procedure>
<procedure xml:id="initiate-sunset">
<title>Initiating the Sunset Workflow</title>
<para>
If a sunset date is set for the new user, you can trigger the sunset
workflow to deactivate the user account when the end of his work period is
reached.
</para>
<step>
<para>
To trigger the sunset workflow, enable the sunset task scanning schedule.
The schedule is disabled by default.
</para>
<para>
Modify the schedule configuration file
(<filename>samples/usecase/usecase2/conf/schedule-taskscan_sunset.json</filename>),
setting the <literal>"enabled"</literal> property to <literal>true</literal>.
</para>
<screen><userinput>$ cd /path/to/openidm
$ grep "enabled" samples/usecase/usecase2/conf/schedule-taskscan_sunset.json
</userinput>
<computeroutput>"enabled" : true,</computeroutput></screen>
<para>
The scan runs every minute, and checks the repository for users that have
a sunset date that is anything up to one day after the current date.
When the scan is triggered, it locates users whose contracts are about to
end, and starts the sunset workflow on these users. When the workflow is
initiated, it assigns a task to the manager of the affected user. In this
example, the task is assigned to <literal>user.0</literal>.
</para>
</step>
<step>
<para>
When the sunset schedule has been enabled, log into OpenIDM UI as
<literal>user.0</literal> (with password <literal>Passw0rd</literal>). If
the user's sunset date is within one day of the current date, a "Contract
Termination" task becomes available under the 'My tasks' section for the
manager of that user.
</para>
<para>
Select the contract termination task and click Details.
</para>
</step>
<step>
<para>
In the Decision field, select either "Accept termination" or
"Modify date", then click Complete.
</para>
<para>
When you accept the termination, the user's account status is set to
<literal>inactive</literal> and the HR administrative user receives a
notification to that effect, next time that user logs into the UI. The
deactivated user is no longer able to log into the UI.
</para>
<para>
If you select to modify the date, the sunset date of that user is changed
to the value that you specify in the End Date field on that form. The
management user receives a UI notification that the employee's contract
has been extended.
</para>
</step>
<step>
<para>
Shut down OpenIDM before you proceed with the next use case.
</para>
<screen>$ cd /path/to/openidm
$ /shutdown.sh
</screen>
</step>
</procedure>
</section>
<section xml:id="use-case-3">
<title>Use Case 3 - User Access Request</title>
<para>
This use case simulates a user access request, with two levels of approval
for the request.
</para>
<para>
If you want to use email notification with this workflow, follow the
instructions in <xref linkend="configure-email-notification" /> before you
start the workflow, substituting
<filename>usecase3/conf/external.email.json</filename> and
<filename>usecase3/workflow/accessRequest.bpmn20.xml</filename> for the
files described in that procedure.
</para>
<procedure>
<step>
<para>
Start OpenIDM with the configuration for use case 3.
</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/usecase/usecase3
</screen>
</step>
<step>
<para>
Log into the UI as <literal>user.1</literal> with password
<literal>Passw0rd</literal>.
</para>
<para>
<literal>user.1</literal> belongs to the HR department and, in this
workflow, is requesting access to a Project system.
</para>
</step>
<step>
<para>
Click on the Access Request Process in the list of available processes and
click Start to start the workflow.
</para>
<para>
A User Access Request appears in the list of tasks for
<literal>user.1</literal>.
</para>
</step>
<step>
<para>
Select the User Access Request task and click Details.
</para>
<para>
The resulting form indicates the various systems to which the user may
request access.
</para>
<para>
<emphasis>Access to Business system</emphasis>. This field reflects the
current value of the <literal>"accounts"</literal> property for that user
in the repository. If the value includes <literal>"Business"</literal>
this field is True.
</para>
<para>
<emphasis>Access to Project system</emphasis>. Set this field to True to
request Project access for <literal>user.1</literal>.
</para>
<para>
<emphasis>Send Email Notification</emphasis>. Indicates whether an email
should be sent to alert the manager of the new access request. The
email details used here are defined when you configure email notification,
as described in <xref linkend="configure-email-notification" />. If you
select not to send an email notification, the notification is simply added
to the OpenIDM repository, and appears when the manager logs into the UI.
</para>
<para>
Select either Cancel, to terminate the process, or Request, to start a
user task, assigned to the manager of the user requesting access
(<literal>user.0</literal> in this example).
</para>
</step>
<step>
<para>
Log out of the UI and log back in as the manager (<literal>user.0</literal>
with password <literal>Passw0rd</literal>).
</para>
</step>
<step>
<para>
Under "Tasks that are in my group's queue" click "User Access Request
Approval" and select "Assign to me".
</para>
<para>
Note that the "User Access Request Approval" task has now moved under
"My tasks".
</para>
</step>
<step>
<para>
Under "My tasks" click "User Access Request Approval" and click Details.
</para>
</step>
<step>
<para>
The details of the access request are displayed. The manager is able to
modify the access rights. Select Accept or Reject to approve or deny the
request.
</para>
<para>
Rejecting the request results in a notification being sent to the user
who made the request. If you have enabled email notification, a single
email is sent to the account defined when you configure email notification,
as described in <xref linkend="configure-email-notification" />.
</para>
<para>
Accepting the request initiates a second approval task, assigned to the
<literal>systemadmin</literal> user.
</para>
<mediaobject>
<alt>Accepting an access request</alt>
<imageobject>
<imagedata fileref="images/ui-access-request.png" format="PNG" />
</imageobject>
</mediaobject>
<para>
Click Complete to complete the task.
</para>
</step>
<step>
<para>
Log out of the UI and log in as the <literal>systemadmin</literal> user
(with password <literal>Passw0rd</literal>).
</para>
<para>
This user now has one User Access Request Approval task in his queue.
</para>
</step>
<step>
<para>
Select the task and click Details.
</para>
<para>
This task interface is similar to that of the task that was assigned to
the manager.
</para>
<para>
Rejecting the request results in a notification being sent to the user
who made the request.
</para>
<para>
Accepting the request updates the managed/user record in OpenIDM, to
reflect the approved access changes.
</para>
<para>
If you have enabled email notification, a single email is sent to the
account defined when you configured the external email service
(<xref linkend="configure-email-notification" />), indicating whether the
request has been accepted or rejected.
</para>
</step>
</procedure>
<para>
Note that this sample includes an <emphasis>escalation</emphasis> step that
is attached to the manager approval task. If the manager does not complete
assessment of the user task within ten minutes of its initiation, a new user
task is created and assigned to the <literal>superadmin</literal> user. This
task has the same interface and functionality as the task assigned to the
manager. Accordingly, when the <literal>superadmin</literal> user completes
the task, the execution is passed to the <literal>systemadmin</literal> user
for approval.
</para>
<para>
Shut down OpenIDM before you proceed with the next use case.
</para>
<screen>$ cd /path/to/openidm
$ /shutdown.sh</screen>
</section>
<section xml:id="use-case-4">
<title>Use Case 4 - Orphan Account Detection</title>
<para>
This use case demonstrates two asynchronous tasks, started from a
reconciliation process:
</para>
<itemizedlist>
<listitem>
<para>
Detecting orphan accounts on a target object set
</para>
</listitem>
<listitem>
<para>
Handling ambiguous results during correlation
</para>
</listitem>
</itemizedlist>
<para>
This use case relies on a customized synchronization configuration (mapping)
file, named <filename>syncManagedBusiness.json</filename>, in the
<filename>/path/to/openidm/samples/usecase/usecase4/conf</filename>
directory.
</para>
<para>
This file defines a mapping (<literal>recon_managedUser_systemBusiness</literal>)
between a source (managed users) and a target object set. The target object
set is defined in the file
<literal>samples/usecase/usecase4/data/business.csv</literal>. The
<filename>business.csv</filename> file includes all users from the initial
reconciliation (described in <xref linkend="use-case-1" />). These users are
categorized as <literal>employees</literal>, and therefore include the
property <literal>"accounts" : ["Business"]</literal> in their managed user
entry (see <xref linkend="use-case-2" /> for an explanation of the User
Type).
</para>
<para>
The mapping includes the following <literal>"validSource"</literal> field:
</para>
<programlisting>"validSource" : {
"type" : "text/javascript",
"file" : "script/isSourceValidBusiness.js"
}, </programlisting>
<para>
This field references a script which specifies that only those users who
are employees are taken into account during the reconciliation.
</para>
<para>
In addition, the <literal>business.csv</literal> file includes the following
users:
</para>
<itemizedlist>
<listitem>
<para>
<literal>user.50</literal>. This user is defined <emphasis>only</emphasis>
in the .csv file, and not in the managed/user repository. When a
reconciliation operation is run, this user is detected as an
<emphasis>orphan account</emphasis>. The orphan account workflow is
triggered when an "UNQUALIFIED" or "UNASSIGNED" situation is encountered,
as indicated in this section of the mapping:
</para>
<programlisting>{
"situation" : "UNQUALIFIED",
"action" : {
"workflowName" : "orphanAccountReport",
"type" : "text/javascript",
"file" : "workflow/triggerWorkflowFromSync.js"
}
},
{
"situation" : "UNASSIGNED",
"action" : {
"workflowName" : "orphanAccountReport",
"type" : "text/javascript",
"file" : "workflow/triggerWorkflowFromSync.js"
}
}</programlisting>
</listitem>
<listitem>
<para>
<literal>user.33</literal>. This user has a <literal>"userName"</literal>
attribute of <literal>"user.3"</literal> (which is the same as the
<literal>"userName"</literal> attribute of the user,
<literal>user.3</literal>). The correlation query of the reconciliation
operation is based on the <literal>"userName"</literal> attribute. During
the correlation query, two candidate users are therefore correlated with
the same managed user (<literal>user.3</literal>), and the result is
ambiguous. The manual match workflow is triggered when an "AMBIGUOUS"
situation is encountered, as indicated in this section of the mapping:
</para>
<programlisting>{
"situation" : "AMBIGUOUS",
"action" : {
"workflowName" : "manualMatch",
"type" : "text/javascript",
"file" : "workflow/triggerWorkflowFromSync.js"
}
}</programlisting>
</listitem>
</itemizedlist>
<procedure>
<step>
<para>
Before you start with this use case, rename the mapping file to
<filename>sync.json</filename>.
</para>
<screen>$ cd /path/to/openidm/samples/usecase/usecase4/conf
$ mv syncManagedBusiness.json sync.json</screen>
</step>
<step>
<para>
Start OpenIDM with the configuration for use case 4.
</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/usecase/usecase4
</screen>
<para>
You will see a warning in the Felix console about a password not being
defined in the CSV file (<literal>WARN Password attribute is not defined.
[CSVFileConfiguration]</literal>). You can ignore this warning.
</para>
</step>
<step>
<para>
Run a reconciliation operation, according to the mapping defined in
<filename>sync.json</filename>.
</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request POST \
"https://localhost:8443/openidm/recon?_action=recon&amp;mapping=recon_managedUser_systemBusiness"</screen>
<para>
When the reconciliation operation finds the ambiguous entry
(<literal>user.3</literal>) and the orphan entry (<literal>user.50</literal>)
in the CSV file, two asynchronous workflows are launched
(<literal>manualMatch</literal> and <literal>orphanAccountReport</literal>),
as indicated in the mapping file, described previously.
</para>
</step>
<step>
<para>
Log into the UI as the <literal>systemadmin</literal> user, with password
<literal>Passw0rd</literal>.
</para>
</step>
<step>
<para>
Select the Manual Linking task from the My tasks list and click Details.
</para>
<para>
The <emphasis>Possible targets</emphasis> field presents a list of target
entries to which the ambiguous record can be linked. In this example,
<literal>user.3 - Atrc, Aaron</literal> and
<literal>user.33 - Atrc, Aaron</literal> are the two candidate users found
in the target object set by the correlation query. When you select one of
these values, the workflow manually links the managed user
(<literal>user.3</literal>) to the selected user.
</para>
<para>
If you select Ignore, here, no action is taken (no link is created), and
the workflow terminates.
</para>
</step>
<step>
<para>
Select the Orphan Account task from the My tasks list and click Details.
</para>
<para>
The <emphasis>Link to</emphasis> field enables you to enter an existing
managed user ID to which this orphan account should be linked. For the
purposes of this example, enter <literal>user.5</literal>.
</para>
<para>
The <emphasis>Delete</emphasis> option deletes the user from the target
object set (the CSV file in this case) and terminates the workflow.
</para>
</step>
<step>
<para>
Shut down OpenIDM before you proceed with the next use case.
</para>
<screen>$ cd /path/to/openidm
$ /shutdown.sh</screen>
</step>
</procedure>
</section>
<section xml:id="use-case-5">
<title>Use Case 5 - Certification</title>
<para>
This use case includes two scheduled tasks that demonstrate a certification
workflow.
</para>
<para>
The first scheduled task fetches all the managed users and begins a
certification workflow for each user. The workflow shows the roles that are
assigned to each user and allows you to accept (certify) or change those
role assignments. The second scheduled task fetches all the defined managed
roles and begins a certification workflow for the roles. The workflow
demonstrates managed role assignment.
</para>
<para>
In this use case, four managed roles are defined, based on the departments
to which the managed users belong. The managed roles are <literal>Human
Resources</literal>, <literal>Production Planning</literal>,
<literal>Sales and Distribution</literal>, and <literal>Treasury and
Payments</literal>. Every user is assigned a dynamic role by default, which
corresponds to that user's department.
</para>
<note>
<para>
By default the scheduled tasks used in this workflow run every minute, so
you will need to wait a minute before logging into the UI, after enabling
the schedules. You can change the frequency by editing the
<literal>"schedule"</literal> property in the schedule configuration files
(<filename>schedule-certification.json</filename> and
<filename>schedule-certificationEntitlements.json</filename>). This
property takes standard cron syntax. Every minute, a new task is created
for each user or role, so you will see several tasks in the group queue if
you log in to the UI after some time. In a live deployment, this kind of
workflow would probably only run once every few months.
</para>
</note>
<procedure>
<step>
<para>
Start OpenIDM with the configuration for use case 5.
</para>
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/usecase/usecase5</screen>
</step>
<step>
<para>
Define the four managed roles over the REST interface, by sending the
following PUT requests to the <literal>managed/role</literal> endpoint.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-None-Match: *" \
--request PUT \
--data '{
"properties": {
"description": "Role for Human Resources department"
},
"assignments": {
"ad1": {
"attributes": [
{
"value": [
"CN=cisco_vpn,DC=example,DC=com"
],
"assignmentOperation": "mergeWithTarget",
"unassignmentOperation": "removeFromTarget",
"name": "memberOf"
}
]
}
},
"name": "Human Resources"
}' \
"https://localhost:8443/openidm/managed/role/human-resources"</userinput>
<userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-None-Match: *" \
--request PUT \
--data '{
"properties": {
"description": "Role for Production Planning department"
},
"assignments": {
"ad1": {
"attributes": [
{
"value": [
"CN=intranet,DC=example,DC=com",
"CN=email,DC=example,DC=com",
"CN=radius_dialin,DC=example,DC=com"
],
"assignmentOperation": "mergeWithTarget",
"unassignmentOperation": "removeFromTarget",
"name": "memberOf"
}
]
}
},
"name": "Production Planning"
}' \
"https://localhost:8443/openidm/managed/role/production-planning"</userinput>
<userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-None-Match: *" \
--request PUT \
--data '{
"properties": {
"description": "Role for Sales and Distribution department"
},
"assignments": {
"ad1": {
"attributes": [
{
"value": [
"CN=intranet,DC=example,DC=com",
"CN=email,DC=example,DC=com"
],
"assignmentOperation": "mergeWithTarget",
"unassignmentOperation": "removeFromTarget",
"name": "memberOf"
}
]
}
},
"name": "Sales and Distribution"
}' \
"https://localhost:8443/openidm/managed/role/sales-distribution"</userinput>
<userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-None-Match: *" \
--request PUT \
--data '{
"properties": {
"description": "Role for Treasury and Payments department"
},
"assignments": {
"ad1": {
"attributes": [
{
"value": [
"CN=intranet,DC=example,DC=com"
],
"assignmentOperation": "mergeWithTarget",
"unassignmentOperation": "removeFromTarget",
"name": "memberOf"
}
]
}
},
"name": "Treasury and Payments"
}' \
"https://localhost:8443/openidm/managed/role/treasury-payments"</userinput>
</screen>
</step>
<step>
<para>
To trigger the user certification scheduled task, enable the schedule in
the schedule configuration file
(<filename>schedule-certification.json</filename>).
</para>
<screen><userinput>$ cd /path/to/openidm/samples/usecase/usecase5/conf/
$ more schedule-certification.json</userinput>
<computeroutput>{
"enabled" : true,
"type" : "cron",
...
}</computeroutput></screen>
</step>
<step>
<para>
Log into the UI as <literal>user.0</literal> with password
<literal>Passw0rd</literal>.
</para>
<para>
<literal>user.0</literal> represents the manager of the users who are
being certified.
</para>
</step>
<step>
<para>
Under "Tasks that are in my group's queue" click "Role Status Check". A
scheduled task has been started for each managed user. Choose one of the
users, for example, user.1, and select "Assign to me" under the Actions
column.
</para>
<para>
The "Role Status Check" task for that user moves under "My tasks".
</para>
</step>
<step>
<para>
Under "My tasks" click "Role Status Check" and click Details.
</para>
</step>
<step>
<para>
The <emphasis>Access Status Check</emphasis> window shows the details of
the user for whom the certification is being processed, and a list of
roles that can be assigned.
</para>
<para>
An <literal>x</literal> in the first column indicates that the role is
currently assigned to the user. A value in the second column indicates the
roles that will be assigned to the user when the certification process is
complete.
</para>
<para>
If the role is dynamic, that is, assigned to the user based on
the department to which the user belongs, the value is read-only. user.1
has the <literal>human-resources</literal> role assigned dynamically, as a
function of the department to which this user belongs.
</para>
<mediaobject>
<alt>Workflow showing current role assignment</alt>
<imageobject>
<imagedata fileref="images/access-status-check.png" format="PNG"/>
</imageobject>
</mediaobject>
</step>
<step>
<para>
Select the appropriate roles that should be assigned to this user, then
select one of the following options from the "Certification result" list:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis role="strong">Change.</emphasis> The user's role assignments
are updated, based on the values specified in the second column.
</para>
</listitem>
<listitem>
<para>
<emphasis role="strong">Certify.</emphasis> The user's role assignments
are not updated. In other words, the user's current role assignments are
certified.
</para>
</listitem>
<listitem>
<para>
<emphasis role="strong">Escalate.</emphasis> The task is reassigned to
the superadmin user. To test this, log out, and log in again as the
<literal>superadmin</literal>. The superadmin can select whether to
change or certify the role assignments.
</para>
</listitem>
</itemizedlist>
<para>
When you have completed the role selection, and the action to be taken,
click Complete.
</para>
<para>
Clicking <emphasis>Requeue</emphasis> here simply returns the task to the
list of pending tasks in that group's queue.
</para>
</step>
<step>
<para>
Log out of the UI.
</para>
<para>
This is the end of the first scheduled task.
</para>
</step>
<step>
<para>
Trigger the managed role certification by enabling the scheduled task in
the schedule configuration file
(<filename>schedule-certificationEntitlements.json</filename>).
</para>
<screen><userinput>$ cd /path/to/openidm/samples/usecase/usecase5/conf/
$ more schedule-certificationEntitlements.json</userinput>
<computeroutput>{
"enabled" : true,
"type" : "cron",
...
}</computeroutput></screen>
</step>
<step>
<para>
Log into the UI as <literal>systemadmin</literal> with password
<literal>Passw0rd</literal>.
</para>
</step>
<step>
<para>
Under "My tasks" select "Entitlement Status Check".
</para>
</step>
<step>
<para>
Under the "Key" column, you will see the names of the various managed
roles whose entitlements are being certified in this workflow.
</para>
<para>
Select one of the entitlement check tasks (for example, for the
<literal>human-resources</literal> role) and click Details.
</para>
<mediaobject>
<alt>Role entitlements task in the UI</alt>
<imageobject>
<imagedata fileref="images/entitlement-check.png" format="PNG"/>
</imageobject>
</mediaobject>
</step>
<step>
<para>
The Role Status Check panel shows the name, ID and description of the role
whose assignments or entitlements you are certifying. For each assignment,
the name of the attribute whose value is assigned, and the assignment and
unassignment operations are indicated.
</para>
<para>
The only field that can be edited on this panel is the "Value" field,
which specifies the value that should be used for the named attribute when
this role is assigned to a user. To edit the value, click in the field and
either replace the existing value or press Enter at the end of the
existing value to add a new value. Because this attribute is multivalued,
multiple values are indicated by typing them on separate lines.
</para>
<para>
For more information about managed roles and assignment and unassignment
operations, see <link xlink:show="new"
xlink:href="integrators-guide##configuring-custom-roles"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Configuring
Custom Roles</citetitle></link>.
</para>
</step>
<step>
<para>
Enter the values that should be used for this attribute, then select one
of the following options from the "Certification result" list:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis role="strong">Update.</emphasis> The role definition is
updated to use the attribute value or values that you specified in the
"Value" field.
</para>
</listitem>
<listitem>
<para>
<emphasis role="strong">Certify.</emphasis> The role definition is not
updated and the current assignment value is certified.
</para>
</listitem>
</itemizedlist>
<para>
When you have completed the role selection, and the action to be taken,
click Complete.
</para>
<para>
This is the end of the role entitlement workflow.
</para>
</step>
<step>
<para>
Shut down OpenIDM before you proceed with the next use case.
</para>
<screen>$ cd /path/to/openidm
$ /shutdown.sh</screen>
</step>
</procedure>
</section>
<section xml:id="use-case-6">
<title>Use Case 6 - Password Change Reminder</title>
<para>
This use case demonstrates using the task scanner to trigger a password
change reminder workflow for managed users.
</para>
<para>
In this example, each managed user entry in OpenIDM has a dedicated
attribute, <literal>lastPasswordSet</literal>, that stores the date on which
the password was last changed. The value of this attribute is updated by an
<literal>onStore</literal> script, defined in the managed user configuration
file (<filename>conf/managed.json</filename>), as follows:
</para>
<programlisting>
"onStore" : {
"type" : "text/javascript",
"file" : "script/onStoreManagedUser.js"
},
</programlisting>
<para>
When a new password is stored for a user, the script sets the date on which
this change was made. The task scanner periodically scans the
<literal>lastPasswordSet</literal> attribute, and starts the workflow if the
password was changed more than an hour ago. This condition is configured in
the schedule configuration file
(<filename>schedule-taskscan_passwordchange.json</filename>):
</para>
<screen><userinput>$ cd /path/to/openidm
$ more samples/usecase/usecase6/conf/schedule-taskscan_passwordchange.json</userinput>
<computeroutput>
...
"condition" : {
"before" : "${Time.now - 1h}"
},
....</computeroutput>
</screen>
<para>
Obviously, in a real deployment, the period between required password
changes would be longer, and this value would need to be set accordingly.
For the purposes of testing this use case, you might want to set the value
to a shorter period, such as <literal>"${Time.now - 1m}"</literal>, which
will send the notification one minute after a password change.
</para>
<para>
By default, the workflow sends notifications to the user entry, visible when
the user logs into the UI. If you want notifications sent by email,
configure the external email service, as follows:
</para>
<procedure>
<step>
<para>
Edit the settings in the file
<filename>/path/to/openidm/samples/usecase/usecase6/conf/external.email.json</filename>
to match the settings of your mail server. For example:
</para>
<screen><userinput>$ cd /path/to/openidm
$ more samples/usecase/usecase6/conf/external.email.json</userinput>
<computeroutput>
{
"host" : "smtp.gmail.com",
"port" : "587",
"username" : "my-username"
"password" : "my-password",
"mail.smtp.auth" : "true",
"mail.smtp.starttls.enable" : "true"
}</computeroutput>
</screen>
</step>
<step>
<para>
Enable email notification in the script file that starts the workflow
(<filename>samples/usecase/usecase6/script/passwordchange.js</filename>).
For example:
</para>
<screen><userinput>$ cd /path/to/openidm
$ more samples/usecase/usecase6/script/passwordchange.js</userinput>
<computeroutput>
/*global objectID*/
(function () {
var params = {
"userId" : objectID,
"emailEnabled" : "true",
"_key": "passwordChangeReminder"
};</computeroutput>
</screen>
</step>
<step>
<para>
Make sure that all users have a valid email address as the value of their
<literal>mail</literal> attribute, in the OpenIDM repository.
</para>
</step>
</procedure>
<para>
The task scanning schedule is disabled by default. To test this use case,
follow these steps:
</para>
<procedure>
<step>
<para>
Enable the task scanning schedule by setting <literal>enabled</literal> to
<literal>true</literal> in the schedule configuration file
(<filename>schedule-taskscan_passwordchange.json</filename>).
</para>
<screen><userinput>$ cd /path/to/openidm
$ more samples/usecase/usecase6/conf/schedule-taskscan_passwordchange.json</userinput>
<computeroutput>
{
"enabled" : true,
...
</computeroutput>
</screen>
</step>
<step>
<para>Start OpenIDM with the configuration for use case 6.
<screen>$ cd /path/to/openidm
$ /startup.sh -p samples/usecase/usecase6</screen>
</para>
</step>
<step>
<para>
Log into the UI as any of the users listed in the introduction to this
section (for example, <literal>user.4</literal>, with password
<literal>Passw0rd</literal>).
</para>
<para>
The user sees the following notification upon login:
</para>
<mediaobject>
<alt>Password expiry notification</alt>
<imageobject>
<imagedata fileref="images/pwd-expiry.png" format="PNG" />
</imageobject>
</mediaobject>
<para>
If the password has not been changed after five minutes, a second
notification is sent to the user.
</para>
<mediaobject>
<alt>Second password expiry notification</alt>
<imageobject>
<imagedata fileref="images/pwd-expiry2.png" format="PNG" />
</imageobject>
</mediaobject>
<para>
If the password has not been changed two minutes after this second
notification, the user's account is deactivated and that user is no longer
able to log into the UI.
</para>
</step>
<step performance="optional">
<para>
To avoid the second notification, or the account deactivation, you can
change the user password through the UI, as follows:
</para>
<substeps>
<step>
<para>
Log into the UI as the user whose password you want to change and click
Change Security Data at the top right of the page.
</para>
</step>
<step>
<para>
Enter the existing password (in this case <literal>Passw0rd</literal>).
</para>
</step>
<step>
<para>
Enter a new password that conforms to the requirements of the password
policy.
</para>
</step>
</substeps>
</step>
</procedure>
</section>
</section>
</chapter>