Azure AD Leaver Issue

When we trigger Leaver as part of Azure AD Unit Testing, we are getting “Response Code - 403 Error - Insufficient privileges to complete the operation” as error. After checking logs and Provisioning Plan, we found Dynamic Groups present which is not allowing to remove other normal Azure AD Groups and getting failed as part of Access Request.

@krm7 - could you please suggest how can we handle and resolve the issue ?

Hi @manikandaprabhu_absa - you can use a Before Provisioning rule to look for group removals. Check the managed attribute “groupType” attribute to see if it contains “DynamicMembership”, if so then remove it from the plan.

Hi Ryan Toornburg,

We have more than 100 Dynamic Groups present which we cannot handle through Before Provisioning Rule.

@manikandaprabhu_absa - if a user could potentially have a large number of dynamic groups, that would definitely not make sense to try to do that. I believe there was a post awhile back about grouping it into a single query. I will look to see if I can find it unless someone else knows off hand.

I agree for this solution.

  1. Check the ManagedAttribute attribute such as groupType / groupTypes.
  2. If it contains DynamicMembership, remove that AttributeRequest from the plan.
    Before Provisioning Rule | SailPoint Developer Community

Hi @narayanag ,

We don’t have groupType/groupTypes orDynamicMembership in the plan.

@manikandaprabhu_absa pls share provisiongplan out from logs

Groups are going this way. you can modify your rule accordingly

@manikandaprabhu_absa

Please go through below Post. This may help you.

Hi @narayanag,

Azure AD Dynamic Group Issue.xml (1.8 KB)

Please find the logs files as requested

Hi @sukarande

As we have more than 100 dynamic groups in PROD, this will not fix the issue.

Hi @manikandaprabhu_absa

Adding to the investigation, I would recommend enabling debug logging in the Azure AD Before Provisioning Rule and reviewing the complete provisioning plan generated during the Leaver process.

While the current assumption is that Dynamic Groups are causing the failure, it would be useful to verify exactly which operation is triggering the 403 error. We worked on the issue involving Guest B2B account creation, the initial error message indicated an Azure permission problem like 403 error, but detailed provisioning logs revealed that SailPoint was attempting an unsupported operation (setting password-related attributes for Guest users).

Similarly, for this Leaver scenario, the provisioning plan should be reviewed to determine:

  • Which group memberships SailPoint is attempting to remove.
  • Whether any Dynamic Groups are included in the request.
  • Whether the 403 error occurs specifically during the removal of a Dynamic Group or another entitlement operation.
  • Whether any unsupported attributes or operations are being sent as part of the deprovisioning request.

If Dynamic Groups are present in the provisioning plan, Azure AD will reject membership removal requests because Dynamic Group memberships are managed by rules and cannot be modified directly. In that case, logic can be added in the Before Provisioning Rule to identify and exclude Dynamic Groups from deprovisioning operations before the request is sent to Azure.

This approach will help confirm the exact root cause and prevent SailPoint from attempting unsupported operations during the Leaver process.

The overall number of dynamic groups does not really matter. What is important is how many dynamic groups might possibly be removed for your average disable transaction. If it is not a large number then it is not a heavy lift for the Before Rule. In your group schema do you have groupTypes aggregated?

If you are on IIQ versions >= 8.5 or 8.4p3 or 8.3p5, you can use the “Group Membership Filter” Entra ID connector configuration documentation which will make it so that the group membership of dynamic groups wouldn’t be aggregated into the system.

@manikandaprabhu_absa You can also consider having a customization rule to not aggregate the dynamic groups assigned on the users.. In that way, when leaver triggers, it’ll remove all the direct groups and should go through fine.

@manikandaprabhu_absa - You can handle which creating the termination provisioning plan. Check if the group type is a dynamic group, dont add it to the plan. Try the following code:



    Identity identity = context.getObjectByName(Identity.class,identityName);
    String aadAppName = "Azure AD";
    Application aadApp = context.getObject(Application.class, aadAppName);	
    IdentityService is = new IdentityService(context);
    List aadLinks = is.getLinks(identity, aadApp);
    List accountReqList = new ArrayList();
    for(Link link:aadLinks){
      List listOfCubeGroups = new ArrayList();
      ProvisioningPlan.AccountRequest acctReq = new ProvisioningPlan.AccountRequest();
      acctReq.setApplication(aadAppName);
      acctReq.setNativeIdentity(link.getNativeIdentity());
      acctReq.setOperation(ProvisioningPlan.AccountRequest.Operation.Modify);
      if (null != link.getAttribute("groups")){
        if ((link.getAttribute("groups")) instanceof String) {
          listOfCubeGroups.add(link.getAttribute("groups"));
        } else if((link.getAttribute("groups")) instanceof List) {
          List temp = link.getAttribute("groups");
          for (String groupID : temp){
            listOfCubeGroups.add(groupID);
          }
        }
        for (String group: listOfCubeGroups){
          QueryOptions qoGroup = new QueryOptions();
          qoGroup.addFilter(Filter.eq("application.name",aadAppName));
          qoGroup.addFilter(Filter.eq("type", "group"));
          qoGroup.addFilter(Filter.eq("value", group));  
          qoGroup.setCloneResults(true);
          Iterator iterator = context.search(ManagedAttribute.class, qoGroup);
          while (iterator.hasNext()){
            ManagedAttribute ma = iterator.next();
            if ((null == ma.getAttribute("groupTypes") || !(Util.nullSafeContains(ma.getAttribute("groupTypes"),"DynamicMembership")))){
              acctReq.add(new AttributeRequest("groups",ProvisioningPlan.Operation.Remove,group));
            }
          }
        }
      }
      accountReqList.add(acctReq);
    }