SailPoint Identity Fusion Connector


:spiral_notepad: Description SaaS Connector: SailPoint Identity Fusion
:balance_scale: Legal Agreement By using this CoLab item, you are agreeing to SailPoint’s Terms of Service for our developer community and open-source CoLab.
:hammer_and_wrench: Repository Link GitHub - sailpoint-oss/colab-saas-conn-sailpoint-identity-fusion
:open_book: New to SaaS connectors in the CoLab? Read the getting started guide for SaaS Connectors in the CoLab.
:hospital: Supported by Community Developed

Overview

Originally developed by @fernando_delosrios. Now maintained by @developer_relations_team .

This is a concept custom SaaS connector with two main goals in mind:

  • Creating unique identifiers for identities
  • Helping with the deduplication process of identities from multiple sources

Find more detailed information on the Github repo.

Requirements

  • @sailpoint/connector-sdk”: “1.1.11”
  • “axios”: “^1.6.8”
  • “axios-retry”: “^4.0.0”
  • “fast-levenshtein”: “3.0.0”
  • “markdown-it”: “^14.0.0”
  • “sailpoint-api-client”: “1.3.2”
  • “transliteration”: “^2.3.5”
  • “uuid”: “^9.0.1”
  • “velocityjs”: “^2.0.6”
  • “typescript”: “^5.3.3”

Guide

Other Installation Notes

If you the below error in the logs, make sure you’ve installed node.js/typescript properly and your npm is working. Mine was bugged, but after a clean install, it fixed the issue. - Thanks to @tim-leo

Supported Operations

  • Test Connection
  • Account Enable
  • Account Disable
  • Account List
  • Account Read
  • Entitlement List
  • Schema Discovery
8 Likes

This SaaS Connector is awesome! Fixes a lot of issues with duplicate identities

2 Likes

We are looking forward to the developer day to see it in action again!

1 Like

I am really excited about this connector. Since I work primarily in higher ed, I see a lot of use for deduplication across sources (HCM, SIS, Alum, Admissions, etc.), so thank you for making this available!

I do have a question related my initial experience with it so far:
I imported the connector into my tenant and have configured a single source. One thing I’ve noticed that seems odd is that it creates a new proxy account/identity for the person assigned to “Manual reviewer identity or governance group” every time the aggregation is run. Is this intentional or is this a misconfiguration on my part?

Thanks,
Matt

Hi Matt. Happy to hear it’s helpful. I believe what you’re experiencing is a bug that could be triggered by your configuration, but definitely a bug because I experienced it myself.

I’m currently working on a new version that should fix it. I’m quite busy at the moment but I’ll try my best to release it really soon.

Stay tuned.

I do see that I am currently getting the UUID for the Identity Fusion Connector set as the identity display name. Perhaps if I update the display name to match the reviewer’s display name, the proxy accounts would all be correlated to the one identity.

I think overall that there are 2 pieces that aren’t clear from the information I’ve read here and in the repo. First, how do I setup the Identity Profile, specifically, do I need transforms that look at firstValid between each of the sources configured? Second, how do I configure the entitlement schema. From the demo and the documentation, it seems like the entitlements should be automatic.

Thanks

Ah, I see. Ok thanks.

For future reference - In my Identity Profile, I’m just mapping the attributes to the Identity Fusion account attributes. Lifecycle state is being set to a static of active for now, and enabling the Identity Fusion account so that correlation on the original source can take place.

The entitlements on the Identity Fusion connector just need to be imported. I was thinking that since they are included in the data/status.ts file that somehow they would be imported automatically, but I just needed to run an entitlement aggregation.

Since my identity attributes are being mapped correctly now, I no longer see proxy accounts being generated every time for the reviewer - their account exists once on the Identity Fusion source with the ‘reviewer’ entitlement.

Seems to be working as expected so far, now that I’ve updated my configuration.

Thanks

1 Like

After account aggregation, only my account was imported as i defined myself as reviewer in AccessProfile. all accounts from the direct connection SQL Loader connector were imported in the account sources but not in the fusion-connector source. and when i try to discover schema on the account schema, no schema is found.
is there something i need to do again ?

Is your SQL Loader source authoritative? Are those accounts correlated already? If so, it’s totally expected as Fusion only processes uncorrelated accounts. What is not right is the schema is not discovered so check your configuration, your credentials, your connector version, enable debug logs and share your findings.

Yes sure, the SQL Loader is an authoritative source and the accounts are uncorrelated accounts. the configuration seems to be ok and the connector is the actual version

SQL Loader cannot be an authoritative source and have uncorrelated accounts by definition, unless you mean SQL Loader is configured as a source in the Identity Fusion configuration. Please clarify this bit. Identity Fusion source is supposed to be your authoritative source instead of the other sources in its configuration. Check debug logs too when discovering the schema.

the SQL Loader is a source in my Identity Fusion configuration and i think after aggregation, both proxy accounts and uncorrelated accounts supposed to be imported to both sources. but after aggregation only the uncorrelated accounts are imported in the SQL Loader source.

I’m hitting the discover schema issue as well. It doesn’t even load in the static account schema it seems.
Log section below. I’m seeing that it doesn’t error at all, and definitely finds the schema to create - however, it doesn’t post in the tenant. PAT permissions are double checked and appropriate. What I’m noticing is it actually blanks out the OOTB schema, and we can’t seem to get it back.

[2025-03-26T12:34:38.479-05:00] INFO  | invokeCommand    ▶︎ Command execution started : std:account:discover-schema, for connector version 2.
[2025-03-26T12:34:38.486-05:00] INFO  | connectorMessage ▶︎ {"--INPUT--":{"schema":{"attributes":[],"childHierarchy":false,"displayAttribute":"uniqueId","identityAttribute":"uniqueId","includePermissions":false,"nativeObjectType":"User","type":"account"}},"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:38.486-05:00] INFO  | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"Paginating call, offset = 0\n","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:38.488-05:00] INFO  | connectorMessage ▶︎ {"--CONFIG--":{"acctAggregationEnd":1743005951748,"attributeMerge":"first","baseurl":"https://[redacted].api.identitynow.com","beforeProvisioningRule":null,"clientId":"2f55543f76ff48c9826c797c09dce73e","clientSecret":"df0c1dc0745841b377cc4f888aa4534f4bee201ab5f746bfcd7a908b4390c514","cloudAuthoritativeSourcePrecedence":90,"cloudCacheUpdate":1743007366296,"cloudDisplayName":"Identity-Fusion","cloudIdentityProfileName":"Identity-Fusion","connectionType":"direct","connectorName":"Identity Fusion (tag: latest)","credentialProviderEnabled":false,"deleteEmpty":false,"deleteThresholdPercentage":10,"deltaAggregation":null,"forceAggregation":false,"formPath":null,"global_merging_identical":null,"global_merging_score":null,"healthy":true,"idnProxyType":"sp-connect","managementWorkgroup":null,"merging_attributes":[],"merging_expirationDays":null,"merging_isEnabled":false,"merging_map":[],"merging_score":null,"recommendationStatus":"ERROR","reset":false,"since":"2025-03-26T14:52:36.243Z","slpt-source-diagnostics":"{\"connector\":\"\",\"status\":\"SOURCE_STATE_HEALTHY\",\"healthy\":true,\"healthcheckDisabled\":false,\"healthcheckCount\":14,\"lastHealthcheck\":1743007320064,\"statusChanged\":1743000756243}","sourceConnected":true,"sourceDescription":"Identity-Fusion","sources":["a"],"spConnDebugLoggingEnabled":true,"spConnectorInstanceId":"358feeea-0bbd-459e-9104-de47d32a8471","spConnectorSpecId":"8374b6a6-d690-408e-b8e4-fcafec0de359","spConnectorSupportsCustomSchemas":true,"status":"SOURCE_STATE_HEALTHY","templateApplication":"Identity Fusion (tag: latest)","uiMarkAsAuthoritative":true,"uid_case":"upper","uid_digits":10,"uid_normalize":true,"uid_scope":"platform","uid_spaces":true,"uid_template":"#set($initial = $firstname.substring(0, 1))$initial$lastname$counter"},"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:38.488-05:00] INFO  | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"Building dynamic schema.","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:38.488-05:00] DEBUG | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"ContextHelper: Initializing SDK client.","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:38.488-05:00] DEBUG | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"ContextHelper: Looking for connector instance","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:39.119-05:00] DEBUG | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"   buildDynamicSchema: Fetching sources.","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:39.123-05:00] DEBUG | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"   buildDynamicSchema: Fetching schemas.","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:39.123-05:00] DEBUG | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"   buildDynamicSchema: Compiling attributes.","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:39.123-05:00] DEBUG | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"   buildDynamicSchema: Defining static attributes.","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:39.124-05:00] DEBUG | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"   buildDynamicSchema: Processing attribute merge mapping.","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:39.124-05:00] DEBUG | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"   buildDynamicSchema: Processing existing attributes.","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:39.124-05:00] DEBUG | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"   getEmailWorkflow: Fetching workflows","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:39.164-05:00] DEBUG | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","message":"   getEmailWorkflow: Workflow found","requestId":"a01957f26db346a7991f0f7a6655e8e8","version":2}
[2025-03-26T12:34:39.280-05:00] INFO  | connectorMessage ▶︎ {"commandType":"std:account:discover-schema","invocationId":"c7a784e0-6b0b-4009-ac50-02766c38d1a3","requestId":"a01957f26db346a7991f0f7a6655e8e8","schema":{"attributes":[{"description":"Unique ID","name":"uniqueID","required":true,"type":"string"},{"description":"UUID","name":"uuid","required":true,"type":"string"},{"description":"History","multi":true,"name":"history","type":"string"},{"description":"Statuses","entitlement":true,"managed":false,"multi":true,"name":"statuses","schemaObjectType":"status","type":"string"},{"description":"Actions","entitlement":true,"managed":true,"multi":true,"name":"actions","schemaObjectType":"action","type":"string"},{"description":"Account IDs","entitlement":false,"multi":true,"name":"accounts","type":"string"},{"description":"Reviews","entitlement":false,"multi":true,"name":"reviews","type":"string"},{"description":"sources","entitlement":false,"multi":false,"name":"sources","type":"string"},{"description":"Disabled","entitlement":false,"multi":false,"name":"IIQDisabled","type":"string"}],"displayAttribute":"uuid","identityAttribute":"uuid"},"version":2}
[2025-03-26T12:34:39.295-05:00] INFO  | commandOutcome   ▶︎ Command completed: std:account:discover-schema, for connector version 2.output_count=1 keep_alive_count=0 state_count=0. Elapsed time 815ms

Is the Identity Fusion connector supposed to be the only authoritative source in a tenant? Ideally, we would want this to take in the sources that we currently have as “authoritative”, and use that to establish a baseline and begin to merge.

But if this connector only functions properly by processing uncorrelated and accounts, and an existing tenant with several auth sources HAS no uncorrelated accounts - how can this functionality still be used?

My only thought is to convert existing auth sources into non-auth, but the logically challenge that pose is huge.

This is a bug in ISC that is being fixed so it should be resolved in the next few days.

2 Likes