Page tree
Skip to end of metadata
Go to start of metadata

The following approval-related operations are currently available via REST service:

  • starting an approval process,
  • determining the status of the approval process.

The following is doable, but currently only using an unsupported "hack":

  • approving or rejecting an item (i.e. the actual decision making).

In this document we'll show how to carry out these operations.

Starting an approval process

In midPoint the approval process is started automatically when an operation requiring approval is started. I.e. there's no special "start an approval process" method.

Let us illustrate this on an example.

This is user peter:

<user xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
    oid="cac0694d-62d8-441b-a277-0a33b8caa0f7">
    <name>peter</name>
</user>

This is role sensitive that we want to assign to peter:

<role xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
    oid="d4930444-c5e5-4710-af96-19f79eb078cb">
    <name>sensitive</name>
</role>

The role has an approver, named paul:

<user xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
    oid="3b5b5d18-b1d9-4125-b435-a5d3aece8546">
    <name>paul</name>
    <assignment>
        <targetRef oid="d4930444-c5e5-4710-af96-19f79eb078cb" type="RoleType" relation="approver"/>
    </assignment>
    <assignment>
        <targetRef oid="00000000-0000-0000-0000-000000000004" type="RoleType"/> <!--  Superuser, to avoid authorization issues -->
    </assignment>
    <credentials>
        <password>
            <value>5ecr3t</value>
        </password>
    </credentials>
</user>

Paul has an assignment to role sensitive with a relation of approver, so it is an approver for all assignments of that role.

Now let's start the approval process. We will do that by assigning role special to user peter.

curl.exe -v --user administrator:5ecr3t -H "Content-Type: application/xml" -X PATCH http://localhost:8080/midpoint/ws/rest/users/cac0694d-62d8-441b-a277-0a33b8caa0f7 -d @assign-sensitive-role.xml
assign-sensitive-role.xml
<objectModification
         xmlns="http://midpoint.evolveum.com/xml/ns/public/common/api-types-3" 
         xmlns:t="http://prism.evolveum.com/xml/ns/public/types-3" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3">
    <t:itemDelta>
        <t:modificationType>add</t:modificationType>
        <t:path>assignment</t:path>
        <t:value xsi:type="c:AssignmentType">
            <c:targetRef oid="d4930444-c5e5-4710-af96-19f79eb078cb" type="c:RoleType">
                <!-- sensitive -->
            </c:targetRef>
        </t:value>
    </t:itemDelta>
</objectModification>

The above XML is sent to the REST service and it will be applied (as an object delta) to object cac0694d-62d8-441b-a277-0a33b8caa0f7, i.e. peter. It has one item delta, in particular creation of an assignment to d4930444-c5e5-4710-af96-19f79eb078cb i.e. to the sensitive role.

The response is then like this:

HTTP/1.1 204
Date: Thu, 25 Oct 2018 12:31:26 GMT

I.e. the operation was successful.

Determining the status of the approval process

The approval processes are wrapped into the task objects. So they can be retrieved just like any other using the REST search operation. The only difference is that the work items that are part of the task objects are not retrieved by default, so they have to be requested explicitly. An example:

get-approval-tasks-for-peter.bat
curl.exe -v --user administrator:5ecr3t -H "Content-Type: application/xml" -X POST "http://localhost:8080/midpoint/ws/rest/tasks/search?include=workflowContext%%2FworkItem" -d @get-approval-tasks-for-peter.xml
get-approval-tasks-for-peter.xml
<q:query xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3">
    <q:filter>
       <q:and>
          <q:ref>
             <q:path>objectRef</q:path>
             <q:value oid="26b53b59-ed98-4519-9245-46519ea629fc"></q:value>	<!-- peter -->
          </q:ref>
          <q:equal>
             <q:path>category</q:path>
             <q:value>Workflow</q:value>
          </q:equal>
          <q:equal>
             <q:path>executionStatus</q:path>
             <q:value>waiting</q:value>
          </q:equal>
       </q:and>
    </q:filter>
</q:query> 

The above search query returns all approval processes that deal with the user 26b53b59-ed98-4519-9245-46519ea629fc i.e. peter and are stil waiting to be resolved.

Note that there are two kinds of approval-related tasks:

  1. Operation-level tasks, covering the whole operation. Each operation can consist of one or more elementary actions, like "add assignment to role R1", "add assignment to role R2", "remove assignment of role R3".
  2. Individual approval tasks; each covering a single elementary action, like "add assignment to role R1". Each such task corresponds to a single approval process.

The above query would result in the following (some comments added):

<t:object xmlns:t="http://prism.evolveum.com/xml/ns/public/types-3" xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3" xmlns:apti="http://midpoint.evolveum.com/xml/ns/public/common/api-types-3" xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3" xmlns:icfs="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/resource-schema-3" xmlns:org="http://midpoint.evolveum.com/xml/ns/public/common/org-3" xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3" xmlns:ri="http://midpoint.evolveum.com/xml/ns/public/resource/instance-3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="apti:ObjectListType">

    <!-- This is elementary operation-level task. It deals with the assigning of "sensitive" role to user "peter". -->

    <apti:object oid="3cc5c1f4-040d-40b1-9a72-27539bc83681" version="2" xsi:type="c:TaskType">
        <name>Approval of: Assigning role "sensitive" to user "peter"</name>
        <taskIdentifier>1540504610111-0-1</taskIdentifier>
        <ownerRef oid="00000000-0000-0000-0000-000000000002" relation="org:default" type="c:UserType"/>
        <channel>http://midpoint.evolveum.com/xml/ns/public/model/channels-3#rest</channel>
        <parent>1540504610068-0-1</parent>
        <executionStatus>waiting</executionStatus>
        <waitingReason>other</waitingReason>
        <category>Workflow</category>
        <handlerUri>http://midpoint.evolveum.com/xml/ns/public/workflow/process-instance-shadow/handler-3</handlerUri>
        <resultStatus>in_progress</resultStatus>
        <objectRef oid="cac0694d-62d8-441b-a277-0a33b8caa0f7" relation="org:default" type="c:UserType"/>		<!-- peter -->
        <progress>0</progress>
        <recurrence>single</recurrence>
        <binding>tight</binding>
        <schedule/>
        <workflowContext>
            <processInstanceId>10114</processInstanceId>			<!-- this is process instance ID in Activiti -->
            <processName>ItemApproval</processName>
            <processInstanceName>Assigning role "sensitive" to user "peter"</processInstanceName>
            <localizableProcessInstanceName xsi:type="c:SingleLocalizableMessageType">	<!-- this is the process name in localizable form -->
                <key>DefaultPolicyConstraint.Short.assignmentModification.toBeAdded</key>
                <argument>
                    <localizable xsi:type="c:SingleLocalizableMessageType">
                        <key>ObjectSpecification</key>
                        <argument>
                            <localizable xsi:type="c:SingleLocalizableMessageType">
                                <key>ObjectTypeLowercase.RoleType</key>
                                <fallbackMessage>RoleType</fallbackMessage>
                            </localizable>
                        </argument>
                        <argument>
                            <value>sensitive</value>
                        </argument>
                    </localizable>
                </argument>
                <argument>
                    <localizable xsi:type="c:SingleLocalizableMessageType">
                        <key>ObjectSpecification</key>
                        <argument>
                            <localizable xsi:type="c:SingleLocalizableMessageType">
                                <key>ObjectTypeLowercase.UserType</key>
                                <fallbackMessage>UserType</fallbackMessage>
                            </localizable>
                        </argument>
                        <argument>
                            <value>peter</value>
                        </argument>
                    </localizable>
                </argument>
            </localizableProcessInstanceName>
            <startTimestamp>2018-10-25T23:56:50.066+02:00</startTimestamp>
            <requesterRef oid="00000000-0000-0000-0000-000000000002" relation="org:default" type="c:UserType"/>
            <objectRef oid="cac0694d-62d8-441b-a277-0a33b8caa0f7" relation="org:default" type="c:UserType"/>		<!-- peter -->
            <targetRef oid="d4930444-c5e5-4710-af96-19f79eb078cb" relation="org:default" type="c:RoleType"/>		<!-- sensitive -->
            <stageNumber>1</stageNumber>
            <changeProcessor>com.evolveum.midpoint.wf.impl.processors.primary.PrimaryChangeProcessor</changeProcessor>
            <processInterface>itemApprovalProcessInterface</processInterface>
            <processorSpecificState xsi:type="c:WfPrimaryChangeProcessorStateType">
                <changeAspect>com.evolveum.midpoint.wf.impl.processors.primary.policy.PolicyRuleBasedAspect</changeAspect>
                <deltasToProcess>	<!-- this is delta to be approved/rejected -->
                    <focusPrimaryDelta>
                        <t:changeType>modify</t:changeType>
                        <t:objectType>c:UserType</t:objectType>
                        <t:oid>cac0694d-62d8-441b-a277-0a33b8caa0f7</t:oid>
                        <t:itemDelta>
                            <t:modificationType>add</t:modificationType>
                            <t:path>c:assignment</t:path>
                            <t:value>
                                <targetRef oid="d4930444-c5e5-4710-af96-19f79eb078cb" type="c:RoleType"/>
                            </t:value>
                        </t:itemDelta>
                    </focusPrimaryDelta>
                </deltasToProcess>
            </processorSpecificState>
            <processSpecificState xsi:type="c:ItemApprovalProcessStateType">
                <approvalSchema>	<!-- this is the approval schema according to which the approval(s) are being gathered: in this case, it is a simple one-step approval -->
                    <stage id="1">
                        <number>1</number>
                        <approverRef oid="3b5b5d18-b1d9-4125-b435-a5d3aece8546" relation="org:default" type="c:UserType"/>
                        <outcomeIfNoApprovers>reject</outcomeIfNoApprovers>
                        <groupExpansion>byClaimingWorkItem</groupExpansion>
                    </stage>
                </approvalSchema>
                <policyRules/>
            </processSpecificState>
            <event xsi:type="c:CaseCreationEventType">		<!-- events related to this process; currently here is only the 'process started' event -->
                <timestamp>2018-10-25T23:56:50.066+02:00</timestamp>
                <initiatorRef oid="00000000-0000-0000-0000-000000000002" relation="org:default" type="c:UserType">
                    <targetName>administrator</targetName>
                </initiatorRef>
            </event>
            <workItem>		<!-- currently open work items -->
                <externalId>10217</externalId>
                <name>Assigning role "sensitive" to user "peter"</name>
                <createTimestamp>2018-10-25T23:56:50.136+02:00</createTimestamp>
                <assigneeRef oid="3b5b5d18-b1d9-4125-b435-a5d3aece8546" type="c:UserType">
                    <targetName>paul</targetName>
                </assigneeRef>
                <originalAssigneeRef oid="3b5b5d18-b1d9-4125-b435-a5d3aece8546" type="c:UserType">
                    <targetName>paul</targetName>
                </originalAssigneeRef>
                <stageNumber>1</stageNumber>
            </workItem>
        </workflowContext>
    </apti:object>

	<!-- This is the "umbrella task"; actually it wraps only a single elementary operation-level task, described above -->

    <apti:object oid="dbaa9640-3c80-4451-8abf-010b3f24b8d9" version="1" xsi:type="c:TaskType">
        <name>Approving and executing change of user "peter" (started 25-Oct-2018 23:56:50)</name>
        <taskIdentifier>1540504610068-0-1</taskIdentifier>
        <ownerRef oid="00000000-0000-0000-0000-000000000002" relation="org:default" type="c:UserType"/>
        <channel>http://midpoint.evolveum.com/xml/ns/public/model/channels-3#rest</channel>
        <executionStatus>waiting</executionStatus>
        <waitingReason>otherTasks</waitingReason>
        <category>Workflow</category>
        <handlerUri>http://midpoint.evolveum.com/xml/ns/public/workflow/prepare-root-operation/handler-3</handlerUri>
        <otherHandlersUriStack>
            <uriStackEntry>
                <handlerUri>http://midpoint.evolveum.com/xml/ns/public/model/operation/handler-3</handlerUri>
                <recurrence>single</recurrence>
                <binding>tight</binding>
            </uriStackEntry>
        </otherHandlersUriStack>
        <resultStatus>in_progress</resultStatus>
        <objectRef oid="cac0694d-62d8-441b-a277-0a33b8caa0f7" relation="org:default" type="c:UserType"/>
        <progress>0</progress>
        <recurrence>single</recurrence>
        <binding>tight</binding>
        <schedule/>
        <modelOperationContext>
            <state>primary</state>
            <channel>http://midpoint.evolveum.com/xml/ns/public/model/channels-3#rest</channel>
            <focusContext>
                <objectOldRef oid="cac0694d-62d8-441b-a277-0a33b8caa0f7" relation="org:default" type="c:UserType"/>
                <objectNewRef oid="cac0694d-62d8-441b-a277-0a33b8caa0f7" relation="org:default" type="c:UserType"/>
                <primaryDelta>
                    <t:changeType>modify</t:changeType>
                    <t:objectType>c:UserType</t:objectType>
                    <t:oid>cac0694d-62d8-441b-a277-0a33b8caa0f7</t:oid>
                </primaryDelta>
                <objectTypeClass>com.evolveum.midpoint.xml.ns._public.common.common_3.UserType</objectTypeClass>
                <oid>cac0694d-62d8-441b-a277-0a33b8caa0f7</oid>
                <iteration>0</iteration>
                <iterationToken/>
                <secondaryDeltas/>
            </focusContext>
            <focusClass>com.evolveum.midpoint.xml.ns._public.common.common_3.UserType</focusClass>
            <doReconciliationForAllProjections>false</doReconciliationForAllProjections>
            <executionPhaseOnly>false</executionPhaseOnly>
            <projectionWave>1</projectionWave>
            <executionWave>0</executionWave>
            <lazyAuditRequest>false</lazyAuditRequest>
            <requestAudited>false</requestAudited>
            <executionAudited>false</executionAudited>
            <requestAuthorized>true</requestAuthorized>
            <stats/>
            <requestMetadata>
                <requestTimestamp>2018-10-25T23:56:50.047+02:00</requestTimestamp>
                <requestorRef oid="00000000-0000-0000-0000-000000000002" relation="org:default" type="c:UserType"/>
                <createChannel>http://midpoint.evolveum.com/xml/ns/public/model/channels-3#rest</createChannel>
            </requestMetadata>
        </modelOperationContext>
        <workflowContext>
            <localizableTaskName xsi:type="c:SingleLocalizableMessageType">
                <key>ApprovingAndExecuting.ChangeOf</key>
                <argument>
                    <localizable xsi:type="c:SingleLocalizableMessageType">
                        <key>ObjectSpecification</key>
                        <argument>
                            <localizable xsi:type="c:SingleLocalizableMessageType">
                                <key>ObjectTypeLowercase.UserType</key>
                                <fallbackMessage>UserType</fallbackMessage>
                            </localizable>
                        </argument>
                        <argument>
                            <value>peter</value>
                        </argument>
                    </localizable>
                </argument>
                <argument>
                    <value>25-Oct-2018 23:56:50</value>
                </argument>
            </localizableTaskName>
            <startTimestamp>2018-10-25T23:56:50.067+02:00</startTimestamp>
            <requesterRef oid="00000000-0000-0000-0000-000000000002" relation="org:default" type="c:UserType"/>
            <objectRef oid="cac0694d-62d8-441b-a277-0a33b8caa0f7" relation="org:default" type="c:UserType"/>
            <changeProcessor>com.evolveum.midpoint.wf.impl.processors.primary.PrimaryChangeProcessor</changeProcessor>
        </workflowContext>
    </apti:object>
</t:object>

Approving or rejecting a work item

This is currently not supported via REST directly. However, it can be achieved using a workaround (an euphemism for really ugly hack):

approve-work-item.bat
curl.exe --user administrator:5ecr3t -H "Content-Type: application/xml" -X POST "http://localhost:8080/midpoint/ws/rest/rpc/executeScript" -d @approve-work-item.xml
approve-work-item.xml
<?xml version="1.0"?>
<s:executeScript xmlns:s="http://midpoint.evolveum.com/xml/ns/public/model/scripting-3" xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <s:action>
        <s:type>execute-script</s:type>
        <s:parameter>
            <s:name>script</s:name>
            <c:value xsi:type="c:ScriptExpressionEvaluatorType">
                <c:code>midpoint.workflowService.completeWorkItem(
                            '10217',        /* this is work item ID */ 
                            true,           /* true for approval, false for rejection */ 
                            null,           /* this is comment */ 
                            null, new com.evolveum.midpoint.schema.result.OperationResult('completeWorkItem'))</c:code>
            </c:value>
        </s:parameter>
        <s:parameter>
            <s:name>forWholeInput</s:name>
            <c:value>true</c:value>
        </s:parameter>
    </s:action>
</s:executeScript>

Note that you have to provide correct work item ID as the first parameter of completeWorkItem method.

Unfortunately, the approval/rejection is logged under administrator account. It is not possible to use non-admin account to carry out this action, because Groovy script execution requires the strongest authorization (because of the security implications).

  • No labels