PingOne Advanced Identity Cloud

Workflow for entitlement grant with custom approvers

In this example, an administrator wants to create a basic entitlement grant workflow that uses a custom list of approvers in the Approval node.

Administrators need to carry out the following tasks:

Assumptions

  • You have designated an end user or a test user who can approve the request.

Example

Task 1: Create a custom glossary property

The initial task is to create a custom entitlement glossary property, Approvers, that lets an administrator easily set a custom list of approvers.

  1. In the Advanced Identity Cloud admin UI, click Governance > Glossary.

  2. Click Entitlement and then Entitlement Glossary Item.

  3. In the Add Entitlement Glossary Item modal, enter the following, and click Save.

    Field Description

    Name

    Enter a label for the entitlement glossary item. For example, approvers.

    Display Name

    Enter a display name for the entitlement glossary item. For example, Approvers.

    Description (optional)

    Enter a general description for the glossary item.

    Type

    Select User.

    Multi-Valued

    Click Multi-Valued.

    Enumerated Values

    Leave disabled.

Task 2: Create a workflow with custom approvers

Create a new workflow called Basic Entitlement Grant Custom Approvers.

An example of an entitlement grant workflow using custom approvers.
  • 1 Use a Script node to perform a context check for the request.

    Click to display the Request Context Check script
    var content = execution.getVariables();
    var requestId = content.get('id');
    var context = null;
    var skipApproval = false;
    var lineItemId = false;
    try {
      var requestObj = openidm.action('iga/governance/requests/' + requestId, 'GET', {}, {});
      if (requestObj.request.common.context) {
        context = requestObj.request.common.context.type;
        lineItemId = requestObj.request.common.context.lineItemId;
        if (context == 'admin') {
          skipApproval = true;
        }
      }
    }
    catch (e) {
      logger.info("Request Context Check failed "+e.message);
    }
    
    logger.info("Context: " + context);
    execution.setVariable("context", context);
    execution.setVariable("lineItemId", lineItemId);
    execution.setVariable("skipApproval", skipApproval);
  • 2 Use an IF/ELSE node and name it Context Gateway. If skipApproval==true, route it to the Auto Approval node. If skipApproval==false, route it to the Approval Task node.

  • 3 Use a Script node for the Auto Approval task.

    Click to display the Auto Approval script
    var content = execution.getVariables();
    var requestId = content.get('id');
    var context = content.get('context');
    var lineItemId = content.get('lineItemId');
    var queryParams = {
      "_action": "update"
    }
    var lineItemParams = {
      "_action": "updateRemediationStatus"
    }
    try {
      var decision = {
          "decision": "approved",
          "comment": "Request auto-approved due to request context: " + context
      }
      openidm.action('iga/governance/requests/' + requestId, 'POST', decision, queryParams);
    }
    catch (e) {
      var failureReason = "Failure updating decision on request. Error message: " + e.message;
      var update = {'comment': failureReason, 'failure': true};
      openidm.action('iga/governance/requests/' + requestId, 'POST', update, queryParams);
    
    }
  • 4 Use a Script node to create an approval task with custom approvers.

    Click to display the Approval Task properties with custom approvers script
    (function() {
        var content = execution.getVariables();
        var requestId = content.get('id');
        var entitlementId = null;
        var users = [];
    
        try {
          var requestObj = openidm.action('iga/governance/requests/' + requestId, 'GET', {}, {});
          entitlementId = requestObj.request.common.entitlementId;
        }
        catch (e) {
          failureReason = "Validation failed: Error reading request with id " + requestId;
        }
        try{
          var glossary = openidm.action('iga/governance/resource/' + entitlementId +'/glossary', 'GET', {}, {})
          let approvers = glossary.approvers
          for(var i = 0; i < approvers.length; i++){
            var userId = approvers[i];
            users.push({
              "id": userId, "permissions": {"approve": true, "reject": true, "reassign": true, "modify": true, "comment": true}
            })
    
          }
    
        }
        catch (e){
          failureReason = "Validation failed: Error reading request with id " + requestId;
        }
    
        if(users.length > 0){
          return users;
        }
        else {
          // default approver logic
        }
    })()
  • 5 Use the Script node to validate the entitlement grant.

    Click to display the Entitlement Grant Validation script
    logger.info("Running entitlement grant request validation");
    
    var content = execution.getVariables();
    var requestId = content.get('id');
    var failureReason = null;
    var applicationId = null;
    var assignmentId = null;
    var app = null;
    var assignment = null;
    var existingAccount = false;
    
    try {
      var requestObj = openidm.action('iga/governance/requests/' + requestId, 'GET', {}, {});
      applicationId = requestObj.application.id;
      assignmentId = requestObj.assignment.id;
    }
    catch (e) {
      failureReason = "Validation failed: Error reading request with id " + requestId;
    }
    
    // Validation 1 - Check application exists
    if (!failureReason) {
      try {
        app = openidm.read('managed/alpha_application/' + applicationId);
        if (!app) {
          failureReason = "Validation failed: Cannot find application with id " + applicationId;
        }
      }
      catch (e) {
        failureReason = "Validation failed: Error reading application with id " + applicationId + ". Error message: " + e.message;
      }
    }
    
    // Validation 2 - Check entitlement exists
    if (!failureReason) {
      try {
        assignment = openidm.read('managed/alpha_assignment/' + assignmentId);
        if (!assignment) {
          failureReason = "Validation failed: Cannot find assignment with id " + assignmentId;
        }
      }
      catch (e) {
        failureReason = "Validation failed: Error reading assignment with id " + assignmentId + ". Error message: " + e.message;
      }
    }
    
    // Validation 3 - Check the user has application granted
    if (!failureReason) {
      try {
        var user = openidm.read('managed/alpha_user/' + requestObj.user.id, null, [ 'effectiveApplications' ]);
        user.effectiveApplications.forEach(effectiveApp => {
          if (effectiveApp._id === applicationId) {
            existingAccount = true;
          }
        })
      }
      catch (e) {
        failureReason = "Validation failed: Unable to check existing applications of user with id " + requestObj.user.id + ". Error message: " + e.message;
      }
    }
    
    // Validation 4 - If account does not exist, provision it
    if (!failureReason) {
      if (!existingAccount) {
        try {
          var request = requestObj.request;
          var payload = {
            "applicationId": applicationId,
            "startDate": request.common.startDate,
            "endDate": request.common.endDate,
            "auditContext": {},
            "grantType": "request"
          };
          var queryParams = {
            "_action": "add"
          }
    
          logger.info("Creating account: " + payload);
          var result = openidm.action('iga/governance/user/' + request.common.userId + '/applications' , 'POST', payload,queryParams);
        }
        catch (e) {
          failureReason = "Validation failed: Error provisioning new account to user " + request.common.userId + " for application " + applicationId + ". Error message: " + e.message;
        }
      }
    }
    
    if (failureReason) {
      logger.info("Validation failed: " + failureReason);
    }
    execution.setVariable("failureReason", failureReason);
  • 6 Use the Script node to reject the request.

    Click to display the Reject Request script
    logger.info("Rejecting request");
    
    var content = execution.getVariables();
    var requestId = content.get('id');
    
    logger.info("Execution Content: " + content);
    var requestIndex = openidm.action('iga/governance/requests/' + requestId, 'GET', {}, {});
    var decision = {'outcome': 'denied', 'status': 'complete', 'decision': 'rejected'};
    var queryParams = { '_action': 'update'};
    openidm.action('iga/governance/requests/' + requestId, 'POST', decision, queryParams);
  • 7 Use an IF/ELSE node and name it Validation Gateway. If validationFlowSuccess==true, route it to the Auto Provisioning node. If validationFlowFailure==false, route it to the Entitlement Grant Validation Failure node.

  • 8 Use the Script node to run auto provisioning.

    Click to display the Auto Provisioning script
    logger.info("Auto-Provisioning");
    
    var content = execution.getVariables();
    var requestId = content.get('id');
    var failureReason = null;
    
    try {
      var requestObj = openidm.action('iga/governance/requests/' + requestId, 'GET', {}, {});
      logger.info("requestObj: " + requestObj);
    }
    catch (e) {
      failureReason = "Provisioning failed: Error reading request with id " + requestId;
    }
    
    if(!failureReason) {
      try {
        var request = requestObj.request;
        var payload = {
          "entitlementId": request.common.entitlementId,
          "startDate": request.common.startDate,
          "endDate": request.common.endDate,
          "auditContext": {},
          "grantType": "request"
        };
        var queryParams = {
          "_action": "add"
        }
    
        var result = openidm.action('iga/governance/user/' + request.common.userId + '/entitlements' , 'POST', payload,queryParams);
      }
      catch (e) {
        failureReason = "Provisioning failed: Error provisioning entitlement to user " + request.common.userId + " for entitlement " + request.common.entitlementId + ". Error message: " + e.message;
      }
    
      var decision = {'status': 'complete', 'decision': 'approved'};
      if (failureReason) {
        decision.outcome = 'not provisioned';
        decision.comment = failureReason;
        decision.failure = true;
      }
      else {
        decision.outcome = 'provisioned';
      }
    
      var queryParams = { '_action': 'update'};
      openidm.action('iga/governance/requests/' + requestId, 'POST', decision, queryParams);
      logger.info("Request " + requestId + " completed.");
    }
  • 9 Use the Script node to process an entitlement grant validation failure.

    Click to display the entitlement grant validation failure
    var content = execution.getVariables();
    var requestId = content.get('id');
    var failureReason = content.get('failureReason');
    
    var decision = {'outcome': 'not provisioned', 'status': 'complete', 'comment': failureReason, 'failure': true, 'decision': 'approved'};
    var queryParams = { '_action': 'update'};
    openidm.action('iga/governance/requests/' + requestId, 'POST', decision, queryParams);

Download the JSON file for this workflow here.

Learn more about importing or exporting workflows in workflow editor canvas.