How to use identitySelector or matchExpression as a generic query?

Which IIQ version are you inquiring about?

8.3p3

Please share any other relevant files that may be required (for example, logs).

Inside one of our roles (bundle), we have it set up using a Match list. The xml displays it as so:

<IdentitySelector>
    <MatchExpression and="true">
        <MatchTerm name="title" type="IdentityAttribute" value="Test Title"/>
        <MatchTerm name="jml" type="IdentityAttribute" value="Joiner"/>
    </MatchExpression>
</IdentitySelector>

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

I’m trying to create a rule that will take the input of any “role name” and return the list of users that would qualify for that role. The rule needs to be generic enough so that it can accept the identitySelector or MatchExpression and return that list of users.

Something along the lines of this (even though this isn’t working):

String roleName = "Role Test";
Bundle bundle = context.getOjbectByName(Bundle.class,roleName);

IdentitySelector selector = bundle.getSelector(); 
return selector.getMatchExpression().getIdentities(context); 

Is something like this possible? Does anyone have a working example?

If possible, it will also need to expand to include the other role assignment criteria (Match List, Filter, Script, Rule, Population), where it accepts the criteria regardless of type, and searches for users that match the criteria.

Hi @supafongboon ,

  1. Firstly retrieve the bundle object , if the bundle exists and the type of role is business then retrieve the selector from the bundle object , as only business roles have assignment rules option by default.

  2. From the selector object , retrieve the MatchExpression and from the MatchExpression retrieve the MatchTerms.

  3. From the list of MatchTerms , retrieve the filter criteria used for assigning the corresponding role and create a QueryOptions object with the Filters in MatchTerms.

  4. And then use this QueryOptions object to get the identities which match the assignment rule of the bundle.

    Try this approach and let me know if it is working.

1 Like

I put this together and tested it successfully in my local environment with one of my roles. Either way, this should give you an idea of something to build on.

Just a heads up, this approach could have performance issues with large user populations since it runs at O(n) complexity.

public List getUsersForRole(String roleName) {
  List qualifyingUsers = new ArrayList();
  
  // Get the bundle/role
  Bundle bundle = context.getObjectByName(Bundle.class, roleName);
  if (bundle == null) {
    log.warn("Bundle not found: " + roleName);
    return qualifyingUsers;
  }
  
  // Get the selector
  IdentitySelector selector = bundle.getSelector();
  if (selector == null) {
    log.warn("No selector found for bundle: " + roleName);
    return qualifyingUsers;
  }
  
  // Get the match expression
  IdentitySelector.MatchExpression matchExpr = selector.getMatchExpression();
  if (matchExpr == null) {
    log.warn("No match expression found for bundle: " + roleName);
    return qualifyingUsers;
  }
  
  // Build filter from MatchExpression
  Filter filter = buildFilterFromMatchExpression(matchExpr);
  
  // Build query options
  QueryOptions qo = new QueryOptions();
  qo.addFilter(filter);
  
  // Search for matching identities
  Iterator it = context.search(Identity.class, qo);
  
  try {
    while (it != null &amp;&amp; it.hasNext()) {
      Identity identity = it.next();
      if (identity != null) {
        qualifyingUsers.add(identity);
      }
    }
  } finally {
    Util.flushIterator(it);
  }
  
  return qualifyingUsers;
}

private Filter buildFilterFromMatchExpression(IdentitySelector.MatchExpression matchExpr) {
  List terms = matchExpr.getTerms();
  boolean isAnd = matchExpr.isAnd();
  
  if (terms == null || terms.isEmpty()) {
    return null;
  }
  
  List filters = new ArrayList();
  
  for (IdentitySelector.MatchTerm term : terms) {
    String attributeName = term.getName();
    Object value = term.getValue();
    
    Filter f = Filter.eq(attributeName, value);
    filters.add(f);
  }
  
  // Combine filters based on AND/OR logic
  if (filters.size() == 1) {
    return filters.get(0);
  }
  
  if (isAnd) {
    return Filter.and(filters);
  } else {
    return Filter.or(filters);
  }
}


return getUsersForRole("IT Staff"); // Enter the role you want to return a list of users for
3 Likes

Hi Sunny, I’ve been trying to get this to work in my environment, but I keep getting the error:

“The application script threw an exception: sailpoint.tools.GeneralException: ClassCastExceoption BSF info: Role Analysis Rule at line: 0 column: columnNo”

Hi Chathurya, after working through some of the errors, I get to a final error that says:

“Exception running rule: The application script threw an exception: sailpoint.tools.GeneralException: ClassCastExceoption BSF info: Role Analysis Rule 2 at line: 0 column: columnNo”

Try starting small out small and verify that what I provided works. Import this file and change the role name to something in your system. You can run this rule in Debug and it should work. Pasted below and attached for convenience.

Rule-getUsersForRole.xml (2.4 KB)

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule language="beanshell" name="getUsersForRole">
  <Source><![CDATA[
    import sailpoint.object.*;
    import sailpoint.tools.*;

    public List getUsersForRole(String roleName) {
      List qualifyingUsers = new ArrayList();

      // Get the bundle/role
      Bundle bundle = context.getObjectByName(Bundle.class, roleName);
      if (bundle == null) {
        log.warn("Bundle not found: " + roleName);
        return qualifyingUsers;
      }

      // Get the selector
      IdentitySelector selector = bundle.getSelector();
      if (selector == null) {
        log.warn("No selector found for bundle: " + roleName);
        return qualifyingUsers;
      }

      // Get the match expression
      IdentitySelector.MatchExpression matchExpr = selector.getMatchExpression();
      if (matchExpr == null) {
        log.warn("No match expression found for bundle: " + roleName);
        return qualifyingUsers;
      }

      // Build filter from MatchExpression
      Filter filter = buildFilterFromMatchExpression(matchExpr);

      // Build query options
      QueryOptions qo = new QueryOptions();
      qo.addFilter(filter);

      // Search for matching identities
      Iterator it = context.search(Identity.class, qo);

      try {
        while (it != null && it.hasNext()) {
          Identity identity = it.next();
          if (identity != null) {
            qualifyingUsers.add(identity);
          }
        }
      } finally {
        Util.flushIterator(it);
      }

      return qualifyingUsers;
    }

    private Filter buildFilterFromMatchExpression(IdentitySelector.MatchExpression matchExpr) {
      List terms = matchExpr.getTerms();
      boolean isAnd = matchExpr.isAnd();

      if (terms == null || terms.isEmpty()) {
        return null;
      }

      List filters = new ArrayList();

      for (IdentitySelector.MatchTerm term : terms) {
        String attributeName = term.getName();
        Object value = term.getValue();

        Filter f = Filter.eq(attributeName, value);
        filters.add(f);
      }

      // Combine filters based on AND/OR logic
      if (filters.size() == 1) {
        return filters.get(0);
      }

      if (isAnd) {
        return Filter.and(filters);
      } else {
        return Filter.or(filters);
      }
    }

    return getUsersForRole("IT Staff"); // Enter the role you want to return a list of users for
  ]]></Source>
</Rule>

I must have imported something in incorrectly, but this worked for me!

Is there a way to make it accept all the different assignment rules types for roles (MatchList, Filter, Script, Rule, Population)?

No promises that this works, but it should give you a start. Please remember O(n) performance will come to haunt you.

Rule-getUsersForRole_v2.xml (6.3 KB)

Thanks! I’ll take a look at that and keep performance in mind.

When trying to use the rule with a Filter as an assignment rule, the rule errors since it’s returning a compoundFilter instead of a filter (is my guess).

Exception running rule: BeanShell script error: bsh.EvalError: Sourced file: inline evaluation of: 'import sailpoint.object.*; import sailpoint.tools.*; import sailpoint.obje ...' : Command not found: getUsersByFilter(sailpoint.object.CompoundFilter) : at Line: 29 : in file: inline evaluation of: 'import sailpoint.object.*; import sailpoint.tools.*; import import sailpoint.obje ...' : getUsersByFilter ( selector.getFilter() )

Is there a way to utilize the compoundFilter instead of a regular filter?

Try changing the method from:

private List getUsersByFilter(Filter filter) {

to:

private List getUsersByFilter(CompoundFilter filter) {
    List qualifyingUsers = new ArrayList();

    if (filter == null) {
      return qualifyingUsers;
    }

    QueryOptions qo = new QueryOptions();
    qo.addFilter(filter.getFilter()); // Need to get the filter from the object

    Iterator it = context.search(Identity.class, qo);

    try {
      while (it != null && it.hasNext()) {
        Identity identity = it.next();

        if (identity != null) {
          qualifyingUsers.add(identity);
        }
      }
    } finally {
      Util.flushIterator(it);
    }

    return qualifyingUsers;
  }

This has an overloaded method to support CompoundFilter in case you didn’t know where to include it. Not sure what else you are looking for since you earlier marked this solved.

Rule-getUsersForRole_v3.xml (6.9 KB)

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