Manager Correlation with Complex Nested Attributes (ADP)

Abstract

There’s limited resources describing an issue with jsonPath attribute mapping and correlating ACCOUNT attributes to IDENTITY attributes.

The ideal accountObject contains explicit keys for the desired output values, but what if the attribute value you’re looking for is nested in a list or list of lists? jsonPath, with conditional statements, will be able to find the value, but depending on where the key lies, the output value may either be “foo” or [“foo”].

This is the case with ADP’s workersV2 API where various attributes are nested under a list (workerAssignments) such as “title”, “department”, and most notably “manager”. Generally this is a non issue for mapping Identity Attributes to identities, but when the ACCOUNT attribute has a value of [“foo”] and is comparing against and identity attribute value “foo” correlation fails.

interpreting the rawResponseObject

ADP nests title, department, manager, and other ephemeral worker data under workAssignemts.

[
    {
        "id": "0123456",
        "name": "john",
        "workAssignments": [
            {
              "title": "Engineer",
              "department": "IT",
              "manager": "654321",
              "primary": false
            },
            {
              "title": "SysAdmin",
              "department": "Finance",
              "manager": "654321",
              "primary": true
            }
        ]
    },
   ...
]

Fortunately in the list of workAssignments, there’s a key \ value indicator that we can search with JSON path to get the most recent employee data.

{ ...
    "connectorAttributes": {...
        "connectionParameters": [...
            "refMappingObj"
                    "id": "id",
                    "name": "name",
                    "title": "workAssignments[?(@.primary==true)].positionID",
                    "department": "workAssignments[?(@.primary==true)].department",
                    "manager": "workAssignments[?(@.primary==true)].manager"
        ]
    }
  }
}

processedResponseObject

The jsonPath for any of the values nested in the list are represented [value], whereas the direct attribute are strings.

{
    "id":"0123456",
    "name":"john",
    "title":[Engineer],
    "department":[IT],
    "manager":[654321]
}

Correlation and Conflicts

Source - Attribute manager has a type set as String

  • Aggregation HTTP Get Operations
    • attributeMapping for manager = workAssignments[?(@.primaryIndicator==true)].manager
    • Sailpoint interprets the manager string value as [654321] despite it being a string
    • The connector does not attempt to normalize it as a string, similar to that of setting the attribute type to “multi-valued” however, multi-valued account attributes are not supported (hidden) from the manager correlation.

Source - Attribute name has a type set as String

  • Aggregation HTTP Get Operations
    • attributeMapping for AttributeB jsonPath
      • attributeMapping for name = name
    • Sailpoint interprets the name string value as “john”

Identity Profile Mapping

  • manager mapped to IdentityAttribute
    • Identity Attribute is represented as a string “654321”
  • name mapped to IdentityAttribute
    • Identity Attribute is represented as a string “john”

Let’s review the comparitive operators for a Manager Correlation on the source: ADP

.

IdentityAttribute: id == AccountAttribute: manager

Or

654321 == [654321] # Which is False

.

The discrepancy largely impacts correlation as the Identity Attributes vs. Account Attributes greatly differ in type. Identity Attributes appear to be normalized, however the Account Attributes are still represented as a jsonPath output enclosed with [].

Workaround \ Solution

Disclaimer: As always approach with caution

For our case, every attribute mapped is intended to be a string (no multi-valued account attributes), so we took a more dynamic approach (converting all values of “list” to string), however the example below is explicitly for the managerID (example) Account Attribute.

import connector.common.JsonUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import sailpoint.tools.GeneralException;

for (int i = 0; i < processedResponseObject.size(); i++) {
    Map responseMap = (Map) processedResponseObject.get(i);
    if (responseMap != null) {
        Object value = responseMap.get("managerID");
        if (value instanceof List) {
            List listValue = (List) value;
            if (listValue.size() > 0) {
                responseMap.put("managerID", listValue.get(0).toString());
            } else {
                responseMap.put("managerID", "");
            }
        } else {
            if (value != null) {
                responseMap.put("managerID", value.toString());
            } else {
                responseMap.put("managerID", "");
            }
        }
    }
}

return processedResponseObject;

Applying this as an AfterRule to the AggregateUsers and GetObject HTTP operations normalized the enclosed jsonPath results so that all account attribute values are strings and allowed both the Identity and Manager correlation to function as expected.

1 Like