Unable to Combine Workgroups and Users in identity select list for Forwarding User

Which IIQ version are you inquiring about?

8.3

I am trying to create a filter in IdentityIQ that includes both workgroups and individual users. The goal is to create an identity select list for forwarding purposes, where users should see both users who share the same Orginsation-attribute value and members of specific workgroups marked as “approval groups.”

I have tried a script that collects both types of identities and adds them to a filter, but I am having trouble getting both types to display properly in the UI. I either get only users or only workgroups, and sometimes I encounter errors. Here is the current script I am using:

<entry key="forwardingIdentitySuggest">
    <value>
        <IdentityFilter name="forwardingIdentitySuggest" order="Ascending">
            <FilterScript>
                <Script>
                    <Source>
                        import sailpoint.object.Filter;
                        import sailpoint.object.Identity;
                        import sailpoint.object.QueryOptions;
                        import java.util.List;
                        import java.util.ArrayList;
                        import java.util.Iterator;

                        QueryOptions qo = new QueryOptions();

                        // Step 1: Create a filter to find approval workgroups
                        Filter workgroupUserFilter = null;
                        List approvalGroups = new ArrayList();

                        // Filter to get only workgroups
                        Filter workgroupFilter = Filter.eq("workgroup", true);
                        qo.addFilter(workgroupFilter);

                        // Fetch matching workgroups and add approval groups
                        List mapApproval = context.getObjects(Identity.class, qo);
                        Iterator iterator = mapApproval.iterator();

                        while (iterator.hasNext()) {
                            Identity approvalGroup = (Identity) iterator.next();
                            String approvalGroupAttribute = (String) approvalGroup.getAttribute("ApprovalGroup");

                            if (approvalGroupAttribute != null && approvalGroupAttribute.equals("true")) {
                                approvalGroups.add(approvalGroup);
                            }
                        }

                        // Step 2: Add all approval groups to user filter
                        for (Object group : approvalGroups) {
                            if (group instanceof Identity) {
                                Identity workgroup = (Identity) group;
                                Filter currentFilter = Filter.eq("workgroups.name", workgroup.getName());
                                if (workgroupUserFilter == null) {
                                    workgroupUserFilter = currentFilter;
                                } else {
                                    workgroupUserFilter = Filter.or(workgroupUserFilter, currentFilter);
                                }
                            }
                        }

                        // Step 3: Add OrgAttribute filter for logged-in user
                        Identity identity = context.getObjectById(Identity.class, loggedInUser);
                        if (identity != null) {
                            Object OrgAttributeValue = identity.getAttribute("OrgAttribute");
                            if (OrgAttributeValue != null) {
                                Filter OrgAttributeFilter = Filter.eq("OrgAttribute", OrgAttributeValue.toString());
                                if (workgroupUserFilter == null) {
                                    workgroupUserFilter = OrgAttributeFilter;
                                } else {
                                    workgroupUserFilter = Filter.or(workgroupUserFilter, OrgAttributeFilter);
                                }
                            }
                        }

                        // Step 4: Apply the final filter to QueryOptions
                        if (workgroupUserFilter != null) {
                            qo = new QueryOptions();
                            qo.addFilter(workgroupUserFilter);
                        }

                        return qo;
                    </Source>
                </Script>
            </FilterScript>
            <OrderBy>
                <String>name</String>
            </OrderBy>
        </IdentityFilter>
    </value>
</entry>

Issues Encountered:

  • I am only able to get either users or groups to appear in the select list, but not both.
  • I sometimes receive a generic error message: “The system has encountered a serious error while processing your request.”

Questions:

  • How can I ensure that both users and workgroups are included in the final result?
  • Are there specific limitations in IIQ that could prevent workgroups and users from being combined in this way?
  • Is there a different approach I should consider to achieve the desired filtering?

Thank you in advance for any help or suggestions you may have!

Looks like your OR filter is not correct adding during for loop …

workgroupUserFilter = Filter.or(workgroupUserFilter, currentFilter);
 workgroupUserFilter = Filter.or(workgroupUserFilter, OrgAttributeFilter);

trace this filter and check what is the final filter.

@mihe1606

Can you make your question more clear if possible, is your Identity attributes OrgAttribute and ApprovalGroup are both searchable and named columns?

If I understand correctly you want to the queryOptions to select the workgroups which has ApprovalGroup marked as true and Identities who are having OrgAttribute value same as users OrgAttribute? Is this what you are expecting or anything else

Also where are trying to use this code, in any form and report task definition, can you provide more insight

To clarify:

  • Both OrgAttribute and ApprovalGroup are searchable and are available as named columns in IdentityIQ.
  • My goal is indeed to have QueryOptions select workgroups that have ApprovalGroup marked as true and to include users who have the same OrgAttribute value as the logged-in user.
  • I am using this code for an identity select list for forwarding purposes, within a form-based interaction.

try this

           import sailpoint.object.Filter;
                        import sailpoint.object.Identity;
                        import sailpoint.object.QueryOptions;
                        import java.util.List;
                        import java.util.ArrayList;
                        import java.util.Iterator;

                        QueryOptions qo = new QueryOptions();
                        Identity identity = context.getObjectById(Identity.class, loggedInUser);

                        Filter wrggrpFlt= Filter.and(Filter.eq("workgroup", true),Filter.eq("ApprovalGroup","true"));
						
						Filter identityFlt=null;
						
						Filter finalFilter=null;
						
						if(identity.getAttribute("OrgAttribute")){
                         identityFlt= Filter.eq("OrgAttribute", identity.getAttribute("OrgAttribute"));
						}
					
						if(identityFlt!=null){
							finalFilter=Filter.or(wrggrpFlt,identityFlt)
						}
						else {
						finalFilter=	wrggrpFlt;
							
						}

						qo.addFilter(finalFilter);
                        return qo;

Thanks for the suggested code changes.

I tested your code with combined filters using Filter.or(). While the log shows the correct values for both workgroups and users, nothing appears in the search box in the UI. It seems that despite the correct construction, the combined filter doesn’t return any visible results at runtime.

Any further ideas on why this might be happening?
Thanks again!

Please share your complete form.xml if possible, is this custom form from a quick link, if so please use filterString instead of this and set the filterString accordingly as per above code.

You can add the final filter to filterString attribute of the field like below -
``

<Field displayName="Select Identity" dynamic="true" filterString="" multi="true" name="forwardingIdentity" type="Identity">
      <Attributes>
        <Map>
          <entry key="filterString">
            <value>
              <Script>
                <Source>
                              // Create a final filter to set
                            field.setFilterString(filter.toString());  
                        </Source>
              </Script>
            </value>
          </entry>
        </Map>
      </Attributes>
    </Field>

I’m a bit lost about where exactly to place this code. Should I put it in the IdentitySelectorConfiguration object, or do I need to add it in a XML configuration that defines the UI form fields, such as <Field> tags?

@mihe1606 you have to place it under the field tags, please share your form xml or at least this field related complete tag, will share you the update the code

The form.xml object is still in its default template state.

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE sailpoint PUBLIC "sailpoint.dtd" "sailpoint.dtd">

<!-- (c) Copyright 2010 SailPoint Technologies, Inc., All Rights Reserved. -->

<!--
  Initialization file for SailPoint forms.
-->
<sailpoint>

<!-- ====================================================================

  Identity refresh form.  This is the default "template" form used in the
  dynamic generation of work item forms to ask provisioning questions
  during the background refresh task.

========================================================================= -->

<Form name='Identity Refresh' type="Workflow">
  <Attributes>
    <Map>
      <entry key='pageTitle' value="provision_identity_refresh_title"/>
      <entry key='pageTitleParam' value='$(identityName)'/>
    </Map>
  </Attributes>

  <Section type='text'>
    <Field displayName="provision_identity_refresh_description"/>
  </Section>

  <Section label="provision_target_identity" type='datatable'>
    <Field displayName="provision_account_id" value='script:identity.getName()'/>
    <Field displayName="provision_first_name" value='script:identity.getFirstname()'/>
    <Field displayName="provision_last_name" value='script:identity.getLastname()'/>
    <Field displayName="provision_assigned_roles">
      <Script><Source>
          import sailpoint.api.ObjectUtil;
          import sailpoint.tools.Util;
          List names = ObjectUtil.getObjectNames(identity.getAssignedRoles());
          return Util.listToCsv(names);
      </Source></Script>
    </Field>
    <Attributes>
      <Map>
        <entry key='hideNulls' value='true'/>
      </Map>
    </Attributes>
  </Section>

  <!-- More sections inserted here -->

  <Button label="button_ok" action='next'/>
  <Button label="button_cancel" action='cancel'/>
  <Button label="button_return" action='cancel' readOnly='true'/>

</Form>

<!-- ====================================================================

  Identity update form.  This is the default "template" form used in the
  dynamic generation of work item form to ask provisioning questions
  during interaction with the IIQ Define->Identities pages.

========================================================================= -->

<Form name='Identity Update' type="Workflow">
  <Attributes>
    <Map>
      <entry key='pageTitle' value="provision_identity_update_title"/>
      <entry key='pageTitleParam' value='$(identityName)'/>
    </Map>
  </Attributes>

  <Section type='text'>
    <Field displayName="provision_identity_update_description"/>
  </Section>

  <Section label="provision_request_information" type='datatable'>
    <Field displayName="provision_requester">
      <Script>
        <Source>
          import sailpoint.object.Identity;

          Identity launchIdentity = context.getObject(Identity.class, launcher);

          return launchIdentity == null ? launcher : launchIdentity.getDisplayableName();
        </Source>
      </Script>
    </Field>
    <Field displayName="provision_requested_roles" value='ref:newRoles'/>
    <Attributes>
      <Map>
        <entry key='hideNulls' value='true'/>
      </Map>
    </Attributes>
  </Section>

  <Section label="provision_target_identity" type='datatable' columns='3'>
    <Field columnSpan="1" displayName="provision_first_name" value='script:(identity != null) ? identity.getFirstname() : null'/>
    <Field columnSpan="1" displayName="provision_last_name" value='script:(identity != null) ? identity.getLastname() : null'/>
    <Field columnSpan="1" displayName="provision_account_id" value='script:(identity != null) ? identity.getDisplayableName() : null'/>
    <Field columnSpan="3" displayName="provision_assigned_roles">
      <Script><Source>
          import java.util.ArrayList;
          import java.util.List;
          import sailpoint.object.Bundle;
          import sailpoint.tools.Util;

          String names = null;

          if (identity != null) {
              List&lt;String&gt; roleNames = new ArrayList&lt;String&gt;();

              for (Bundle bundle : Util.iterate(identity.getAssignedRoles())) {
                  roleNames.add(bundle.getDisplayableName());
              }

              names = Util.listToCsv(roleNames);
          }

          return names;
      </Source></Script>
    </Field>
    <Attributes>
      <Map>
        <entry key='hideNulls' value='true'/>
      </Map>
    </Attributes>
  </Section>

  <!-- More sections inserted here -->

  <Button label="button_ok" action='next'/>
  <Button label="button_cancel" action='cancel'/>
  <Button label="button_return" action='cancel' readOnly='true'/>

</Form>

</sailpoint>

Try adding IncludeWorkgroups filter in references under your IdentityFilter tag.

<IdentityFilter>
...
<IncludedFilterReferences>
				<String>IncludeWorkgroups</String>
			</IncludedFilterReferences>
</IdentityFilter>

@mihe1606

Where is this code you was mentioning, I don’t see this field

I typically make entries into IdentitySelectorConfiguration when I have a custom form object that has an identity field where I need to change the sort order of identities. By default it’s sorted by name, whereas I want it sorted by last name.

A typical entry I would use would look like this replacing My Custom Form with the name of your form object and name with the name of that field :

<entry key="My Custom Form-form-name-field">
  <value>
    <IdentityFilter ignoreGlobal="true" name="Global" order="Ascending">
      <FilterSrc>
        <FilterSource>
          <ParameterizedFilter>
            <FilterTemplate>
              <FilterParameters>
                <String>parts</String>
              </FilterParameters>
              <FilterString>

                  #if($parts.size() == 1)
                    firstname.startsWithIgnoreCase("$parts.get(0)") || lastname.startsWithIgnoreCase("$parts.get(0)") || email.startsWithIgnoreCase("$parts.get(0)") || name.startsWithIgnoreCase("$parts.get(0)"))
                  #elseif($parts.size() == 2)
                    (firstname.startsWithIgnoreCase("$parts.get(0)") &amp;&amp; lastname.startsWithIgnoreCase("$parts.get(1)")) || name.startsWithIgnoreCase("$parts.get(0) $parts.get(1)")
                  #end

              </FilterString>
            </FilterTemplate>
          </ParameterizedFilter>
        </FilterSource>
      </FilterSrc>
      <OrderBy>
        <String>lastname</String>
        <String>email</String>
        <String>firstname</String>
        <String>name</String>
        <String>id</String>
      </OrderBy>
    </IdentityFilter>
  </value>
</entry>

Tried that already, but it didn’t work.

I’ve already added my entry in the IdentitySelectorConfiguration.xml to set up the filtering logic, but I’m uncertain about where exactly to place the <Field> part of the code:Should it be in this file: IdentitySelectorConfiguration.xml? or somewhere else?

<Field displayName="Select Identity" dynamic="true" filterString="" multi="true" name="forwardingIdentity" type="Identity">
  <Attributes>
    <Map>
      <entry key="filterString">
        <value>
          <Script>
            <Source>
              // Create a final filter to set
              field.setFilterString(filter.toString());
            </Source>
          </Script>
        </value>
      </entry>
    </Map>
  </Attributes>
</Field>

I am quite new to IdentityIQ, so any guidance on where to put this code would be really helpful.