Technical Components required for Dynamic Attribute Population Across Multiple Authoritative Sources in SailPoint ISC

Problem

When an identity is discovered across multiple authoritative sources, SailPoint ISC uses Identity Profiles to determine which source takes precedence.

  • The Priority Rule: The evaluation order is determined by the priority number configured within the Identity Profiles. A lower priority number signifies a higher evaluation precedence (e.g., Priority 1 is higher than Priority 2).
  • Standard Behaviour: The identity profile with the higher priority (lower number) dictates the mapping configuration used to populate the Identity Attributes on the identity cube.

Diagnosis

The Challenge: The Inactive High-Priority Source

Let’s consider a scenario with two authoritative sources: Authz-A (Priority 1 - High) and Authz-B (Priority 2 - Low).

  1. If an identity has active accounts in both sources, the mapping configurations of Authz-A are automatically used.
  2. If the account in Authz-A becomes disabled or inactive, you might expect ISC to automatically fall back and populate identity attributes from the active Authz-B account.
  3. However, this does not happen automatically. If the identity remains correlated to the Authz-A profile, ISC will continue to evaluate the mappings defined for Authz-A, potentially resulting in stale or missing identity data if that source is no longer updating or providing valid data.

Conversely, if an identity transitions dynamically between profiles via native UI evaluation rules, the attributes will update automatically. But when you need to selectively pull data across both sources while an identity is tied to a specific profile, you must implement a custom solution using SailPoint Transforms.

Solution

Active Identity Profile Strategy

To solve this, we can design an architecture that dynamically computes the “truest” active source and conditionally overrides individual identity attributes.

Let’s look at an enterprise scenario featuring four authoritative sources prioritized as follows:

image

Implementation Workflow

  1. Create a Technical Identity Attribute: Name this attribute Active Identity Profile.

  2. Deploy a Root Calculation Transform: Map a dedicated transform to this attribute. This transform evaluates the source-level data (such as Start Date, End Date, Account State, etc.) across all sources, considering their priority order, to calculate exactly which identity profile should be considered active.

  3. Build Master Attribute Overrides: For each identity attribute in scope, implement a master transform that reads the calculated Active Identity Profile and dynamically selects the correct source value.

Transform Blueprint: Calculate the Active Authoritative Source

Refer below set of transforms which will perform the calculation of which is active authoritative source for the user

Test - Master - Static - CheckWDIsActive.json (5.5 KB)

Test - Master - Static - CheckOHSNAPIsActive.json (9.4 KB)

Test - Master - Static - CheckNERMIsActive.json (9.5 KB)

Test - Master - Static - CheckCTIsActive.json (9.4 KB)

Test - Master - Static - ActiveIdentityProfile.json (12.3 KB)

Transform Blueprint: Master Attribute Controller

Below is the design pattern for a master transform (e.g., Test - Master - Static - DeptCode). It leverages a static transform type combined with firstValid lookups to pull cross-source attributes into variables, utilizing a Velocity script to handle the conditional fallback logic.

{

  "name": "Test - Master - Static - DeptCode",

  "type": "static",

  "attributes": {

    "requiresPeriodicRefresh": true,

    "ActiveIdentityProfile": {

      "attributes": {

        "values": [

          {

            "attributes": {

              "id": "Test - Master - Static - ActiveIdentityProfile"

            },

            "type": "reference"

          },

          {

            "attributes": {

              "value": "N/A"

            },

            "type": "static"

          }

        ]

      },

      "type": "firstValid",

      "ignoreErrors": true

    },

    "WorkDayDeptCode": {

      "attributes": {

        "values": [

          {

            "attributes": {

              "sourceName": "Workday",

              "attributeName": "DEPARTMENT_CODE"

            },

            "type": "accountAttribute"

          },

          {

            "attributes": {

              "value": "N/A"

            },

            "type": "static"

          }

        ]

      },

      "type": "firstValid",

      "ignoreErrors": true

    },

    "CactusDeptCode": {

      "attributes": {

        "values": [

          {

            "attributes": {

              "sourceName": "CACTUS",

              "attributeName": "DEPARTMENT_CODE"

            },

            "type": "accountAttribute"

          },

          {

            "attributes": {

              "value": "N/A"

            },

            "type": "static"

          }

        ]

      },

      "type": "firstValid",

      "ignoreErrors": true

    },

    "OHSNAPDeptCode": {

      "attributes": {

        "values": [

          {

            "attributes": {

              "sourceName": "OHSNAP",

              "attributeName": "DEPARTMENT_CODE"

            },

            "type": "accountAttribute"

          },

          {

            "attributes": {

              "value": "N/A"

            },

            "type": "static"

          }

        ]

      },

      "type": "firstValid",

      "ignoreErrors": true

    },

    "NERMDeptCode": {

      "attributes": {

        "values": [

          {

            "attributes": {

              "sourceName": "NERM",

              "attributeName": "DEPARTMENT_CODE"

            },

            "type": "accountAttribute"

          },

          {

            "attributes": {

              "value": "N/A"

            },

            "type": "static"

          }

        ]

      },

      "type": "firstValid",

      "ignoreErrors": true

    },

    "value": "#if( $ActiveIdentityProfile != 'N/A' && $ActiveIdentityProfile == 'WORKDAY' && $WorkDayDeptCode != 'N/A' )$WorkDayDeptCode#{elseif}($ActiveIdentityProfile != 'N/A' && $ActiveIdentityProfile == 'CACTUS' && $CactusDeptCode != 'N/A')$CactusDeptCode#{elseif}($ActiveIdentityProfile != 'N/A' && $ActiveIdentityProfile == 'NERM' && $NERMDeptCode != 'N/A')$NERMDeptCode#{elseif}($ActiveIdentityProfile != 'N/A' && $ActiveIdentityProfile == 'OHSNAP' && $OHSNAPDeptCode != 'N/A')$OHSNAPDeptCode#{else}#end"

  },

  "internal": false

}

Key Development Takeaways

  1. Decoupled Logic: The root transform (Test - Master - Static - ActiveIdentityProfile) encapsulates complex lifecycle logic and account status checks across child transforms.

  2. Clean Fallbacks: By declaring local variables for each source using firstValid and defaulting to “N/A”, the Velocity script avoids evaluating null pointers, ensuring deterministic output.

  3. Data Integrity: This pattern guarantees your target identity attributes pull dynamically from whichever source is genuinely active at any given moment, safeguarding down-stream provisioning from stale or corrupted source data.

For referring the design of this solution, refer the below SailPoint developer’s forum post.

High Level Design of Handling Multi-Authoritative Sources and Dynamic Attribute Population in SailPoint ISC - Identity Security Cloud (ISC) / ISC Community Knowledge Base - SailPoint Developer Community