Need to bypass spadmin approval as fallback approver for owner approval if entitlement owner is not present

Which IIQ version are you inquiring about?

8.4

Share all details about your problem, including any error messages you may have received.

I am using LCM provisioning for access request and i have manager,owner and security officer as approval scheme and approvalsplit point as owner but if the owner is not present it is sending the approval to spadmin and what i want is if owner is not present it just skips the owner approval and send directly to security officer or auto approve the owner approval if it is pending with spadmin.

@Sammy271200 You need to introduce an assignment rule to handle this where you review the owner status and accordingly return the owner. Please let us know if you need any help with it.

You can write an approval assignment rule, and attach that rule to your lcm workflow, You can get the current approver in the rule, and check, if the current approver exist or active, if it is active send the approver to current approver else send it to security office or auto approver/finish it.

Yes, as others have mentioned, this can be handled using an Approval Assignment Rule.

In the rule, you can validate whether the entitlement owner exists and is active. If the owner is available, return the owner as the approver. If the owner is missing or inactive, you can either:

  • Route the approval directly to the next approver (for example, the Security Officer), or
  • Auto-approve that approval step, depending on your organization’s approval policy.

This approach avoids the default fallback to spadmin and gives you full control over the approval routing. Please give it a try and let us know.

Hi All,

I am using the below approval assignment rule, can you please me with the changes to bypass the owner approval if owner is not present and where i have to add this rule in LCM workflow.

<?xml version='1.0' encoding='UTF-8'?> Injects Entitlement Owner approval between Manager and Security Officer for privileged entitlements only. import sailpoint.object.*; import sailpoint.object.Workflow.Approval; import java.util.*; import org.apache.log4j.Logger;
Logger ruleLog = Logger.getLogger("rule.ElevatedEntitlementOwnerApproval");
ruleLog.info("Entering Elevated Entitlement Owner Approval Rule");

List newApprovals = new ArrayList();
if (approvals != null) {
    newApprovals.addAll(approvals);
}

if (approvalSet != null) {

    Map ownerToItems = new HashMap();

    for (ApprovalItem item : approvalSet.getItems()) {

        String appName = item.getApplication();
        String attrName = item.getName();
        Object attrValue = item.getValue();

        if (appName == null || attrName == null || attrValue == null) {
            continue;
        }

        String entValue = (attrValue instanceof List)
            ? (String) ((List) attrValue).get(0)
            : (String) attrValue;

        Application app = context.getObjectByName(Application.class, appName);
        if (app == null) {
            ruleLog.warn("Could not resolve Application: " + appName);
            continue;
        }

        ManagedAttribute ma = ManagedAttributer.get(context, app, false, attrName, entValue, null);

        if (ma != null && ma.isPrivileged()) {

            Identity owner = ma.getOwner();

            if (owner == null) {
                ruleLog.warn("Privileged entitlement has no owner, skipping owner step: " + attrName);
                continue;
            }

            String ownerKey = owner.getName();

            List itemList = (List) ownerToItems.get(ownerKey);
            if (itemList == null) {
                itemList = new ArrayList();
                ownerToItems.put(ownerKey, itemList);
            }
            itemList.add(item);
        }

        context.decache(app);
    }

    List ownerApprovals = new ArrayList();
    Iterator it = ownerToItems.keySet().iterator();
    while (it.hasNext()) {
        String ownerName = (String) it.next();
        List items = (List) ownerToItems.get(ownerName);

        ApprovalSet ownerSet = new ApprovalSet();
        for (Object o : items) {
            ownerSet.add((ApprovalItem) o);
        }

        Approval ownerApproval = new Approval();
        ownerApproval.setOwner(ownerName);
        ownerApproval.setName("Entitlement Owner Approval");
        ownerApproval.setDescription("Entitlement Owner Approval - Elevated Access");
        ownerApproval.setApprovalSet(ownerSet);
        ownerApproval.addArg("workItemTargetClass", "sailpoint.object.Identity");
        ownerApproval.addArg("workItemTargetName", ownerName);

        ownerApprovals.add(ownerApproval);

        ruleLog.info("Injected Entitlement Owner approval for: " + ownerName);
    }

    if (!ownerApprovals.isEmpty() && newApprovals.size() >= 2) {
        newApprovals.addAll(1, ownerApprovals);
    } else if (!ownerApprovals.isEmpty()) {
        ruleLog.warn("Expected at least 2 base approvals, found " + newApprovals.size() + ". Appending instead.");
        newApprovals.addAll(ownerApprovals);
    }
} else {
    ruleLog.info("approvalSet was null.");
}

ruleLog.info("Exiting rule. Final approval count: " + newApprovals.size());
return newApprovals;

Hello Samarth Sharma,

Can you check below?
But you need to handle if the security owner is inactive or null
```
Identity owner = ma.getOwner();

if (owner == null) {
continue;
}

String ownerKey = owner.getName();

List itemList = (List) ownerToItems.get(ownerKey);
if (itemList == null) {
itemList = new ArrayList();
ownerToItems.put(ownerKey, itemList);
}
itemList.add(item);

===============Replace above with below======

Identity owner = ma.getOwner();

/\*
 \* If the entitlement owner exists and is active,
 \* route to the owner.
 \* Otherwise route to Security Officer.
 \*/
String ownerKey = null;

if (owner != null && !owner.isInactive()) {
	ownerKey = owner.getName();
} else {
	ownerKey = "SecurityOfficer";   // Fallback approver
}

List itemList = (List) ownerToItems.get(ownerKey);

if (itemList == null) {
	itemList = new ArrayList();
	ownerToItems.put(ownerKey, itemList);
}

itemList.add(item);

Dear @harishabn ,

We have security officer as a workgroup and there will be everytime users that will be active only

Can you use below and see?

Logger ruleLog = Logger.getLogger("rule.ElevatedEntitlementOwnerApproval");ruleLog.info("Entering Elevated Entitlement Owner Approval Rule");

List newApprovals = new ArrayList();
if (approvals != null) {
newApprovals.addAll(approvals);
}

if (approvalSet != null) {
Map ownerToItems = new HashMap();

for (ApprovalItem item : approvalSet.getItems()) {

    String appName = item.getApplication();
    String attrName = item.getName();
    Object attrValue = item.getValue();

    if (appName == null || attrName == null || attrValue == null) {
        continue;
    }

    String entValue = (attrValue instanceof List)
        ? (String) ((List) attrValue).get(0)
        : (String) attrValue;

    Application app = context.getObjectByName(Application.class, appName);
    if (app == null) {
        ruleLog.warn("Could not resolve Application: " + appName);
        continue;
    }

    ManagedAttribute ma = ManagedAttributer.get(context, app, false, attrName, entValue, null);

	if (ma != null && ma.isPrivileged()) {

		Identity owner = ma.getOwner();

		String ownerKey;

		if (owner != null && !owner.isInactive()) {
			ownerKey = owner.getName();
		} else {
			//Place your workgroup below
			ownerKey = "SecurityOfficer";

			ruleLog.warn(
				"Privileged entitlement [" + entValue +
				"] has no active owner. Routing to [" +
				ownerKey + "]."
			);
		}

		List itemList = (List) ownerToItems.get(ownerKey);

		if (itemList == null) {
			itemList = new ArrayList();
			ownerToItems.put(ownerKey, itemList);
		}

		itemList.add(item);
	}

    context.decache(app);
}

List ownerApprovals = new ArrayList();
Iterator it = ownerToItems.keySet().iterator();
while (it.hasNext()) {
    String ownerName = (String) it.next();
    List items = (List) ownerToItems.get(ownerName);

    ApprovalSet ownerSet = new ApprovalSet();
    for (Object o : items) {
        ownerSet.add((ApprovalItem) o);
    }

    Approval ownerApproval = new Approval();
    ownerApproval.setOwner(ownerName);
    ownerApproval.setName("Entitlement Owner Approval");
    ownerApproval.setDescription("Entitlement Owner Approval - Elevated Access");
    ownerApproval.setApprovalSet(ownerSet);
    ownerApproval.addArg("workItemTargetClass", "sailpoint.object.Identity");
    ownerApproval.addArg("workItemTargetName", ownerName);

    ownerApprovals.add(ownerApproval);

    ruleLog.info("Injected Entitlement Owner approval for: " + ownerName);
}

if (!ownerApprovals.isEmpty() && newApprovals.size() >= 2) {
    newApprovals.addAll(1, ownerApprovals);
} else if (!ownerApprovals.isEmpty()) {
    ruleLog.warn("Expected at least 2 base approvals, found " + newApprovals.size() + ". Appending instead.");
    newApprovals.addAll(ownerApprovals);
}

} else {
ruleLog.info("approvalSet was null.");
}

ruleLog.info("Exiting rule. Final approval count: " + newApprovals.size());
return newApprovals;

@harishabn overall it looks good but it seems it may throw lazily initialisation exception when you have multiple items. Have you tested this with different combinations? If yes, then that’s great and this should work for the use case and @Sammy271200 should try it.