Saas Connector - custom - access requests not routing to approval step

We have a custom saas connector - scim built very similar to the one from demo days 2024 by @mbluteau

Everything works as expected in the sandbox, but production access requests (access profile) are not routing to the approval step.

The following does work in prod as expected -

  • test connection
  • account aggregation
  • entitlement aggregation
  • enable/disable account
  • create account via CLI

Access requests - approval configured or not, never make it past the “PENDING” stage. Anyone seen this?

Thanks!

Hi @questjj,

Have you tried using the command sail conn logs to retrieve the logs from ISC? It might provide more details about why the access requests are stuck in the PENDING stage.
Link for logging,

Hope this helps!

Yes, sail conn logs shows no trace of activity. I can see connector activity for things like enable/disable. Since the request isnt even routing to approval, I wouldnt think I would see anything in the sail conn log. Requests are stuck at the initial step, prior to moving to the approval phase so we havent even entered into the connectors custom logic yet.

The behavior is similar to if you wrote a JDBC connector with openconnector and never wired up the jdbcProvisionRule, except this will enter provisioning for other commands such as enable/disable.

Okay, got it. I think there is an issue with Access Profile. Could you please ensure that the access profile is correctly linked to the entitlements in production. Meaning, run an entitlement aggregation to see if that has changed or not.
Also, check if you have enabled the Access Profile in Prod.

Thanks Sachin, ive done all that, looks fine. Im wondering if the account schema for this connector type requires the entitlement attribute to be named “groups”. Would be odd, but looking at the documentation it states:

  • groupAttribute: Identifies the attribute used to map accounts to entitlements. For example, a web service can define groups that users are members of, and the groups grant entitlements to each user. In this case, groupAttribute is “groups,” and there is also an account attribute called “groups”.
1 Like

I think you might be right about this. After reading this I remember I haven’t built a connector with any other entitlement types apart from “groups”

I think @fernando_delosrios may have mentioned something like this but my memory is fuzzy. He can chime in if that’s the case.

I caught that entitlement type has to be “groups” a while back, but wondered if I also had to have “groups” as the attribute name on the account schema, where I was mapping “products” attribute to entitlement type “groups”. Tried renaming/remapping the account attribute to “groups”, didnt help.

One thing that is different in the airtable vs discourse examples is in the account schema, on the attribute type if you select type “groups” or type “string”. Would like to know that answer. I’ve tried all the combinations but could be missing something.

Can you post your connector_spec.json file?

Hi guys, we currently support multiple entitlement schemas. It’s just a question of aligning your entitlement schemas with your connector responses, especially the entitlement type.

One thing you may want to check is that your account schema includes an entitlement attribute of the same type you’re requesting. I’d say you do since you were able to create the AP, but check anyway. If you find this was incorrectly configured or you made account schema changes after your entitlement aggregation, reset the entitlements, aggregate them and try again. Ultimately, check there’s no pending manual task that may have been created if for some reason you didn’t register the account create/update operation correctly.

HTH

Also, you may want to have a look at this connector as an example of how to manage multiple entitlement types: IdentityNow Management Connector. It is important your account attributes are set with the right entitlement type and that you aggregate your entitlements AFTER this is set. For those account attributes which are entitlements but no entitlement schema is selected, I don’t really know how they’re reported to the connector, with which type. It would be a matter of debugging it.

Thanks for the replies, ive dumbed this connector down to a single entitlement with a single id/name pair in the entitlement schema, just to see if I could get provisioning to fire. Entitlements aggregate and get attached to accounts without issue.

But please note, provisioning works in our sandbox tenant with no issue. I am leaning towards an issue with this particular tenant.

Heres the spec file:

{
    "name": "lhc-saas-nvoq",
    "commands": [
        "std:account:create",
        "std:account:disable",
        "std:account:enable",
        "std:account:update",
        "std:account:list",
        "std:account:read",
        "std:test-connection",
        "std:entitlement:list",
        "std:entitlement:read"
    ],
    "sourceConfig": [
        {
            "type": "menu",
            "label": "Configuration",
            "items": [
                {
                    "type": "section",
                    "sectionTitle": "Authentication",
                    "sectionHelpMessage": "Provide connection parameters to interact securely with the target application.",
                    "items": [
                        {
                            "key": "token",
                            "label": "Token",
                            "type": "secret"
                        },
                        {
                            "key": "baseUrl",
                            "label": "BaseUrl",
                            "type": "text"
                        },
                        {
                            "key": "tenant",
                            "label": "Tenant",
                            "type": "text"
                        },
                        {
                            "key": "plan",
                            "label": "Plan",
                            "type": "text"
                        },
                        {
                            "key": "rootOrgId",
                            "label": "Root OrgId",
                            "type": "text"
                        },
                        {
                            "key": "voiceJobDisciplines",
                            "label": "Voice JobDisciplines",
                            "type": "list",
                            "helpKey": "Add a list of Job Disciplines to provision nVoq.Voice (Desktop)"
                        },
                        {
                            "key": "idnUrl",
                            "label": "IdentityNow Url",
                            "type": "text",
                            "helpKey": "IdN API Url"
                        },
                        {
                            "key": "idnClientId",
                            "label": "IdentityNow ClientId",
                            "type": "text",
                            "helpKey": "IdentityNow ClientId"
                        },
                        {
                            "key": "idnClientSecret",
                            "label": "IdentityNow Client Secret",
                            "type": "secret",
                            "helpKey": "IdentityNow Client Secret"
                        }
                    ]
                }
            ]
        }
    ],
    "accountSchema": {
        "displayAttribute": "username",
        "identityAttribute": "email",
        "attributes": [
            {
                "name": "uuid",
                "type": "string",
                "description": "Unique identifier for the user account"
            },
            {
                "name": "username",
                "type": "string",
                "description": "Username for the user account"
            },
            {
                "name": "firstName",
                "type": "string",
                "description": "First name of the user account"
            },
            {
                "name": "lastName",
                "type": "string",
                "description": "Last name of the user account"
            },
            {
                "name": "email",
                "type": "string",
                "description": "Email address associated with the user account"
            },
            {
                "name": "enabled",
                "type": "string",
                "description": "Indicates if the account is enabled"
            },
            {
                "name": "user_id",
                "type": "string",
                "description": "Secondary identifier for the user account"
            },
            {
                "name": "groups",
                "type": "group",
                "managed": true,
                "multi": true,
                "entitlement": true,
                "description": "List of product identifiers associated with the user account"
            },
            {
                "name": "user_roles",
                "type": "string",
                "multi": true,
                "entitlement": false,
                "description": "List of Roles identifiers associated with the user account"
            },
            {
                "name": "access",
                "type": "string",
                "description": "Access rights or permissions for the user account"
            },
            {
                "name": "clientGroupOrgTree",
                "type": "string",
                "description": "Organizational hierarchy for the client group"
            },
            {
                "name": "clientGroup",
                "type": "string",
                "description": "lowest level client group"
            },
            {
                "name": "adminOrgTree",
                "type": "string",
                "description": "Organizational hierarchy for the admin group"
            },
            {
                "name": "adminRole",
                "type": "string",
                "description": "Administrative role for the user account"
            },
            {
                "name": "trial",
                "type": "string",
                "description": "trial"
            },
            {
                "name": "plan",
                "type": "string",
                "description": "plan"
            },
            {
                "name": "orderedProducts",
                "type": "string",
                "description": "orderedProducts"
            }
        ]
    },
    "entitlementSchemas": [
        {
            "type": "group",
            "displayAttribute": "name",
            "identityAttribute": "id",
            "attributes": [
                {
                    "name": "id",
                    "type": "string",
                    "description": "Unique id"
                },
                {
                    "name": "name",
                    "type": "string",
                    "description": "name"
                }

            ]
        }
    ],
    "accountCreateTemplate": {
		"fields": [
			{
				"key": "username",
				"label": "username",
				"type": "string",
				"required": true,
				"initialValue": {
					"type": "identityAttribute",
					"attributes": {
						"name": "identificationNumber"
					}
				}
			},
			{
				"key": "email",
				"label": "email",
				"type": "string",
				"required": true,
				"initialValue": {
					"type": "identityAttribute",
					"attributes": {
						"name": "email"
					}
				}
			},
			{
				"key": "firstName",
				"label": "firstName",
				"type": "string",
				"required": true,
				"initialValue": {
					"type": "identityAttribute",
					"attributes": {
						"name": "firstName"
					}
				}
			},
			{
				"key": "lastName",
				"label": "lastName",
				"type": "string",
				"required": true,
				"initialValue": {
					"type": "identityAttribute",
					"attributes": {
						"name": "lastName"
					}
				}
			},
			{
				"key": "enabled",
				"label": "enabled",
				"type": "string",
				"required": true,
				"initialValue": {
					"type": "static",
					"attributes": {
						"value": "true"
					}
				}
			},
			{
				"key": "jobDiscipline",
				"label": "jobDiscipline",
				"type": "string",
				"required": true,
				"initialValue": {
					"type": "identityAttribute",
					"attributes": {
						"name": "jobDiscipline"
					}
				}
			},
			{
				"key": "serviceLine",
				"label": "serviceLine",
				"type": "string",
				"required": true,
				"initialValue": {
					"type": "identityAttribute",
					"attributes": {
						"name": "serviceLine"
					}
				}
			},
			{
				"key": "employeeId",
				"label": "employeeId",
				"type": "string",
				"required": true,
				"initialValue": {
					"type": "identityAttribute",
					"attributes": {
						"name": "identificationNumber"
					}
				}
			}
        ]
    }
}

Also, as I was worried there were stuck tasks or entitlement changes confusing things while debugging that could impact request flow, I deployed a new connector type, different name, wired up a new source to this connector type, ent agg, account agg, access profile creation… Same result.

You can see here, an access profile request, with no approvals configured is stuck in a Pending state indefinitely.

As a test, I deployed a second Saas Framework connector to this source and it did move past pending state. Very strange.