Multi-level approval for access request

Which IIQ version are you inquiring about?

[8.3]

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

Hi community, I am new to development for multi-level approval for access request. May I know if there is any best practice to initiate this.
For example : based on a role attribute when can have :

  • case 1 : having 1 level of approval
  • case 2 : having 2 levels of approval
  • case 3 : having 3 levels of approvals

as all aprovals are specific workgroups

NB : I tried it with nested approvals in the Approve step of the workflow (Approve and provision subprocess ) the approvals and sent but nothing is provisionned despite all approvals being approved

Thank you.

Hi @alshahim04 ,

You can use “Approval Assignment rule” in Approve step of the workflow (Approve and provision subprocess) to set the approvals based on the specific roles requested by user.

Hello @Harikrishna_06 ,
Thank you for your answer , is there any example code for assignement rule that demonstrates how to do it ?

Best regards

Hi @alshahim04 ,

Below is the example for Approval Assignment Rule

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule created="1749531601821" id="c0a8386e974411c481975835ab9d07b3" language="beanshell" modified="1750158611705" name="Approval_Assignement_Rule_Example" significantModified="1749556633413" type="ApprovalAssignment">
  <Description>
    This example rule switches all of the owners to spadmin.  The idea 
    of this rule is to allow some customization of the approvals 
    so the ownership can be cacluated for cases where you might
    use and exteneded attribute or some other means outside our
    default mechanisms to derive the owner of the Approval.

    This rule is typically configured on the Approval Step
    in the LCM Provisioning Workflow or can be set on any
    steps based on the "Provisioning Approval" step 
    library.

    Since 6.2
  </Description>
  <Signature>
    <Inputs>
      <Argument name="log">
        <Description>
          The log object associated with the SailPointContext.
        </Description>
      </Argument>
      <Argument name="context">
        <Description>
          A sailpoint.api.SailPointContext object that can be used to query the database if necessary.
        </Description>
      </Argument>
      <Argument name="approvals">
        <Description>
          List of approvals generated by the approvalScheme, maybe null if there were no
          approvals enabled.
        </Description>
      </Argument>
      <Argument name="approvalSet">
        <Description>
          Representation of the cart, also found on the approvals generated by the 
          default schemes.
        </Description>
      </Argument>
    </Inputs>
    <Returns>
      <Argument name="newApprovals">
        <Description>

        </Description>
      </Argument>
    </Returns>
  </Signature>
  <Source>

  import org.apache.log4j.Logger;
 import sailpoint.object.Workflow.Approval;
 import sailpoint.object.ApprovalSet;
 import sailpoint.object.ApprovalItem;
 import java.util.List;
 import java.util.ArrayList;
 import sailpoint.object.Custom;
 import sailpoint.object.Identity;

 Logger logger = Logger.getLogger("mylog.log");
 logger.info("Entering the Rule Custom_ApprovalSet_For_New_Owner_Rule");

 Identity vpIdentity = context.getObjectByName(Identity.class, "Name of the identity");
 String vpIdentityName = vpIdentity.getName();
 logger.info("The VP Identity name is: " + vpIdentityName);

 Custom custom = context.getObject(Custom.class, "FinanceGroups");
 List financeADGroups = (custom != null) ? custom.getList("FinanceGroupsList") : null;

 logger.info("The finance AD groups are: " + financeADGroups);
 logger.info("The Approvals are: " + approvals.toString());

 for (Approval approval : approvals) {
 logger.info("Approval in list: " + approval.toString());
 }

 logger.info("The Approval Set is: " + approvalSet.toString());

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

 // Flag to track if at least one finance group is found
 boolean financeGroupFound = false;

 if (approvalSet != null) {
 for (ApprovalItem item : approvalSet.getItems()) {
 logger.info("The ApprovalItems are: " + item.toString());

 if (item.getValue() != null &amp;&amp; !item.getValue().isEmpty()) {
 String groupName = item.getValue().get(0);
 logger.info("The GroupName is: " + groupName);

 if (financeADGroups != null &amp;&amp; financeADGroups.contains(groupName)) {
 logger.info("The logic is inside Finance Block");
 financeGroupFound = true;
 } else {
 logger.info("The Group value is not a Finance Group");
 }
 } else {
 logger.info("The GroupName list is empty or null.");
 }
 }
 } else {
 logger.info("The ApprovalSet is null.");
 }

 // If at least one finance group was found, update the owner once
 if (financeGroupFound) {
 logger.info("At least one finance group found, setting owner...");
 Approval additionalApproval = new Approval();
 additionalApproval.setOwner(vpIdentityName);
 additionalApproval.setDescription("");
 newApprovals.add(additionalApproval);
 }

 logger.info("Exiting the Rule Custom_ApprovalSet_For_New_Owner_Rule");

 return newApprovals;

  </Source>
</Rule>


i tried the rule by adding my buisness logique , i referenced it in Approve step of the workflow (Approve and provision subprocess) , but still when assigning access , it get directly assigned , no further approvals are created ,

here is below my rule

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule language="beanshell" name="Approval_Rule_test1"  type="ApprovalAssignment">
  <Description>A rule used by a Workflow to determine a step action or variable value.

Note that an Attributes map of all variables from the current WorkflowContext, merged with the arguments from the Step, is also passed into the workflow rule.</Description>
  <Signature returnType="Object">
    <Inputs>
      <Argument type="log">
        <Description>
The log object associated with the SailPointContext.
</Description>
      </Argument>
      <Argument type="context">
        <Description>
A sailpoint.api.SailPointContext object that can be used to query the database if necessary.
</Description>
      </Argument>
      <Argument type="approvals">
        <Description>
List of approvals generated by the approvalScheme, maybe null if there were no
          approvals enabled.
</Description>
      </Argument>
      <Argument type="approvalSet">
        <Description>
Representation of the cart, also found on the approvals generated by the
          default schemes.
</Description>
      </Argument>
    </Inputs>
    <Returns>
      <Argument name="approvals">
        <Description>
          The result of the workflow rule; dependent on the rule itself.
        </Description>
      </Argument>
    </Returns>
  </Signature>
  <Source>
  import sailpoint.object.Link;
  import sailpoint.object.Bundle;
  import sailpoint.object.Identity;
  import sailpoint.object.ManagedAttribute;
  import sailpoint.object.Workflow.Approval;
  import sailpoint.object.ApprovalSet;
  import sailpoint.object.ApprovalItem;
  import sailpoint.object.Workflow;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.List;

  
          
    Identity identityObj = context.getObjectByName(Identity.class,identityName);
  
  List newApprovals = new ArrayList();
 if (approvals != null) {
 newApprovals.addAll(approvals);

 }
          
    if(approvalSet != null @and !approvalSet.isEmpty())
    {
        for(ApprovalItem item : approvalSet.getItems())
        {


          	String roleName = item.getValueList().get(0);
            Bundle role = context.getObjectByName(Bundle.class, roleName);

            if(role != null)
            {
                String roleType = role.getType();
 				
				String sensitive = role.getAttribute("sensitive");
	
					
				if("yes".equalsIgnoreCase(sensitive)){
     
                Identity mangerIdentity = identityObj.getManager();
                String managerOfManager = mangerIdentity.getManager() != null ? mangerIdentity.getManager().getName() : null;
                if(managerOfManager != null){ 

                  Approval additionalApproval = new Approval();
                  additionalApproval.setOwner(managerOfManager);
                  additionalApproval.setDescription("test approval");
                  newApprovals.add(additionalApproval);

                }
              }
            }

 
                context.decache(role);
            }          
        }
    }
   }


  
return newApprovals;</Source>
</Rule>

Hi @alshahim04 ,

Steps to Troubleshoot:

  1. Add loggers to check whether proper data is getting or not and also use logs to check whether it enters into the if condition or not.

  2. Check the “sensitive” attribute data type and modify according

hi @Harikrishna_06 ,

I followed the troublshout steps , the role attribute works fine and i also logged the final approvals list , i got this : list : [sailpoint.object.Workflow$Approval@667f9caf]

Hi @alshahim04 ,

Can you please share your logs. And also print the newApprovals list.

Hi @Harikrishna_06
This is the new approval List : [sailpoint.object.Workflow$Approval@667f9caf], created when looping on approvalSet,
Soory for other logs i connot provide all logs due to regulation

Hi @alshahim04,

Are you getting new approvers or not?

Hi @Harikrishna_06 ,
No , i’am not getting new approvers , the access request is directly approved

Hi @alshahim04,

Did you find the new approver in the newapprovers list when printing the logs.

Hi @Harikrishna_06 ,
sorry for the delay now it works fine , one of my bundles was buggy ,

I have a second question if possible , on my third level of validation i have to set the owner as an identity and a workgroup [manger + workgroup] as one owner for example, is it possible to define the approval mode as Any for this level of approval

Hi @alshahim04,

I need to check it.

Hi @Harikrishna_06 ,

I found a way , by creating a parrent approval and setting it’s mode “any“, and creating two childs approval one for each workgroups,

it worked this way ,

Thank you for all your valuable help
Regards