Friday, June 19, 2020

OIC: Identity Propagation In Structured Process

When a process calls a service you sometimes have a requirement that some user identity needs to be propagated to the service call. This article describes how you can propagate the identity (but alas not the principle) of a user on behalf of whom a service call is executed.

Updated on June 22 to add a missing, last step.

When calling a service in a structured process you sometimes must pass on the identity of the user that called the service. This could be the case when that service call is done to a SaaS application and it is required to track on behalf of whom that service is called. The identity (user name) only is not enough when authentication must happen using the principle (security token) of the user, but there are applications that can handle this using some combination of a system user (or client id plus secret) with an on behalf of user. And there are situations where having an on behalf of user only is enough, like when storing data in a database table with audit columns (you don’t want all the end users also to be database users so passing on the user’s principle to the DB would not make sense).

It is not always trivial who that on behalf of user should be. Take for example the following process model:

  • On the top a flow implementing the 4-eye principle. The first user does something after which the second user reviews it. Which identity should be passed on, that of the first or the second user?
  • Below that a flow where the user activity is optional. When that user activity is not executed, what identity should be passed on?
  • After that an exception flow to handle a fault with calling the service. This is handled by some Applications Administrator that may choose to retry. Which identity should be passed on, that of the Process Owner or the administrator?
There is no good or bad answer, it depends. You can decide to keep it simple though and choose for always using the identity of the last user that executed a Human Task no matter where in the process that is. And if there is none, then use the identity of the “system user” that started the process instance.

Now how to achieve this? In short:
  • In the Start event of the process set some “user” payload element to the creator of the process.
  • Whenever a Human Task is finished, replace that with the id of the user that did that.
  • When the service is called, pass it on as a custom header element.
Putting the id as plain text in the header is not exactly 100% hack-proof but spoofing it is also not trivial. Considering that calls are done over SSL it just might be secure enough.

In Detail

I work with one single process payload data object as much as possible. Let’s call that processPayload. You can add an element to that called onBehalfOfuser. In the Start event you can instantiate that with the creator predefined variable:

In the output mapping of every Human Task map the to the processPayload.onBehalfOfUser:

In case of an OIC Integration (or ORDS REST Handler) you can pass that on as a custom header element. In case of an Integration you configure that in the trigger activity.

In case of an ORDS REST Handler you can configure that as an HTTP header parameter:

When calling the service, you map the payload.onBehalfOfUser to the header parameter, which either will have the value of the creator of the process, or that user id of the last Human Task that has been executed.

Finally, to make the Integration backward compatible you can use an choose-when-otherwise construction to default the identity with the invokedBy meta data element: