Access Request Approval - Level 2 approval skipped

Hi,

I wanted to create a 2 level approval access request in which any access request for Active Directory Security group would be assigned a custom approval owner stored inside a custom object at second level after manager approval at first level. I have written this approvalAssignmentRule to satisfy the requirement.

The approvalMode is serial, approvalScheme is manager, owner, approvalSplitPoint is owner

However at the second level of approval is being skipped. I have attached the logs as a txt file due to character limitations

Upon looking at the trace, after manager approval the Approval Step ends. Could someone help?

import sailpoint.object.Workflow;
import sailpoint.object.Workflow.Approval;
import sailpoint.object.ApprovalSet;
import sailpoint.object.Identity;
import sailpoint.object.Application;
import sailpoint.object.ManagedAttribute;
import sailpoint.object.Custom;
import sailpoint.object.ApprovalItem;
import sailpoint.tools.GeneralException;
import sailpoint.object.Attributes;
import sailpoint.api.SailPointContext;
import sailpoint.object.IdentityItem;
import sailpoint.api.SailPointFactory;
import sailpoint.tools.xml.XMLObjectFactory;
import sailpoint.api.ObjectUtil;
import sailpoint.tools.Util;

public String getADSecurityGroupOwner(String adSecGroup) {
    // Query the custom object by name "ADSecurityGroupsOwners"
	String returnValue = null;
    try {
		Custom customObject = context.getObjectByName(Custom.class, "ADSecurityGroupsOwners");
    
		// Fetch the owner name based on the AD security group name from the custom object
		if (customObject != null) {
		  System.out.println("Initializing ADSecurityGroupsOwners");
			Attributes customAttributes = customObject.getAttributes(); //null checks for custom attribues
			String owner = (String) customAttributes.get(adSecGroup);
			System.out.println("******************Custom Owner= " + owner);
			if (owner != null) {
				returnValue = owner;
			}
		}
	}
	catch (Exception e){
	System.out.println("Exception Occured: " + e.getMessage());
	e.printStackTrace();
	}
	return returnValue;
}

// Helper method to fetch the value from the custom object "ADSecurityGroupsOwners"
public String getADSecurityGroupId(String adGroupName) {
    // Query the custom object by name "ADSecurityGroupsOwners"
    String returnValue=null;
	try {
	Custom customObjectId = context.getObjectByName(Custom.class, "ADSecurityGroupID");
    // Fetch the owner name based on the AD security group name from the custom object
    if (customObjectId != null) { 
      System.out.println("Initializing ADSecurityGroupID");
        Attributes customAttributesId = customObjectId.getAttributes();
        String adGID = (String) customAttributesId.get(adGroupName);
		System.out.println("******************adGID= " + adGID);
        if (adGID != null) {
            returnValue = adGID;
        }
    }
    } catch (Exception e){
	System.out.println("Exception Occured: " + e.getMessage());
	e.printStackTrace();
	}
	return returnValue;
}


try {
	Approval newApproval = new Approval();
	List newApprovalList = new ArrayList();
	ApprovalSet newSet1=new ApprovalSet();
	ApprovalSet newSet2=new ApprovalSet();
	newSet1=approvalSet.clone();
	System.out.println("******************newSet1= " + newSet1.toXml());
	// Validating approvalSet
    if (newSet1!= null) {
        // Fetch Approval Items from approvalSet
        List<ApprovalItem> aItems = newSet1.getItems();
			
        if (aItems != null){
            // Iterating through ApprovalItems from approvalSet
            for (ApprovalItem aItem : aItems) {
                System.out.println("******************aItem = " + aItem.toXml());
                if (aItem != null) {
                    // Fetch the application name of the ApprovalItem
                    String app1 = aItem.getApplicationName();
                    Application app = context.getObjectByName(Application.class, app1);
                    System.out.println("******************Application Name = " + app);
                    // if the application name is equal to AD perform the block
                    if (app1 != null && app1.equalsIgnoreCase("AD")) {
                        String adGroupName = aItem.getDisplayValue();
						adGroupName=adGroupName.replace("\\","\\\\");
                        //System.out.println("******************ADGroup = " + adGroup1 + value);
						String adGroupID = getADSecurityGroupId(adGroupName);
						System.out.println("******************Printing GroupID = " + adGroupID);
                        ManagedAttribute adGroup = context.getObjectById(ManagedAttribute.class, adGroupID);
                        System.out.println("******************ADGroup = " + adGroup);
                        if (adGroup != null) {
							String groupType = adGroup.getAttribute("GroupType");
                            System.out.println("******************ADGroup Type = " + groupType);
                            if (groupType != null) {
								if (groupType.toLowerCase().contains("security")) {
									String adSecGroup = adGroup.getDisplayName();
									adSecGroup=adSecGroup.replace("\\","\\\\");
									System.out.println("******************AD Group Display Name = " + adSecGroup);
									String ownerName = getADSecurityGroupOwner(adSecGroup);
									System.out.println("******************AD Group Custom Owner Name = " + ownerName);
                                    if (ownerName != null){
										System.out.println("******************ApprovalItem = " + aItem);
										aItem.setOwner(ownerName);
										System.out.println("******************ApprovalItemOwner = " + aItem.getOwner());
                                        //removedapprovalset.add
										newSet2.add(XMLObjectFactory.getInstance().clone(aItem, context));
									} else {
                                        System.out.println("****************** Custom object Owner*************** Custom object owner could not be resolved");
                                    }
                                } else {
                                        aItem.setOwner(adGroup.getOwner());
										newSet2.add(XMLObjectFactory.getInstance().clone(aItem, context));
                                        //removedapprovalset.add
                                }
                            }
                        }
                    } else if (app1 != null && app1.equalsIgnoreCase("healthds")){
                        aItem.setOwner(app.getOwner());
						newSet2.add(XMLObjectFactory.getInstance().clone(aItem, context));
                    } else {
                        String aItemOwner = aItem.getOwner();
                        if (aItemOwner != null){
                            aItem.setOwner(aItemOwner);
							newSet2.add(XMLObjectFactory.getInstance().clone(aItem, context));
                        } else {
                            aItem.setOwner(app.getOwner());
							newSet2.add(XMLObjectFactory.getInstance().clone(aItem, context));
                        }
                    }
                }
            }
			
		}
		newApproval.setApprovalSet(newSet2);
		System.out.println("****************** ApprovalSet NewSet2*************** " + newSet2.toXml());
		System.out.println("****************** Approval*************** " + newApproval.toXml());
		newApprovalList.add(newApproval);
		System.out.println("****************** New Approval List*************** " + newApprovalList.size());
		System.out.println("****************** New Approval List*************** " + newApprovalList);
return newApprovalList;

    }
} catch (GeneralException e) {
    // Handle the GeneralException (or any other exception) here
    System.out.println("Error: " + e.getMessage());
	e.printStackTrace();
}


Logs Attached as txt file here
Heimdall LCM Provisioning Trace.txt (247.2 KB)

Hi @sreeram

In your rule, you are creating new approvalSet object, but it is not being included in approvals object. This object is a input argument in the rule

<Argument type="approvals">
        <Description>
List of approvals generated by the approvalScheme, maybe null if there were no
          approvals enabled.
       </Description>
</Argument>

You should include newApprovalList into approvals object to set the new approval item

<Returns>
    <Argument type="approvals">
        <Description>
Return a lIst of Workflow.Approval objects that should be included during the approval process.
        </Description>
     </Argument>
</Returns>

For this case, return the approvals object in the following way


if (newApprovalList!= null && !newApprovalList.isEmpty()) {
    approvals.addAll(newApprovalList);
}

return approvals;

1 Like

Hi @ismaelmoreno1,

Thanks for the response.

I have amended the rule to include these changes you suggested, and the issue persists. Its skips the L2 approval as soon as the manager level approval is granted. Upon looking at the trace (Added here in the reply), the workitem state value turns “Finished” as soon as the manager approval is granted. The rule successfully updates the owner however the workitem state being set to “Finished” may be the reason the L2 approval is being skipped.

Another observation I could draw from the trace is that, after the approvalSplitpoint the approval is supposed to be split and processed in parallel, parallelpoll mode however here the approval continues in serial mode.

Is there any way to reset the workitem state flag? I have cross checked the flags

  1. setPreviousApprovalDecisions is set to “false”
  2. clearApprovalDecisions is set to “true”
Starting step Start
Ending step Start
Starting step Approval
******************newSet1= <?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE ApprovalSet PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<ApprovalSet>
  <ApprovalItem application="AD" assignmentId="afad8b6e7be549649a5fd1a95fca3202" displayValue="DEMO\Account Operators" id="86097baab01a48e1bee98a3559cf1b13" name="memberOf" nativeIdentity="CN=Amanda.Ross,OU=SailPointIIQ,DC=DEMO,DC=COM" operation="Add" owner="Walter.Henderson" state="Finished" value="CN=Account Operators,CN=Builtin,DC=DEMO,DC=COM">
    <Attributes>
      <Map>
        <entry key="attachmentConfigList"/>
        <entry key="attachments"/>
        <entry key="flow" value="AccessRequest"/>
        <entry key="id" value="0a00020f886e11a081886ff4557f0060"/>
        <entry key="interface" value="LCM"/>
        <entry key="operation" value="EntitlementAdd"/>
      </Map>
    </Attributes>
  </ApprovalItem>
</ApprovalSet>

******************aItem = <?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE ApprovalItem PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<ApprovalItem application="AD" assignmentId="afad8b6e7be549649a5fd1a95fca3202" displayValue="DEMO\Account Operators" id="86097baab01a48e1bee98a3559cf1b13" name="memberOf" nativeIdentity="CN=Amanda.Ross,OU=SailPointIIQ,DC=DEMO,DC=COM" operation="Add" owner="Walter.Henderson" state="Finished" value="CN=Account Operators,CN=Builtin,DC=DEMO,DC=COM">
  <Attributes>
    <Map>
      <entry key="attachmentConfigList"/>
      <entry key="attachments"/>
      <entry key="flow" value="AccessRequest"/>
      <entry key="id" value="0a00020f886e11a081886ff4557f0060"/>
      <entry key="interface" value="LCM"/>
      <entry key="operation" value="EntitlementAdd"/>
    </Map>
  </Attributes>
</ApprovalItem>

******************Application Name = sailpoint.object.Application@70b723ce[id=0a00020f886c163e81886df1297909e8,name=AD]
Initializing ADSecurityGroupID
******************adGID= 0a00020f886e11a081886ff4557f0060
******************Printing GroupID = 0a00020f886e11a081886ff4557f0060
******************ADGroup = group/memberOf/CN=Account Operators,CN=Builtin,DC=DEMO,DC=COM
******************ADGroup Type = Security
******************AD Group Display Name = DEMO\\Account Operators
Initializing ADSecurityGroupsOwners
******************Custom Owner= Carl.Foster
******************AD Group Custom Owner Name = Carl.Foster
******************ApprovalItem = sailpoint.object.ApprovalItem@70f52e49
******************ApprovalItemOwner = Carl.Foster
****************** ApprovalSet NewSet2*************** <?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE ApprovalSet PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<ApprovalSet>
  <ApprovalItem application="AD" assignmentId="afad8b6e7be549649a5fd1a95fca3202" displayValue="DEMO\Account Operators" id="86097baab01a48e1bee98a3559cf1b13" name="memberOf" nativeIdentity="CN=Amanda.Ross,OU=SailPointIIQ,DC=DEMO,DC=COM" operation="Add" owner="Carl.Foster" state="Finished" value="CN=Account Operators,CN=Builtin,DC=DEMO,DC=COM">
    <Attributes>
      <Map>
        <entry key="attachmentConfigList"/>
        <entry key="attachments"/>
        <entry key="flow" value="AccessRequest"/>
        <entry key="id" value="0a00020f886e11a081886ff4557f0060"/>
        <entry key="interface" value="LCM"/>
        <entry key="operation" value="EntitlementAdd"/>
      </Map>
    </Attributes>
  </ApprovalItem>
</ApprovalSet>

****************** Approval*************** <?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Approval PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Approval>
  <ApprovalSet>
    <ApprovalItem application="AD" assignmentId="afad8b6e7be549649a5fd1a95fca3202" displayValue="DEMO\Account Operators" id="86097baab01a48e1bee98a3559cf1b13" name="memberOf" nativeIdentity="CN=Amanda.Ross,OU=SailPointIIQ,DC=DEMO,DC=COM" 
operation="Add" owner="Carl.Foster" state="Finished" value="CN=Account Operators,CN=Builtin,DC=DEMO,DC=COM">
      <Attributes>
        <Map>
          <entry key="attachmentConfigList"/>
          <entry key="attachments"/>
          <entry key="flow" value="AccessRequest"/>
          <entry key="id" value="0a00020f886e11a081886ff4557f0060"/>
          <entry key="interface" value="LCM"/>
          <entry key="operation" value="EntitlementAdd"/>
        </Map>
      </Attributes>
    </ApprovalItem>
  </ApprovalSet>
</Approval>

****************** New Approval List*************** 1
****************** New Approval List*************** [sailpoint.object.Workflow$Approval@4cd30d50]
Starting approval group in mode serial
Starting approval group in mode serial
Ending approval group in mode serial
Ending approval group in mode serial
Ending approval group in mode serial
Ending step Approval
Starting step Process Approval Decisions

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.