PingOne Advanced Identity Cloud

Violation workflow

In this example, an administrator creates a workflow that:

  • Processes a single violation task.

  • If the violation outcome is Remediate, it remediates the violation, validates the result, and removes the entitlements.

  • If the violation outcome is Allow, it creates an exception.

  • If the violation outcome is expiration, it goes to a manual decision via the Fulfillment node.

  • If the end user tasked with the manual fulfillment approves of the various outcomes, the workflow is complete.

  • If the end user tasked with the manual fulfillment denies the resulting outcomes, the workflow calls a reject requests script, and loops back for another manual confirmation.

Assumptions

  • Each violation has an owner.

  • Make sure to catch any error/failure conditions.

Example

An example of a violation handling workflow.
  • 1 The Violation node routes the violation to the appropriate outcome. Options are: Remediate, Allow, and Expiration.

  • 2 The Remediate Violation Script node gets the context information for the violation and sets the remediationResponse.

    Click to display Remediate Violation script
    logger.info("Remediating violation");
    
    var content = execution.getVariables();
    var violationId = content.get('id');
    var remediation = content.get('remediation');
    logger.info("Remediating violation - violationId: " + violationId + ', remediation payload: ' + remediation);
    
    var remediationContent = null;
    
    var remediationResponse = openidm.action('iga/governance/violation/' + violationId + '/remediate', 'POST', remediation);
    logger.info("Remediating response: " + remediationResponse);
    
    remediationContent = remediationResponse.decision.remediation;
    execution.setVariable("remediation", remediationContent);
  • 3 The Remediate Violation IF/ELSE node routes successful validations to an auto remove script node and validation failures to a failure handling node.

  • 4 The Remove Grants Auto script node removes the entitlement grants that caused the violation.

    Click to display Auto Remove Entitlement Grants script
    logger.info("Removing grants automatically");
    
    var content = execution.getVariables();
    var violationId = content.get('id');
    var failureReason = null;
    var phaseName = content.get('phaseName');
    var violationObj;
    
    logger.info("Removing entitlement grants for violation " + violationId + " with phase name " + phaseName);
    
    try {
      violationObj = openidm.action('iga/governance/violation/lookup/' + violationId, 'GET', {}, {});
    }
    catch (e) {
      failureReason = "Removing entitlement grants failed: Error reading violation with id " + violationId + ". Error message: " + e.message;
    }
    
    if (!failureReason) {
      var remediation = violationObj.decision.remediation;
      var failedDeprovisioning = false;
      var deprovisionedIds = [];
      for(var grant of violationObj.violatingAccess) {
        if (!remediation.grantIds.includes(grant.compositeId)) {
          continue;
        }
    
        var userId = violationObj.user.id;
        logger.info("Removing entitlement grant: " + grant.compositeId + ", user: " + userId + ", violation: " + violationId);
    
        try {
          var payload = {
            entitlementId: grant.assignment.id
          };
          logger.info('Payload to remove grant: ' + JSON.stringify(payload));
    
          var queryParams = {
            "_action": "remove"
          }
    
          var result = openidm.action('iga/governance/user/' + userId + '/entitlements', 'POST', payload,queryParams);
          execution.setVariables(result);
    
          logger.info("Deprovisioned " + grant.assignment.id + " successfully, user " + userId + + ", violation: " + violationId);
          deprovisionedIds.push(grant.compositeId);
        }
        catch (e) {
          failureReason = failureReason + ". Removing grants failed: Error deprovisioning entitlement" + grant.assignment.id + " from user. Error message: " + e.message + ".";
          failedDeprovisioning = true;
        }
      }
    
      if (!failedDeprovisioning) {
        openidm.action('iga/governance/violation/' + violationId + '/remediation/status/complete', 'POST', {});
      } else {
        failureReason = failureReason + ". Grants removed: " + deprovisionedIds;
      }
    }
    
    if (failureReason) {
      var update = { 'comment': failureReason };
      openidm.action('iga/governance/violation/' + violationId + '/comment', 'POST', update, {});
    }
  • 5 The Allow Violation script node logs the information. If a failure arises, Identity Governance posts the failure with the reason.

    Click to display Allow Violation script node
    logger.info("Allowing violation");
    var content = execution.getVariables();
    var violationId = content.get('id');
    var phaseName = content.get('phaseName');
    logger.info("Violation to be allowed: " + violationId + " with phase name " + phaseName);
    
    var failureReason = null;
    try {
        var allowResponse = openidm.action('iga/governance/violation/' + violationId + '/allow', 'POST', {});
    logger.info("Violation " + violationId + " was allowed successfully.");} catch (e) {
        failureReason = "Failed allowing violation with id " + violationId + ". Error message: " + e.message;
    }
    
    if (failureReason) {
        var update = { "comment": failureReason };
        try {
            openidm.action('iga/governance/violation/' + violationId + '/phases/' + phaseName + '/comment', 'POST', update, {});
        } catch (e) {
            openidm.action('iga/governance/violation/' + violationId + '/comment', 'POST', update, {});
        }
    }
  • 6 The Fulfillment node requests a manual completion of the task by an authorized end user, typically during review time. If successful, the task is fulfilled, and the workflow is complete.

  • 7 The Reject Request script node retrieves the requestID, logs the rejection, and sends a reject request.

    Click to display 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);

Download the JSON file for this workflow here.

Learn more about how to import or export workflows in workflow editor canvas.