Web Services SaaS Connector

Using the new web services saas source to connect and provision to a custom rest service and finding strange behavior from the add entitlement calls.

Previously (using the web services connect via VA) I would expect the following HTTP operations to happen when requesting two entitlements for a source where the user didn’t previously exist:

  1. Create user
  2. Add entitlement: entitlement 1
  3. Add entitlement: entitlement 2

Using the new connector I get a different behavior:

  1. Create user
  2. Add entitlement: entitlement1,entitlement2
  3. Add entitlement: entitlement1,entitlement2

I am still getting the same number of requests come to the API of the end application, however the two entitlement requests including both entitlements requested in csv format.

Is anyone else seeing similar behavior??

I have tried messing with the “Add or Remove Entlitlements in s Single Request” under Additional Settings however if the box is checked then I get further funny behavior of getting 2 x create user requests and no entitlement requests.

Any help greatly appreaciated!

Cheers

Hi Chris,
Thank you for your post.
Have you implemented the methods of the custom connector ?
Could you please let us know how did you implement the custom connector ?

Hi Rakesh, this isn’t a custom connector. It is a web-services-saas.

Thanks

Chris

Chris. Can you link to the documentation you followed when configuring this connector? Also, can you share your configuration details, minus any sensitive information?

Hi @colin_mckibben

Here is the source… configured just like the standard web services connector (that works via VA).

{
    "description": "xxx",
    "owner": {
        "type": "IDENTITY",
        "id": "xxx",
        "name": "chris.smith"
    },
    "cluster": {
        "type": "CLUSTER",
        "id": "0f93b7f3c1304c77b57830f28bb1e774",
        "name": "sp_connect_proxy_cluster"
    },
    "accountCorrelationConfig": {
        "type": "ACCOUNT_CORRELATION_CONFIG",
        "id": "f1d1cea77767416bbb1e89b8fca5bd83",
        "name": "xxx"
    },
    "accountCorrelationRule": null,
    "managerCorrelationMapping": null,
    "managerCorrelationRule": null,
    "beforeProvisioningRule": null,
    "schemas": [
        {
            "type": "CONNECTOR_SCHEMA",
            "id": "3ec6fbee14b4425e9db102368274ebc9",
            "name": "account"
        },
        {
            "type": "CONNECTOR_SCHEMA",
            "id": "9b503ff2e97445ddac5071f96f715d5f",
            "name": "projects"
        },
        {
            "type": "CONNECTOR_SCHEMA",
            "id": "0a72f71140964e8fbbabfda4994f7039",
            "name": "groups"
        },
        {
            "type": "CONNECTOR_SCHEMA",
            "id": "5e4b263e88f44d9fb9136c7a7fd774a5",
            "name": "global_roles"
        }
    ],
    "passwordPolicies": null,
    "features": [
        "PROVISIONING",
        "ENABLE",
        "PASSWORD",
        "UNLOCK"
    ],
    "type": "7aa95c2a-6c38-4f39-9bb9-040f11641ee3",
    "connector": "web-services-saas",
    "connectorClass": "",
    "connectorAttributes": {
        "healthCheckTimeout": 90,
        "idnProxyType": "sp-connect",
        "ServerTimeZone": null,
        "deltaAggregationEnabled": false,
        "accesstoken": null,
        "connectionType": "direct",
        "client_id": "xxx",
        "spConnectorInstanceId": "6fa1f603-9fbb-4058-ba58-cde883a5f79a",
        "dateEvalFormat": null,
        "password": null,
        "addRemoveEntInSingleReq": true,
        "cloudExternalId": "76362",
        "client_secret": "xxx",
        "sourceConnected": true,
        "createAccountWithEntReq": false,
        "disableCookies": false,
        "private_key": null,
        "formPath": null,
        "objectNotFoundErrorMsg": null,
        "refresh_token": null,
        "cloudCacheUpdate": 1695143628620,
        "privateKeyPassword": null,
        "authenticationMethod": "OAuth2Login",
        "connectorName": "Web Services SaaS",
        "enableStatus": null,
        "since": "2023-09-19T12:36:23.204452Z",
        "status": "SOURCE_STATE_HEALTHY",
        "spConnectorSupportsCustomSchemas": true,
        "supportsDeltaAgg": true,
        "skipGetObjectInCreate": true,
        "oAuthJwtHeader": null,
        "genericWebServiceBaseUrl": "xxx",
        "connectionParameters": [
            {
                "httpMethodType": "GET",
                "pagingInitialOffset": 0,
                "sequenceNumberForEndpoint": "1",
                "uniqueNameForEndPoint": "Test Connection",
                "curlCommand": null,
                "rootPath": null,
                "body": {
                    "bodyFormData": null,
                    "jsonBody": null,
                    "bodyFormat": null
                },
                "customAuthUrl": null,
                "paginationSteps": null,
                "responseCode": [
                    "200"
                ],
                "resMappingObj": null,
                "contextUrl": "/getUsers3?applicationName=xxx",
                "pagingSize": 50,
                "curlEnabled": false,
                "header": null,
                "operationType": "Test Connection",
                "parentEndpointName": null
            },
            {
                "httpMethodType": "GET",
                "pagingInitialOffset": 0,
                "sequenceNumberForEndpoint": "2",
                "uniqueNameForEndPoint": "Account Aggregation",
                "curlCommand": null,
                "rootPath": "items",
                "body": {
                    "bodyFormData": null,
                    "jsonBody": null,
                    "bodyFormat": null
                },
                "customAuthUrl": null,
                "paginationSteps": "TERMINATE_IF $response.hasNext$ != TRUE\n$endpoint.fullUrl$ = $application.baseUrl$ + \"/getUsers3?applicationName=xxx&limit=100&next=\" + $response.cursor$",
                "responseCode": [
                    "200"
                ],
                "resMappingObj": {
                    "projects": "data.projects",
                    "last_login": "data.last_login",
                    "global_roles": "data.global_roles",
                    "groups": "data.groups",
                    "last_name": "data.last_name",
                    "is_administrator": "data.is_administrator",
                    "enabled": "enabled",
                    "username_href": "data.username_href",
                    "application": "application",
                    "created_on": "data.created_date",
                    "first_name": "data.first_name",
                    "email": "data.email",
                    "username": "username"
                },
                "contextUrl": "/getUsers3?applicationName=xxx&limit=100",
                "pagingSize": 50,
                "curlEnabled": false,
                "header": null,
                "operationType": "Account Aggregation",
                "parentEndpointName": null
            },
            {
                "httpMethodType": "POST",
                "pagingInitialOffset": 0,
                "sequenceNumberForEndpoint": "3",
                "uniqueNameForEndPoint": "provisionUser",
                "curlCommand": null,
                "rootPath": null,
                "body": {
                    "bodyFormData": null,
                    "jsonBody": "{\n    \"email\": \"$plan.email$\",\n    \"username\": \"$plan.nativeIdentity$\",\n    \"first_name\": \"$plan.first_name$\",\n    \"last_name\": \"$plan.last_name$\",\n    \"applicationName\": \"xxx\"\n}",
                    "bodyFormat": "raw"
                },
                "customAuthUrl": null,
                "paginationSteps": null,
                "responseCode": [
                    "200"
                ],
                "resMappingObj": null,
                "contextUrl": "/provisionUser",
                "pagingSize": 50,
                "curlEnabled": false,
                "header": null,
                "operationType": "Create Account",
                "parentEndpointName": null
            },
            {
                "httpMethodType": "POST",
                "pagingInitialOffset": 0,
                "sequenceNumberForEndpoint": "4",
                "uniqueNameForEndPoint": "AddEntitlement-groups",
                "curlCommand": null,
                "rootPath": null,
                "body": {
                    "bodyFormData": null,
                    "jsonBody": "{\n\"applicationName\": \"xxx\",\n\"username\": \"$plan.nativeIdentity$\",\n\"group\": \"$plan.groups$\",\n\"entitlementType\": \"group\"\n}",
                    "bodyFormat": "raw"
                },
                "customAuthUrl": null,
                "paginationSteps": null,
                "responseCode": [
                    "200"
                ],
                "resMappingObj": null,
                "contextUrl": "/addEntitlement",
                "pagingSize": 50,
                "curlEnabled": false,
                "header": null,
                "operationType": "Add Entitlement-groups",
                "parentEndpointName": null
            },
            {
                "httpMethodType": "GET",
                "pagingInitialOffset": 0,
                "sequenceNumberForEndpoint": "5",
                "uniqueNameForEndPoint": "Get Object",
                "curlCommand": null,
                "rootPath": "items",
                "body": {
                    "bodyFormData": null,
                    "jsonBody": null,
                    "bodyFormat": null
                },
                "customAuthUrl": null,
                "paginationSteps": null,
                "responseCode": [
                    "200"
                ],
                "resMappingObj": {
                    "projects": "data.projects",
                    "last_login": "data.last_login",
                    "global_roles": "data.global_roles",
                    "groups": "data.groups",
                    "last_name": "data.last_name",
                    "is_administrator": "data.is_administrator",
                    "enabled": "enabled",
                    "username_href": "data.username_href",
                    "application": "application",
                    "created_on": "data.created_date",
                    "first_name": "data.first_name",
                    "email": "data.email",
                    "username": "username"
                },
                "contextUrl": "/getUser?applicationName=xxx&username=$getObject.nativeIdentity$",
                "pagingSize": 50,
                "curlEnabled": false,
                "header": null,
                "operationType": "Get Object",
                "parentEndpointName": null
            }
        ],
        "lockStatus": null,
        "oauth_request_parameters": {
            "audience": "xxx"
        },
        "grant_type": "CLIENT_CREDENTIALS",
        "hasFullAggregationCompleted": true,
        "deltaAggregation": {
            "std:entitlement:list": null,
            "std:account:list": null
        },
        "possibleHttpErrorMessages": null,
        "connectionTimeout": "60",
        "token_url": "xxx",
        "spConnEnableStatefulCommands": false,
        "oauth_body_attrs_to_exclude": null,
        "spConnectorSpecId": "7aa95c2a-6c38-4f39-9bb9-040f11641ee3",
        "deleteThresholdPercentage": 10,
        "oauth_headers": null,
        "privateKey": null,
        "templateApplication": "Web Services SaaS",
        "apiToken": null,
        "healthy": true,
        "private_key_password": null,
        "cloudDisplayName": "xxx (WS SaaS)",
        "oAuthJwtPayload": null,
        "oauth_headers_to_exclude": null,
        "updateAttrWithChangePassword": false,
        "beforeProvisioningRule": null,
        "username": null
    },
    "deleteThreshold": 10,
    "authoritative": false,
    "healthy": true,
    "status": "SOURCE_STATE_HEALTHY",
    "since": "2023-09-19T12:36:23.204452Z",
    "connectorId": "web-services-saas",
    "connectorName": "Web Services SaaS",
    "connectionType": "direct",
    "connectorImplementationId": "web-services-saas",
    "managementWorkgroup": null,
    "id": "d453cbd29b274b7db562b68152ee40db",
    "name": "xxx (WS SaaS)",
    "created": "2023-09-18T19:51:32.439Z",
    "modified": "2023-09-28T13:03:32.672Z"
}

Think the issue is that $plan.groups$ is giving me a CSV of all of the groups in the plan rather than 2 x addEntitlement method each with one of the entitlements.

Cheers,

Chris

The part I’m confused on is which “web service connector” you are using. You say you are using one configured just like the VA version. Can you be very specific on which connector you used? A link to the documentation your referenced would make that clear.

Sorry I thought it was obvious from the json above:

"connectorName": "Web Services SaaS",

Here is a link to the SailPoint documentation site:
https://documentation.sailpoint.com/connectors/saas/web_services/help/SaaS_Connectivity/Web_Services/Integrating_SailPoint_Web_Services.html

Oh I see. It’s a generic web service connector built on the new SaaS connectivity framework. In my opinion, I would skip the web service saas connector and either use the VA based web service connector or just build your own SaaS connector using our extensive documentation: SaaS Connectivity | SailPoint Developer Community. The web service SaaS connector doesn’t give you any benefit over using one of the other two options. My recommendation is as follows:

The webservice Saas connector, like the VA based one, works well when your web service fits within the intended configuration options provided in the UI. As soon as your web service behaves differently than what the connector expects, it becomes much more difficult to implement and troubleshoot, which is what you seem to be encountering here.

@colin_mckibben yeah just seems very strange that it would send the same request to the addEntitlement end point twice. Like exactly the same request and then have a csv of the two entitlements (the same in both requests) which would have previously been sent in two separate requests (as single values vs concatenated in a csv).

Can anyone check that this is the intended functionality as it seems like it would be a very limiting factor in the usage of the new connector type. Potentially a bug?

As I can recode the backend endpoint to accept the CSV, and ignore the multiple requests, but don’t want to do that if it is a bug that is going to be fixed.

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