Repository navigation
added more documentation for SaaS Connectivity #1222
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| --- | ||
| id: application-discovery-list | ||
| title: Application Discovery List | ||
| pagination_label: Application Discovery List | ||
| sidebar_label: Application Discovery List | ||
| keywords: ['connectivity', 'connectors', 'application discovery'] | ||
| description: Return the applications that the source knows about. | ||
| slug: /connectivity/saas-connectivity/commands/application-discovery-list | ||
| tags: ['Connectivity', 'Connector Command'] | ||
| --- | ||
|
|
||
| | Input/Output | Data Type | | ||
| | :----------- | :------------------------------------------: | | ||
| | Input | StdApplicationDiscoveryListInput | | ||
| | Output | StdApplicationDiscoveryListOutput | | ||
|
|
||
| ### Example StdApplicationDiscoveryListInput | ||
|
|
||
| ```javascript | ||
| { | ||
| "datasetId": "sso-okta:applications" | ||
| } | ||
| ``` | ||
|
|
||
| ### Example StdApplicationDiscoveryListOutput | ||
|
|
||
| ```javascript | ||
| { | ||
| "id": "app-5678", | ||
| "primaryAppName": "Slack", | ||
| "description": "Team messaging", | ||
| "status": "ACTIVE", | ||
| "connectorCategory": "sso", | ||
| "appUrl": "https://example.slack.com", | ||
| "usersCount": "250", | ||
| "riskLevel": "Low" | ||
| } | ||
| ``` | ||
|
|
||
| ## Description | ||
|
|
||
| The application discovery list command returns the applications that the source knows about. For example, an identity provider (SSO) or a configuration management database (CMDB) tracks the apps that a company uses. SailPoint Identity Security shows the results in Application Discovery. | ||
|
|
||
| The tenant must have the Application Discovery license (`idn:application-discovery`). | ||
|
|
||
| To use this command, you must specify this value in the `commands` array: `std:application-discovery:list` | ||
|
|
||
| ### Declare datasets in the connector spec | ||
|
|
||
| Add a `datasets` object to `connector-spec.json`. Each key is a dataset ID. Set `type` to `std:application_discovery`. | ||
|
|
||
| ```json | ||
| { | ||
| "commands": ["std:test-connection", "std:application-discovery:list"], | ||
| "datasets": { | ||
| "sso-okta:applications": { | ||
| "type": "std:application_discovery", | ||
| "name": "discovered-application", | ||
| "identityAttribute": "id", | ||
| "displayAttribute": "primaryAppName", | ||
| "schema": { | ||
| "type": "object", | ||
| "properties": { | ||
| "id": { "type": "string" }, | ||
| "primaryAppName": { "type": "string" }, | ||
| "description": { "type": "string" } | ||
| }, | ||
| "required": ["id", "primaryAppName", "description"] | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### When SailPoint Identity Security calls the command | ||
|
|
||
| An application discovery starts in one of these ways: | ||
|
|
||
| - An admin calls the [start application discovery API](/docs/api/start-application-discovery-v-1) with the dataset IDs. On-demand runs have a daily limit for each source. | ||
| - A source schedule of type `APPLICATION_DISCOVERY` starts it. The schedule has a cron expression and the dataset IDs: | ||
|
|
||
| ```json | ||
| { | ||
| "type": "APPLICATION_DISCOVERY", | ||
| "cronExpression": "15 * * * *", | ||
| "config": { | ||
| "datasetIds": ["sso-okta:applications"] | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| SailPoint Identity Security sends `input.datasetIds` with the datasets to discover. SailPoint Identity Security can also send `additionalParameters` to pass extra data to some SailPoint connectors, for example the location of a file to read. Your connector does not need to use it. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are From what I can tell, the platform sends |
||
|
|
||
| If an application is missing from two discovery runs in a row, SailPoint Identity Security sets its status to `INACTIVE`. | ||
|
|
||
| ### Output fields | ||
|
|
||
| Each application needs `id`, `primaryAppName`, and `description`. All other fields are optional. | ||
|
|
||
| | Field | Values | | ||
| | :---- | :----- | | ||
| | `status` | A string, for example `ACTIVE` or `INACTIVE`. | | ||
| | `connectorCategory` | The kind of source, for example `sso` or `cmdb`. | | ||
| | `riskLevel` | `High`, `Medium`, or `Low`. | | ||
| | `riskScore` | A number. | | ||
| | `usersCount` | A string. Convert numbers with `String()`. | | ||
|
|
||
| The application list in SailPoint Identity Security shows the name, description, category, discovery connector, business criticality, status, and the first and last discovery dates. The details page of each application shows the other fields. | ||
|
|
||
| ## Implementation | ||
|
|
||
| The SDK has two ways to register this command, but only one can be used at a time. | ||
|
|
||
| | Method | Use it when | | ||
| | :----- | :---------- | | ||
| | `stdApplicationDiscoveryListWithDataset` | Your connector declares datasets. This is the method for new connectors. | | ||
| | `stdApplicationDiscoveryList` | Your connector has no datasets. The input is an empty object. | | ||
|
|
||
| With `stdApplicationDiscoveryListWithDataset`, the SDK calls your handler once for each dataset ID and adds `datasetId` to each object that you send. | ||
|
|
||
| Call `res.send()` once for each application. | ||
|
|
||
| ```typescript | ||
| import { | ||
| Context, | ||
| createConnector, | ||
| readConfig, | ||
| Response, | ||
| StdApplicationDiscoveryListInput, | ||
| StdApplicationDiscoveryListOutput, | ||
| } from '@sailpoint/connector-sdk' | ||
| import { MyClient } from './my-client' | ||
|
|
||
| export const connector = async () => { | ||
| const config = await readConfig() | ||
| const client = new MyClient(config) | ||
|
|
||
| return createConnector() | ||
| .stdApplicationDiscoveryListWithDataset(async (context: Context, input: StdApplicationDiscoveryListInput, res: Response<StdApplicationDiscoveryListOutput>) => { | ||
| const apps: { id: string; name: string; description: string; url: string; userCount: number; active: boolean }[] = | ||
| await client.getApplications(input.datasetId) | ||
| for (const app of apps) { | ||
| res.send({ | ||
| id: app.id, | ||
| primaryAppName: app.name, | ||
| description: app.description, | ||
| status: app.active ? 'ACTIVE' : 'INACTIVE', | ||
| connectorCategory: 'sso', | ||
| appUrl: app.url, | ||
| usersCount: String(app.userCount), | ||
| }) | ||
| } | ||
| }) | ||
| } | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| --- | ||
| id: authenticate | ||
| title: Authenticate | ||
| pagination_label: Authenticate | ||
| sidebar_label: Authenticate | ||
| keywords: ['connectivity', 'connectors', 'authenticate', 'pass-through authentication'] | ||
| description: Check a user's credentials on the source for pass-through authentication. | ||
| slug: /connectivity/saas-connectivity/commands/authenticate | ||
| tags: ['Connectivity', 'Connector Command'] | ||
| --- | ||
|
|
||
| | Input/Output | Data Type | | ||
| | :----------- | :---------------------: | | ||
| | Input | StdAuthenticateInput | | ||
| | Output | StdAuthenticateOutput | | ||
|
|
||
| ### Example StdAuthenticateInput | ||
|
|
||
| ```javascript | ||
| { | ||
| "identity": "john.doe", | ||
| "key": { | ||
| "simple": { | ||
| "id": "john.doe" | ||
| } | ||
| }, | ||
| "username": "john.doe", | ||
| "password": "<password>", | ||
| "schema": { | ||
| "displayAttribute": "displayName", | ||
| "identityAttribute": "id", | ||
| "groupAttribute": "groups", | ||
| "attributes": [ | ||
| { | ||
| "name": "id", | ||
| "description": "Unique ID", | ||
| "type": "string" | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Example StdAuthenticateOutput | ||
|
|
||
| ```javascript | ||
| { | ||
| "identity": "john.doe", | ||
| "key": { | ||
| "simple": { | ||
| "id": "john.doe" | ||
| } | ||
| }, | ||
| "disabled": false, | ||
| "locked": false, | ||
| "attributes": { | ||
| "id": "john.doe", | ||
| "displayName": "John Doe", | ||
| "email": "example@sailpoint.com" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Description | ||
|
|
||
| The authenticate command supports pass-through authentication. With pass-through authentication, users sign in to SailPoint Identity Security with their username and password from the source. SailPoint Identity Security does not store these passwords. It sends them to the connector, and the connector tests them against the source. | ||
|
|
||
| If the admin sets the sign-in method to **Directory Connection** with this source, SailPoint Identity Security sends `std:authenticate` each time a user signs in. The connector must do these steps: | ||
|
|
||
| 1. Test the username and password against the source. | ||
| 2. If the credentials are valid, get the user's account from the source. | ||
| 3. Send the account to SailPoint Identity Security. SailPoint Identity Security then lets the user sign in. | ||
|
|
||
| If the credentials are not valid, throw a `ConnectorError`. SailPoint Identity Security then rejects the sign-in. | ||
|
|
||
| The output has the same shape as the account read output, and it can also include `permissions`. The input includes the account schema of the source in `input.schema`. Use it to decide which attributes to return. | ||
|
|
||
| To use this command, you must specify this value in the `commands` array: `std:authenticate` | ||
|
|
||
| ### Disabled and locked accounts | ||
|
|
||
| Let the source decide whether a disabled or locked user can sign in. If the source accepts the credentials, send the account. Set `disabled` and `locked` to the values from the source. | ||
|
|
||
| ### Usernames | ||
|
|
||
| The username that reaches the connector depends on what the user types and on the account correlation of the identity profile. If the user cannot sign in, and the connector logs show no `std:authenticate` command, look at the correlation settings first. | ||
|
|
||
| ## Implementation | ||
|
|
||
| ```typescript | ||
| import { | ||
| ConnectorError, | ||
| Context, | ||
| createConnector, | ||
| readConfig, | ||
| Response, | ||
| StdAuthenticateInput, | ||
| StdAuthenticateOutput, | ||
| } from '@sailpoint/connector-sdk' | ||
| import { MyClient } from './my-client' | ||
|
|
||
| export const connector = async () => { | ||
| const config = await readConfig() | ||
| const client = new MyClient(config) | ||
|
|
||
| return createConnector() | ||
| .stdAuthenticate(async (context: Context, input: StdAuthenticateInput, res: Response<StdAuthenticateOutput>) => { | ||
| const account = await client.authenticate(input.username, input.password) | ||
| if (!account) { | ||
| throw new ConnectorError(`Authentication failed for ${input.username}`) | ||
| } | ||
| res.send({ | ||
| identity: account.id, | ||
| disabled: !account.active, | ||
| locked: account.locked, | ||
| attributes: { | ||
| id: account.id, | ||
| displayName: account.displayName, | ||
| email: account.email, | ||
| }, | ||
| }) | ||
| }) | ||
| } | ||
| ``` | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you confirm
std:application_discovery(with the underscore) is the correct dataset type? The command has a hyphen instead of an underscore. If it is, I would add a short note that it differs from the command name, since it will be easy to copy incorrectly.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes this is actually correct.