# SailPoint Web Services Connector Documentation > Web Services VA Connector Documentation # Documentation # Web Services Before/After Operation Rule > [!WARNING] > > When creating custom rules, verify that any log events that contain sensitive data are removed. If you add custom log events for testing while creating custom rules, they may expose sensitive data in the log files. The Web Services connector uses the following operation rules: - [Web Services Before Operation Rule](<#before-operation-rule>) - [Web Services After Operation Rule](<#after-operation-rule>) You can create Before and After Operation rules through the [Create Connector Rule]() API, as well as update them through the [Update Connector Rule]() API. > [!NOTE] > > **Standard Template for the Before Operation Rule** > > ```json > { > "description": "The Web Services connector will call this rule before performing ANY defined operation.\nThis rule can be used to add/update values in the endpoint object before performing the operation and/or add persistent values to the application's data.", > "type": "WebServiceBeforeOperationRule", > "signature": { > "input": [ > { > "name": "application", > "description": "The application associated with the operation being processed.", > "type": null > }, > { > "name": "requestEndPoint", > "description": "The current request information containing the header, body, context url, method type, response attribute map, and response code. \nThis object can be modified directly and returned by the rule to update the endpoint information \n that is used by the current operation", > "type": null > }, > { > "name": "oldResponseMap", > "description": "earlier response object ", > "type": null > }, > { > "name": "restClient", > "description": "REST Client Object", > "type": null > }, > { > "name": "provisioningPlan", > "description": "A ProvisioningPlan object containing the payload of the http request. A provisioning plan has an account request which defines the operation to be performed on the account. \n An account request can contain multiple attribute requests and each attribute request represents an operation on a single account attribute.", > "type": null > }, > { > "name": "partition", > "description": "If applicable, a Partition object with the current aggregation's partitioning information.", > "type": null > } > ], > "output": { > "name": "Map", > "description": "An updated or unmodified 'requestEndPoint' object. If application object modifications are desired, create a map containing keys 'updatedEndPoint' and 'connectorStateMap' and use it as the return value; \n Within the new map, the 'updatedEndPoint' can be set to an updated or unmodified 'requestEndPoint' object. \nThe 'connectorStateMap' will be saved as persistent values in the application definition.", > "type": null > } > }, > "sourceCode": { > "version": "1.0", > "script": "// source code" > }, > "attributes": null, > "id": "2b9280857b252a16017130d8a7756f24", > "name": "Before Operation Rule Template for Web Services Connector", > "created": "2021-08-10T15:57:58.005Z", > "modified": "2023-01-30T10:47:42.124Z" > } > ``` > [!NOTE] > > You need to add the `beforeRule` as explained in [SailPoint's Rule Guide]() to use the Web Service Before Operation Rule. > [!NOTE] > > **Standard Template for the After Operation Rule** > > ```json > { > "description": "The Web Services connector will call this rule after performing ANY defined operation. \nThis rule can be used to update the parsed resource object and/or add persistent values to the application's data. ", > "type": "WebServiceAfterOperationRule", > "signature": { > "input": [ > { > "name": "application", > "description": "The application whose data file is being processed.", > "type": null > }, > { > "name": "requestEndPoint", > "description": "The current request information contain header, body ,response object", > "type": null > }, > { > "name": "processedResponseObject", > "description": "Response Object processed by the Web services connector", > "type": null > }, > { > "name": "rawResponseObject", > "description": "Response Object returned from the end system", > "type": null > }, > { > "name": "restClient", > "description": "REST Client Object", > "type": null > } > ], > "output": { > "name": "Map", > "description": "A newly created map containing a 'data' key and optionally, a 'connectorStateMap' key. The 'data' value should be set to a map containing a parsed list of accounts/groups.\nThe 'connectorStateMap' value can be set to a map containing values that will be persisted to the application definition.", > "type": null > } > }, > "sourceCode": { > "version": "1.0", > "script": "\nimport sailpoint.object.ResourceObject;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap; " > }, > "attributes": null, > "id": "2c9180857b252a16017b30c8e75c6e23", > "name": "After Operation Rule Template for Web Services Connector", > "created": "2021-08-10T15:57:57.980Z", > "modified": "2021-08-31T08:14:12.647Z" > } > ``` > [!NOTE] > > You need to add the `afterRule` as explained in [SailPoint's Rule Guide]() to use the Web Service After Operation Rule. ## Before Operation Rule The Before Operation Rule is used to calculate attributes before a web service operation call. This rule is used by the Web Services connector before performing operations such as Test Connection and Aggregation. > [!NOTE] > > Refer to [Java docs]() for more information. ### Input Objects The following table lists the input objects for `WebServiceBeforeOperationRule`: | Object | Type | Description | | --- | --- | --- | | `application` | `sailpoint.object.Application` | The application whose data file is being processed. | | `requestEndPoint` | `sailpoint.connector.webservices.EndPoint` | Current request information. It contains the header, body, context URL, method type, response attribute map, successful response code. | | `oldResponseMap` | `java.util.Map` | The response object returned from earlier endpoint configuration of the same operation type, such as Account Aggregation, Get Object, etc. | | `restClient` | `sailpoint.connector.webservices.WebServicesClient` | A Web Services Client (HTTP Client) object that enables you to call the Web Services API target system. | | `provisioningPlan` | `sailpoint.object.ProvisioningPlan` | Used to update the payload of the HTTP request. A provisioning plan has an account request which defines the operation to be performed on the account. An account request can contain multiple attribute requests, and each attribute request represents an operation on a single account attribute. This argument enables the user to update the body/payload or URL attributes of the endpoint object using the `provisioningPlan` information. | ### Return Objects The Web Services Before Operation Rule uses the following return objects: ```text sailpoint.connector.webservices.EndPoint sailpoint.connector.webservices.Map ``` The rule allows the user to return the endpoint object (`requestEndPoint`) or a map. The map can hold `updatedEndPoint` and `connectorStateMap` keys, where the value expected is the `Endpoint` (`requestEndPoint`) and `connectorStateMap` objects, respectively. The `connectorStateMap` object is a map that contains the key and value of the attribute that must be updated in the application through the Before Operation Rule. ### Examples of the Before Operation Rule The following example displays the rule used by the Web Services connector before performing operations such as Test Connection and Aggregation. > [!NOTE] > > **Before Operation Rule Example** > > ```xml > > > > > This rule is used by the Web Services connector before performing any operation like testconnection, aggregation etc. > > import com.google.gson.Gson; > import sailpoint.tools.Util; > Map obj = (Map) application.getAttributeValue("transientValues"); > if(null != obj) { > String cursor = obj.get("cursor"); > if(Util.isNotNullOrEmpty(cursor)) { > Map postBodyMap = (Map) requestEndPoint.getBody(); > postBodyMap.put("jsonBody", "{\"cursor\":\"" + cursor + "\"}"); > requestEndPoint.setFullUrl(requestEndPoint.getFullUrl() + "/continue"); > } > } > return requestEndPoint; > > ]]> > > ``` The following example is for the `provisioningPlan` rule: > [!NOTE] > > **Before Operation Rule Example for provisioningPlan** > > ```java > import java.util.ArrayList; > import java.util.HashMap; > import java.util.Map; > import connector.common.JsonUtil; > import connector.common.Util; > import sailpoint.connector.webservices.EndPoint; > import sailpoint.connector.webservices.WebServicesClient; > import sailpoint.object.Application; > import sailpoint.object.ProvisioningPlan; > import sailpoint.object.ProvisioningPlan.AccountRequest; > > Map body = requestEndPoint.getBody(); > String jsonBody = (String) body.get("jsonBody"); > log.info("Rule - Modify Body: running"); > > try { > > Map jsonMap = JsonUtil.toMap(jsonBody); > if (jsonMap != null) { > Object roleEntry = jsonMap.get("webSiteAndRole"); > String role = ""; > if (roleEntry != null && roleEntry instanceof ArrayList) { > ArrayList rolesArray = (ArrayList) roleEntry; > if (rolesArray.size() > 0) { > role = (String) rolesArray.get(0); > } > } else if (roleEntry != null) { > role = (String) roleEntry; > } > > jsonMap.remove("webSiteAndRole"); > jsonMap.put("webSiteAndRole", role); > > log.info("Rule - Modify Body: setting webSiteAndRole = " + role); > String webID = ""; > if (provisioningPlan != null) { > log.info("Rule - Modify Body: plan is not null"); > for (AccountRequest accReq : Util.iterate(provisioningPlan.getAccountRequests())) { > log.info("Rule - Modify Body: iterating over account requests"); > for (ProvisioningPlan.AttributeRequest attReq : Util.iterate(accReq.getAttributeRequests())) { > log.info("Rule - Modify Body: iterating over attribute requests"); > String attrName = attReq.getName(); > String value = null; > if (attrName != null && "webId".equalsIgnoreCase(attrName)) { > webID = (String) attReq.getValue(); > log.info("Rule - Modify Body: setting webID = " + webID); > } > } > } > } else { > log.info("Rule - Modify Body: plan is null"); > } > > if (!"".equals(webID)) { > jsonMap.put("webID", webID); > } > > // Add in any other missing fields > if (!jsonMap.containsKey("webLogonEmail")) { > jsonMap.put("webLogonEmail", ""); > } > > if (!jsonMap.containsKey("taxID")) { > jsonMap.put("taxID", ""); > } > > if (!jsonMap.containsKey("taxIdType")) { > jsonMap.put("taxIdType", ""); > } > > if (!jsonMap.containsKey("actorLogonId")) { > jsonMap.put("actorLogonId", ""); > } > > String finalBody = JsonUtil.render(jsonMap); > body.put("jsonBody", finalBody); > requestEndPoint.setBody(body); > } > } catch (Exception ex) { > log.error("Rule - Modify Body: " + ex); > } > > return requestEndPoint; > ``` The following is an example of the Web Services connector executing the Before Operation Rule on a target system API: > [!NOTE] > > **Before Operation Rule Example Executed on a Target System API** > > ```java > import connector.common.JsonUtil; > import sailpoint.connector.webservices.WebServicesClient; > try { > WebServicesClient client = new WebServicesClient(); > String url = "http://hostname:portnumber/RestFormDataWS/beforeRuleMock"; > Map args = new HashMap(); > args.put(WebServicesClient.ARG_URL, url); > client.configure(args); > Map header = new HashMap(); > // Information can be fetched from requestEndpoint and updated in the header and body > header.put("Authorization","XXXX XXXX"); > header.put("Content-Type","application/json"); > > List allowedStatuses = new ArrayList(); > allowedStatuses.add("2**"); > > Map payload = new HashMap(); > payload.put("jsonBody","{\"user\":{\"userId\":\"RinkuSharma\",\"firstName\":\"Rinku\",\"lastName\":\"Sharma\",\"title\":\"manager\"}}"); > > String response = client.executePost(url, payload, header, allowedStatuses); > // if response contains token it can be updated in the requestEndpoint header or body > // the requestEndpoint will be used for execution of the particular operation configured > log.info("response: " + response); > } catch (Exception e) { > log.error(e.getMessage(), e); > } > ``` The following example displays the Before Operation Rule being used to update the values for endpoint and application attributes before execution of the endpoint: ```java Map updatedInfoMap = new HashMap(); requestEndPoint.setFullUrl(requestEndPoint.getFullUrl().replaceAll("&&", "&")); Map connectorStateMap = new HashMap(); connectorStateMap.put("accesstoken","Bearer accessTokenGeneratedInBeforeRuleScript"); updatedInfoMap.put("updatedEndPoint",requestEndPoint); updatedInfoMap.put("connectorStateMap",connectorStateMap); return updatedInfoMap; ``` ## After Operation Rule The After Operation Rule is used to calculate attributes after a web service operation call. It is used by the Web Services connector to update parsed resource objects and save `connectorStateMap` values. The list of objects converts to Resource objects and the `connectorStateMap` values are updated in the application object permanently. The returned map holds the `data` key for the resource object list and the `connectorStateMap` key for updated attributes that must be saved in the application. > [!NOTE] > > Refer to [Java docs]() for more information. ### Input Objects | Object | Type | Description | | --- | --- | --- | | `application` | `sailpoint.object.Application` | Application whose data file is being processed. | | `requestEndPoint` | `sailpoint.connector.webservices.EndPoint` | Current request information. It contains the header, body, context URL, method type, response attribute map, successful response code. | | `processedResponseObject` | `List>` | This object is a list of map objects for accounts and groups. The map objects contain keys as identity attributes for the application schema, and the associated values are all the account and group attributes passed by the connector after parsing the respective API response. | | `rawResponseObject` | `String` | String object which holds the raw response returned from the target system, which can be in JSON or XML form. | | `restClient` | `sailpoint.connector.webservices.WebServicesClient` | A Web Services Client (HTTP Client) object that enables you to call the Web Services API target system. | ### Return Objects > [!NOTE] > > **java.util.Map** > > The `Map` object returned from the After Operation Rule may contain any or all of the following: > > - Updated list of account/group resource objects; identified by key `data` > - Attribute values to be updated into the application via connector state map; identified by key `connectorStateMap` > > Each resource (account/group) object is a `Map`-type object which contains key-value pairs, where the key represents the schema attribute name and the value represents the account/group attribute value. ### Examples for After Operation Rules The following example displays the After Operation Rule used to update accounts, groups, and application attribute values after execution of the endpoint: > [!NOTE] > > **After Operation Rule Example for Updating Accounts, Groups, and Application Attributes** > > ```java > import java.util.HashMap; > import java.util.List; > import java.util.Map; > import java.util.Map.Entry; > import java.util.Iterator; > > //We can parse the response(rawResponseObject) to fetch from the respective executed Endpoint operation. > Map updatedMapInfo = new HashMap(); > if (processedResponseObject != null){ > > for (Map iterateMap : processedResponseObject) { > if (iterateMap != null ) { > Set keySet = iterateMap.keySet(); > for (String s : keySet) { > if (s.equals("given_name")) { > String forStr = (String) iterateMap.get("given_name"); > forStr = "TEST"+ forStr; > iterateMap.put("given_name", forStr); > } > } > } > } > updatedMapInfo.put("data", processedResponseObject); > } > Map connectorStateMap = new HashMap(); > connectorStateMap.put("refresh_token","refreshTokenGeneratedInAfterRuleScript"); > updatedInfoMap.put("connectorStateMap",connectorStateMap); > return updatedMapInfo; > ``` The following example displays the After Operation Rule being used by the Web Services connector to update the resource object: > [!NOTE] > > **After Operation Rule Example for Updating the Resource Object** > > ```java > import connector.common.JsonUtil; > import java.util.HashMap; > import java.util.Map.Entry; > import java.util.Map; > import java.util.List; > import java.util.ArrayList; > import javax.net.ssl.HttpsURLConnection; > import java.io.BufferedReader; > import java.io.PrintStream; > import java.io.StringWriter; > import java.text.SimpleDateFormat; > import sailpoint.tools.GeneralException; > > Map updatedMapInfo = new HashMap(); > List list = new ArrayList(); > ArrayList Roles = new ArrayList(); > Map response = (Map) JsonUtil.toMap(rawResponseObject); > int RoleSize = 0; > String newName; > List Finallist = new ArrayList(); > List workspace = new ArrayList(); > > log.error("RULEWS response at start" + response); > if (response.get("data") != null) { > > list = (ArrayList) response.get("data"); > > for(int d = 0; d < list.size(); d++ ){ > > Map responseMap = (Map) list.get(d); > > if (responseMap.get("attributes") != null) { > Map newmap = new HashMap(); > Map data = (Map) responseMap.get("attributes"); > newmap.put("firstName", data.get("firstName")); > newmap.put("lastName",data.get("lastName")); > newmap.put("displayName",data.get("displayName")); > newmap.put("userName",data.get("userName")); > newmap.put("email",data.get("email")); > > if (data.get("workspaceMemberships") != null) { > ArrayList Workspacedetail = (ArrayList) data.get("workspaceMemberships"); > for (int i = 0; i < Workspacedetail.size(); i++) { > Map work = (Map) Workspacedetail.get(i); > for (int w = 0; w < work.size(); w++) { > if (work.get("workspaceName") != null) { > workspace.add(work.get("workspaceName")); > Roles = (ArrayList) work.get("workspaceRoles"); > for (int r = 0; r < Roles.size(); r++) { > if (Roles.get(r) != null) { > newName = Roles.get(r).toString() + " - " + work.get("workspaceName"); > if(newName != null) { > Roles.set(r, newName); > newmap.put("workspaceRoles", Roles); > } > } > } > } > break; > } > } > } > > Finallist.add(newmap); > > } > } > > } > log.error("RULEWS newmap at end" + newmap); > log.error("RULEWS Finallist at end" + Finallist); > > log.error("RULEWS processedResponseObject Before is " + processedResponseObject); > > updatedMapInfo.put("data", Finallist); > log.error("RULEWS updatedMapInfo is " + updatedMapInfo); > > return updatedMapInfo; > log.error("RULEWS processedResponseObject after is " + processedResponseObject); > > ]] > ``` ## Web Services Classes Used in Before and After Operation Rules This section describes the following types of Web Services classes: - `WebServicesClient` - `EndPoint` class > [!NOTE] > > The Web Services classes mentioned in this section are general guidelines. New classes and methods may be added. ### WebServicesClient #### Constructor | Signature | Description | | --- | --- | | `public WebServicesClient()` | Default constructor. | | `public WebServicesClient(java.util.Map args) throws java.lang.Exception` | Constructor that configures the client using the given args. | #### Methods | Method | Description | | --- | --- | | `public void configure(java.util.Map args) throws java.lang.Exception` | Configure connection parameters. See the `ARG_*` constants. | | `public java.lang.String executeGet(java.util.Map headers, java.util.List allowedStatuses) throws java.lang.Exception` | Execute method GET with headers. Parameters: `headers` (Request headers), `allowedStatuses` (Allowed status codes). | | `public java.lang.String executeGet(java.lang.String url, java.util.Map headers, java.util.List allowedStatuses) throws java.lang.Exception` | Execute method GET with URL and headers. Parameters: `url` (Request URL), `headers` (Request headers), `allowedStatuses` (Allowed status codes). Returns a Response object. | | `public java.lang.String executePost(java.lang.String url, java.lang.Object payload, java.util.Map headers, java.util.List allowedStatuses) throws java.lang.Exception` | Execute method POST with URL, payload, and headers. Parameters: `url`, `payload` (Request body), `headers`, `allowedStatuses`. | | `public java.lang.String executePost(java.lang.String url, java.lang.Object payload, java.util.List allowedStatuses) throws java.lang.Exception` | Execute method POST with URL and payload. Parameters: `url`, `payload`, `allowedStatuses`. Returns a Response object. | | `public java.lang.String executePut(java.lang.String url, java.lang.Object payload, java.util.List allowedStatuses) throws java.lang.Exception` | Execute method PUT with URL and payload. Parameters: `url`, `payload`, `allowedStatuses`. | | `public java.lang.String executePut(java.lang.String url, java.lang.Object payload, java.util.Map headers, java.util.List allowedStatuses) throws java.lang.Exception` | Execute method PUT with URL, payload, and headers. Returns a Response object. | | `public java.lang.String executePatch(java.lang.String url, java.lang.Object payload, java.util.List allowedStatuses) throws java.lang.Exception` | Execute method PATCH with URL and payload. | | `public java.lang.String executePatch(java.lang.String url, java.lang.Object payload, java.util.Map headers, java.util.List allowedStatuses) throws java.lang.Exception` | Execute method PATCH with URL, payload, and headers. Returns a Response object. | | `public java.util.Map getResponseHeaders()` | Get last executed request's response headers. | | `public java.lang.String executeDelete(java.lang.String url, java.util.List allowedStatuses) throws java.lang.Exception` | Execute method DELETE with URL. Parameters: `url`, `allowedStatuses`. | | `public java.lang.String executeDelete(java.lang.String url, java.util.Map headers, java.util.List allowedStatuses) throws java.lang.Exception` | Execute method DELETE with URL and headers. Returns a Response object. | ### EndPoint Class #### Constructor | Signature | Description | | --- | --- | | `public EndPoint()` | Sets the EndPoint. | #### Methods | Method | Description | | --- | --- | | `public void setAfterRule(java.lang.String value)` | Sets the after rule name. | | `public void setBeforeRule(java.lang.String value)` | Sets the before rule name. | | `public void setParseRule(java.lang.String value)` | Sets the parsing rule. | | `public void setHttpMethodType(java.lang.String value)` | Sets the HTTP method (PUT, POST, GET, PATCH, and DELETE) for the particular operation (Create User, Update User, Account Aggregation, etc.). | | `public void setOperationType(java.lang.String value)` | Sets the operation (Account Aggregation, Group Aggregation, Create Account) for the particular operation record. | | `public void setRootPath(java.lang.String value)` | Sets the root of the JSON response returned from the managed system for the particular operation. | | `public void setBaseUrl(java.lang.String value)` | Sets the base URL (the machine ID or IP and the port where the service is executing) for the operation that needs to be performed. Ideally this should be common for all the operations. | | `public void setContextUrl(java.lang.String value)` | Sets the context URL for the particular operation. | | `public void setFullUrl(java.lang.String value)` | Sets the complete URL (endpoint) of the operation that needs to be performed for the particular operation. | | `public void setSequenceNumberForEndpoint(int value)` | Sets the sequence number for the particular operation. | | `public void setUniqueNameForEndPoint(java.lang.String value)` | Sets a unique operation name for the particular operation. | | `public void setResMappingObj(java.util.Map value)` | Sets the response mapping for the response attribute returned in the JSON response from the managed system for the particular operation. The key is the attribute name (attribute in the schema) and the value is the JSON response path after the root path. | | `public void setHeader(java.util.Map value)` | Sets HTTP header information in the form of key-value pairs (for example, `key='ContentType' Value='Application/JSON'`). | | `public void addHeader(java.lang.String entry, java.lang.String value)` | Adds a key-value pair if the header exists, or creates a header and adds it. | | `public void setBody(java.util.Map value)` | Sets the HTTP body information as a Map. The map contains three keys: `bodyFormat`, `bodyFormData`, and `jsonBody`. The `bodyFormat` value can be `raw`, meaning the user has provided values as a raw JSON string, otherwise the user has provided values in key-value format that must be converted into JSON. | | `public void setResponseCode(java.util.List value)` | Sets the value of successful response codes as a list (200, 299, 201). If the connector receives any other response codes, it considers them request failures. | | `public java.lang.String getAfterRule()` | Fetches the name of the after rule assigned to the particular operation. | | `public java.lang.String getBeforeRule()` | Fetches the name of the before rule assigned to the particular operation. | | `public java.lang.String getHttpMethodType()` | Fetches the HTTP method type (GET, PUT, POST, DELETE, and PATCH) provided to the particular operation. | | `public java.lang.String getOperationType()` | Fetches the operation type (Account Aggregation, Create Account, Group Aggregation) provided to the particular operation. | | `public java.lang.String getRootPath()` | Fetches the root path provided to the particular operation. | | `public java.lang.String getBaseUrl()` | Fetches the base URL, which is common for all operations. | | `public java.lang.String getContextUrl()` | Fetches the context URL provided to the particular operation. | | `public java.lang.String getFullUrl()` | Fetches the full URL, which is a combination of the base URL and the context URL for the particular operation. | | `public int getSequenceNumberForEndpoint()` | Fetches the sequence number for the particular operation, which decides the priority of execution for an operation if there are multiple endpoints of the same operation type. | | `public java.lang.String getUniqueNameForEndPoint()` | Fetches the unique name provided to the particular operation. | | `public java.util.Map getResMappingObj()` | Fetches the response mapping map, which has the key as the schema attribute and the value as a JSON path in the JSON response. | | `public java.util.Map getHeader()` | Fetches the HTTP header map that holds the header information for the particular operation. | | `public java.util.Map getBody()` | Fetches the body map that holds the body information with keys such as `bodyFormat`, `jsonBody`, and `bodyFormData`. `bodyFormat` can have `raw` or `formData` values; `bodyFormData` is a map; `jsonBody` is a string with the whole JSON code. | | `public java.util.List getResponseCode()` | Fetches the success response code list values, which decide whether an operation was successful, for the particular operation. | | `public sailpoint.object.Attributes getAttributes()` | Fetches all attributes. | | `public java.lang.Object getAttribute(java.lang.String name)` | Fetches a single attribute. | | `public Boolean getBooleanAttributeValue(java.lang.String name)` | Fetches a Boolean value for a specific attribute. | | `public java.lang.String getStringAttributeValue(java.lang.String name)` | Fetches a string value for a specific attribute. | | `public void setAttribute(java.lang.String name, java.lang.Object value)` | Sets a specified attribute to a specified value. | | `public java.lang.String getPaginationSteps()` | Fetches the paging steps as a string which decides how account and group paging works. | | `public void setPaginationSteps(java.lang.String paginationSteps)` | Sets the paging steps as a string which decides how account and group paging works. | | `public java.lang.String toString()` | Overrides `toString` in the `java.lang.Object` class. | | `public java.lang.String getResponseBody()` | Retrieves the last executed request's response body. | | `public void setXpathNamespaces(Map xpathNamespaces)` | Sets XPath namespaces using the supplied map object. | | `public Map getXpathNamespaces()` | Retrieves XPath namespaces. | | `public int getPagingInitialOffset()` | Retrieves the initial page offset. | | `public void setPagingInitialOffset(int pagingInitialOffset)` | Sets the initial paging offset. | | `public int getPagingSize()` | Retrieves the page limit. | | `public void setPagingSize(int pagingLimit)` | Sets the page limit. | # Configuration Parameters For the Web Services source you can configure the values of the following attributes using the SailPoint REST API. For the usage of the SailPoint REST APIs for the following attributes and keys, refer to: - API to get source details - [list-sources]() - API to get a specific source's current schema details - [list-schemas]() - API to add a new schema attribute to a source - [create-schema]() - [SailPoint REST API - Update Source (Partial)]() ## createAccountWithEntReq By default, the Web Services source creates an account for a `Create Account` operation and then adds the entitlements one by one. For example, if there are three entitlements (Role, Group, Profile), the source executes three requests and three API calls are sent. Adding the `createAccountWithEntReq` attribute merges all the entitlement requests in a single API call. Use the `createAccountWithEntReq` attribute key with the value `true` to enable the functionality of sending entitlements with create account in a single request to the managed system. Default value: `false` ## throwBeforeAfterRuleException During aggregation, if an exception is displayed from `WebServiceBeforeOperationRule` or `WebServiceAfterOperationRule`, then aggregation continues and completes successfully. Set the value of the `throwBeforeAfterRuleException` flag to `true` to terminate the aggregation by displaying an error message. This flag can be set only for Account and entitlement aggregation. Default value: `false` > [!NOTE] > > This flag is not applicable for child endpoints. ## throwProvBeforeRuleException During provisioning, Get Object, or Test Connection operations, if an exception is thrown by the Before Operation Rule, then the operation fails. To ignore the exception in the log file and proceed with provisioning, set the value of `throwProvBeforeRuleException` to `false`. This flag can be set for all operations except Account and entitlement aggregation. ## throwProvAfterRuleException During provisioning, Get Object, or Test Connection operations, if an exception is thrown by the After Operation Rule, then the operation fails. To ignore the exception in the log file and proceed with provisioning, set the `throwProvAfterRuleException` attribute key with `false` as a value. This flag can be set for all operations except Account and entitlement aggregation. ## enableHasMore If `enableHasMore` is set to `true`, then the termination of aggregation depends on the value of the `hasMore` attribute. Use the `enableHasMore` attribute key with `true` as a value. The `hasMore` attribute is the Boolean attribute that is set in the `transientValues` map in the Before or After Operation Rule. Unless the value of the `hasMore` attribute is `false`, aggregation isn't terminated. If `enableHasMore` is set to `false`, then the aggregation terminates if the number of accounts returned is zero. Use the `enableHasMore` attribute key with `false` as a value. ## lockStatus To use the Lock/Unlock feature, add the `lockStatus` attribute in the application Debug page as provided in the following example: ```xml ``` In the example, `status` is an account schema attribute that indicates if the account is locked or not. The value (`inactive`) helps the Web Services connector distinguish between the locked and unlocked account. The Web Services connector does not support provisioning of lock account. ## possibleHttpErrors If an API endpoint does not send expected error codes to flag failure conditions, you can manually configure error codes with all possible HTTP error codes and messages that the API endpoint might return, which can then result in the failure of operations. > [!NOTE] > > These errors don't prompt the connector to retry After Operation Rule errors or Before Operation Rule errors. Use the `possibleHttpErrors` attribute with `["errorCodes","errorMessages"]` as the value. Occasionally, the Web Services connector returns the HTTP status code `200` but the response payload may contain errors. In this case, the connector must fail the request, or an OAuth token generation must try to regenerate the token. You can also configure these possible HTTP error codes and messages to specify invalid or expired token errors. In this case, the connector regenerates and saves the token for OAuth 2.0 authentication, then retries the operation with the newly generated access token. > [!NOTE] > > This flag is not applicable for child endpoints. ## isGetObjectRequiredForPTA To use the Web Services source for Pass-Through Authentication, set the `isGetObjectRequiredForPTA` attribute key to `true`. For new Web Services sources, the default value for `isGetObjectRequiredForPTA` is `true`. - When set to `true`, it executes the Get Object operation to verify if the entered username (considered as an identity attribute) is present on the managed system or not. - When set to `false`, it skips the Get Object operation and the Pass-Through Authentication operation must have response mapping with account object schema attributes. Refer to [Pass-Through Authentication]() for more information. ## objectNotFoundErrorMsg Based on the error message list, the source decides whether to display the `objectNotFoundErrorMsg` error. For example, you can create an entry for `objectNotFoundErrorMsg` with a custom error message to identify multiple exceptions by setting the `objectNotFoundErrorMsg` attribute key with `["404: Not Found", "404"]` as the value. ## authenticationFailedErrorMsg Based on the error message list, the source decides whether to display the `authenticationFailedErrorMsg` error. For example, you can create an entry for `authenticationFailedErrorMsg` with custom error messages to identify exceptions (there can be multiple): - Key - `connector_authenticationFailedErrorMsg` - Value - `["Authentication Failed"]` ## expiredPasswordErrorMsg Based on the error message list, the source decides whether to throw the `expiredPasswordErrorMsg` error. For example, you can create an entry for `expiredPasswordErrorMsg` with a custom error message to identify exceptions (there can be multiple) by setting the `expiredPasswordErrorMsg` attribute key with `["Password Expired"]` as a value. If the response contains a string that matches `expiredPasswordErrorMsg`, then the connector redirects the user from the login page to the Change Password page. > [!NOTE] > > If you use OAuth 2.0 authentication and you have the error messages for expired password correctly set, the connector tries to refresh the access token after the first failed connection attempt if the authentication endpoint supports it. ## updateAttrWithChangePassword To enable single requests for change password and update operations, use the `updateAttrWithChangePassword` attribute key with `true` as a value. If the value of the `updateAttrWithChangePassword` attribute is `true` in the source and the plan contains no attribute request named "password" (change password), then the specific Update operation type endpoint is invoked. Setting the value of the `updateAttrWithChangePassword` attribute to `true` does not include requests for add or remove entitlements. These requests are executed independently. ## disableCookies By default, the Web Services source supports cookies. Disable cookies by adding the `disableCookies` attribute key with `true` as a value. This attribute is not applicable for the authentication API call operation. ## addRemoveEntInSingleReq Add or remove multiple entitlements such as Role, Permissions, or Profile. To send multiple entitlement requests in a single request to the managed system, set the value of the `addRemoveEntInSingleReq` parameter to `true` as shown in the following example: ```xml true ``` If `addRemoveEntInSingleReq` is set to `true`, then the payload for entitlements must also be set as shown in the following example: ```text {"group_id" : $plan.groups$, "permission":$plan.permission$, "roles": $plan.roles$ } ``` ## skipGetObjectInCreate The Web Services connector supports the `skipGetObjectInCreate` attribute (Boolean) to skip the `getObject` call if it is present during the Create provisioning operation. ## deleteStatus This attribute marks whether an object is deleted during delta aggregation. To set the value of `deleteStatus`, set the value as shown in the following example: ```xml ``` > [!NOTE] > > Additional configurable attributes are available beyond those documented here. Refer to the SailPoint REST API links above to list a source's current configuration and confirm available attribute keys before setting a new one. ## Configuration for Response When configuring the Web Services source, map the schema attribute as follows for JSON and XML. ### JSON Response Configuration Single endpoint - In a JSON response, all the attributes can be mapped as follows, considering the Root Path as `$.list`: ```text Id = id displayName = displayName username = jive.username enabled = jive.enabled emails = emails[*].value ``` Multiple endpoints - Refer to the following response example for the first and second endpoints: | Type | Response Example | Response Mapping | | --- | --- | --- | | First endpoint | `{"meta": {...}, "resources": ["01dcc3dd-5b72-4fb2-a43b-424e092bd6af", "032b704e-1467-48b3-ad70-29a04f1a20ab", "042ab092-918f-4ed3-97eb-196fbe917e77"], "errors": []}` | Response Attribute Mapping: `uid = $`. Root Path: `$.resources.*` | | Second endpoint | Context URL - `/users/entities/users/v1?ids=$response.uid$`. Example: `{"meta": {...}, "resources": [{"uid": "john.doe@santander.us", "firstName": "John", "lastName": "Doe", "uuid": "01dcc3dd-5b72-4fb2-a43b-424e092bd6af", "customer": "81971f9d094d494bae5a5fd97052509f"}], "errors": []}` | Response Attribute Mapping: `firstName = $.resources[0].firstName`, `lastName = $.resources[0].lastName`. Root Path: not required | Parsing JSON array - The following is an example for parsing a JSON array: ```json [1,10,21,31,46,89,90,67,88,98,101] ``` The response mapping for the above example is: - Response Attribute Mapping (`id` is an attribute in the schema): `id = $` - Root Path: `$.*` ### XML Response Configuration Example 1 - XML response for mapping: ```xml ..... true User 123456 Alias CName1 test@test.com false test@test.com Test Test 1 ``` Example 2 - XML response for mapping: ```xml DillardsEveryone example@example.com gage5.test5@test5.dillards.com ``` For more specific examples of the JSON and XML format responses or inputs for the supported fields or operations on the Web Services source, refer to [Operations Reference](). ## Additional Configuration Attributes for OAuth2 The following attributes are applicable only if **Authentication Type** is selected as OAuth2. For the Web Services source you can configure the values of these attributes using the SailPoint REST API. For the usage of the SailPoint REST APIs for these attributes and keys, refer to [list-sources](), [list-source-schemas](), [create-source-schema](), and [SailPoint REST API - Update Source (Partial)](). | Attribute | Description | | --- | --- | | `oauth_headers` | To have customized headers as a part of the access token generation request, use the `oauth_headers` attribute key with the value as `{"Content-Type":"application/x-www-form-urlencoded"}`. Web Services uses the access token configured in the application as the authorization header for each endpoint; users no longer need to specify the authorization header for each endpoint. If authorization is provided at the endpoint level, it takes precedence over the access token. SailPoint recommends providing the authorization header suffix in the access token provided (for example, `Bearer `). If no prefix is provided, Web Services uses `Bearer` as the default Authorization header prefix. To send additional headers for token generation, use the `saml_headers` attribute key with the value as `{"":""}`. | | `oauth_headers_to_exclude` | By default, an Authorization BASIC header with a Base64-encoded Client ID and Client Secret is part of the access token generation request. Some managed systems do not support this header. If there is no Authorization BASIC header required for such managed systems, it can be excluded from the request. Use the `oauth_headers_to_exclude` attribute key with the value as `"Authorization, Xrftoken"`. | | `oauth_request_parameters` | For some managed systems, custom request parameters may be required to be part of the access token generation request. Use the `oauth_request_parameters` attribute key with the value as `{"":""}`. Example body: `[{"op": "add", "path": "/connectorAttributes/oauth_request_parameters", "value": { "": "" }}]` | | `oauth_body_attrs_to_exclude` | To delete any of the standard request attributes which are not supported by managed systems' access token generation requests, use the `oauth_body_attrs_to_exclude` attribute key with the value as `"customParamKey,customParamValue"`. | | `saml_headers` | (Optional) Used for SAML assertion generation; if additional header information is required, use the `saml_headers` attribute key with the value as `{"":""}`. | | `saml_headers_to_exclude` | (Optional) Used for SAML assertion generation; the key provided here is excluded from the header while executing the SAML Assertion generation request. Use the `saml_headers_to_exclude` attribute key with the value as `"Authorization,CUSTOM_HEADER"`. | | `oAuthJwtHeader` | Contains the `alg` (algorithm used for signing the JWT assertion). Use the `oAuthJwtHeader` attribute key with the value as `["alg":"RS256"]`. If required, additional header attributes can be provided in this map. | | `oAuthJwtPayload` | Contains `aud` (Audience), `exp` (Expiry of the JWT assertion), `iss` (Issuer), and `sub` (Subject). Use the `oAuthJwtPayload` attribute key with the value as `["aud", "exp", "iss", "sub"]`. If required, additional payload attributes can be provided in this map. For additional attributes like `jti`, `iat`, `nbf`, if only the key (not the value) is available in the map, the connector uses the default values for those attributes. | # Configuring Web Services for Integration > [!WARNING] > > When configuring the source, do not hard code sensitive data. If sensitive data is hard coded, it can lead to that data being exposed when moving to a production environment. SailPoint recommends putting sensitive information in the encrypted attribute value list in the application XML and then using the encrypted variable name when configuring the source. For example, if you want to add the custom variable `Custom_Variable` in the encrypted list, append the variable name in the following list: `` This section describes the various configurations to be performed to support the following features. ## Pass-Through Authentication Configure Pass-Through Authentication on existing Web Services. 1. On the **Additional Settings** page, select the **Get Object Required for Pass-Through Authentication** checkbox. > **Notes** > > - When selected, it executes the Get Object operation to verify if the entered Username (considered an identity attribute) is present on the managed system or not. > - When deselected, it skips the Get Object operation and the Pass-Through Authentication operation must have response mapping with account object schema attributes. 2. (Optional) If you need to configure error messages for Pass-Through Authentication, use the following entry keys: - `objectNotFoundErrorMsg` - `authenticationFailedErrorMsg` - `expiredPasswordErrorMsg` The following process is an example to configure Pass-Through Configuration. ### Pass-Through Authentication General Information 1. In the **Operation Name** field, enter `Pass-Through Authentication` as the operation name. 2. From the **Operation Type** dropdown list, select **Pass-Through Authentication**. 3. In the **Authentication URL** field, enter the URL specific to the Pass-Through Authentication. 4. In the **HTTP Method** dropdown list, select **POST**. ### Pass-Through Authentication Header and Body The HTTP body is used to post data with a request. The Header has the data keys and their corresponding values. These key-value pairs are sent as part of the Header in the HTTP Request. 1. Under the **Header** tab, enter the following **Key**/**Value** pairs: - **Key** = `SOAPAction`, **Value** = `urn:partner.soap.sforce.com/Soap/queryReq` - **Key** = `Content-Type`, **Value** = `text/xml` Refer to [Header]() for more information. 2. Under the **Body** tab, select the **Raw** radio button. 3. In the **Body** field, enter the XML payload for the Pass-Through Authentication. > **Note** > > The Body has two types: Form Data and Raw. XML format does not support Form Data. > **XML Payload Example** > > ```xml > xmlns:urn=urn:partner.soap.sforce.com"> > > > > > > > > > $authenticate.username$ > $authenticate.password$ > > > > ``` Refer to [Body]() for more information. ### Pass-Through Authentication Response Information Refer to [Response Information]() for more information. The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. 1. In the **Root Path** field, enter `//ns:userInfo`. 2. In the **Success Code** field, enter `2**`. ### Pass-Through Authentication Response Mapping Refer to [Response Mapping]() for more information. Enter the following **Schema Attribute** and **Attribute Path** pairs: - **Schema Attribute** = `Username`, **Attribute Path** = `ns:userName` - **Schema Attribute** = `email`, **Attribute Path** = `ns:userEmail` - **Schema Attribute** = `firstName`, **Attribute Path** = `ns:firstName` ### Pass-Through Authentication XPath Namespace Mapping Refer to [XPath Namespace Mapping]() for more information. Enter the following **Namespace Prefix** and **Namespace URI** pairs: - **Namespace Prefix** = `soapenv`, **Namespace URI** = `http://schemas.xmlsoap.org/soap/envelope/` - **Namespace Prefix** = `ns`, **Namespace URI** = `urn:partner.soap.sforce.com` - **Namespace Prefix** = `xsi`, **Namespace URI** = `http://www.w3.org/2001/XMLSchema-instance` ## Multiple Independent Endpoints Web Services allows aggregation from multiple independent endpoints. The Web Service depends upon the **Operation Type** and the **Parent Endpoint** configuration to determine whether the endpoints of type Aggregation or Get Object must be executed independently. Refer to [HTTP Operations]() for more information on configuring an HTTP operation. - When Aggregation and Get Object endpoints need to aggregate attributes from multiple endpoints in a chained manner, the administrator must configure the parent endpoint name in every child endpoint. There has to be a dependency between the first and subsequent endpoints. The parent endpoint must be explicitly configured using the **Parent Endpoint** configuration tab. - If multiple child endpoints are configured for any given endpoint, then the sequence of execution of child endpoints is determined by the sequence in which they have been configured in the application. For example, if account aggregation requires attributes from four different endpoints (EP1, EP2, EP3, and EP4), then: 1. EP1 aggregates userId and primary email. 2. EP2 aggregates personal information using userId. 3. EP3 aggregates skill ID information using primary email. 4. EP4 aggregates skill name using skill ID from EP3. Where EP = Endpoint and RO = Resource Object/Account object. ### Configuring Multiple Independent Endpoints for Aggregation - For a target system where accounts are aggregated from multiple endpoints and there is no relationship between such endpoints, you can configure Web Services to aggregate information from independent endpoints. - Each endpoint can be configured independently using the same **Operation Type**. No parent endpoint configuration is required. - Every independent endpoint can have a paging of its own, if applicable. - Every endpoint collects resource objects from the configured Web Service. Upon completion of collecting all information, the next independent endpoint is triggered for collecting resource objects. For example, if there are two endpoints EP1 and EP2, then EP1 aggregates accounts from a certain geographic location and EP2 aggregates from another. | Endpoint Name | Child Endpoint(s) | Returns | | | --- | --- | --- | --- | | EP1 | EP2, EP3, EP5 | RO(1, RO(2), RO(3,4), RO(5)), RO(6,7), RO(8) | Independent | | EP2 | \- | RO(2) | Child of EP1 | | EP3 | EP4 | RO(3,4) | Child of EP1 | | EP4 | | RO(4) | Child of EP3 | | EP5 | | RO(5) | Child of EP1 | | EP6 | EP7 | RO(6,7), RO(8) | Independent | | EP7 | | RO(7) | Child of EP6 | | EP8 | | RO(8) | Independent | > [!NOTE] > > **Screenshot** > > [![Multiple Independent Endpoints]()]() ### Parent Endpoint The Parent Endpoint tab displays for aggregation operations. Refer to [Aggregation]() for more information. > [!NOTE] > > **Screenshot** > > [![Parent Endpoint]()]() 1. Select the **Parent Endpoint** from the dropdown list. 2. Select **Save**. ## Enabling Single API Calls The Web Services connector supports sending data for multiple users in a single API call. If the managed system supports sending data for multiple users in a single call, the single API call can be enabled or configured by adding the `evalPattern`. Add the following evaluation pattern function to the **Body** or **URL** to send attributes in the request: ```text evalPattern(pattern,delimiter,count) ``` The following table describes the terminology used in the above evaluation pattern (`evalPattern`) function, which is used to specify the repeated pattern of attributes data to be resolved: | Attributes | Description | | --- | --- | | `pattern` | Repeated pattern for a set of users in the request. | | `delimiter` | Delimiter for the repeated patterns. | | `count` | (Optional) Specifies the number of users' data to be sent with the request endpoint. The default value is 10 for query parameters and 50 for Body parameters. | For example, consider the Get Users data API: - **Required URL**: ```text http://Hostname:8080/identityiq/scim/v2/Users?filter=userName eq "spadmin" or userName eq "abhijit" or userName eq "wadekar" or userName eq "imran" or userName eq "test" ``` - **Modified URL** - The following modified URL used to get users data API has an `evalPattern` placeholder which is replaced with resolved information. The placeholder string is replaced by five repeated patterns of `userName` placeholders and a separator. ```text http://Hostname:8080/identityiq/scim/v2/Users?filter=evalPattern("userName eq $response.userName$"," or ",5) ``` > [!NOTE] > > **Notes** > > - This functionality is not applicable for the first aggregation endpoint. > - If the API supports sending limited user data, then it must be specified in `evalPattern(count)` to avoid failures. Merging of resources is done based on the ID for each endpoint which are provided as placeholders in the pattern. For example: ```text $response.userName$ (userName) ``` Refer to [Dataset Management]() for more information on other configuration capabilities. # Connecting SailPoint and Web Services To connect SailPoint with Web Services, perform the following tasks: ## Adding the Source in SailPoint To connect to SailPoint, perform the following steps. Once the connection is made, you can configure it to meet your company's needs. > [!IMPORTANT] > > By default, the provisioning feature is **disabled**, and the connector only supports read-only operations. To support provisioning operations, you must manually enable the feature in the source configuration. **To configure a new source:** 1. Sign in to SailPoint. 2. Go to **Admin \> Connections \> Sources**. 3. Select **Create New**. 4. Search for the connector by entering the name in the search box, and then select **Configure**. 5. In the **Source Name** field, enter a unique and descriptive name for your source. Source names cannot exceed 128 characters. 6. In the **Description** field, provide additional details about the source to help distinguish it from similar sources. This field allows a maximum of 2,000 characters. 7. In the **Source Owner** field, begin typing the name of an owner. Matches appear after you type two or more letters. For more information, refer to [Assigning a Source Owner](). 8. Under **Connection Type**, select **Direct Connection** or **Flat File**. - **Direct Connection** - A direct connection fetches data from the **Virtual Appliance Cluster** you choose as the application connector for the source. A direct connection configuration allows for real-time updates. For more information about configuring and deploying virtual appliances, refer to the [Virtual Appliance Reference Guide](). - **Flat File** - Select the flat file if no connector is available, or if another system restricts the connection. This option allows only reading and aggregating data as a generic/delimited application. Provisioning activity is unsupported, and additional configuration pages like connection settings and aggregation settings are unavailable. 9. If you selected **Direct Connection**, in **Virtual Appliance Cluster**, select the virtual appliance cluster that will be used as the application connector for the source. 10. (Optional) Select a governance group to grant its members [source]() or [role]() sub-admin level oversight of the source and its access. For more information, refer to [Creating and Managing Governance Groups](). 11. If this source represents a primary system containing your organization's personnel records, select the **Authoritative Source** checkbox. For more information, refer to [Creating Identity Profiles](). 12. Select **Continue**. The source is created, and you are navigated to the **Source Setup \> Base Configuration** page. Continue to configure your connected source there. ## Base Configuration Provide the base configuration parameters. Information you entered in the Create New Source dialog is automatically entered into the fields in the Base Configuration page. You can edit this information if necessary. 1. Enter a unique name and description for the source. 2. In the **Source Owner** dropdown list, select the identity that owns this source. - To find a source owner, begin entering their name. 3. In the **Virtual Appliance Cluster** dropdown list, select the virtual appliance to use when communicating with your organization's systems. For more information, refer to [SailPoint Virtual Appliances](). 4. (Optional) If enabled for your organization, select the **Use a Credential Provider** checkbox to manage the source's authentication using a credential provider. > **Note** > > To add a credential provider, go to **Admin \> Connections \> Credential Providers**. For more information about credential providers, refer to [Credential Providers](). 5. Configure the authentication to allow SailPoint to connect to the source. Refer to [Connection Settings](<#connection-settings>) for more information. 6. (Optional) In the **Governance Group for Source Management** dropdown list, select a governance group to associate with this source. For more information about governance groups, refer to [Associating Governance Groups with a Source](). 7. (Optional) Choose whether to enable or disable provisioning for the source. Provisioning is disabled by default. - **Enable Provisioning** - Set the toggle to **Enabled** to allow the source to create, update, and deactivate accounts in the connected source system. - **Disable Provisioning** - Set the toggle to **Disabled** to disable provisioning for the source. Disabling provisioning will prevent the creation, updating, or deactivating of accounts on this source. 8. Select **Save**. ## Connection Settings This section has the configuration details on authentication types, common configurations, and delta aggregation settings. Select the authentication type your source uses. You can enter the supporting authentication information in the fields provided below your selection. The supporting fields that display change depending on your selected authentication type. The SailPoint Web Services connector supports the following authentication types: - [Basic Authentication](<#basic-authentication>) - [API Token](<#api-token>) - [OAuth 2.0](<#oauth-20>) - [Custom Authentication](<#custom-authentication>) ### Basic Authentication > [!NOTE] > > **Screenshot** > > [![Basic Authentication]()]() 1. From the **Authentication Type** dropdown list, select **Basic Authentication**. 2. In the **Base URL** field, enter the base URL to connect to the target managed system. For example: `https://api.testurl.com` 3. Enter the **Username** and **Password** for the account with the required permissions to execute Web Services. 4. Configure the [Aggregation Settings]() and [Common Configuration]() settings that apply, then select **Save**. ### API Token The connector can authenticate with the source using an API token. The API token you provide is saved to the `accesstoken` attribute in the application configuration. API tokens are given in the following format: ```text token_type API_token ``` For example: ```text Bearer ******** ``` > [!NOTE] > > If the token type is not provided, then the connector automatically uses `Bearer`. #### API Token Placeholders You can reference a saved API token using a placeholder. The token placeholder can be provided as a variable across all endpoints for request components such as: - Request URL - HTTP Headers - Request Body The following is an example of an API token placeholder: ```text $application.accesstoken$ ``` You can define and use multiple API token placeholders if your configuration requires it. Refer to [Custom Authentication](<#custom-authentication>) for more information on API token placeholders. > [!NOTE] > > **Screenshot** > > [![API Token]()]() 1. Select **API Token** as the **Authentication Type**. 2. Enter the **Base URL** to connect to the managed system. For example: `https://api.testurl.com` 3. Enter the **API Token** specific to the managed system. 4. Configure the [Aggregation Settings]() and [Common Configuration]() settings that apply, then select **Save**. ### OAuth 2.0 For all the grant types that you can select, the following fields are common configuration. Other grant type details are described in the following subsections. > [!NOTE] > > **Screenshot** > > [![OAuth 2.0]()]() 1. Select **OAuth 2.0** as the **Authentication Type**. 2. In the **Base URL** field, enter the base URL to connect to the target managed system. For example: `https://api.testurl.com` 3. Enter the **Token URL**. The format is: `https://{your domain}/token` Web Services supports the replacement of attributes in the OAuth 2.0 token URL. For example, if you want to prepare a token URL with sensitive information such as **client\_secret**, `$application.client_secret$` can be used. The corresponding value is determined from the replaced location in the token URL. 4. For **OAuth Headers**, set up the custom headers as part of the access token. Web Services adheres to the generalized specifications of the OAuth 2.0 grant types. However, for some managed target systems, custom headers may be required to be part of the access token generation request. You can add the custom headers as an attribute. > **Note** > > The Content-Type value can only be **application/x-www-form-urlencoded** when Authentication Type is selected as OAuth 2.0. If the managed system expects a Content-Type other than **application/x-www-form-urlencoded**, use Custom Authentication instead of OAuth 2.0. 5. In **OAuth Headers to Exclude**, enter the headers that you want to exclude. By default, an Authorization BASIC header with a Base64-encoded client ID and client secret is part of the access token generation request. Some managed target systems do not support this header. If there is no Authorization BASIC header required for such managed target systems, it can be excluded from the request. 6. For **OAuth Request Parameters**, set up the custom parameters for an access token. For some managed target systems, custom request parameters may be required to be part of the access token generation request. You can add the custom request parameter as an attribute. 7. For **OAuth Body Attributes to Exclude**, enter the attributes that you want to exclude. To remove any of the standard request parameters that are not supported by managed target systems' access token generation requests, configure the request parameters to exclude from the access token request. 8. Select a **Grant Type** and complete its configuration: - [Password Grant Type](<#password-grant-type>) - [Client Credentials](<#client-credentials>) - [Refresh Token](<#refresh-token>) - [JWT Bearer Token](<#jwt-bearer-token>) - [SAML Bearer Assertion](<#saml-bearer-assertion>) 9. Configure the [Aggregation Settings]() and [Common Configuration]() settings that apply, then select **Save**. #### Password Grant Type For the **Password** Grant Type: > [!NOTE] > > **Screenshot** > > [![Password Grant Type]()]() 1. Select **Password** as the **Grant Type**. 2. Enter the **Username** and **Password** to authorize with the source. #### Client Credentials For the **Client Credentials** Grant Type: > [!NOTE] > > **Screenshot** > > [![Client Credentials]()]() 1. Select **Client Credentials** as the **Grant Type**. 2. Enter the **Client ID** and its associated **Client Secret**. These are the client identification and secret for OAuth 2.0 authentication. #### Refresh Token For the **Refresh Token** Grant Type: > [!NOTE] > > **Screenshot** > > [![Refresh Token]()]() 1. Select **Refresh Token** as the **Grant Type**. 2. Enter the **Client ID** and the associated **Client Secret** for OAuth 2.0 authentication. 3. Enter the **Refresh Token** used to generate the access token. Web Services supports OAuth 2.0 Refresh Tokens for the managed target system. The refresh tokens either don't expire or come with a long validity period. #### JWT Bearer Token For the **JWT Bearer Token** Grant Type: > [!NOTE] > > **Screenshot** > > [![JWT Bearer Token]()]() 1. Select **JWT Bearer Token** as the **Grant Type**. 2. Enter the **Private Key** and **Private Key Password** to be used for JWT authentication. 3. Enter the **Client ID** and the associated **Client Secret** for OAuth 2.0 authentication. 4. In **JWT Header**, enter the following: - **Key** - The Key is the algorithm that is used for signing the JWT assertion. It must be the same algorithm that you use for generating the private key. For example, you can use `alg`. - **Value** - The Value is the JWT headers key. For example, you can use the value `RS256`. If required, additional header attributes can be provided in the key-value pair mentioned above. 5. In **JWT Payload**, enter the following: - **Key** - The Payload Key enables you to include information on the JWT Claim. For JWT authentication, it is mandatory to have the payload key for a successful test connection and other operations. The mandatory attributes are: - `aud` (Audience) - `exp` (Expiry of the JWT assertion) - `iss` (Issuer) - `sub` (Subject) If required, additional payload attributes can be provided in this key-value pair based on the target system. - **Value** - The value of the Payload Key. #### SAML Bearer Assertion For the **SAML Bearer Assertion** Grant Type: > [!NOTE] > > **Screenshot** > > [![SAML Bearer Assertion]()]() 1. Select **SAML Bearer Assertion** as the **Grant Type**. 2. Enter the **Client ID** and the associated **Client Secret** for OAuth 2.0 authentication. 3. Enter the **SAML Assertion URL** for generating a SAML Assertion. The SAML Assertion URL supports placeholders for replacement of the source attribute dynamically. For example, if a SAML Assertion URL is required to be prepared with some sensitive information such as a password, use `$application.saml_password$`. The corresponding value is determined from the source and replaced at the appropriate location in the SAML Assertion URL. 4. Enter the **SAML Request Body** that generates a SAML Assertion. SailPoint recommends that you use `$application.saml_username$` and `$application.saml_password$` placeholders in the request body to prevent exposing any sensitive data. 5. Enter the **Username** and **Password** for the service account with required permissions to execute Web Services. 6. In **SAML Headers**, enter the **Key** and respective **Value**. These are used for SAML assertion generation. 7. Enter any **SAML Headers to Exclude** which apply. By default, an Authorization BASIC header with a Base64-encoded resource username and resource password is part of the SAML Assertion generation request. Some managed target systems do not support such a header. If there is no Authorization BASIC header requirement for such target systems, it can be excluded from the request. ### Custom Authentication When you select **Custom Authentication** as the **Authentication Type**, Web Services aggregates the authentication details for all other endpoints. In custom authentication, the Web Services source doesn't authenticate requests and doesn't add any authorization to the HTTP header. To accomplish this, the REST application requires a new token to authenticate the request from the Authentication Server. > [!IMPORTANT] > > If an endpoint does not require authentication at all, you only need to select **Custom Authentication**. Continue to the following steps to set up custom authentication. > [!NOTE] > > **Screenshot** > > [![Custom Authentication]()]() 1. From the **Authentication Type** dropdown list, select **Custom Authentication**. 2. In the **Base URL** field, enter the base URL to connect to the target managed system. For example: `https://api.testurl.com` 3. (Optional) Several optional fields display which you can configure as your authentication configuration requires: - Username - Password - API Token - Resource Owner Username - Resource Owner Password - Private Key - Private Key Password - Client ID - Client Secret - Refresh Token 4. Select **Save**. 5. Go to **HTTP Operations**, and select **Add Operation**. Set the **Operation Type** to **Custom Authentication**. Refer to [HTTP Operations]() for more information about using the HTTP Operations fields. 6. Configure the following for endpoints: - **Authentication URL** - From the endpoint details page, enter the full URL in the **Authentication URL** field. > **Note** > > Ensure that you enter the full URL in this field, unlike the other endpoints where this field takes in the context URL. - **Header and Body**: 1. Configure the Header and Body with the required fields for the token generation. 2. Keys for sensitive attributes updated in the Header and Body must be appended in the encrypted list in the application. > **Caution** > > Don't configure sensitive attributes for the Header and Body through the configuration UI. They should be added using the SailPoint Update Source Partial REST API. Refer to [SailPoint REST API - Update Source (Partial)]() for more information. When you add sensitive attributes to the header, ensure that the attributes are added with the suffix `_CA`. For example, to use a password in the request, add `password_CA`. > **Note** > > If the attributes are not suffixed with `_CA`, the Web Services source might display unusual behavior. For example, if the attribute updated is a password, then it must be added to the header as follows. Before updating the encrypted list: ```json {"encrypted":"accesstoken,password,refresh_token,oauth_token_info,client_secret,private_key,private_key_password,clientCertificate,clientKeySpec,resourceOwnerPassword,custom_auth_token_info"} ``` After updating the encrypted list: ```json {"encrypted":"accesstoken,password,refresh_token,oauth_token_info,client_secret,private_key,private_key_password,clientCertificate,clientKeySpec,resourceOwnerPassword,custom_auth_token_info,password_CA"} ``` After the attributes are added, their values can be used as placeholders in the Header and Body. For example: ```text $application.password_CA$ ``` - Use the `password_CA` attribute key with a value such as `xyz123`. - Add the `password_CA` key to the existing encrypted attribute (comma-separated) using the SailPoint REST API. - Use the `encrypted` attribute key and append `,password_CA` to the existing value. - **Response Mapping** - Configure **Response Attribute Mapping** to obtain the access details from the response. Response mapping is the same as the other endpoints; the key is added under **Response Attribute** and its respective path must be added under **Attribute Path**. > **Notes** > > - The **Response Attribute** value must not be present in the application configuration attributes. After response parsing, the value is stored in key-value format as follows: > > ```xml > > ``` > - Be sure to use a custom name for the **Response Attribute** key other than the default name. For example, instead of using `accesstoken`, you can define it as `customaccesstoken`. > - The `accesstoken` entry can't be used in response mapping for custom authentication. You must use a different, unique entry to save the response. 7. The token value generated after executing the **Custom Authentication** endpoint can be utilized in all other endpoints using placeholders as follows: ```text "$application.$" ``` For example: ```text "$application.customaccesstoken$" ``` If the token type is for a **Bearer** instance, then it can be used as follows: ```text " $application.$" ``` For example: ```text "Bearer $application.customaccesstoken$" ``` 8. Configure the [Aggregation Settings]() and [Common Configuration]() settings that apply, then select **Save**. #### Operational Trigger Timing The point within an operation that custom authentication is triggered may vary depending on the operation you configure. - When performing a Test Connection, the system first executes the custom authentication operation or endpoint. This step is important as it retrieves the `customaccesstoken` or other authentication-related attributes, which are then utilized in the headers or body of the Test Connection operation. - For other operations, the system first verifies whether the `customaccesstoken` or any related authentication attributes are saved. If they are, it utilizes them. If not, it executes the custom authentication operation or endpoint to generate the `customaccesstoken` or any related authentication attributes. If an operation fails, the system checks the returned exception code. If the code is `401` or if the error code/message matches one configured in the **HTTP Error** field on the Additional Settings page, it triggers a custom authentication operation or endpoint. This process generates a `customaccesstoken` or any related authentication attributes. Refer to [HTTP Errors]() for more information on the HTTP Error field. ## Review and Test Perform a test to confirm the connection to SailPoint. 1. Go to **Review and Test**. 2. Confirm that the entries in each field are correct. If you note any mistakes, return to the section and make corrections. 3. Select **Test Connection**. ## SailPoint Application Onboarding SailPoint application onboarding enables you to easily onboard new applications and create sources following the successful onboarding of a discovery source. To use this feature, continue to **Discovered Applications** in the SailPoint user interface. For more information, refer to [Application Onboarding]() in the SailPoint SaaS documentation. # Dataset Management Dataset Management lets you review the object types a source collects and control how the source aggregates those objects into SailPoint. Use Dataset Management to view and manage resource attributes, datasets and their resources, enable dataset aggregation schedules, perform manual aggregation, and view aggregation history. > [!NOTE] > > Datasets are also available in SailPoint Agentic Fabric. Contact your Customer Success team and refer to [SailPoint Agentic Fabric]() for more information. For more information, refer to [Managing Datasets and Resources]() for datasets, resources, owner correlation, and aggregation. ## Datasets A *dataset* is a named group of one or more related resources that the source aggregates together. When aggregation runs for a dataset, the source collects all resources in that dataset from the managed system in one aggregation job. Activate or deactivate aggregation at the dataset level, not for individual resources. > [!NOTE] > > Each resource belongs to exactly one dataset for that source. The source defines which resources belong to each dataset. You can enable aggregation and review associated resources, but you cannot create or delete datasets or move resources between them. ### Dataset Aggregation Configure aggregation on the **Dataset Aggregations** tab for each dataset. Configure each dataset separately. During aggregation, your owner correlation rules are automatically applied to link machine identities to their human owners. For more information, refer to [Configuring Dataset Aggregations](). ## Resources A resource defines an object type from the managed system. It specifies the kind of object, the attributes the source collects, and how the source identifies and displays each object. Resources form the building blocks of the data model. In the UI, each resource appears under **Dataset Management** \> **Resources** with its schema. A resource does not run aggregation by itself. The dataset that owns the resource collects it during aggregation. For more information, refer to [Managing Resources](). ### Owner Correlation Configure owner correlation on each resource to link aggregated objects to human owners. If you do not configure owner correlation, or if the mapping produces no match, an owner is not assigned. For more information, refer to [Configuring Owner Correlation](). ## Web Services Datasets A dataset is a named group of one or more related resources that SailPoint aggregates together. Go to **Dataset Management \> Datasets** on your Web Services source to create and manage datasets. Select **Create Dataset** to add a dataset, or select an existing dataset to review its associated resources and configure aggregation. Refer to [Creating Datasets]() for more information on creating datasets. > [!NOTE] > > Configure aggregation for each dataset separately. Refer to [Configuring Dataset Aggregations]() for more information. ## Web Services Resources A resource represents a type of object the connector collects from Web Services, such as agents, applications, or credentials. Each resource defines the attributes collected for that object type and how each object appears in SailPoint. Refer to [Managing Resources]() for more information. ### Managing Resources 1. Go to **Dataset Management \> Resources** on your Web Services source to create and manage resources. 2. Select **Create Resource** to add a resource, or select an existing resource to review its details. 3. When creating a resource, select one of the following resource types: - Agent - Application - Capability - Credential - Device - Account 4. After you create the resource, configure the Resource Aggregation under [HTTP Operations](), then run aggregation. > [!NOTE] > > Refer to [Creating Resources]() for detailed instructions on creating resources. # Configuring Web Services Entitlements ## Multiple Group Objects The Web Services source supports multiple group objects. Add a new endpoint for newly introduced groups or entitlements, such as: - Group Aggregation - `` - Get Object - `` - Add Entitlement - `` - Remove Entitlement - `` Refer to the [listSchema]() API and [createSchema]() API for more information. > [!NOTE] > > **Adding a New Group Schema** > > To support multi groups, add the following API to add a new schema: > > - **Method** - `POST` > - **URI** - `/sources//schemas` > - **JSON Payload**: > > The following JSON example adds the schema for the Role that follows: > > ```json > { > "name": "Role", > "nativeObjectType": "Role", > "identityAttribute": "Id", > "displayAttribute": "Name", > "hierarchyAttribute": null, > "includePermissions": false, > "features": [], > "configuration": {}, > "attributes": [ > { > "name": "Id", > "type": "STRING", > "schema": null, > "description": "Role Id.", > "isMulti": false, > "isEntitlement": false, > "isGroup": false > }, > { > "name": "Name", > "type": "STRING", > "schema": null, > "description": "Role name.", > "isMulti": false, > "isEntitlement": false, > "isGroup": false > } > ] > } > ``` > > The resulting Role: > > ```xml > > > Role Id. > > > Role name. > > > ``` > [!NOTE] > > **Updating the Existing Account Schema** > > As the new group schema (for role object type) has been created, update the relevant account schema attributes to point to the new group schema by making changes in the account schema through the UI, as SailPoint allows you to add the new entitlement in the account schema. > [!NOTE] > > **Add New Endpoint** > > Add a new endpoint for Group Aggregation, Get Object, and Add/Remove Entitlement operations. Update the `connectionParameters` attribute using the PATCH method as follows: > > 1. Add a new dummy endpoint such as Test Connection, Account Aggregation from the SailPoint UI and save it. > 2. With the PATCH API, replace the required operation type with the respective operation type, such as: > > 1. Group Aggregation `` > 2. Get Object `` > 3. Add Entitlement `` > 4. Remove Entitlement `` > > Method - `POST` > > URI - `beta/sources//schemas` > > JSON Payload: > > ```json > [ > {"op":"add","path":"/connectorAttributes/connectionParameters/0/operationType","value":"Group Aggregation-Role"}, > {"op":"add","path":"/connectorAttributes/connectionParameters/1/operationType","value":"Get Object - Role"}, > {"op":"add","path":"/connectorAttributes/connectionParameters/2/operationType","value":"Add Entitlement-Role"}, > {"op":"add","path":"/connectorAttributes/connectionParameters/3/beforeRule","value":"Remove Entitlement-Role"} > ] > ``` > [!IMPORTANT] > > Localization is not applicable for the value of the `OperationType` attribute added from the API. If you provide the operation type in a language other than English, the Web Services source does not configure the group aggregation type (for example, Groepsaggregatie - Rol). ## Configuring Multiple Entitlement Requests The connector can send a single request for several instances of one entitlement type to the managed system. For example, you can send a single request for several instances of `RoleID`. > [!NOTE] > > The connector must send multiple requests for different entitlement types. However, each request for that entitlement type can include several instances. To enable this feature, set the `addRemoveEntInSingleReq` parameter to `true` as follows: ```xml true ``` You can configure the value of this attribute using the SailPoint REST API. Refer to [SailPoint REST API - Update Source (Partial)]() for more information. ```json [ { "op": "replace", "path": "/connectorAttributes/addRemoveEntInSingleReq", "value": "true" } ] ``` The following is an example of the payload: ```json { "RoleID": $plan.addRoleIds$ } ``` - If `addRemoveEntInSingleReq` is set to `false`, then the placeholder value for the attribute marked as an entitlement is passed in separate API requests: First request payload: ```text jsonBody={ "RoleID": "9dd23398-b905-4878-b7ad-bc02d22171d9" } ``` Second request payload: ```text jsonBody={ "RoleID": "8defe39c0-54f6-47b4-8a15-fcc2622923sk" } ``` - If `addRemoveEntInSingleReq` is set to `true`, then the placeholder value for the attribute marked as an entitlement is passed as an array and is executed in a single request: Single request payload: ```text jsonBody={ "RoleID": ["97ee39c0-54f6-47b4-8a15-fcc262292386","8defe39c0-54f6-47b4-8a15-fcc2622923sk"] } ``` ## Add Entitlements When Enabling Accounts When you enable accounts via provisioning, you can associate entitlements with it at the same time. To configure the connector to add entitlements to accounts you enable, add the following to your provisioning plan: ```xml ``` > [!NOTE] > > In the provisioning plan entry, substitute the attribute's name where the example says `` and the desired value for ``. Add additional `AttributeRequest` entries to add more entitlements. ## Remove Entitlements When Disabling Accounts When you disable accounts via provisioning, you can remove any associated entitlements at the same time. To configure the connector to remove entitlements from accounts you disable, add the following to your provisioning plan: ```xml ``` > [!NOTE] > > In the provisioning plan entry, substitute the attribute's name where the example says `` and the desired value for ``. Add additional `AttributeRequest` entries to remove more entitlements. # HTTP Operations In **HTTP Operations**, you can add, edit, delete, and reorder HTTP operations. The connector supports the following operations: - Test Connection - Account Aggregation - Account Delta Aggregation - Group Aggregation - Get Object - Get Object-Group - Create Account - Update Account - Delete Account (using a Before provisioning rule) - Enable Account - Disable Account - Unlock Account - Change Password - Add Entitlement - Remove Entitlement - Pass-through Authentication - Custom Authentication - Get Partitions - Partitioned Account Aggregation > [!NOTE] > > **Notes** > > - The Web Services source supports the Before Provisioning rule, which enables you to delete an account using a rule. For example, you can change the provisioning plan's account operation from `disable` to `delete`. The UI fields are the same and applicable to all the operations that you choose to configure. > - For Entitlement Aggregation, you need to configure the schema manually using the SailPoint APIs. Contact SailPoint Support / Expert Services for assistance. > - For the Web Services source, you can configure the native identity in the provisioning plan using a placeholder such as `$plan.planNativeIdentity$`. > - Access to ExternalDTD is disabled during XML parsing. ## Support for Cookies The Web Services source supports cookies for HTTP requests. The Web Services source supports cookies for multiple endpoints configuration. The source manages the cookies internally for the endpoints configured for the same operation. Cookies from the previous endpoints can be used in all the subsequent endpoints of the same operation type. The Web Services source supports the JSON array as a top element in the HTTP requests. By default, the Web Services source supports cookies. Cookies can be disabled by adding the `disableCookies` attribute key with `true` as a value. This is not applicable for the authentication API call operation. ## Add Operations Configure one or more HTTP operations to manage your source data. The options available to configure the operation vary, depending on your selected **Operation Type**. To add a new HTTP operation, select **Add Operation**. > [!NOTE] > > **Screenshot** > > [![Add Operations]()]() The following topics describe the different configuration tabs that may appear when configuring an operation. ### General Information Enter basic configuration information for the HTTP operation. > [!NOTE] > > **Screenshot** > > [![General Information]()]() 1. In the **Operation Name** field, enter a unique name for the operation that you want to execute. You can change the name of an operation later if needed. > **Note** > > SailPoint recommends that you create a unique name for the operation to help you distinguish it from other operations. For example, if you have two account aggregation endpoints for your source, you can name them "Account Aggregation-1" and "Account Aggregation-2". > **Caution** > > Renaming an existing operation breaks any configured relationships, including endpoint and parent-child relationships. To ensure proper functionality, you must reconfigure any parent-child relationships after renaming an operation. 2. In the **Operation Type** dropdown list, select the name of the operation that you want to execute. > **Note** > > You must configure a Partitioned Account Aggregation operation to support partitioning for static and dynamic. Additionally, to support dynamic partitioning you must also configure a Get Partition operation. 3. Unless it's required for your configuration, leave **Use cURL Command** disabled. > **Note** > > If your configuration requires cURL, refer to [Add an Operation with cURL](<#add-an-operation-with-curl>). 4. In the **Context URL** field, enter the authentication (Context) URL specific to your operation. The connector appends the context URL to the source's Base URL. This can be empty depending on the endpoint of the managed system. For example: `/2/team/members/list` The following are a few keywords that are used in the Context URL along with the placeholder `$`: - `plan` - `response` - `application` - `getobject` - `authenticate` > **Important** > > If the Context URL contains certain special characters, you may need to disable the `skipEncodingDecodingUrl` key. Refer to the [Troubleshooting]() topic. Special characters that may cause issues with the Context URL may include, but aren't limited to, commas (`,`), open and close parentheses or brackets (`()`, `[]`, and `{}`), or pound signs (`#`) for more information. 5. In the **HTTP Method** field, select the appropriate method from the dropdown list. HTTP method is supported by the respective operation. For example, you can select **GET**, **PUT**, **POST**, **DELETE**, or **PATCH**. 6. Select **Save**. #### Support for Expression Language in URLs The web services connector supports expression language in URLs. To use expressions in a URL, wrap them with `_#`. The following objects can support expression language when you use them with placeholders: - Response - Plan - Application For example: ```text https://domain.com/2/team/members/list/_#$response.data$.length()_# /2/team/members/list/_#'hello'.concat('world')_# /2/team/members/list/_# 5 >= 4_# ``` #### Add an Operation with cURL If required, you can enable **Use cURL Command** while configuring the general information. When you enable **Use cURL Command** in most operations, the options for **Context URL** and **HTTP Method** are removed, and you only need to provide the cURL command. The endpoint cURL command for an operation which contains the complete request URL, HTTP Method, Header, and Body is provided in the following example: ```text curl --location --request POST 'https://api.dropbox.com/2/team/members/list' \ --header 'Authorization: $application.accesstoken$' \ --header 'Content-Type: application/json' \ --data-raw '{"limit":1}' ``` In this example, consider the following: - Complete request URL: `https://api.dropbox.com/2/team/members/list` > **Note** > > The URL must be in `http://` or `https://` format. You can add a placeholder URL, but it must have `http://` or `https://` at the beginning of the URL string. You can't use a placeholder URL on its own. - HTTP Method: ```text POST --header 'Authorization: $application.accesstoken$' \ --header 'Content-Type: application/json' \ ``` - Header - Body: ```text --data-raw '{"limit":1}' ``` ### Header The header holds the key and value for a given HTTP operation that you want to execute. The connector sends these key-value pairs as part of the header in HTTP requests. > [!NOTE] > > **Screenshot** > > [![Header]()]() The following example displays a sample key-value pair, where `Authorization` is the header **Key** and `$application.accesstoken$` is the **Value**. ```text Authorization - $application.accesstoken$ Content-Type - application/json ``` > [!NOTE] > > If you don't provide the content type in the Header, the source sets Content-Type as `application/json`. 1. Enter the header **Key** used for the operation. 2. Enter the **Value** of the header key used for the operation. 3. Select **Save**. #### Content Types - JSON request, JSON response: `Content-Type= application/json (optional), Accept (optional)` - XML request, XML response: `Content-Type= application/xml or text/xml or */xml (required), Accept (optional)` - JSON request, XML response: `Content-Type= application/json (optional), Accept = application/xml or text/xml or */xml (required)` - XML request, JSON response: `Content-Type= application/xml or text/xml or */xml (required), Accept = application/json (required)` #### Support for Expression Language in the Header Values The web services connector supports expression language in the Header. To use expressions in the Header, wrap them with `_#`. The following objects can support expression language when you use them with placeholders: - Response - Plan - Application For example, the following example displays sample key-value pairs: ```text Count - _#2+2_# Service-Name - _#$application.serviceName$.concat('service')_# ``` ### Body This is the standard HTTP body used for posting the data with a request. The Body can be configured as one of two types, **Form Data** or **Raw** data entry. Either of these is used for a specific operation. > [!NOTE] > > **Screenshot** > > [![Body]()]() #### Form Data 1. Select **Form Data**. 2. Add the respective data **Key** and **Value**. The Web Services source will not display an error when an endpoint's body type is selected as **Form Data** and the form entries are empty. The key-value pairs are sent as part of the Body in JSON format. XML does not support form data. #### Raw 1. Select **Raw**. 2. Enter the data in the **Body** field. Select **Save**. > **JSON Example** > > You can use this entry without a placeholder: > > ```json > { > "limit": 10, > "cursor": "abcd1234" > } > ``` > > You can use this entry with a placeholder: > > ```json > { > "group_id" : "$plan.groups$", > "permission":"$plan.permission$", > "roles": "$plan.roles$" > } > ``` > [!NOTE] > > **XML Example** > > ```xml > > > > ... > > > > ... > > > ``` #### Additional Information for Body The following keywords are used in the Body along with the placeholder `$`: - `plan` - `response` - `application` - `getobject` - `authenticate` #### Handling the "$" Character in the URL and Body The Web Services source correctly extracts and handles the `$` character in the URL and Body, along with the placeholders. #### Placeholder Details ##### The JSON Request with the Placeholder in the Body/Payload If the body contains a placeholder that is not present in the provisioning plan, response, or source, the source removes the key value from the JSON payload. For example: ```json { "type": "$plan.type$", "id": "$plan.nativeIdentity$", "title": "$plan.title$", "externalid": "12345" } ``` If the plan does not contain the title attribute request, the source removes the title key and value. For example: ```json { "type": "student", "id": "STUD121", "externalid": "12345" } ``` ##### The XML Request with the Placeholder in the Body/Payload If the body contains a placeholder that is not present in the provisioning plan, response, or source, the source removes the value from the XML payload. Refer to the following example: ```xml $plan.fname$ $plan.lname$ $plan.nativeIdentity$ permanent worker ``` If the plan does not contain a `lname` value in the attribute request, the source removes the `lname` value as displayed in the following example: ```xml John wid121 permanent worker ``` > [!CAUTION] > > Depending on the behavior of the API, some servers may interpret keys with a missing value as a sign that the attribute value should be blank instead of a sign that the value should be null, which may cause undesired effects. ##### URL If the URL contains a placeholder that is not present in the provisioning plan, response, or source, the source removes the value from the Request URL. ##### Header If the header contains a value that is not present in the provisioning plan, response, or source, the source removes the key value from the Request Header. #### Support for Expression Language in the Body The web services connector supports expression language in the Body. To use expressions in the Body, wrap them with `_#`. The following objects can support expression language when you use them with placeholders: - Response - Plan - Application The following example is of a JSON request using expression language in the Body/Payload: ```json { "type": "$plan.type$", "id": "$plan.nativeIdentity$", "name": "_#'hello'.concat('world')_#" "size": _#$response.data$.length()_#, "isActive" : _# 2 >= 2 _# "externalid": "12345" } ``` Do not provide quotes outside the expression for values like Boolean and numbers. For example: ```json { "size": _#$response.data$.length()_#, "isActive" : _# 2 >= 2 _# "count" : _#'Hello'.length()_# } ``` The following is an example of an XML request using expression language in the Body/Payload: ```xml _#'hello'.concat('world')_# $plan.lname$ _#$response.data$.length()_# permanent worker ``` ### Response Information Response Information has a **Root Path** and a **Success Code**. > [!NOTE] > > **Screenshot** > > [![Response Information]()]() The Root Path must be common for all the attributes mentioned in the Response Attribute Mapping for a particular operation. The Success Code is the successful HTTP response code expected by respective Web Service operations. The Success Code field accepts HTTP status codes in CSV format. For example, consider the HTTP response code `200, 201, 203`. If the list does not contain any value, the status codes from `200` to `299` are checked. Successful status codes start with `2`. You can provide `2**` as a Success Code. The Web Services source supports a `null` HTTP response body with custom error messages. For the Web Services source, the pagination with a `null` Root Path in Response Mapping works correctly. The default value for root path is `$`. 1. Enter the **Root Path**. This is the common path present in the JSON / XML response. For example: - **JSON** - `$.members.profile` - **XML** - `//wd:Response_Data/wd:Worker/wd:Worker_Data` 2. Enter the **Success Code**. This is the HTTP success code that serves as a response to the request. 3. Select **Save**. ### Response Mapping Response Mapping is a response attribute returned in JSON/XML format from the managed system for specific operations like create user, update user, or account aggregation. > [!NOTE] > > **Screenshot** > > [![Response Mapping]()]() 1. In the **Schema Attribute** field, enter the attributes expected in the JSON or XML response from the URL as a part of the schema. 2. In the **Attribute Path** field, enter the JSON or XML path of the specific attribute in the returned response. The Root Path configured in [Response Information](<#response-information>) is prefixed to the attribute path you enter. For example, based on the examples in Response Information: - **JSON**: | Root Path | Attribute Path | Resulting JSON Path | | --- | --- | --- | | `$.members.profile` | `member_id` | `$.members.profile.member_id` | - **XML**: | Root Path | Attribute Path | Resulting XPath | | --- | --- | --- | | `//wd:Response_Data/wd:Worker/wd:Worker_Data` | `sf:FirstName` | `//wd:Response_Data/wd:Worker/wd:Worker_Data/sf:FirstName` | 3. Select **Save**. In the Web Services source, you have to add the schema attributes manually for the respective Web Services-based target system. The source accurately handles any incorrect JSON attribute paths in the endpoint's response mapping configuration. ### XPath Namespace Mapping Configure the XML **Namespace Prefix** and its corresponding **Namespace URL**, which identify uniquely named elements and attributes in XML requests and responses. > [!NOTE] > > **Screenshot** > > [![XPath Namespace Mapping]()]() > [!NOTE] > > **Notes** > > - Absence of non-standard XML Namespaces results in errors while response parsing. > - If any non-standard XML Namespace exists in the response, configure the same in the XML Namespace mapping where the **Key** is the Namespace Prefix and the **Value** is the Namespace URL. > - If a default Namespace is present, add a temporary Namespace Prefix with the default Namespace URL in the XML Namespace mappings. Use this temporary prefix in the XPath elements within the scope of the default Namespace. 1. Add the **Namespace Prefix** and **Namespace URL** pair to be used in the XML operation. 2. Select **Save**. # Integrating SailPoint with Web Services This connector allows you to configure any web service supported managed system which can read and write on the managed system using the respective managed system Web Services. Web Services supports JSON and XML for read and write. > [!WARNING] > > When configuring the source, do not hard code sensitive data. If sensitive data is hard coded, it can lead to that data being exposed when moving to a production environment. SailPoint recommends putting sensitive information in the encrypted attribute value list in the application XML and then using the encrypted variable name when configuring the source. For example, if you want to add the custom variable `Custom_Variable` in the encrypted list, append the variable name in the following list: `` > [!NOTE] > > To view the latest features, enhancements, and fixes for all SaaS connectors, refer to the [SaaS Release Notes]() page. ## Supported Managed Systems The SailPoint Web Services connector supports SOAP and REST web services with XML and JSON response format. ## Prerequisites - Configure at least one virtual appliance cluster and successfully test the connection. Refer to the [Virtual Appliance Reference Guide]() for more information. - Web Services must be accessible. ## Required Permissions The user/administrator must have the required permissions to call the Web Services API of the managed system. ## Supported Features The Web Services source supports the features listed below. - Test Connection - Account Aggregation - Account Delta Aggregation - Create, Update, Delete Accounts > **Note** > > Delete Account is possible using a Before Operation rule. For example, you can change the provisioning plan's account operation from `disable` to `delete`. Refer to [Web Services Before Operation Rule]() for more information. - Enable, Disable Accounts - Get Object - Entitlement Aggregation - Add/Remove Entitlement - Add entitlements when enabling accounts - Remove entitlements when disabling accounts - Change Password - Passthrough Authentication - Unlock Account: The schema attribute is Account Lock Status. - Authentication Additional credentials are required to connect the Web Service source to the managed system. The following are the supported authentication methods: - Basic Authentication - OAuth2 Authentication - API Token (This source does not generate OAuth tokens based on a client ID and client secret key. You need to provide an access token - API token). - No/Custom Authentication The Web Services source supports XML format for the Basic Authentication using username and password. > **Note** > > For the API endpoints with SSL, provide the client certificate details, refer to [Common Configuration](). - Expression language use in URLs, Header values, and Body > **Note** > > The connector supports expression language with string and primitive data types such as Boolean and numbers. It does not support Collection(s) and Array(s). Refer to [Using Expression Language]() for more information. - Supports a rate limit mechanism which handles as prescribed by the IETF implementation. Refer to [RateLimit Header Fields for HTTP]() for more information. The rate limiting mechanism is engaged after receiving the 429 status code in the response. An exponential back-off depending upon the Retry-After response header occurs before attempting the re-trigger of the request. At maximum, the API request re-trigger is attempted at, twice, after receiving the first 429 response. The URL is encoded regardless of the `throttleEnabled` flag value. - Multiple Group Objects The Web Services source supports the multiple group objects. Refer to [Multiple Group Objects]() for more information. - Application layer proxy > [!IMPORTANT] > > The Web Services Source manages the request for multiple operations performed sequentially. Refer to [SailPoint Source Features]() for more information on features. # Keywords The Web Service source supports the following keywords for various configuration attributes such as Authentication URL, Headers, Body (JSON and Form-data) for a single or multiple endpoints. ## plan Used for configuring the provisioning operations such as create account and update account. For example: Authentication URL - `/api/core/v3/people/$plan.nativeIdentity$` **JSON Body example for plan**: ```json {"new_members": [ { "email": "$plan.email$", "first_name": "$plan.first_name$", "surname": "$plan.surname$", "send_welcome_email": $plan.send_welcome_email$, "role": { ".tag": "member_only" } } ] } ``` ## response Used for multiple endpoints, where the response from the first endpoint is provided as an input for the second endpoint. For example, there are two endpoints for account aggregation: - The first endpoint returns a response as a list of `member_ids` that is an input for the second endpoint. - The second endpoint's JSON body is: `{"members_info":[{"member_id":"$response.member_id$"}]}` ## application Used to get other configuration attributes from the current source. For example: ```text "$application.$", ``` Where `` is a source configuration attribute. ## getobject Used while performing the `Aggregate Account` operation (get a single account details). The `$getobject` allows you to use any attribute of the account. For example, `$getObject.lastLoginDate$`. - JSON body: ```json {"members": [ { ".tag": "member_id", "member_id": "$getobject.nativeIdentity$" } ] } ``` - Authentication URL for get object: ```text /api/v4/admin/$getobject.nativeIdentity$ ``` ## nativeIdentity Indicates the `AccountID` identity attribute in the plan or during the `getobject` operation. For example, `nativeIdentity` is used along with the keyword as follows: - **getobject** - `$getobject.nativeIdentity$` - **plan** - `$plan.nativeIdentity$` > [!NOTE] > > There may be instances where `nativeIdentity` is present in the account request for account creation. In such cases, `nativeIdentity` may occasionally reflect different values. ## planNativeIdentity Represents the Plan's `nativeIdentity` in the Provisioning plan. For example, `planNativeIdentity` is used along with the keyword as follows: - **plan** - `$plan.planNativeIdentity$` Web Services can be configured with the native identity from the provisioning plan using the placeholder `$plan.planNativeIdentity$`. > [!NOTE] > > There is a possibility that `nativeIdentity` may be present in the account creation request. It may sometimes correspond to different values. ## authenticate To provide the username and password in the endpoint configuration, use the following placeholders: ```text $authenticate.username$ $authenticate.password$ ``` Refer to [Pass-Through Authentication]() for more information on configuration. > [!NOTE] > > SailPoint recommends using a placeholder in the body and URL rather than adding sensitive information directly. For example: > > ```text > https://TESTMACHINE:9096/users/user/$application.accesstoken$ > ``` > > Attributes mapped to a raw JSON response may contain formatted values similar to `".tag": "member_id"`, such as: > > ```text > ['.tag'] > ['@etag'] > ['@@test'] > ['complex.name'] > ['role name'] > ['role_name'] > ``` ## Using Expression Language The Web Services virtual appliance-based connector supports expression language in URLs, Header values, and in the Body section. The following objects can support expression language when you use them with placeholders: - Response - Plan - Application ### Writing Expression Language To use expressions in a Web Services configuration, wrap them with `_#`. Placeholders can be used within an expression. For example: ```text _#$response.data$.length()_# ``` One or more placeholders can be used with an expression. For example: ```text _#$application.city$.concat($application.city2$)_# ``` Expressions can also be written without any placeholder. For example: ```text _#'hello'.concat('world')_# ``` To represent a value in the URL, Header values, and Body sections, you can also use multiple expressions. For example: ```text "Address" : "_#$application.city$.concat($application.city2$)_# lane name, street name, _#$application.city2$.concat($application.city$)_#" ``` You can configure consecutive expressions. For example: ```text _#$application.city$.concat($application.city2$)_#_#$application.city2$.concat($application.city$)_# ``` To provide a string or literal value, enter it within single quotes (`'`). For example: ```text _#'hello'.concat('world')_# ``` ### Supported Operations The connector supports using expression language for the following operations. #### String (Literal) Operations | Operation | Description | | --- | --- | | `concat` | Concatenates strings. | | `length` | Returns the length of a string. | | `toUpperCase` | Converts a string to uppercase. | | `toLowerCase` | Converts a string to lowercase. | | `replace` | Replaces a substring within a string. | | `substring` | Extracts a substring. | #### Relational Operators The connector supports six relational operators. `[SPACE]` has no impact within the expression for relational operations. | Operator | | | --- | --- | | `>` | Greater than | | `<` | Less than | | `==` | Equal to | | `!=` | Not equal to | | `>=` | Greater than or equal to | | `<=` | Less than or equal to | #### Arithmetic Operators The connector supports five arithmetic operators. `[SPACE]` has no impact within the expression for arithmetic operations. | Operator | | | --- | --- | | `+` | Addition | | `-` | Subtraction | | `/` | Division | | `*` | Multiplication | | `%` | Modulus | #### Logical Operators The connector supports three logical operators. `[SPACE]` has no impact within the expression for logical operations. | Operator | | | --- | --- | | `&&` | Logical AND | | `\|\|` | Logical OR | | `!` | Logical NOT | ### Support for Expression Language in URLs, Headers, and Body Refer to [Support for Expression Language in the Header Values]() and [Support for Expression Language in the Body](). # JSON and XML Response Examples This section provides specific examples of the following format responses or inputs for the supported fields or the operations on the Web Services source: - [JSON Response Examples](<#json-operations>) - [XML Response Examples](<#xml-operations>) ## JSON Operations This section provides examples of JSON responses for the supported operations. ### Test Connection > [!NOTE] > > SailPoint recommends that you have a single endpoint set up for test connections because there may be timeout issues for multiple endpoints in test connections. This topic provides an example of a JSON response for a test connection operation. > [!NOTE] > > **Test Connection Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Test Connection (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Test Connection**. > 3. In the **Context URL** field, enter the URL specific to the test connection. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Test Connection General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs are sent as part of the header in the HTTP request. > > [![Test Connection Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for a test connection. > > In the **Raw** field, enter the JSON payload for the test connection. > > [![Test Connection Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Test Connection Response Information]()]() > > On the **Response Mapping** tab: > > Below is an example of a schema that is mapped to JSON response. Refer to [Configuration for Response]() for more information. > > [![Test Connection Response Mapping]()]() ### Aggregation This topic provides an example of a JSON response for an account aggregation operation. Using the Web Services source, you can have multiple account aggregation operations. For example: Aggregation - 1 and Aggregation - 2. #### Account Aggregation - 1 You can aggregate two attributes from EndPoint1 and three more attributes from EndPoint2. When you configure multiple operations, the response of first operation can be used as an input in the second operation. > [!NOTE] > > **Account Aggregation - 1 Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Account Aggregation - 1 (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Account Aggregation**. > 3. In the **Context URL** field, enter the URL specific to the account aggregation. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Account Aggregation - 1 General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Account Aggregation - 1 Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for an account aggregation. > > In the **Raw** field, enter the JSON payload for the account aggregation. > > [![Account Aggregation - 1 Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. Refer to [Raw API Response for Account Aggregation - 1](<#raw-api-response-for-account-aggregation-1>) as an example. > > [![Account Aggregation - 1 Response Information]()]() > > On the **Response Mapping** tab: > > Refer to [Raw API Response for Account Aggregation - 1](<#raw-api-response-for-account-aggregation-1>) for an example of response mapping. For additional examples of the raw JSON response for which the **Response Information** schema is mapped, refer to [Configuration for Response](). > > [![Account Aggregation - 1 Response Mapping]()]() ##### Raw API Response for Account Aggregation - 1 The following is an example of a raw response for the given response information and response mapping. ```json { "members": [ { "profile": { "groups": "testGroup", "name": { "display_name": "testName1" }, "team_member_id": "153", "email": "test153@orgName.com" }, "role": { ".tag": "tagName1" } }, { "profile": { "groups": "testGroup2", "name": { "display_name": "testName2" }, "team_member_id": "154", "email": "test154@orgName.com" }, "role": { ".tag": "tagName2" } } ] } ``` > [!CAUTION] > > JSON attributes whose names include a period that does not indicate a child object need to be enclosed in square brackets and double quotes. For example, `["manager.user_name"]`. #### Account Aggregation - 2 For example, during aggregation of Dropbox, the response of the first endpoint will return the `id`, `Username`, `firstName`, among others. This response must be provided as an input to the second endpoint. This can be provided with the help of a keyword "response" (`$response.team_member_id$`), where `team_member_id` is the value fetched from Account Aggregation -1 and it is an identity attribute in the source schema. > [!NOTE] > > **Account Aggregation - 2 Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Account Aggregation - 2 (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Account Aggregation**. > 3. In the **Context URL** field, enter the URL specific to the account aggregation. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Account Aggregation - 2 General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Account Aggregation - 2 Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for an account aggregation. > > In the **Raw** field, enter the JSON payload for the account aggregation. > > To fetch additional attributes from another endpoint, use the id (identity attribute) from the previous response. Add these attributes in **Schema Attribute** section of **Response Mapping** of the first end point (Account Aggregation - 1). > > In the following screenshot, `$response.team_member_id$` represents the identity that was aggregated in the Account Aggregation-1 and is mentioned previously in the schema mapping section of Account Aggregation -1. > > [![Account Aggregation - 2 Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. Refer to [Raw API Response for Account Aggregation - 2](<#raw-api-response-for-account-aggregation-2>) as an example. > > [![Account Aggregation - 2 Response Information]()]() > > [![Account Aggregation - 2 Response Information 2]()]() > > On the **Response Mapping** tab: > > Below is an example of a schema that is mapped to XML response. Refer to [Raw API Response for Account Aggregation - 2](<#raw-api-response-for-account-aggregation-2>) for an example of response mapping. For additional examples, refer to [Configuration for Response](). > > [![Account Aggregation - 2 Response Mapping]()]() > > On the **Parent Endpoint** tab: > > In the following example, Account Aggregation -1 (JSON) is the parent endpoint and Account Aggregation - 2(JSON) is its child endpoint. > > From the **Parent Endpoint Name** dropdown list, select **Account Aggregation - 1 (JSON)**, as shown below. > > [![Account Aggregation - 2 Parent Endpoint]()]() ##### Raw API Response for Account Aggregation - 2 The following is an example of a raw response for the given response information and response mapping. ```json { "profile": { "email_verified": "Yes", "name": { "given_name": "Test123", "surname": "surnameValue" }, "status": { ".tag": "tagValue" } } } ``` > [!CAUTION] > > JSON attributes whose names include a period that does not indicate a child object need to be enclosed in square brackets and double quotes. For example, `["manager.user_name"]`. ### Delta Aggregation This topic provides an example of a JSON response for an account delta aggregation operation. > [!NOTE] > > **Delta Aggregation Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Account Aggregation - 3` as the operation name. > 2. From the **Operation Type** dropdown list, select **Account Delta Aggregation**. > 3. In the **Context URL** field, enter the URL specific to the account delta aggregation. For example, the URL specified in the context URL is `/users?filter=meta.lastModifiedDate gt "$application.lastAggregationDate_account$"` ; where the `lastAggregationDate_account` is the last successful aggregation timestamp. > > > **Note** > > > > The default time period is in format: "`yyyy-MM-dd'T'kk:mm:ss'Z'`" If you want to change the time period format, use the following key-value pair to update the source via API: **key**: `connector_dateTimePattern` **value**: "`yyyy-MM-dd'T'kk:mm:ss'Z'`" **key** : `connector_serverTimeZone` **value**: "`UTC`" > 4. In the **HTTP Method** dropdown list, select **GET**. > > [![Delta Aggregation General Information]()]() > > On the **Headers** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Delta Aggregation Headers]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Delta Aggregation Response Information]()]() > > On the **Response Mapping** tab: > > Refer to [Configuration for Response]() for more information about the raw JSON response on which the **Response Information** schema is mapped. > > [![Delta Aggregation Response Mapping]()]() > > On the **Parent Endpoint** tab: > > From the **Parent Endpoint Name** dropdown list, if needed select the endpoint on which the current operation is dependent to process the request. > > [![Delta Aggregation Parent Endpoint]()]() > > On the **Paging** tab: > > 1. In the **Initial Page Offset**, select the page offset required. > 2. From the **Page Size**, select the required page size for delta aggregation. > 3. In the **Paging Steps** field, enter any necessary paging steps defined. > > [![Delta Aggregation Paging]()]() ### Entitlement Aggregation This topic provides an example of a JSON response for an entitlement aggregation operation. > [!NOTE] > > **Entitlement Aggregation Example** > > On the **General Information** tab: > > As displayed in the following screenshot, in the **Operation Name** field, enter Entitlement Aggregation as name of the operation. Select Entitlement Aggregation in the **Operation Type** dropdown list. In the **Context URL** field, enter the context URL specific to Entitlement Aggregation. Select POST in the **HTTP Method** dropdown list. > > [![Entitlement Aggregation General Information]()]() > > On the **Header and Body** tab: > > The HTTP body is used for posting the data with a request. The Header has the data keys and their corresponding values. These key value pairs will be sent as part of Header in the HTTP Request. The Body is of two types, Form Data and Raw. Either of these is used for Entitlement Aggregation. In the **Raw** field, enter the JSON payload for Entitlement Aggregation. > > [![Entitlement Aggregation Header and Body]()]() > > On the **Response Information** tab: > > Root Path is the common path present in the JSON response. The Success Code is the successful HTTP response code expected by the respective Web Service operation. > > [![Entitlement Aggregation Response Information]()]() > > On the **Response Mapping** tab: > > [![Entitlement Aggregation Response Mapping]()]() ### Create Account This topic provides an example of a JSON response for a create account operation. > [!NOTE] > > **Create Account Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Create Account (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Create Account**. > 3. In the **Context URL** field, enter the URL specific to the create account operation. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Create Account - 1 General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Create Account - 1 Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for account creation. > > In the **Raw** field, enter the JSON payload for the account creation. > > In the following screenshot, the `$plan` keyword represents the provisioning plan that is passed to the provision method. For example, `$plan.member_email$` checks for the email in the attribute request and updates in the body after it is found. > > [![Create Account - 1 Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Create Account - 1 Response Information]()]() > > On the **Response Mapping** tab: > > Refer to [Configuration for Response]() for more information about the raw JSON response on which the **Response Information** schema is mapped. > > [![Create Account - 1 Response Mapping]()]() ### Add Entitlement This topic provides an example of a JSON response for an add entitlement operation. > [!NOTE] > > **Add Entitlement Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Add Entitlement (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Add Entitlement**. > 3. In the **Context URL** field, enter the URL specific to the entitlement. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Add Entitlement General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Add Entitlement Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for adding entitlements. > > In the **Raw** field, enter the JSON payload for the entitlement. > > In the following screenshot, the `plan.nativeIdentity` keyword signifies the AccountID (identity attribute) in the account request of the plan. If the plan contains the identity attribute of an account, it can be updated in the payload with `$plan.nativeIdentity$`. > > [![Add Entitlement Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Add Entitlement Response Information]()]() > > On the **Response Mapping** tab: > > Refer to [Configuration for Response]() for more information about the raw JSON response on which the **Response Information** schema is mapped. > > [![Add Entitlement Response Mapping]()]() ### Remove Entitlement This topic provides an example of a JSON response for a remove entitlement operation. > [!NOTE] > > **Remove Entitlement Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Remove Entitlement (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Remove Entitlement**. > 3. In the **Context URL** field, enter the URL specific to the entitlement. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Remove Entitlement General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Remove Entitlement Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for removing entitlements. > > In the **Raw** field, enter the JSON payload for the entitlement. > > In the following screenshot, the `plan.nativeIdentity` keyword signifies the AccountID (identity attribute) in the account request of the plan. If the plan contains the identity attribute of an account, it can be updated in the payload with `$plan.nativeIdentity$`. > > [![Remove Entitlement Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Remove Entitlement Response Information]()]() > > On the **Response Mapping** tab: > > Refer to [Configuration for Response]() for more information about the raw JSON response on which the **Response Information** schema is mapped. > > [![Remove Entitlement Response Mapping]()]() ### Update Account This topic provides an example of a JSON response for an update account operation. > [!NOTE] > > **Update Account Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Update Account (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Update Account**. > 3. In the **Context URL** field, enter the URL specific to the account. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Update Account General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Update Account Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for updating accounts. > > In the **Raw** field, enter the JSON payload for the account. > > [![Update Account Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Update Account Response Information]()]() > > On the **Response Mapping** tab: > > Refer to [Configuration for Response]() for more information about the raw JSON response on which the **Response Information** schema is mapped. > > [![Update Account Response Mapping]()]() ### Get Object This topic provides an example of a JSON response for a get object operation. > [!NOTE] > > **Get Object Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Get Object (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Get Object**. > 3. In the **Context URL** field, enter the URL specific to the get object. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Get Object General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Get Object Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for get object. > > In the **Raw** field, enter the JSON payload for get object. > > In the following screenshot, the `$nativeIdentity$` signifies the AccountID (identity attribute) in the plan or during getObject operation. For example, `nativeIdentity` is used along with the keyword as follows: > > getobject: getObject.nativeIdentity > > This `$nativeIdentity$` can be used in the Authentication URL. > > [![Get Object Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Get Object Response Information]()]() > > On the **Response Mapping** tab: > > Refer to [Configuration for Response]() for more information about the raw JSON response on which the **Response Information** schema is mapped. > > [![Get Object Response Mapping]()]() ### Enable Account This topic provides an example of a JSON response for an enable account operation. #### Enable Account - 1 To enable an account using the Web Services source you may set two operations such as Enable Account -1 and Enable Account - 2. In the first operation (Enable Account -1), the get object can be done and the returned response object is used as the input for the second operation (Enable Account - 2). Refer to the Header and Body of [Enable Account - 2](<#enable-account-2>). > [!NOTE] > > **Enable Account - 1 Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Enable Account - 1 (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Enable Account**. > 3. In the **Context URL** field, enter the URL specific to the account. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Enable Account - 1 General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Enable Account - 1 Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for enabling an account. > > In the **Raw** field, enter the JSON payload for the account. > > [![Enable Account - 1 Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Enable Account - 1 Response Information]()]() > > On the **Response Mapping** tab: > > Refer to [Configuration for Response]() for more information about the raw JSON response on which the **Response Information** schema is mapped. > > [![Enable Account - 1 Response Mapping]()]() #### Enable Account - 2 > [!NOTE] > > **Enable Account - 2 Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Enable Account - 2 (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Enable Account**. > 3. In the **Context URL** field, enter the URL specific to the account. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Enable Account - 2 General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Enable Account - 2 Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for enabling an account. > > In the **Raw** field, enter the JSON payload for the account. > > [![Enable Account - 2 Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Enable Account - 2 Response Information]()]() ### Disable Account This topic provides an example of a JSON response for a disable account operation. #### Disable Account - 1 To disable an account using the Web Services source you must set two operations such as Disable Account -1 and Disable Account - 2. In the first operation (Disable Account -1), the get object is done and the returned object is used as the input for the second operation (Disable Account - 2). Refer to the Header and Body of [Disable Account - 2](<#disable-account-2>). > [!NOTE] > > **Disable Account - 1 Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Disable Account - 1 (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Disable Account**. > 3. In the **Context URL** field, enter the URL specific to the account. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Disable Account - 1 General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Disable Account - 1 Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for disabling an account. > > In the **Raw** field, enter the JSON payload for the account. > > [![Disable Account - 1 Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Disable Account - 1 Response Information]()]() > > On the **Response Mapping** tab: > > Refer to [Configuration for Response]() for more information about the raw JSON response on which the **Response Information** schema is mapped. > > [![Disable Account - 1 Response Mapping]()]() #### Disable Account - 2 > [!NOTE] > > **Disable Account - 2 Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Disable Account - 2 (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Disable Account**. > 3. In the **Context URL** field, enter the URL specific to the account. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Disable Account - 2 General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Disable Account - 2 Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for disabling an account. > > In the **Raw** field, enter the JSON payload for the account. > > [![Disable Account - 2 Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Disable Account - 2 Response Information]()]() ### Change Password This topic provides an example of a JSON response for a change password operation. > [!NOTE] > > **Change Password Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Change Password (JSON)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Chance Password**. > 3. In the **Context URL** field, enter the URL specific to the change password operation. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Change Password General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Change Password Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. You can use either of them for changing a password. > > In the **Raw** field, enter the JSON payload for the password change. > > [![Change Password Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Change Password Response Information]()]() ## XML Operations This section provides examples of XML responses for the supported operations. ### Test Connection This topic provides an example of an XML response for a test connection operation. > [!NOTE] > > **Test Connection Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Test Connection (XML)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Test Connection**. > 3. In the **Context URL** field, enter the URL specific to the test connection. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Test Connection General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs are sent as part of header in the HTTP request. > > [![Test Connection Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. The XML format does not support **Form Data**. > > In the **Raw** field, enter the XML payload for the test connection. > > [![Test Connection Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the XML response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Test Connection Response Information]()]() ### Account, Entitlement, or Get Object Aggregation This topic provides an example of an XML response for an aggregation operation. #### Account Aggregation - 1 Using the Web Services source, you can have multiple account aggregation operations. For example: Aggregation - 1 and Aggregation - 2. You can aggregate two attributes from EndPoint1 and three more attributes from EndPoint2. When you configure multiple operations, the response of first operation can be used as an input in the second operation. > [!NOTE] > > **Account Aggregation - 1 Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Account Aggregation - 1 (XML)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Account Aggregation**. > 3. In the **Context URL** field, enter the URL specific to the account aggregation. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Account Aggregation - 1 General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Account Aggregation - 1 Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. The XML format does not support **Form Data**. > > In the **Raw** field, enter the XML payload for the account aggregation. > > [![Account Aggregation - 1 Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the XML response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Account Aggregation - 1 Response Information]()]() > > On the **Response Mapping** tab: > > Below is an example of a schema that is mapped to XML response. Refer to [Configuration for Response]() for more information. > > [![Account Aggregation - 1 Response Mapping]()]() > > On the **XPath Namespace Mapping** tab: > > The namespace **xmlns** is the default namespace for the example mentioned in this section, and it is represented as **ns** in the following screenshot. > > [![Account Aggregation - 1 XPath Namespace Mapping]()]() #### Account Aggregation - 2 For example, during aggregation of Dropbox, the response of the first endpoint will return `id`, `Username`, `firstName`, among others. This response must be provided as an input to the second endpoint, this can be provided with help of a keyword "response" (`$response.team_member_id$`), where the `team_member_id` is the value fetched from Account Aggregation -1 and it is an identity attribute in the source schema. > [!NOTE] > > **Account Aggregation - 2 Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Account Aggregation - 2 (XML)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Account Aggregation**. > 3. In the **Context URL** field, enter the URL specific to the account aggregation. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Account Aggregation - 2 General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Account Aggregation - 2 Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. The XML format does not support **Form Data**. > > In the **Raw** field, enter the XML payload for the account aggregation. > > To fetch additional attributes from another endpoint, use the `id` (identity attribute) from the previous response. Add these attributes in **Schema Attribute** section of **Response Mapping** of the first end point (Account Aggregation - 1). > > In the following screenshot the `$response.team_member_id$` represents the identity that was aggregated in Account Aggregation-1 and mentioned in the schema mapping section of Account Aggregation -1. > > [![Account Aggregation - 2 Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the XML response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Account Aggregation - 2 Response Information]()]() > > On the **Response Mapping** tab: > > Below is an example of a schema that is mapped to XML response. Refer to [Configuration for Response]() for more information. > > [![Account Aggregation - 2 Response Mapping]()]() > > On the **XPath Namespace Mapping** tab: > > The namespace **xmlns** is the default namespace for the example mentioned in this section, and it is represented as **ns** in the following screenshot. > > [![Account Aggregation - 2 XPath Namespace Mapping]()]() > > On the **Parent Endpoint** tab: > > In the following example, Account Aggregation -1 (JSON) is the parent endpoint and Account Aggregation - 2(JSON) is its child endpoint. > > From the **Parent Endpoint Name** dropdown list, select **Account Aggregation - 1 (JSON)**, as shown below. > > [![Account Aggregation - 2 Parent Endpoint]()]() ### Create Account This topic provides an example of an XML response for a create account operation. > [!NOTE] > > **Create Account Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Create Account (XML)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Create Account**. > 3. In the **Context URL** field, enter the URL specific to the account creation. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Create Account General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Create Account Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. The XML format does not support **Form Data**. > > In the **Raw** field, enter the XML payload for the account creation. > > In the following screenshot, the `$plan` keyword represents the Provisioning Plan that is passed to the provision method. For example, `$plan.LastName` checks for the last name in the attribute request and updates in the body after it is found. > > [![Create Account Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the XML response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Create Account Response Information]()]() > > On the **Response Mapping** tab: > > Below is an example of a schema that is mapped to XML response. Refer to [Configuration for Response]() for more information. > > [![Create Account Response Mapping]()]() > > On the **XPAth Namespace Mapping** tab: > > The namespace **xmlns** is the default namespace for the example mentioned in this section, and it is represented as **ns** in the following screenshot. > > [![Create Account XPAth Namespace Mapping]()]() ### Account Delta Aggregation This topic provides an example of an XML response for the delta aggregation operation. #### Account Delta Aggregation - 3 Using the Web Services source, you can perform account delta aggregation operations. > [!NOTE] > > **Account Delta Aggregation - 3 Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Account Aggregation - 3` as the operation name. > 2. From the **Operation Type** dropdown list, select **Account Delta Aggregation**. > 3. In the **Context URL** field, enter the URL specific to the account delta aggregation. For example, the URL specified in the context URL is `/users?filter=meta.lastModifiedDate gt "$application.lastAggregationDate_account$"` ; where the `lastAggregationDate_account` is the last successful aggregation timestamp. > > > **Note** > > > > The default time period is in format: "`yyyy-MM-dd'T'kk:mm:ss'Z'`" If you want to change the time period format, use the following key-value pair to update the source via API: **key**: `connector_dateTimePattern`**value**: "`yyyy-MM-dd'T'kk:mm:ss'Z'`" **key** : `connector_serverTimeZone`**value**: "`UTC`" > 4. In the **HTTP Method** dropdown list, select **GET**. > > [![Account Delta Aggregation - 3 General Information]()]() > > On the **Headers** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Account Delta Aggregation - 3 Headers]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the JSON response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Account Delta Aggregation - 3 Response Information]()]() > > On the **Response Mapping** tab: > > Refer to [Configuration for Response]() for more information about the raw JSON response on which the **Response Information** schema is mapped. > > [![Account Delta Aggregation - 3 Response Mapping]()]() > > On the **XPath Namespace Mapping** tab: > > The namespace **xmlns** is the default namespace for the example mentioned in this section, and it is represented as **ns**. > > [![Account Delta Aggregation - 3 XPath Namespace Mapping]()]() > > On the **Parent Endpoint** tab: > > From the **Parent Endpoint Name** dropdown list, if needed select the endpoint on which the current operation is dependent to process the request. > > [![Account Delta Aggregation - 3 Parent Endpoint]()]() > > On the **Paging** tab: > > 1. In the **Initial Page Offset**, select the page offset required. > 2. From the **Page Size**, select the required page size for delta aggregation. > 3. In the **Paging Steps** field, enter any necessary paging steps defined. > > [![Account Delta Aggregation - 3 Paging]()]() ### Get Object This topic provides an example of an XML response for a get object operation. > [!NOTE] > > **Get Object Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Get Object (XML)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Get Object**. > 3. In the **Context URL** field, enter the URL specific to the get object. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Get Object General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Get Object Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. The XML format does not support **Form Data**. > > In the **Raw** field, enter the XML payload for the get object. > > The `$nativeIdentity$` signifies the AccountID (identity attribute) in the plan or during the get object operation. For example, `nativeIdentity` is used along with the following keywords: > > - **getobject** - `$getObject.nativeIdentity$` > - **plan** - `$plan.nativeIdentity$` > > [![Get Object Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the XML response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Get Object Response Information]()]() > > On the **Response Mapping** tab: > > Below is an example of a schema that is mapped to XML response. Refer to [Configuration for Response]() for more information. > > [![Get Object Response Mapping]()]() > > On the **XPath Namespace Mapping** tab: > > The namespace **xmlns** is the default namespace for the example mentioned in this section, and it is represented as **ns** in the following screenshot. > > [![Get Object XPath Namespace Mapping]()]() ### Add Entitlement This topic provides an example of an XML response for an add entitlement operation. > [!NOTE] > > **Add Entitlement Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Add Entitlement (XML)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Add Entitlement**. > 3. In the **Context URL** field, enter the URL specific to the entitlement. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Add Entitlement General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Add Entitlement Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. The XML format does not support **Form Data**. > > In the **Raw** field, enter the XML payload for the entitlement. > > [![Add Entitlement Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the XML response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Add Entitlement Response Information]()]() ### Enable Account This topic provides an example of an XML response for an enable account operation. > [!NOTE] > > **Enable Account Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Enable Account (XML)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Enable Account**. > 3. In the **Context URL** field, enter the URL specific to the account. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Enable Account General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Enable Account Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. The XML format does not support **Form Data**. > > In the **Raw** field, enter the XML payload for the account. > > Here the `plan.nativeIdentity` keyword signifies the AccountID (identity attribute) in the account request of the plan. For example, `nativeIdentity` is used along with the following keywords: > > - **getobject** - `$getObject.nativeIdentity$` > - **plan** - `$plan.nativeIdentity$` > > > **Note** > > > > If the target system expects the complete account object as payload, you must write a Before Operation Rule to fetch the complete object details and update the body attribute endpoint. Refer to [Web Services Before Operation Rule]() for more information. > > [![Enable Account Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the XML response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Enable Account Response Information]()]() ### Disable Account This topic provides an example of an XML response for a disable account operation. > [!NOTE] > > **Disable Account Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Disable Account (XML)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Disable Account**. > 3. In the **Context URL** field, enter the URL specific to the account. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Disable Account General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Disable Account Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. The XML format does not support **Form Data**. > > In the **Raw** field, enter the XML payload for the account. > > Here the `plan.nativeIdentity` keyword signifies the AccountID (identity attribute) in the account request of the plan. For example, `nativeIdentity` is used along with the following keywords: > > - **getobject** - `$getObject.nativeIdentity$` > - **plan** - `$plan.nativeIdentity$` > > [![Disable Account Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the XML response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Disable Account Response Information]()]() ### Update Account This topic provides an example of an XML response for a disable account operation. > [!NOTE] > > **Update Account Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Update Account (XML)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Update Account**. > 3. In the **Context URL** field, enter the URL specific to the account. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Update Account General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Update Account Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. The XML format does not support **Form Data**. > > In the **Raw** field, enter the XML payload for the account. > > [![Update Account Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the XML response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Update Account Response Information]()]() ### Change Password This topic provides an example of an XML response for a disable account operation. > [!NOTE] > > **Change Password Example** > > On the **General Information** tab: > > 1. In the **Operation Name** field, enter `Change Password (XML)` as the operation name. > 2. From the **Operation Type** dropdown list, select **Change Password**. > 3. In the **Context URL** field, enter the URL specific to the password change. > 4. In the **HTTP Method** dropdown list, select **POST**. > > [![Change Password General Information]()]() > > On the **Header and Body** tab: > > The Header has the data keys and their corresponding values. These key value pairs will be sent as part of the Header in the HTTP Request. > > [![Change Password Header]()]() > > The HTTP body is used for posting the data with a request. The body has two data entry types, **Form Data** and **Raw**. The XML format does not support **Form Data**. > > In the **Raw** field, enter the XML payload for the account. > > [![Change Password Body]()]() > > On the **Response Information** tab: > > The **Root Path** is the common path present in the XML response. The **Success Code** is the successful HTTP response code expected by the respective Web Service operation. By default, the success code is `2**`. > > [![Change Password Response Information]()]() # Pagination Web Services supports generic paging for Account and Entitlement Aggregations. > [!NOTE] > > **Notes** > > - If there are multiple Account or Entitlement Aggregation operations (endpoints) configured, paging is supported only for the first operation instance of Account or Entitlement Aggregation. > - By default, the page size is 50 and page offset is 0. > - The Web Services source correctly evaluates the `)` character within a string in the paging configuration. The following are methods to embed paging in the Web Services connector: - [Before and After Operation Rules Configuration](<#before-and-after-operation-rules-configuration>) - [Configure Paging](<#configure-paging>) ## Before and After Operation Rules Configuration To embed pagination in the Web Services connector, manual processing is required in the Before and After Operation Rules. Refer to [Web Services Before/After Operation Rule]() for more information on the rules. The Web Services connector relies on temporary information stored in the application object in the `transientValues` map. ### Paging with searchAfter Parameter The Web Services connector supports paging with the Before Rule and After Rule using the `searchAfter` array parameter. This parameter is used in the Before Rule to modify the request body for paginated search results. - `searchAfter` array - An array used in the Before Rule to modify the request body for paginated search results. - `hasMore` - A Boolean parameter that explicitly indicates whether more records are available for aggregation. #### Web Services Before Rule for Paging The Before Rule alters the URL and request parameters if the value of the `hasMore` parameter is set to `true` and the request to aggregate additional accounts is triggered. If the `hasMore` parameter is not set or it is set to `false`, the pagination request terminates, except for the initial request. The administrator must write the Before Rule for account and group aggregation properly. To support the `searchAfter` array parameter in pagination, refer to the following Before Rule sample for the account aggregation request in Perform Search: ```java import connector.common.JsonUtil; import java.util.Map; //The hasMore parameter must be set to TRUE by an earlier pagination process' AfterRule setting. //This parameter setting is mandatory as it acts as the deciding factor for terminating the pagination request. //If the hasMore parameter is not set, or if it is set to FALSE, the pagination request terminates for every //aggregation process except the initial process. Map transientValues = application.getAttributeValue("transientValues"); //The connector checks if it is the initial request or not. If it is, //then it executes without the searchAfter parameter. //If it is not the initial request, then the connector checks the search //after value(s) updated in the transientValues map in the After Operation //rule. It updates the searchAfter parameter with value in the request body. if(transientValues != null ) { log.debug("Before Rule: transientValues-->"+JsonUtil.render(transientValues)); Map body = requestEndPoint.getBody(); String jsonBody = (String) body.get("jsonBody"); Map jsonMap = JsonUtil.toMap(jsonBody); jsonMap.put("searchAfter", transientValues.get("searchAfterArray")); String finalBody = JsonUtil.render(jsonMap); body.put("jsonBody", finalBody); log.debug("Before Rule: Request Body-->"+jsonMap); requestEndPoint.setBody(body); } return requestEndPoint; ``` The Web Services Before Rule checks for transient values. If transient values are present, then it updates the request body with the `searchAfter` parameter. #### Web Services After Rule for Paging The After Rule determines whether the managed system has more records that can be aggregated and added as entries in the `transientValues` map. It also sets the `hasMore` key with a value of `true` or `false` depending upon the number of records aggregated. The After Rule stores the `searchAfter` array and `hasMore` parameter values in the `transientValues` map within the application object. This map stores the necessary information used by the Before Rule to manipulate the next API call. > [!IMPORTANT] > > Ensure that the parameter indicating whether the managed system contains more records is stored by the key named `hasMore`. This field is mandatory as it is the deciding factor for aborting the pagination requests. In the following example, the `searchAfter` entry is added into the `transientValues` map. The last object of the `processedResponseObject` list is used to get the `searchAfter` parameter value. This value determines how sorting works. The administrator must write the After Rule for account and group aggregation properly. Refer to the following sample After Rule for account aggregation requests in Perform Search: > [!NOTE] > > The provided example works correctly as long as no updates are needed in the resource objects. It may trigger a warning message in the logs, however it functions as intended. ```java import java.util.Map; //The expected number of objects from the pagination result. Integer expectedRecordsCount = 250; //The connector then checks if processedResponseObject is null or empty. //If it's null or empty then there's no need to process the request. if (processedResponseObject!= null && !processedResponseObject.isEmpty()) { //The connector fetches the last object to get the updated value of the searchAfter parameter. Map lastRecord = processedResponseObject.get(processedResponseObject.size()-1); //Attribute value on which sorting works, this attribute value will be used in the searchAfter parameter. String id = (String)lastRecord.get("id"); String[] searchAfterArray= new String[]{id}; log.debug("AFTER RULE: searchAfterArray ==> " + id); Integer fetchedRecordsCount = 0; if(null != processedResponseObject) { fetchedRecordsCount = ((List) processedResponseObject).size(); } //If the fetched records are equal to the expected number of records, //the hasMore value will be set to TRUE and pagination will continue. boolean hasMore = (fetchedRecordsCount != 0 && null != expectedRecordsCount && fetchedRecordsCount.equals(expectedRecordsCount)); log.debug("AFTER RULE: Has More? ==> " + hasMore); Map transientValues = application.getAttributeValue("transientValues"); if(transientValues == null) { transientValues = new HashMap(); application.setAttribute("transientValues", transientValues); } transientValues.put("hasMore", hasMore); if(hasMore){ transientValues.put("searchAfterArray", searchAfterArray); } } ``` ### Paging for Dropbox The administrator must write the Before Rule and After Rule for Dropbox account and group aggregation as follows. #### Dropbox Before Rule See the sample Before Rule for the account aggregation request in the Web Services connector for Dropbox using V2 in `examplerules.xml` file by name `Example WSBeforeRl DropboxPaging` as follows: ```java import sailpoint.tools.Util; Map obj = (Map) application.getAttributeValue("transientValues"); System.out.println("BEFORE RULE: Transient Values ==> " + obj); if(null != obj) { String offset = obj.get("offset"); System.out.println("BEFORE RULE: offset value ==> " + offset); String urlString = (String) requestEndPoint.getFullUrl(); if(Util.isNotNullOrEmpty(offset)) { System.out.println("BEFORE RULE: requestEndpoint ==> " + requestEndPoint); System.out.println("BEFORE RULE: URL ==> " + urlString); URL tempUrl = new URL(urlString); String queryString = tempUrl.getQuery(); System.out.println("BEFORE RULE: Query String ==> " + queryString); if(Util.isNotNullOrEmpty(queryString)) { StringBuffer queryParams = new StringBuffer(); String[] params = tempUrl.getQuery().split("&"); for (String param : params) { if(queryParams.length() > 0) queryParams.append("&"); if(param.startsWith("sysparm_offset=")) { queryParams.append("sysparm_offset="); queryParams.append(offset); } else { queryParams.append(param); } } urlString = urlString.replace(tempUrl.getQuery(), queryParams.toString()); } } System.out.println("BEFORE RULE: Updated Query String ==> " + urlString); requestEndPoint.setFullUrl(urlString); } System.out.println("BEFORE RULE: requestEndpoint Updated ==> " + requestEndPoint); return requestEndPoint; ``` For Dropbox V2, the Web Services After Rule stores the cursor returned from the previous team membership listing API in the `transientValues` map in the application. The URL is modified to redirect to the paging API and the cursor is sent as a part of the form data. Ensure that the `hasMore` flag is set by the earlier requests of the After Rule. #### Dropbox After Rule Configuring paging for Dropbox has specific instructions. Refer to the sample After Rule for the account aggregation request in the Web Services connector for Dropbox using V2 in `examplerules.xml` by name `Example WSAfterRl DropboxPaging` as follows: ```java Integer fetchedRecordsCount = 0; if(null != processedResponseObject) { fetchedRecordsCount = ((List) processedResponseObject).size(); } Integer expectedCount = null; Integer offset = null; URL url = new URL(requestEndPoint.getFullUrl()); System.out.println("AFTER RULE: Original Url ==> " + url); String[] params = url.getQuery().split("&"); for (String param : params) { String name = param.split("=")[0]; String value = param.split("=")[1]; switch(name) { case "sysparm_limit": expectedCount = Integer.parseInt(value); break; case "sysparm_offset": offset = Integer.parseInt(value); break; default: } } System.out.println("AFTER RULE: Fetch Count ==> " + fetchedRecordsCount); System.out.println("AFTER RULE: Limit Count ==> " + expectedCount); System.out.println("AFTER RULE: Fetch Offset ==> " + offset); Boolean hasMore = (fetchedRecordsCount != 0 && null != expectedCount && fetchedRecordsCount.equals(expectedCount) && null != offset); System.out.println("AFTER RULE: Has More? ==> " + hasMore); Map transientValues = application.getAttributeValue("transientValues"); if(transientValues == null) { transientValues = new HashMap(); application.setAttribute("transientValues", transientValues); } transientValues.put("hasMore", hasMore); if (hasMore) { if(null != offset) { System.out.println("AFTER RULE: New Offset ==> " + (offset + expectedCount)); transientValues.put("offset", String.valueOf(offset + expectedCount)); } } ``` The Team membership response in Dropbox and Dropbox V2 contains the following elements: - `cursor` - An encrypted token that represents the next page to be aggregated, if any, and forms part of the subsequent API calls. - `has_more` - A Boolean value that explicitly indicates whether more records are available for fetching. The After Rule stores the `cursor` and `has_more` values from the response in the `transientValues` map in the application object. This map stores the necessary information used by the Before Rule to manipulate the next API call. > [!IMPORTANT] > > Ensure that the parameter indicating whether the managed system contains more records is stored by the key named `has_more`. This field is mandatory as it is the deciding factor for aborting the pagination requests. ## Configure Paging Paging can be configured in Account/Entitlement Aggregation endpoints using the **Paging** tab with one of the following methods: - Paging based on limit-offset - Paging based on response markers - Paging based on response header links > [!NOTE] > > The **Paging** tab becomes available when you configure certain HTTP operations, such as account and entitlement aggregation. Refer to [Configuring Paging as an HTTP Operation](<#configuring-paging-as-an-http-operation>) for more information on configuring paging as an HTTP operation. ### Configuration Considerations Consider the following while configuring paging in the **Paging** tab: - Every paging configuration step must start on a new line. - SailPoint recommends providing a space after every operator, condition, or placeholder for correct evaluation of the paging expression. - The paging mechanism follows the placeholder notation for resolution of attribute values: ```text $response.attribute_key$ ``` Any attribute which follows the placeholder notation is resolved or assigned a value depending upon the operator being used. - Intermediate values can also be stored between page requests by using the placeholder notation. To achieve this, any attribute key which does not match any of the predefined keywords can be used. For more information, see the example in [Paging Based on Limit-Offset](<#paging-based-on-limit-offset>) where `$sysparm_offset$` is updated and used between page requests. - For complex expressions or conditions, multiple conditions can be grouped together using parentheses. For example: ```text TERMINATE_IF ($someattribute$ == TRUE) && ($otherattribute$ == NULL) ``` > [!IMPORTANT] > > For more information and implementation of paging, contact SailPoint Services. ### Paging Keywords The paging mechanism has the following predefined set of keywords you can use: | Keyword | Description | | --- | --- | | `application` | Represents the application. `baseUrl` - Base URL configured in the source. | | `endpoint` | Represents endpoint configuration. `relativeURL` - Relative URL of the endpoint. `fullUrl` - Full URL contained within the endpoint. | | `limit` | Indicates page limit configured in the endpoint configuration. | | `offset` | Indicates page offset configured in the endpoint configuration. | | `request` | Represents request body. | | `requestHeaders` | Represents request header. | | `response` | Represents response body object. | | `responseHeaders` | Represents response header. | | `TERMINATE_IF` | Indicates termination condition; multiple conditions can exist. `NO_RECORDS` - Indicates no records retrieved; to be used in conjunction with `TERMINATE_IF`, evaluates to TRUE/FALSE. `RECORDS_COUNT` - Indicates number of records retrieved. | | `NULL` | Indicates null or empty object. | | `REMOVE` | Indicates to remove an attribute. | > [!IMPORTANT] > > Avoid using arithmetic operations in the `TERMINATE_IF` statement. Arithmetic statements should be performed before checking for termination conditions. ### Supported Operators | Type | Operations | | --- | --- | | Regular operations | `+`, `-`, `*`, `/`, `=`, `&&`, and `\|\|` | | Conditional operations | `<`, `>`, `<=`, `>=`, `==`, and `!=` | ### Paging Based on Request Body Configuration Configure paging using request body parameter configuration. For example, an initial aggregation URL for an example managed system is as follows: ```text https://test.com/GetUserList ``` The example URL has the following parameters: - **baseUrl** - `https://test.com` - **relativeURL** - `/GetUserList` The request body is as follows: ```text Body: { "Limit" : 50, "offset": 1 } ``` Use the following configuration steps on the **Paging** tab based on the request body: ```text $limit$ = 50 TERMINATE_IF $RECORDS_COUNT$ < $limit$ $offset$ = $offset$ + 1 $endpoint.fullUrl$ = $application.baseUrl$ + "/GetUserList" $request.PageIndex$ = $offset$ ``` ### Paging Based on Limit-Offset You can limit pagination based on the `$offset$` and `$limit$` placeholders. - `$offset$` - Initial page offset - `$limit$` - Page size For example, in the following configuration, the maximum number of users to fetch per page is 100, and the starting offset of the API is 0. The index in the subsequent page is 101. 1. In **General Information \> Context URL**, enter the following: ```text /v2/users?pageSize=$limit$&index=$offset$ ``` 2. Go to the **Paging** tab and set the following: - **Page Size** - `100` - **Initial Page Offset** - `0` 3. Configure the following in **Paging Steps**: ```text TERMINATE_IF $RECORDS_COUNT$ < $limit$ $offset$ = $offset$ + $limit$ $endpoint.fullUrl$ = $application.baseUrl$ + "/v2/users?pageSize=" + $limit$ + "&index=" + $offset$ ``` #### Managed System Specific Configurations This section describes paging based on limit-offset for ServiceNow and Workday managed systems. ##### For ServiceNow For example, the initial aggregation URL for a ServiceNow managed system is as follows: ```text https://XYZ.service-now.com/api/now/v1/table/sys_user?sysparm_limit=100&sysparm_fields=sys_id ``` The above URL includes the following parameters: - **baseUrl** - `https://XYZ.service-now.com` - **relativeURL** - `api/now/v1/table/sys_user?sysparm_limit=100&sysparm_fields=sys_id` To configure paging based on limit-offset: 1. Use the following for a ServiceNow managed system: ```text TERMINATE_IF $RECORDS_COUNT$ < $sysparm_limit$ $sysparm_offset$ = $sysparm_offset$ + $sysparm_limit$ $endpoint.fullUrl$ = $application.baseUrl$ + "/api/now/v1/table/sys_user?sysparm_fields=sys_id&sysparm_limit=100&sysparm_offset=" + $sysparm_offset$ ``` In this example, the maximum record count is set using `sysparm_limit` and `RECORDS_COUNT`. `RECORDS_COUNT` represents the number of records fetched from the response and `sysparm_limit` can be changed as required. Based on this step, the next page URL is as mentioned in the following steps. 2. The second page URL is based on the paging steps configuration: ```text https://XYZ.com/api/now/v1/table/sys_user?sysparm_limit=100&sysparm_fields=sys_id&sysparm_offset=100 ``` 3. The next page URL is based on the paging steps configuration: ```text https://XYZ.com/api/now/v1/table/sys_user?sysparm_limit=100&sysparm_fields=sys_id&sysparm_offset=200 ``` The paging operation is terminated when `RECORDS_COUNT` is less than `sysparm_limit`, as follows: ```text $RECORDS_COUNT$ < $sysparm_limit$ ``` ##### For Workday For example, the initial aggregation URL for a Workday managed system is as follows: ```text https://XYZ.workday.com/ccx/service/sailpoint_pt1/Human_Resources/v24.1 ``` The above URL includes the following parameters: - **baseUrl** - `https://XYZ.workday.com` - **relativeURL** - `/ccx/service/sailpoint_pt1/Human_Resources/v24.1` The following are the configuration steps in the paging tab based on limit-offset: 1. Use the following for a Workday managed system: ```text TERMINATE_IF $response.wd:Response_Results.wd:Page$ > $response.wd:Response_Results.wd:Total_Pages$ $offset$ = $response.wd:Response_Results.wd:Page$ + 1 $request.bsvc:Response_Filter.bsvc:Page.text()[1]$ = $offset$ ``` In the above example, the number of pages is verified with the response from Workday and compared with the total number of pages. If the current page number is less than the total pages, then the request body (SOAP Body) is updated with the new page by incrementing it. The following is an example of an initial payload request with Initial Page Size (the initial page is the beginning index) as 1 and Page Size (number of records per page) as 10: ```xml .... 1 10 .... ``` 2. Based on the previous paging step, the next payload is as follows. The second aggregation payload increments the offset (page number): ```xml .... 2 10 .... ``` ### Paging Based on Response Markers This section describes paging based on a marker value in the response. Based on the marker value in the response, an aggregation process is terminated or continued. The following table lists examples of response marker based paging for Dropbox, Salesforce, and SuccessFactors. > [!NOTE] > > Other managed systems may use different response marker formats. In some configurations, it may be better to use the Before or After Operation Rule to configure paging. Refer to [Web Services Before/After Operation Rule]() for more information. #### Dropbox ```text TERMINATE_IF $response.has_more$ == FALSE $endpoint.fullUrl$ = $application.baseUrl$ + $endpoint.relativeUrl$ + "/continue" $request.cursor$ = $response.cursor$ REMOVE $request.limit$ ``` #### Salesforce ```text TERMINATE_IF $response.ns:result.ns:done$ != FALSE $request.soapenv:Body$ = "" + $response.ns:result.ns:queryLocator$ + "" ``` #### SuccessFactors ```text TERMINATE_IF $response.ns:result.ns:hasMore$ != TRUE $request.soapenv:Body$ = "" + $response.ns:result.ns:querySessionId$ + "" ``` ### Paging Based on Response Header Links This section describes paging based on response header links. The following table lists examples of response header links-based paging for Basware, ServiceNow, and Okta managed systems. > [!NOTE] > > Other managed systems may use different response header link formats. In some configurations, it may be better to use the Before or After Operation Rule to configure paging. Refer to [Web Services Before/After Operation Rule]() for more information. #### Basware ```text TERMINATE_IF $responseHeaders.x-amz-meta-continuationtoken$ == NULL $requestHeaders.x-amz-meta-continuationtoken$ = $responseHeaders.x-amz-meta-continuationtoken$ ``` #### ServiceNow ```text TERMINATE_IF $responseHeaders.link.next$ == NULL $endpoint.fullUrl$ = $responseHeaders.link.next$ ``` #### Okta ```text TERMINATE_IF $responseHeaders.link.next$ == NULL $endpoint.fullUrl$ = $responseHeaders.link.next$ ``` ## Configuring Paging as an HTTP Operation Configure paging as an HTTP operation. The **Paging** option appears for aggregation operations. Refer to [Pagination](<#pagination>) for more information on the paging feature. > [!NOTE] > > **Screenshot** > > [![Paging]()]() 1. Set the **Initial Page Offset**, which sets the page offset configured in the endpoint configuration. 2. Set the **Page Size**, which determines how many records the connector displays on each page. 3. In **Paging Steps**, enter configuration steps as required for limit-offset, response markers, or response header links paging. 4. Select **Save**. # Partitioning Web Services supports partitioning through the following modes: - **Static Partitioning** - Defines the separate partitions through fixed mappings. - **Dynamic Partitioning** - Discovers partitions at run time based on information returned by a REST or Web Services API call from a remote system. Static and Dynamic partitioning modes can be used at the same time. Partitions can be defined both in fixed configuration blocks and by dynamic values returned from the remote system. When both types of configurations are used, the list of partition records is concatenated and all of the defined partitions are aggregated. Conceptually, each partition retrieves the accounts from the managed system that correspond to a specific field or field values. The connector expects that those values can be passed to a search or filter API exposed by the managed system. The connector supports partitioning through token substitution of a URL pattern and/or a POST payload body's JSON or XML. For example, the Acme Human Resources department groups account searches by their costCenter attribute, and configures the API to return accounts using the following configuration: ```text GET https://acme-hr.com/admin/listAccounts?costCenter=AdminHQ ``` In this example, the API returns account records which belong only to the "AdminHQ" cost center. Assuming an even distribution of accounts to various costCenter values, each value for the costCenter attribute in this example can be mapped to a partition that aggregates the accounts corresponding to that grouping. Each partition is effectively a map of key-value pairs that define a unique grouping of accounts. The partition's key-value pairs are exposed to the Before/After Rules of a Connector Operation. They are available in the **Context URL** field, which is appended to the request, and in the body text of a POST operation. In the Context URL, the partition to aggregate is exposed as the `$partition.*$` keyword, where the asterisk (`*`) is replaced by the field name from the partition. This behaves similarly to the `$response.*` keyword and other tokens used by the Web Services connector. For example, in a partitioned account aggregation type of operation, you could have a Context URL as follows: ```text https://acme-hr.com/admin/listAccounts?costCenter=$partition.costCenter$ ``` When evaluated during aggregation, the partition's costCenter value is substituted for the $-encapsulated field and is then passed to the remote system. In situations where a simple path substitution is not sufficient, the URL can be generated in the Before Operation Rule by modifying the request endpoint's **URL** field. The partition variable is exposed in the Before Operation Rule for use by connector-specific rule logic. ## Partitioning Settings Configure partitioning aggregation to enable parallel data processing across multiple threads, enhancing the performance of aggregation tasks. Refer to [Partitioning](<#partitioning>) for information on configuration. > [!NOTE] > > **Screenshot** > > [![Partitioning Settings]()]() 1. Select **Enable Partitioning**. 2. Specify the **Number of Partitioning Threads** so that the aggregation processes the data in parallel and across multiple threads to help increase the aggregation performance. ## Partitioning Operations Partition Aggregation is supported by the following operation types: - Get Partitions - Partitioned Account Aggregation You must configure a **Get Partition** type connector operation to support dynamic partitioning. You must configure a **Partitioned Account Aggregation** connector operation to support static and dynamic partitioning. The Partitioned Account Aggregation operation is similar to the Account Aggregation endpoint. The only difference between the two is that the Partitioned Account Aggregation operation invokes when Account Aggregation with partitioning is enabled. The Partitioned Account Aggregation receives the `$partition.$` keyword tokens, but the original operation does not. Having these two as separate operations allows the connector to support single-threaded and partitioned (multi-threaded) aggregations with one configuration. ## Configuring Static Partitions The following example displays two static partitions that are identified by different `costCenter` values: ```json [ { "op": "add", "path": "/connectorAttributes/partitions", "value": [ { "name": "Partition 1", "size": 0, "attributes": { "costCenter": "CC-AD" } }, { "name": "Partition 2", "size": 0, "attributes": { "costCenter": "CC-AE" } } ] } ] ``` ## Configuring Dynamic Partitioning When invoked, the Get Partitions operation returns a list of partition records. This is a top-level operation which can be chained by referring to its Parent Operation. For example, a web service that returned the list of unique cost centers inside an HR application from an API request is as follows: ```text GET https://hr.acme.com/admin/listCostCenters { "idList": [ "CC-00", "CC-AA", "CC-AAZY", ... "CC-AZYXWVUT", "CC-AZYXWVUTS" ] } ``` In this example, the JSON payload returns an `idList` that contains an array of string values, and each is a Cost Center name. A Get Partitions operation must be configured to handle this JSON response. The relevant fields are: - **Context URL** - `/admin/listCostCenters` - **Method** - `GET` - **Response - Root Path** - `$.idList.*` - **Response - Schema Attribute** - `costCenter` Attribute Path: `$` - **Response - Schema Attribute** - `name` Attribute Path: `$` By passing the string to the partition's name and the costCenter attribute, the partition's name is rendered cleanly in the Aggregation Task's status interface. Partitions with no assigned name are randomly assigned a UUID value as their name. When the aggregation is performed and partitioning is enabled, it first asks the connector what dynamic partitions it has. The connector then calls this Get Partitions operation and returns the list of partition maps to the aggregation process. Each partition has a `costCenter` field and a name field populated for use in the aggregation operation. ## Configuring Partitioned Account Aggregation Operation The Partitioned Account Aggregation connector operation is invoked once for each partition map. The Partitioned Account Aggregation is conceptually very similar to the regular Account Aggregation operation and serves the same function. The only difference is the Partitioned Account Aggregation operation is always invoked with a `$partition.xxx$` keyword map providing the fields that uniquely describe the partition being aggregated by the operation. The account aggregation operations are designed to coexist. If the user runs a regular, non-partitioned account aggregation, the Account Aggregation operation is used. If the user selects to run a partitioned aggregation, which is specified by which Task and Task Options are selected in SailPoint, then the Partitioned Account Aggregation is used. The connector supports both modes simultaneously. Admins configuring Web Services connectors are encouraged to configure non-partitioned account aggregation before configuring a partitioned one. The connector logic places no restrictions or assumptions on the mode of operation; it freely supports non-partitioned, partitioned, or both at once. The Partitioned Account Aggregation operation expects you to substitute one or more `$partition.xxx$` keyword tokens into the URL for the operation or a POST body delivered to the remote system. Continuing with the earlier example, imagine that you have a system that allows you to return only the accounts or account IDs that exist in a specific Cost Center. That GET request displays as follows: ```text GET https://hr.acme.com/admin/listAccounts?costCenter=CC-AA { "idList": [ "3de42cd8-d0f6-4ff6-b683-e386b246e8da", "73d3eacd-624e-4ca3-8b13-9095ccb9c8b3", ... "67f8ab59-2923-422d-8772-c52cb4185723" ] } ``` Configuring this in a Partitioned Account Aggregation is a matter of entering the `$partition.costCenter$` keyword into the URL as follows: - **Context URL** - `/listAccounts?costCenter=$partition.costCenter$` - **Method** - `GET` - **Response - Root Path** - `$.idList.*` - **Response - Schema Attribute** - `costCenter` Attribute Path: `$` - **Response - Schema Attribute** - `name` Attribute Path: `$` As with the non-partitioned Account Aggregation operation, the Partitioned Account Aggregation operation can be chained with child operations referring to it by name. In the examples above, the API only returns the ID property of the account record. A subsequent GET call must be made to retrieve the full account record. The child operation or sequence of operations that retrieve the full account must reference the Partitioned Account Aggregation. ### Multiple Partitioned Account Aggregation You can use multiple Partitioned Account Aggregation operations. Like the Get Partitions operation, its use is intended to be strictly parent-child invocations. The behavior of multiple top-level peer Partitioned Account Aggregation operations is not recommended. # Retry Configurations > [!IMPORTANT] > > Add a list of retryable error messages to the attributes map of the source configuration. The value must be specified as a list or array even when only a single error string is provided. ## Provisioning Retry Errors > [!NOTE] > > For more information on SailPoint's REST APIs, refer to [Best Practices: REST API Authentication]() and [REST API - Update Source (Partial)]() in the SailPoint Developer Community. SailPoint connectors that support provisioning operations have the ability to retry a failed operation based on configurable error messages. The `retryableErrors` entry in the connector configuration is a list of strings that the connector searches for in the error message received from the managed source. If any of the configured error strings are found in the error message, the connector will attempt to retry the provisioning operation. Add a list of retryable error messages to the attributes map of the source configuration. The value must be specified as a list or array even when only a single error string is provided. If the error message contains one of the specified strings, the connector will initiate a retry attempt. However, if the configured error string is not present in the error message, the connector will consider the operation as failed and will not attempt a retry. Add the following entry in the source XML using the SailPoint REST APIs: For example, Use the SailPoint API by sending a PATCH request to the /v3/sources/{id} endpoint: `PATCH https://{orgName}.api.identitynow.com/v3/sources/:id` In the body of the PATCH, enter the retryable errors as follows: ```json [ { "op": "add", "path": "/connectorAttributes/retryableErrors", "value": [ "", "" ] } ] ``` > [!NOTE] > > Error messages containing very specific information about date/time, sequence ID and so on must be avoided. Error codes or error message substrings would be good candidates for inclusion. # Configuring Source Settings ## Aggregation Settings Configure connector settings related to delta aggregation and partitioning in aggregation processes. Refer to [Partitioning Settings]() for the partitioning settings. ### Delta Aggregation Enable delta aggregation to configure the connector to only aggregate accounts which have had changes since the last aggregation process. This feature can help streamline aggregation processes. > [!NOTE] > > **Screenshot** > > [![Delta Aggregation]()]() 1. Enable **Delta Aggregation** to aggregate accounts that have changed since the last execution. > **Note** > > Delta aggregation based on `account object type` is only applicable for managed systems that support the delta aggregation operation. 2. Enter the **Date Format** to use for the date and time data sent for delta aggregation. 3. In the **Server Timezone** field, specify the timezone for the source's server. 4. Select **Save**. ## Common Configuration 1. In the **Connection Timeout (in seconds)** field, enter the connection timeout value in seconds. 2. The Web Services source supports client certificate authentication for the API endpoints with SSL. Enter the valid details in the **Client Certificate** and **Client Private Key** fields, respectively. Refer to [Converting a Private Key to RSA PEM Format](<#converting-a-private-key-to-rsa-pem-format>) for more information. 3. In the **Account Enable Status Attribute** field, enter the attribute name and value to set the account status while loading accounts. The status of accounts with the specified attribute and value is marked as enabled; the status for all other accounts is disabled. For example, if you enter `status=Active`, the status of all accounts with the `status` attribute set to `Active` is enabled. > **Notes** > > - The **Account Enable Status Attribute** field supports both single-value and multi-value status attributes. If you need to enter multiple values for the **Account Enable Status Attribute**, separate them by using a comma as displayed in the following example: `status=Active,Pending` > - The connector doesn't support the ability to select the *n*-th element (including the first element) from a list. This feature's supported types are string, integer, and Boolean. For example, the expression `values[?(@.name=="accountDisabled")].values[0]` evaluates the expression value in a list format and is therefore not supported. You need to implement the Web Services After Operation Rule to configure enable/disable account for such a scenario. Refer to [Web Services After Operation Rule]() for more information. > - Conditional operators are not supported. Examples of unsupported operators are as follows: > > ```text > status=Active || status=Pending > status=Active && status=Pending > ``` 4. In the **Account Lock Status Attribute** field, provide the value required to check the account lock status. For example, if you enter `status=inactive`, the account schema `status` attribute determines whether the account is locked or not. In this case, all accounts with their `status` attribute set to inactive are considered locked by the connector, and therefore they are not included in provisioning. > **Note** > > The **Account Lock Status Attribute** field supports multiple values for the status attribute. If you need to enter multiple values for **Account Lock Status Attribute**, separate them by using a comma as displayed in the following example: `status=Locked,Inactive` 5. Enable **Use hasMore Attribute for Aggregation Termination** to enable the connector to terminate an aggregation process based on the setting for the `hasMore` attribute. If the `hasMore` attribute is set to `false`, the aggregation is terminated if the number of accounts returned is zero. If **Use hasMore Attribute for Aggregation Termination** is disabled, aggregation processes are not terminated based on the `hasMore` attribute. > **Note** > > The `hasMore` attribute is the Boolean attribute set in the `transientValues` map in the Before/After Operation rule. 6. Select **Save**. ### Converting a Private Key to RSA PEM Format The connector only supports the PEM format for the Client Certificate and the private key. Additionally, the Web Services connector expects the PEM private key to be an RSA PEM private key. The following process enables you to convert the private key to an RSA private key on a Windows computer: 1. Download and extract the latest version of openSSL. 2. Open **cmd** to the OpenSSL path. 3. Copy the **Private\_ADP\_Key.key** file to the extracted OpenSSL path. 4. Run the following command: ```text openssl rsa -in Private_ADP_Key.key -out rsa_private_key.pem ``` This prompts for a pass phrase and must be decrypted as per the following steps. Conversion to a combined PEM file: To convert a PFX file to a PEM file that contains both the certificate and private key, use the following command: ```text # openssl pkcs12 -in filename.pfx -out cert.pem -nodes ``` Conversion to separate PEM files: - Extract the private key from PFX to a PEM file with this command: ```text # openssl pkcs12 -in filename.pfx -nocerts -out key.pem ``` - Export the certificate with this command: ```text # openssl pkcs12 -in filename.pfx -clcerts -nokeys -out cert.pem ``` - Remove the password from the extracted private key with this command: ```text # openssl rsa -in key.pem -out server.key ``` > **Note** > > When using openSSL on the VA, the command works without the additional steps. However, the generated key signature is not accepted. It is suggested not to use openSSL on the VA. 5. Use this **rsa\_private\_key.pem** file in the connector. ## Provisioning Settings > [!NOTE] > > **Screenshot** > > [![Additional Settings - Provisioning]()]() The Web Services connector supports the following provisioning features: - **Create Account With "Ent" Request** - The Create Account operation executes with entitlement attributes. If the Create Account operation response contains the required attributes, including the identity attribute, the account object is created and the account link displays under the identity from whom the account creation was triggered. - **Throw Provisioning Rules** - Configure the connector to set the exception flag and display any exceptions encountered during provisioning. There are three options available: - **Throw Provisioning Before And After Rule Exception** - Set the exception flag during both the WebServicesBeforeOperationRule and the WebServicesAfterOperationRule. - **Throw Provisioning After Rule Exception** - Set the exception flag during the WebServicesAfterOperationRule. - **Throw Provisioning Before Rule Exception** - Set the exception flag during the WebServicesBeforeOperationRule. > **Note** > > The connector does not retry these errors based on the errors configured in the `possibleHttpErrors` attribute. - **Update Attributes with Change Password** - Include a password change and an attribute change in a single request. The **Change Password** operation is used for changing the password on the managed target system. If the provisioning plan contains no attribute request with the name "password", the update operation type endpoint is invoked. Enabling this attribute does not include requests for add or remove entitlement operations. Those requests are executed independently. - **Get Object Required for PTA** - Refer to [Pass-Through Authentication]() for more information. ## Common Configurations for Errors Configure HTTP errors that the connector may encounter during configured HTTP operations. You can configure these HTTP errors using the configuration UI or create an API call to define them. > [!NOTE] > > **Screenshot** > > [![Additional Settings - Common Configuration]()]() ### HTTP Errors When the connector encounters an error during an HTTP operation, it typically fails the operation and retries it. You must manually configure any possible HTTP error codes or messages that the API endpoint may return. Enter the **HTTP Error Keys** and their respective **HTTP Error Values**. You can manually configure HTTP error codes and messages for times when an API endpoint in the Web Services source sends unexpected error codes to flag failure conditions. Manually configuring these codes enables the connector to properly handle them. Configure the source with all possible HTTP error codes and messages that the API endpoint may return. Enter the **HTTP Error Keys** and their respective **HTTP Error Values**. > [!NOTE] > > This is not applicable to the child endpoints. For example: - The Web Services source returns the HTTP status code `200`, but the response payload contains an error. Without the manually entered HTTP error, the source won't know that it must fail the request and retry the operation. - During OAuth token generation, the source needs to regenerate a token to replace an invalid or expired token. You can configure an HTTP error code or message to specify an invalid/expiry token error in this event. The source regenerates and saves the token for OAuth2 authentication, then retries the operation with the newly generated access token. #### Object Not Found Error Messages Enter the error message that the connector displays when it can't find objects or fails to make connections. For example: ```text 404 - Object Not Found ``` #### Authentication Failed Error Messages Enter the error message that the connector displays when authorization fails. For example: ```text Authentication Failed ``` #### Expired Password Error Messages Enter the message that the connector displays when passwords expire. For example: ```text Password Expired ``` #### Disable Cookies The Web Services source can disable cookies while executing HTTP requests. You can disable cookies for all the operations performed except for the authentication API. Refer to [Support for Cookies]() for more information. > [!NOTE] > > If you use OAuth 2.0 authentication and you have the error messages for `expired password` correctly set, the connector tries to refresh the access token after the first failed connection attempt if the authentication endpoint supports it. ### Retryable Errors Definition API Call Add the following API call to the SailPoint REST API to define possible HTTP errors: ```json [ { "op": "add", "path": "connectorAttributes/retryableErrors", "value": [ "", "" ] } ] ``` > [!NOTE] > > Refer to [Best Practices: REST API Authentication]() and [REST API - Update Source (Partial)]() in the SailPoint Developer Community for more information on SailPoint's REST APIs. # Enable Connector Logging This topic provides the steps needed to enable logging on SailPoint using REST APIs. > [!NOTE] > > This topic only applies to VA-based integrations. > [!NOTE] > > The examples provided might not match your configuration. Use the logging levels and logging classes reference at the bottom of the topic to configure your API responses to match your connector. This process is broken up into four steps: 1. Identify the Virtual Appliance (VA) cluster on which you want to enable logging. 2. Get the logging configuration for the existing VA cluster. 3. Update the VA cluster to enable logging levels. 4. Observe logging changes to the logging levels. ### Identify the Virtual Appliance Cluster Select the VA on which you need to enable logging using REST API. If you already know the VA application's `id`, proceed to [Get the Logging Configuration](<#get-the-logging-configuration>). 1. Make the following call to the REST API to return a list of available VA clusters: GET /v3/managed-clusters The REST API returns a response that looks similar to the following: ```json [ { "id": "2c9180866166b5b0016167c32ef31a66", "name": "Development Cluster", "description": "Development Cluster", "clientType": "CCG", "ccgVersion": "373_535_70.2.0", "pinnedConfig": true, "logConfiguration": null }, { "id": "2c9180846a93ce60016ab29f039944de", "name": "Cloud Cluster", "description": "Cloud Cluster", "clientType": "CCG", "ccgVersion": "373_535_70.2.0", "pinnedConfig": true, "logConfiguration": { "clientId": null, "durationMinutes": 60, "expiration": "2020-12-15T19:13:36.079Z", "rootLevel": "DEBUG", "logLevels": { "sailpoint.connector.ADLDAPConnector": "DEBUG" } } } ] ``` > **Note** > > The previous example code shows two VA clusters. One VA cluster has a log configuration and the other does not (refer to the `logConfiguration` value in each returned VA cluster). This is because one of the clusters already has logging enabled. This is just an example configuration, and your environment may not have logging enabled on a cluster. 2. Identify the VA cluster that you want to enable logging on by its name or description and record its `id` attribute. ### Get the Logging Configuration Get your selected VA's cluster logging configuration and identify the values you need to update. 1. Make the following call to the REST API to return the VA cluster's logging configuration. Replace `{id}` with the VA cluster's `id` attribute value recorded earlier. GET /v3/managed-clusters/{id}/log-config - If the VA doesn't have a logging configuration currently set, it returns `204 No Content` as a response. - If the VA has an existing logging configuration, it returns something similar to the following: ```json { "clientId": null, "durationMinutes": 60, "expiration": "2020-12-15T19:13:36.079Z", "rootLevel": "DEBUG", "logLevels": { "sailpoint.connector.ADLDAPConnector": "DEBUG" } } ``` You'll need to configure the following information in the response: - `durationMinutes` is the number of minutes logging should remain enabled. - `rootLevel` is the default level for all logs. For more information, refer to [Logging Levels](<#logging-levels>). - `logLevels` is a map object with logging classes as keys and logging levels as values. - For keys, refer to [Logging Classes](<#logging-classes>) for commonly used logging classes. - For a list of available values, refer to [Logging Levels](<#logging-levels>). ### Update Logging Configuration Update the VA cluster configuration returned by the REST API to update the logging settings as needed. 1. Make the following call to the REST API to update the VA cluster's logging configuration. Replace `{id}` with the VA cluster's `id` attribute value recorded earlier. PUT /v3/managed-clusters/{id}/log-config 2. Submit your configuration changes to the REST API in a JSON body. - If the VA cluster did not already have a logging configuration and you received a `204 No Content` response, you can create a new one. - If the VA returned a configuration, you can edit it to include the changes. The JSON body should be as follows: ```json { "durationMinutes": 60, "rootLevel": "DEBUG", "logLevels": { "sailpoint.connector.ADLDAPConnector": "DEBUG" } } ``` Consider the following as you edit the JSON: - `durationMinutes` is the number of minutes logging should remain enabled. - `rootLevel` is the default level for all logs. For more information, refer to [Logging Levels](<#logging-levels>). - `logLevels` is a map object with logging classes as keys and logging levels as values. - For keys, refer to [Logging Classes](<#logging-classes>) for commonly used logging classes. - For a list of available values, refer to [Logging Levels](<#logging-levels>). If the update was successful, the REST API should return a response similar to the following: ```json { "clientId": null, "durationMinutes": 60, "expiration": "2020-12-15T19:13:36.079Z", "rootLevel": "DEBUG", "logLevels": { "sailpoint.connector.ADLDAPConnector": "DEBUG" } } ``` ### Observe Logging Changes Approximately five minutes after you update the configuration, the VA cluster starts generating log files you can review. You can view the log files in **ccg.log**. ### References The tables in this reference section list information that can be helpful when creating the JSON body you'll use to configure the VA cluster's configuration file. #### Logging Levels | Logging Level | Description | | --- | --- | | ERROR | Designates error events that might still allow the connector to continue. | | WARN | Designates potentially harmful situations. | | INFO | Designates information messages that highlight process at a coarse-grain level. | | DEBUG | Very verbose. Fine grain logging levels used for development and debugging. | | TRACE | Most verbose. Finer grain logging levels than debugging. | #### Logging Classes | Connector | Logging Class | | --- | --- | | Active Directory | sailpoint.connector.ADLDAPConnector sailpoint.connector.LDAPConnector | | AIX | openconnector.connector.unix.AIXConnector openconnector.connector.unix.UnixConnector | | Amazon Web Services | logger.aws.name=openconnector.connector.aws logger.aws.level=trace logger.aws.additivity = false logger.aws.appenderRef.rolling.ref = STDOUT | | Atlassian Suite Cloud | sailpoint.connector.OpenConnectorAdapter openconnector.connector.atlassian.AtlassianConnector | | Atlassian Data Center | sailpoint.connector.OpenConnectorAdapter openconnector.connector.atlassian.AtlassianDataCenterConnector | | Microsoft Entra ID | sailpoint.connector.AzureADConnector | | Box | openconnector.connector.BoxNetConnector sailpoint.connector.OpenConnectorAdapter | | Cerner | openconnector.connector.CernerConnector sailpoint.connector.OpenConnectorAdapter | | Delimited File | logger.DelimitedFileConnector.name = sailpoint.connector.DelimitedFileConnector logger.DelimitedFileConnector.level = debug logger.DelimitedFileConnector.additivity = false logger.DelimitedFileConnector.appenderRef.rolling.ref = STDOUT | | Dropbox | openconnector.connector.DropBoxConnector sailpoint.connector.OpenConnectorAdapter | | Epic | openconnector.connector.EPICConnector sailpoint.connector.OpenConnectorAdapter | | GE Centricity | openconnector.connector.GECentricity sailpoint.connector.OpenConnectorAdapter | | Google Apps / G Suite | openconnector.connector.GoogleAppsDirect sailpoint.connector.OpenConnectorAdapter | | IBM i | openconnector.connector.IBMiConnector | | Lotus Domino | sailpoint.connector.LotusDomino | | JDBC | sailpoint.connector.JDBCConnector | | Sun One LDAP | sailpoint.connector.LDAPConnector | | Linux | openconnector.connector.unix.LinuxConnector sailpoint.connector.OpenConnectorAdapter sailpoint.connector.UnixConnector | | Microsoft Office365 | sailpoint.connector.Office365Connector | | Microsoft SQL Server | sailpoint.connector.mssql.serviceimpl.MSSQLServerConnectorV2 | | Okta | logger.openconnector.name = openconnector.connector.okta.OktaConnector logger.openconnector.level = debug logger.openconnector.additivity = false logger.openconnector.appenderRef.rolling.ref = STDOUT | | Oracle Database | sailpoint.connector.OracleDBConnector sailpoint.connector.JDBCConnector | | Oracle E-Business | sailpoint.connector.OracleEBSConnector sailpoint.connector.JDBCConnector | | Oracle Fusion HCM | openconnector.connector.oraclefusionhcm.OracleFusionHCMConnector sailpoint.connector.OpenConnectorAdapter | | Oracle HCM Cloud | sailpoint.connector.oraclehcmcloud.OracleHCMCloudConnector | | Oracle HRMS | sailpoint.connector.OracleAppsHRMSConnector sailpoint.connector.JDBCConnector | | Oracle Netsuite | openconnector.connector.netsuite.NetsuiteConnector | | PeopleSoft ERP | openconnector.connector.PeopleSoftConnector sailpoint.connector.OpenConnectorAdapter | | PeopleSoft HRMS | sailpoint.connector.PeopleSoftHRMSConnector | | RemedyForce | sailpoint.connector.ForceConnector | | RSA Authentication Manager | openconnector.connector.RSAConnector openconnector.connector.rsa.RSAHTTPClient sailpoint.connector.OpenConnectorAdapter | | Salesforce | sailpoint.connector.ForceConnector | | SAP Concur | openconnector.connector.sapconcur.SAPConcurConnector | | SAP - Direct | sailpoint.connector.SAPConnector sailpoint.connector.SAPInternalConnector | | SAP GRC | logger.SAPGRCConnector.name = sailpoint.connector.sapgrc logger.SAPGRCConnector.level = debug logger.SAPGRCConnector.additivity = false logger.SAPGRCConnector.appenderRef.rolling.ref = STDOUT | | SAP HR/HCM | sailpoint.connector.SAPHRInternalConnector | | SCIM 1.1 | openconnector.connector.SCIMConnector sailpoint.connector.OpenConnectorAdapter | | SCIM 2.0 | openconnector.connector.scim2.SCIM2Connector sailpoint.connector.OpenConnectorAdapter | | ServiceNow | openconnector.connector.servicenow.ServiceNowConnector openconnector.connector.servicenow.ServiceNowRestClient sailpoint.connector.OpenConnectorAdapter | | ServiceNow Service Desk Integration | openconnector.connector.servicedesk.ServiceNowServiceDeskConnector sailpoint.connector.OpenConnectorAdapter | | Siebel | openconnector.connector.SiebelConnector sailpoint.connector.OpenConnectorAdapter | | Snowflake | openconnector.connector.snowflake.SnowflakeConnector sailpoint.connector.OpenConnectorAdapter | | Solaris | openconnector.connector.unix.SolarisConnector openconnector.connector.unix.UnixConnector sailpoint.connector.OpenConnectorAdapter | | SuccessFactors | sailpoint.connector.SuccessFactorsConnector | | Sybase | sailpoint.connector.SybaseDirectConnector sailpoint.connector.JDBCConnector | | Webex | openconnector.connector.Webex sailpoint.connector.OpenConnectorAdapter | | Workday | openconnector.connector.WorkDay sailpoint.connector.OpenConnectorAdapter | | Workday Accounts | openconnector.connector.workdayaccounts openconnector.connector.workdayaccounts.WorkdayAccountsConnector sailpoint.connector.OpenConnectorAdapter | | Web Services | sailpoint.connector.WebServices | | XML | openconnector.connector.XMLConnector sailpoint.connector.OpenConnectorAdapter | | Yammer | openconnector.connector.YammerConnector sailpoint.connector.OpenConnectorAdapter | | Zoom | openconnector.connector.zoom.ZoomConnector sailpoint.connector.OpenConnectorAdapter | # Troubleshooting If you encounter any of the following issues or errors, SailPoint recommends that you follow the guidance provided below to resolve the error before contacting SailPoint Support. For issues or errors that are not addressed in this connector guide, refer to the following resources for troubleshooting information: - [SailPoint Identity Services Documentation]() - [SailPoint Support Knowledge Base]() - [SailPoint Developer Community]() ## EndPoint Not Found in Namespace Error Connector classes are not visible in the beanshell rule, therefore connector class file changes cause before/after Provisioning rules to fail with the following error: ```text sailpoint.tools.GeneralException: Class: EndPoint not found in namespace ``` **Resolution**: Implement before/after operation rules to have direct access to connector APIs. ## RateLimit Headers Not Received Error The Web Services connector checks for the Retry-After response in the response header. If Retry-After is not present it checks for limit, remaining, and reset. If none of the above are present in the response header, it logs "RateLimit headers not received" in the debug file. **Resolution**: Ensure the limit, remaining, and reset are present in the response header. ## Test Connection Fails When Web Services Is Using TLS 1.0 on WebSphere Application Server The Web Services Connector enforces secure communication. As a result, this may cause **Test Connection** to fail with the following error if used with IBM JDK 1.8: ```text [ConnectorException] [Possible suggestions] Ensure configuration parameters are correct with a valid format, Ensure active network connectivity between Source and Target system. [Error details] javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure ``` **Resolution**: Perform the following to add the `com.ibm.jsse2.overrideDefaultTLS` property in the Java properties: 1. Go to **Servers \> Java and Process Management \> Process Definition \> JVM \> Custom Properties** and add the following property: ```text com.ibm.jsse2.overrideDefaultTLS ``` Or add it in the `jvm.options` file. Refer to [Overriding default JVM SSL properties to force use of TLSv1.2]() for more information. 2. Restart the server. ## An Error Occurs During Aggregation if the Attribute in the JSON Response Has a Period (.) in the Name **Issue**: JSON attributes which contain periods (`.`) in their attribute name are not handled properly by the connector. The period in the attribute name shouldn't mean that the attribute is a child of any parent attribute. This applies to any operation which might affect the attribute. **Resolution**: During the attribute path configuration, enclose the attribute name in square brackets and double quotes. For example, express the `manager.user_name` attribute as follows: ```text ["manager.user_name"] ``` Example response: ```text Response: { "data": [ ... { "result": { "manager.user_name": "Test" } } ... ] } Root path: $.data[*] JSON Path: result.["manager.user_name"] ``` ## An Error Occurs During Provisioning if the Request Body Includes a Multivalued Attribute With Quotation Marks **Resolution**: Remove the quotation marks from the multivalued attribute in the request body. For example, the following request body may produce an error. The bold text is a multivalued attribute with quotation marks: ```json { "username":"$plan.nativeIdentity$", "Group":"$plan.Group$", "email":"$plan.email$" } ``` To solve the error, remove the quotation marks so the request body is as follows: ```json { "username":"$plan.nativeIdentity$", "Group":$plan.Group$, "email":"$plan.email$" } ``` ## Unable to Provision Accounts Using Web Services Connector If you have a custom After Provisioning rule in place, this is likely a result of having the `throwProvAfterRuleException` attribute enabled on your Web Services source. As a result, you may receive the following error during account provisioning: ```text Exception occurred while performing 'Create' operation on identity 'null': The application script threw an exception: java.lang.ClassCastException: Cannot cast java.lang.String to int BSF info: {Rule Name} at line: 0 column: columnNo ``` **Resolution**: Review the [Web Services Source Configuration Reference Guide]() for steps on disabling the `throwProvAfterException` attribute using the source API. ## Create Account Operation Fails While Using Recommended Mappings in the Account Policy The create account operation fails even though the recommended attribute mappings are used in the Account Policy. **Resolution**: Ensure that the managed system is enabled to set the account attributes used by the Account Policy, then try the Create account operation again. ## Web Services Aggregation Fails With an HTTP Error 429 Aggregation processes are automatically retried when the connector experiences an HTTP error 429. You may see the following error: ```text HTTP error 429: Too many requests or rate limit exceeded ``` **Resolution**: Configure a valid `Retry-After` response header attribute. The aggregation is implicitly retried based on the `Retry-After` response header attribute. The allowed `Retry-After` value range is from `1` to `180` seconds. If the response header has no `Retry-After` value, then the connector retries a failed process after one second. If the response header has a `Retry-After` value higher than the maximum `180` seconds (three minutes), then the connector retries a failed process after 180 seconds. If the response header has an accepted Retry-After value (three minutes or less), then the retry takes place after that time duration. ## Web Services Aggregation Fails With an Error 500 The connection to the source is timing out. This may be caused by an incorrect Base URL within the source's configuration in SailPoint. You may see the following messages as well: ```text java.lang.RuntimeException - com.sailpoint.pipeline.PipelineException: An internal error occurred handling stream response from the server. - java.lang.RuntimeException: com.sailpoint.pipeline.PipelineException: An internal error occurred handling stream response from the server. Caused by: java.lang.InterruptedException: Timeout waiting for response to message 63 from client ``` **Resolution**: Ensure that the Base URL is correct. 1. In SailPoint, go to **Admin \> Connections \> Sources**. 2. Select the appropriate Web Services source. 3. Go to **Edit Configuration \> Connection Settings**. 4. Ensure the Base URL within the Server Host section is correct. If not, provide the correct URL. 5. Save any changes you make. ## Illegal Character Error Received During Web Services Connector Test Connection The context URL used for the test connection contains a `>` character so it's not encoded properly. ```text Exception occurred in Test Connection.Url: {URL}, Message: java.lang.IllegalArgumentException: Illegal character in query at index 79: {URL}, HTTP Error Code: 0 ``` **Resolution**: Updating the URL to include the encoded character should resolve the issue. 1. In SailPoint, go to **Admin \> Connections \> Sources**. 2. Select the Web Services source. 3. Go to **Edit Configuration \> HTTP Operations**. 4. Find the HTTP Operation used for the test connection. 5. Select **General Information**. 6. Within the **Context URL** field, replace any `>` characters with `%3E`. 7. Save the changes and test the connection. > [!NOTE] > > There may be other characters that aren't being encoded properly. If the URL contains other characters, try replacing them with their ASCII-encoded value equivalents as well. ## Account Aggregation Fails While HTTP Operation Is Configured With Context URL, and URL Contains Special Characters Error message: ```text sailpoint.connector.ConnectorException: Url: Message: 400 : Bad Request, HTTP Error Code: 400 ``` Special characters that may cause issues with the context URL may include, but aren't limited to, commas (`,`), open and close parentheses or brackets (`()`, `[]`, and `{}`), or pound signs (`#`). **Resolution**: If the context URL contains certain special characters, you may need to disable the `skipEncodingDecodingUrl` key. You can disable the `skipEncodingDecodingUrl` key by adding the following to your API: ```json [ { "op": "add", "path": "/connectorAttributes/skipEncodingDecodingUrl", "value": "true" } ] ``` See the [Update Source (Partial)]() article in the SailPoint Developer Community for more information on adding this command to your API. ## The SOAP Body Is Trimmed if the XML Request Body Includes a $ Character **Resolution**: If the SOAP Body contains `$` as a value in the request body, such as with `$Role`, pass the following attribute into the plan as an `AttributeRequest`: > [!NOTE] > > These examples use `$Role` as the value placeholder. Substitute your own as required. ```xml ``` In the **Web Services Operation \> Raw Body** configuration, use `$plan.RoleNm$` as a placeholder in the desired location, as was done in the following example: ```text ``` By making these suggested changes, the SOAP Body should be created in the required format. For a provisioning plan with `$Role`, the attribute request is as follows: ```xml ``` Based on the example attribute request, you can expect the request body to be as follows: ```xml ``` ## Oracle HCM Accounts Are Deleted During Full Aggregation Processes in Web Services Connector The Oracle HCM target system may not be sending the data in the correct order. This reordering of the data may skip data which has been previously aggregated, causing the aggregation process to delete it. **Resolution**: Add the `orderBy` attribute into the **Context URL** field in the account aggregation configuration to get the data in a properly sorted order. Refer to [General Information]() for more information on configuring the **Context URL** field. > [!NOTE] > > Refer to [Sort]() in the *REST API for Oracle Fusion Cloud HCM* documentation for more information on configuring the `orderBy` attribute. ## Test Connection Fails With the Error "Invalid or Missing Credentials, HTTP Error Code: 401" **Resolution**: Verify that the password does not contain the `$` character. The `$` symbol is used by the Web Services Connector for placeholders and can cause the connection to fail. ## All Operations Fail Due to a Missing Cookie Some managed systems require only a cookie for authentication. **Resolution**: Do the following for each operation: 1. Create an endpoint API for cookie generation. 2. Create a second endpoint of the same type and configure an API to execute its required operation. ## The Web Services Source Doesn't Honor the Account Enable Field if It's Set by a Web Services afterOperation Rule **Resolution**: Create a custom Web Services `afterOperation` rule which supports the Account enable field. Review the following options as examples: > [!NOTE] > > **Option 1** > > ```java > import sailpoint.connector.webservices.WebServiceConnectorUtil; > > List processedResponseObject1 = new ArrayList(); > log.error("processedResponseObject===" + processedResponseObject); > for (Map m: processedResponseObject) { > Map newMap = new HashMap(); > String accStatus = (String) m.get("status").get(1); > newMap.put("userId", m.get("userId")); > newMap.put("status", accStatus); > WebServiceConnectorUtil.enableLockResourceObject( > application, newMap); > processedResponseObject1.add(newMap); > } > log.error("processedResponseObject1===" + processedResponseObject1); > Map updatedMapInfo = new HashMap(); > updatedMapInfo.put("data", processedResponseObject1); > return updatedMapInfo; > ``` > [!NOTE] > > **Option 2** > > ```java > import sailpoint.api.SailPointContext; > import sailpoint.connector.webservices.EndPoint; > import sailpoint.connector.webservices.WebServicesClient; > import sailpoint.tools.Util; > import sailpoint.tools.GeneralException; > > List returnObj = new ArrayList(); > Map processedData = new HashMap(); > > if (processedResponseObject != null) { > for (Map personEntry: processedResponseObject) { > if (logic) { > employeeEntry.put("IIQDisabled", true); > } else { > employeeEntry.put("IIQDisabled", false); > } > returnObj.add(personEntry); > } > processedData.put("data", returnObj); > } > return processedData; > ``` ## OOTB WS Connector Is Not Able to Parse the Qualys DTD Response **Resolution**: Follow these steps within the **Account Aggregation** endpoint to resolve the issue: 1. Add **Headers** as Content-Type: ```text application/json ``` 2. Add **Before Operation Rule** and **After Operation Rule**: WS BeforeOperation Rule: ```java //beforeRule import java.util.Map; Map h=requestEndPoint.getHeader(); h.put("Content-Type", "text/xml"); h.put("Accept", "text/xml"); ``` WS AfterOperation Rule: ```java //afterRule import org.json.JSONObject; import org.json.XML; import org.json.JSONException; import connector.common.JsonUtil; import java.util.HashMap; import java.util.Map.Entry; import java.util.Map; import java.util.List; import java.util.ArrayList; import javax.net.ssl.HttpsURLConnection; import java.io.BufferedReader; import sailpoint.tools.GeneralException; import com.google.gson.Gson; import org.json.*; import sailpoint.integration.*; // We are getting the response from the API in rawResponseObject in xml format and in the below line we are converting it to JSONObject. JSONObject xmlJSONObj = XML.toJSONObject((String)rawResponseObject); String jsonPrettyPrintString = xmlJSONObj.toString(4); List Finlist = new ArrayList(); // Getting the Map from the Json Map response = new Gson().fromJson(jsonPrettyPrintString, Map.class); Map USER_LIST_OUTPUT = response.get("USER_LIST_OUTPUT"); Map USER_LIST = USER_LIST_OUTPUT.get("USER_LIST"); List Finallist = USER_LIST.get("USER"); for(int d = 0; d < Finallist.size(); d++ ){ Map newmap = new HashMap(); // Updating value from CONTACT_INFO map Map CONTACT_INFO = Finallist.get(d).get("CONTACT_INFO"); String FIRSTNAME = CONTACT_INFO.get("FIRSTNAME"); String email = CONTACT_INFO.get("EMAIL"); newmap.put("FIRSTNAME", FIRSTNAME); newmap.put("EMAIL", email); // Updating value direct from list newmap.put("USER_STATUS", Finallist.get(d).get("USER_STATUS")); newmap.put("BUSINESS_UNIT", Finallist.get(d).get("BUSINESS_UNIT")); newmap.put("USER_ROLE", Finallist.get(d).get("USER_ROLE")); newmap.put("USER_LOGIN",Finallist.get(d).get("USER_LOGIN")); newmap.put("USER_ID",Finallist.get(d).get("USER_ID")); Finlist.add(newmap); } Map updatedMapInfo = new HashMap(); updatedMapInfo.put("data", Finlist); return updatedMapInfo; ``` > **Important** > > - Use these sample rules as a baseline for your configuration at your own discretion. SailPoint Support and AAA teams do not maintain or update these samples; they cannot fulfill requests for modifications. > - For advanced customizations or in-depth changes, SailPoint's Expert Services team is available to assist you. This is a billable service and requires an available balance of Expert Services (ES) hours. # Timeout Errors and Settings Timeout errors might occur when SailPoint is waiting for a response from the Virtual Appliance (VA). These errors are applicable to all connectors and tend to occur during the setup of sources or when sources are down. This document is designed to give specific information that can be used to resolve these errors. Each timeout attribute has a default time value that is listed in seconds or minutes. Increasing the time value may resolve the error as it will allow for longer communication time between the two systems, thus avoiding the timeout error. > [!IMPORTANT] > > Add the necessary attributes or values before performing the "replace" operation, as missing attributes will cause the operation to fail. To increase the communication time, increase the value of the appropriate timeout attribute. Then submit the change to the VA using the SailPoint REST API. > [!NOTE] > > For more information on SailPoint's REST APIs, refer to [Best Practices: REST API Authentication]() and [REST API - Update Source (Partial)]() in the SailPoint Developer Community. ### aggregateTimeout **Description:** This parameter is set for the aggregation timeout, measured in seconds. **Resolution:** Increase the `aggregateTimeout` value gradually to optimize aggregation. Start with 180, then increase to 600, 900, and finally 1800. The maximum value is 3600 seconds. For example: If your current time value is 180 seconds, update the `aggregateTimeout` attribute as follows: ```json [ { "op": "replace", "path": "/connectorAttributes/aggregateTimeout", "value": 600 } ] ``` ### healthCheckTimeout **Description:** This parameter is set for the test connection and health check timeout. **Resolution:** The default value is 30 seconds. If the timeout error continues, increase the value in 15 second increments and try again. For example: If your current time value is 30 seconds, update the `healthCheckTimeout` attribute as follows: ```json [ { "op": "replace", "path": "/connectorAttributes/healthCheckTimeout", "value": 45 } ] ``` ### provisioningTimeout **Description:** This parameter is set for provisioning timeout. **Resolution:** Increase the `provisioningTimeout` value gradually to optimize provisioning. Start with 180, then increase to 360, and finally 600. The maximum value is 600 seconds. For example: If your current time value is 180 seconds, update the `provisioningTimeout` attribute as follows: ```json [ { "op": "replace", "path": "/connectorAttributes/provisioningTimeout", "value": 360 } ] ``` ### timeout **Description:** This parameter is set for pass-through authentication timeout. **Resolution:** The default value is 15 seconds. If the timeout error continues, increase this value in 15 second increments and try again. For example: If your current time value is 15 seconds, update the `timeout` attribute as follows: ```json [ { "op": "replace", "path": "/connectorAttributes/timeout", "value": 30 } ] ``` ### apiTimeout **Description:** This parameter is set for API time tracking; customers can check it using an external tool. **Resolution:** The default value is 60 seconds. If the error continues, increase the value by 15 second increments and try again. For example: If your current time value is 60 seconds, update the `apiTimeout` attribute as follows: ```json [ { "op": "replace", "path": "/connectorAttributes/apiTimeout", "value": "75" } ] ``` ### timeoutInSeconds **Description:** This parameter helps prevent the VA from waiting indefinitely for an API response, ensuring efficient handling of API requests. For example: If your current time value is 30 seconds, update the `timeoutInSeconds` attribute as follows: ```json [ { "op": "replace", "path": "/connectorAttributes/timeoutInSeconds", "value": "15" } ] ```