After Operation Rule Entitlement Issue

Hey all! Writing an after operations rule for a web services connector and I’m running into an issue. This particular source has a list users endpoint, but the data doesn’t return the roles. In order to get the roles, we have to call the users endpoint passing the role name in the query parameter to get the users who have the role. Since there is no payload which shows the user with their roles, an after operation rule was necessary.

Steps:

  1. Get users
  2. Get roles
  3. pass role names to get users query param to get users with those roles.
  4. Create new user map which creates role attribute from value used in step 3.

While the aggregation does execute, no roles are attached to the account objects. Any ideas?

Rule:

import connector.common.JsonUtil;
import connector.common.Util;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import sailpoint.connector.webservices.EndPoint;
import sailpoint.connector.webservices.WebServicesClient;
import sailpoint.connector.webservices.WebServicesConstants;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Logger log = LoggerFactory.getLogger("ApiService");

Map updatedMapInfo = new HashMap();

List execute(String URL, Map header, String methodType, String payload) {
    try {
        WebServicesClient client = new WebServicesClient();
        Map args = new HashMap();
        args.put(WebServicesClient.ARG_URL, URL);
        client.configure(args);
        List allowedStatuses = new ArrayList();
        allowedStatuses.add("2**");
        if ("GET".equalsIgnoreCase(methodType)) {
            String response = client.executeGet(URL, header, allowedStatuses);
            // Handle response parsing
            try {
                return JsonUtil.toList(response);
            } catch (Exception e) {
                // If parsing to List fails, handle as Map and convert to List
                Map responseMap = JsonUtil.toMap(response);
                return new ArrayList(responseMap.values());
            }
        } else {
            log.error("execute Exception ===> Unknown Method Type");
            throw new RuntimeException("execute Exception ===> Unknown Method Type");
        }
    } catch (Exception ex) {
        log.error("getClient Exception ===> " + ex.getMessage(), ex);
        throw new RuntimeException("getClient Exception ===> " + ex.getMessage(), ex);
    }
}

List executeGETRoles(EndPoint requestEndPoint) {
    String baseURL = "https://api.workvivo.us/v1/roles";
    return execute(baseURL, requestEndPoint.getHeader(), "GET", null);
}

List executeGETUsersInRoles(EndPoint requestEndPoint, String roleName) {
    try {
        String encodedRoleName = URLEncoder.encode(roleName, StandardCharsets.UTF_8.toString());
        String baseURL = "https://api.workvivo.us/v1/users?in_roles=" + encodedRoleName;
        return execute(baseURL, requestEndPoint.getHeader(), "GET", null);
    } catch (UnsupportedEncodingException e) {
        log.error("URL encoding error: " + e.getMessage(), e);
        throw new RuntimeException("URL encoding error: " + e.getMessage(), e);
    }
}

List roleObjList = executeGETRoles(requestEndPoint);

if (roleObjList == null) {
    log.error("Roles list is null");
    return new HashMap(); // Return an empty map if no roles
}

Map rawResponseObjectMap = JsonUtil.toMap(rawResponseObject);
List usersList = (List) rawResponseObjectMap.get("content");
List finalList = new ArrayList();

if (usersList != null) {
    for (Object role : roleObjList) {
        List usersInRole = executeGETUsersInRoles(requestEndPoint, (String) role);

        if (usersInRole != null && !usersInRole.isEmpty()) {
            for (Object userObj : usersInRole) {
                Map user = (Map) userObj;
                Map newUserMap = new HashMap();
                newUserMap.put("Name", user.get("name"));
                newUserMap.put("Email", user.get("email"));
                newUserMap.put("Role", role);
                finalList.add(newUserMap);
            }
        }
    }
}

updatedMapInfo.put("data", finalList);

return updatedMapInfo;

Thanks!

1 Like

Hi Joe,

Just want to double check that you’ve patched the source to add the after operation rule to the account aggregation operation?

After you run the account aggregation, are the Name and Email attributes populated for each account? Also are accounts guaranteed to only have one role?

Thanks,

Liam

1 Like

Hey Liam, thanks for the response. Yes I can confirm the rule is added to the source request. I had syntax errors initially so I know it’s being parsed. The attributes do populate after the account aggregations and users can have more than one role yes.

If users can have more than 1 role, the way the rule is setup it looks like you could end up with multiple userMap entries for a single account.

For example if userA has roleA and roleB then your rule logic would add two ‘newUserMap’ objects into the final list for a single account. If name or email is the unique identifier for the account this may be causing the issue? Since the connector would attempt to treat them as separate accounts … and I don’t believe the web services connector is smart enough to merge these two account objects and make the Role attribute multi-valued either.

I would suggest setting up the rule to loop through all the roles and append each role to a corresponding ‘newUserMap’ object’s Role attribute as an array. Once you’ve looped through all the roles, then add each ‘newUserMap’ to the finalList. That way your ‘newUserMap’ objects will have the below structure:

{
    "Name": "UserA",
    "Email": "[email protected]",
    "Role": ["RoleA", "RoleB"]
}

Ensure on the account schema that the Role attribute is set to multi-valued as well. I’m not 100% sure if this is the exact root cause or another issue but worth a try?

Thanks,

Liam

1 Like

Hi Joe

This thread may help you. I have linked to a post in the thread, but worth reading the whole thing

You can then also search the forum for ‘reverse entitlement’ and it will lead to other helpful posts.

1 Like

This solved my issue - thank you so much!

1 Like

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