SailPointIdentityIQ

SailPoint IdentityIQ context pack enables XSOAR customers to utilize the deep, enriched contextual data in the SailPoint predictive identity platform to better drive identity-aware security practices.

Identity and Access Management · SailPoint IdentityIQ

Details

IDSailPointIdentityIQ
ProviderSailPoint Technologies
CategoryIdentity and Access Management
From Version6.0.0
Docker Imagedemisto/python3:3.12.14.12277297
Supported ModulesAgentix XSIAM Cloud Posture Security EDR Cortex Cloud Cloud Runtime Security

README

SailPoint IdentityIQ context pack enables XSOAR customers to utilize the deep, enriched contextual data in the SailPoint predictive identity platform to better drive identity-aware security practices.
This integration was integrated and tested with version 8.1 of SailPoint IdentityIQ.
Supported Cortex XSOAR versions: 6.0.0 and later.

Configure SailPointIdentityIQ in Cortex

Parameter Description Required
identityiq_url IdentityIQ Server URL (e.g. https://identityiq-server.com/identityiq) True
client_id Client Id (for OAuth 2.0) True
client_secret Client Secret (for OAuth 2.0) True
isFetch Fetch incidents False
insecure Trust any certificate (not secure) False
proxy Use system proxy settings False
incidentType Incident type False
max_fetch Maximum number of incidents per fetch False
first_fetch First fetch time False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

identityiq-search-identities


Search identities by search/filter parameters (id, email, risk & active) using IdentityIQ SCIM API’s.

Base Command

identityiq-search-identities

Input

Argument Name Description Required
id Internal id of the identity being requested. Optional
email Email address of the identity being requested. Optional
active Determines whether search will return only active identities. Default is true. Optional
risk Numeric value of baseline risk score, users above this will be returned. Optional

Context Output

Path Type Description
IdentityIQ.Identity.userName String The IdentityIQ username (primary id).
IdentityIQ.Identity.id String The IdentityIQ internal id (uuid).
IdentityIQ.Identity.name.formatted String The display name of the identity.
IdentityIQ.Identity.name.familyName String The last name of the identity.
IdentityIQ.Identity.name.givenName String The first name of the identity.
IdentityIQ.Identity.active Boolean Indicates whether the id is active or inactive in IdentityIQ.
IdentityIQ.Identity.manager.userName String The IdentityIQ username (primary id) of the identities manager.
IdentityIQ.Identity.lastModified Date Timestamp of when the identity was last modified.
IdentityIQ.Identity.displayName String The display name of the identity.
IdentityIQ.Identity.emails Unknown Array of email objects.
IdentityIQ.Identity.emails.type String Type of the email being returned.
IdentityIQ.Identity.emails.value String The email address of the identity.
IdentityIQ.Identity.emails.primary Boolean Indicates if this email address is the identities primary email.
IdentityIQ.Identity.entitlements Unknown Array of entitlements objects that the identity has.
IdentityIQ.Identity.roles Unknown Array of role objects that the identity has.
IdentityIQ.Identity.capabilities Unknown Array of string representations of the IdentityIQ capabilities assigned to this identity.

Command Examples

!identityiq-search-identities
!identityiq-search-identities id=8a8080824df45873014df45bd97400c9
!identityiq-search-identities email=jerry.bennett@sailpointdemo.com
!identityiq-search-identities active=False
!identityiq-search-identities risk=500
!identityiq-search-identities active=False risk=500

Human Readable Output

Results

Identity

id userName displayName name emails sailpointUser extendedUser entitlements roles capabilities active
8a8080824df45873014df45bd97400c9 Adam.Kennedy Adam Kennedy formatted: Adam Kennedy
familyName: Kennedy
givenName: Adam
{‘type’: ‘work’, ‘value’: ‘Adam.Kennedy@sailpointdemo.com’, ‘primary’: True} capabilities:
lastRefresh: 2020-10-08T15:45:47.034-05:00
jobTitle: Payroll Analyst II
employeeId: 1b2c3a4e
administrator: {}
employeeType: Employee
phone: 5124152339
isManager: false
location: London
accounts: {‘displayName’: ‘1b2c3a4e’, ‘value’: ‘8a8080824df45873014df45bd97500ca’, ‘$ref’: ‘http://localhost:8088/iiq/scim/v2/Accounts/8a8080824df45873014df45bd97500ca’},
{‘displayName’: ‘Adam.Kennedy’, ‘value’: ‘8a8080824df45873014df45c164601d8’, ‘$ref’: ‘http://localhost:8088/iiq/scim/v2/Accounts/8a8080824df45873014df45c164601d8’},
{‘displayName’: ‘AKENNE’, ‘value’: ‘8a8080824df45873014df45d012705ae’, ‘$ref’: ‘http://localhost:8088/iiq/scim/v2/Accounts/8a8080824df45873014df45d012705ae’},
{‘displayName’: ‘Adam.Kennedy’, ‘value’: ‘8a8080824df45873014df45da06308b0’, ‘$ref’: ‘http://localhost:8088/iiq/scim/v2/Accounts/8a8080824df45873014df45da06308b0’}
riskScore: 82
department: Accounting
region: GB
manager: {“displayName”: “Doug Testman”, “value”: “8a8080824df45873014df45bcfab008d”, “$ref”: “http://localhost:8088/iiq/scim/v2/Users/8a8080824df45873014df45bcfab008d”}       true

identityiq-get-policyviolations


Fetch policy violation by id or all policy violations using IdentityIQ SCIM API’s.

Base Command

identityiq-get-policyviolations

Input

Argument Name Description Required
id Internal id of the policy violation being requested. Optional

Context Output

Path Type Description
IdentityIQ.PolicyViolation.policyName String Name of the policy that was violated.
IdentityIQ.PolicyViolation.constraintName String Name of the constraint being violated.
IdentityIQ.PolicyViolation.status String Status of the violation (open/closed).
IdentityIQ.PolicyViolation.description String Description of the policy/conflict.
IdentityIQ.PolicyViolation.identity.value Unknown Internal id of the IdentityIQ identity in violation.
IdentityIQ.PolicyViolation.identity.displayName String Display name of the IdentityIQ identity in violation.
IdentityIQ.PolicyViolation.id String Internal id of the task result.

Command Example

!identityiq-get-policyviolations
!identityiq-get-policyviolations id=8a8080824df45873014df46036521328

Human Readable Output

Results

PolicyViolation

id policyName constraintName status description identity owner
8a8080824df45873014df46036521328 SOD Policy Accounts Payable Access-Accounts Receivable Access Accounts Payable Access - Accounts Receivable Access constraint Open   displayName: Frank Testson
value: 8a8080824df45873014df45bc8480065
$ref: http://localhost:8088/iiq/scim/v2/Users/8a8080824df45873014df45bc8480065
displayName: Rick Testson
value: 8a8080824df45873014df45bbbb9002b
$ref: http://localhost:8088/iiq/scim/v2/Users/8a8080824df45873014df45bbbb9002b

identityiq-get-taskresults


Fetch task result by id or all task results using IdentityIQ SCIM API’s.

Base Command

identityiq-get-taskresults

Input

Argument Name Description Required
id Internal id of the task result being requested. Optional

Context Output

Path Type Description
IdentityIQ.TaskResult.id String Internal id of the task result.
IdentityIQ.TaskResult.progress String String representation of the status of the task.
IdentityIQ.TaskResult.launched Date Date representation of when the task was launched in IdentityIQ.
IdentityIQ.TaskResult.taskDefinition String Name of the task template that this task result is an instantiation of.
IdentityIQ.TaskResult.host String Host name of the IdentityIQ application server that is executing this task.
IdentityIQ.TaskResult.type String Type of the task being executed.
IdentityIQ.TaskResult.pendingSignoffs Number Number of signoffs on the task result that have not been done.
IdentityIQ.TaskResult.completionStatus String Status of task ‘success’, ‘termianted’, ‘failure’, etc.
IdentityIQ.TaskResult.launcher String Name of the IdentityIQ identity who launched the task.
IdentityIQ.TaskResult.name String Unique name of the task that was launched.
IdentityIQ.TaskResult.completed Date Timestamp of when the task was completed (if not currently executed).

Command Example

!identityiq-get-taskresults
!identityiq-get-taskresults id=0a0000016b951ded816bb41351e901b3

Human Readable Output

Results

TaskResult

id name type host progress completionStatus launched taskDefinition pendingSignoffs launcher completed taskSchedule partitioned terminated messages attributes
0a0000016b951ded816bb41351e901b3 Joiner: DannyFieldsPS Workflow     Success 2019-07-02T14:04:53.471-05:00 Workflow Launcher 0 Scheduler 2019-07-02T14:04:53.480-05:00   false false   {‘value’: ‘\n’, ‘key’: ‘workflowSummary’}

identityiq-get-accounts


Fetch accounts by search/filter parameters (id, display_name, last_refresh, native_identity, last_target_agg, identity_name & application_name) using IdentityIQ SCIM API’s.

Base Command

identityiq-get-accounts

Input

Argument Name Description Required
id Internal id of the account to be returned. Optional
display_name displayName of the account to be returned. Optional
last_refresh Timestamp of the last time the account(s) were refreshed from the target system.
[format : yyyy-MM-dd’T’HH:mm:ss or yyyy-MM-dd].
Optional
native_identity Unique identifier of the account on the target system. Optional
last_target_agg Timestamp of the last targeted aggregation of the account from the target system.
[format : yyyy-MM-dd’T’HH:mm:ss or yyyy-MM-dd].
Optional
identity_name Unique name of the identity for which all accounts will be returned. Optional
application_name Unique name of the application for which all accounts will be returned. Optional

Context Output

Path Type Description
IdentityIQ.Account.id String Internal id of the account.
IdentityIQ.Account.identity.value String Internal id of the identity that this account belongs to.
IdentityIQ.Account.identity.displayName String Display name of the identity that this account belongs to.
IdentityIQ.Account.hasEntitlements Boolean True if the account has access entitlements assigned to it, else false.
IdentityIQ.Account.application.value Unknown Internal id of the application that this account is on.
IdentityIQ.Account.application.displayName String Display name of the application that this account is on.
IdentityIQ.Account.nativeIdentity String The name of the account as it exists on the application.
IdentityIQ.Account.lastRefreshed Date Timestamp of when this account was last refreshed in IdentityIQ.

Command Example

!identityiq-get-accounts
!identityiq-get-accounts id=8a8080824df45873014df45bb504000e
!identityiq-get-accounts last_refresh=2020-10-05T15:53:46
!identityiq-get-accounts native_identity=1b2c
!identityiq-get-accounts last_target_agg=2020-10-05T15:53:46
!identityiq-get-accounts identity_name=Amanda.Ross
!identityiq-get-accounts application_name=TRAKK
!identityiq-get-accounts identity_name=Amanda.Ross application_name=TRAKK

Human Readable Output

Results

Account

id displayName identity hasEntitlements application nativeIdentity active lastRefresh manuallyCorrelated application locked
8a8080824df45873014df45bb504000e 1b displayName: Jerry Bennett
userName: Jerry.Bennett
value: 8a8080824df45873014df45bb503000d
$ref: http://localhost:8088/iiq/scim/v2/Users/8a8080824df45873014df45bb503000d
false displayName: Human Resources
value: 8a8080824df44d48014df4542d7402aa
$ref: http://localhost:8088/iiq/scim/v2/Applications/8a8080824df44d48014df4542d7402aa
1b true 2015-06-14T18:16:00.389-05:00 false displayName: Human Resources
value: 8a8080824df44d48014df4542d7402aa
$ref: http://localhost:8088/iiq/scim/v2/Applications/8a8080824df44d48014df4542d7402aa
false

identityiq-disable-account


Disable account’s active status by id using IdentityIQ SCIM API’s.

Base Command

identityiq-disable-account

Input

Argument Name Description Required
id Internal id of the specific account to be disabled. Required

Context Output

Path Type Description
IdentityIQ.AccountDisable.active Boolean Indicates the status of account (should be false after request is successfully completed).

Command Example

!identityiq-disable-account id=8a8080824df45873014df45c719f038c

Human Readable Output

Results

Account

id displayName identity hasEntitlements application nativeIdentity active lastRefresh manuallyCorrelated application locked
8a8080824df45873014df45c719f038c Jerry.Bennett displayName: Jerry Bennett
userName: Jerry.Bennett
value: 8a8080824df45873014df45bb503000d
$ref: http://localhost:8088/iiq/scim/v2/Users/8a8080824df45873014df45bb503000d
true displayName: Active Directory
value: 8a8080824df44d48014df45440d502cf
$ref: http://localhost:8088/iiq/scim/v2/Applications/8a8080824df44d48014df45440d502cf
CN=Jerry Bennett,OU=Brussels,OU=Europe,OU=Demo,DC=seri,DC=sailpointdemo,DC=com false 2020-12-16T16:39:56.638-06:00 false displayName: Active Directory
value: 8a8080824df44d48014df45440d502cf
$ref: http://localhost:8088/iiq/scim/v2/Applications/8a8080824df44d48014df45440d502cf
false

identityiq-enable-account


Enable account’s active status by id using IdentityIQ SCIM API’s.

Base Command

identityiq-enable-account

Input

Argument Name Description Required
id Internal id of the specific account to be enabled. Required

Context Output

Path Type Description
IdentityIQ.AccountDisable.active Boolean Indicates the status of account (should be true after request is successfully completed).

Command Example

!identityiq-enable-account id=8a8080824df45873014df45c719f038c

Human Readable Output

Results

Account

id displayName identity hasEntitlements application nativeIdentity active lastRefresh manuallyCorrelated application locked
8a8080824df45873014df45c719f038c Jerry.Bennett displayName: Jerry Bennett
userName: Jerry.Bennett
value: 8a8080824df45873014df45bb503000d
$ref: http://localhost:8088/iiq/scim/v2/Users/8a8080824df45873014df45bb503000d
true displayName: Active Directory
value: 8a8080824df44d48014df45440d502cf
$ref: http://localhost:8088/iiq/scim/v2/Applications/8a8080824df44d48014df45440d502cf
CN=Jerry Bennett,OU=Brussels,OU=Europe,OU=Demo,DC=seri,DC=sailpointdemo,DC=com true 2020-12-16T16:39:56.638-06:00 false displayName: Active Directory
value: 8a8080824df44d48014df45440d502cf
$ref: http://localhost:8088/iiq/scim/v2/Applications/8a8080824df44d48014df45440d502cf
false

identityiq-delete-account


Delete account by id using IdentityIQ SCIM API’s.

Base Command

identityiq-delete-account

Input

Argument Name Description Required
id Internal id of the specific account to be deleted. Required

Context Output

There is no context output for this command.

Command Example

!identityiq-delete-account id=8a8080824df45873014df45bb335000c

Human Readable Output

Account deleted successfully!

identitytiq-get-launched-workflows


Fetch launched workflow by id or all launched workflows using IdentityIQ SCIM API’s.

Base Command

identitytiq-get-launched-workflows

Input

Argument Name Description Required
id Internal id of the specific launched workflow being requested. Optional

Context Output

Path Type Description
IdentityIQ.Workflow.workflowName String Name of the workflow that was launched.
IdentityIQ.Workflow.identityRequestId String Unique id of the identity request that launched this workflow (if exists).
IdentityIQ.Workflow.workflowCaseId String Internal id of the workflowcase for this workflow.
IdentityIQ.Workflow.launched Date Timestamp of when this workflow was launched.
IdentityIQ.Workflow.targetClass String Type of object targeted by the workflow, usually identity.
IdentityIQ.Workflow.targetName String Unique name of the object (username in the case of identity).
IdentityIQ.Workflow.type String The type of workflow.
IdentityIQ.Workflow.id String Internal id of the workflow.
IdentityIQ.Workflow.completionStatus String Status of workflow – ‘success’, ‘failure’, ‘pending’ etc.
IdentityIQ.Workflow.launcher String Name of the identity that launched the workflow.
IdentityIQ.Workflow.terminated Boolean Indicates whether this workflow was terminated due to error or intentionally stopped.
IdentityIQ.Workflow.name String Name of the workflow that was launched.
IdentityIQ.Workflow.attributes Unknown Array of key/value pairs that are the inputs and their values to the workflow.
IdentityIQ.Workflow.output Unknown Array of key/type/value objects that list the output of the workflow.

Command Example

!identitytiq-get-launched-workflows
!identitytiq-get-launched-workflows id=0a0000016b951ded816bb41348e20197

Human Readable Output

Results

Workflow

id name workflowName identityRequestId workflowCaseId launched targetClass targetName type completionStatus launcher terminated attributes partitioned completed pendingSignoffs taskDefinition launchedWorkflow
0a0000016b951ded816bb41348e20197 Joiner: Nick       2019-07-02T14:04:51.148-05:00     Workflow Success Scheduler false {‘value’: ‘\n’, ‘key’: ‘workflowSummary’} false 2019-07-02T14:04:51.169-05:00 0 Workflow Launcher output: {‘type’: ‘application/xml’, ‘value’: ‘\n’, ‘key’: ‘workflowSummary’}
input: {}
workflowSummary:

workflowName: Joiner: Nick

identityiq-get-roles


Fetch role by id or all roles using IdentityIQ SCIM API’s.

Base Command

identityiq-get-roles

Input

Argument Name Description Required
id Internal id of the specific role being requested. Optional

Context Output

Path Type Description
IdentityIQ.Role.name String Unique name of the role object in IdentityIQ.
IdentityIQ.Role.owner.value String Internal id of the role owner identity.
IdentityIQ.Role.owner.displayName String Displayname of the owner of the role.
IdentityIQ.Role.active Boolean Indicates whether the role is active in IdentityIQ.
IdentityIQ.Role.displayableName String Display name of the role in IdentityIQ.
IdentityIQ.Role.permits Unknown Array of roles that this role permits in IdentityIQ.
IdentityIQ.Role.type.name String Template role on which this role is based.
IdentityIQ.Role.type.autoAssignment Boolean Indicates whether this type of role can be auto-assigned to identities.
IdentityIQ.Role.type.displayName String Display name of the template role on which this role was based.
IdentityIQ.Role.type.manualAssignment String Indicates whether this role type can be manually assigned.
IdentityIQ.Role.descriptions.value String Description of the role shown in the UI.

Command Example

!identityiq-get-roles
!identityiq-get-roles id=8a8080824df45873014df45f8b6810e9

Human Readable Output

Results

Role

id name owner active displayableName permits type descriptions requirements
8a8080824df45873014df45f8b6810e9 All Users displayName: The Administrator
value: 8a8080824df44d48014df44def7100dd
$ref: http://localhost:8088/iiq/scim/v2/Users/8a8080824df44d48014df44def7100dd
true All Users   iiq: false
requirements: true
permits: true
displayName: Business
manualAssignment: true
name: business
autoAssignment: true
assignmentSelector: true
{‘locale’: ‘en_US’, ‘value’: ‘Role that grants access all users should have’} {‘displayName’: ‘User Basic’, ‘value’: ‘8a8080824df45873014df45f8b1810e6’, ‘$ref’: ‘http://localhost:8088/iiq/scim/v2/Roles/8a8080824df45873014df45f8b1810e6’}

identityiq-get-entitlements


Fetch entitlement by id or all entitlements using IdentityIQ SCIM API’s.

Base Command

identityiq-get-entitlements

Input

Argument Name Description Required
id Internal id of the specific entitlement being requested. Optional

Context Output

Path Type Description
IdentityIQ.Entitlement.application.value String Internal id of the application that this entitlement resides on.
IdentityIQ.Entitlement.application.displayName String Display name of the application that this entitlement resides on.
IdentityIQ.Entitlement.attribute String String representing the attribute on the application that this entitlement represents.
IdentityIQ.Entitlement.type String String representing the type of attribute on the application that this entitlement represents.
IdentityIQ.Entitlement.descriptions Unknown Array of description objects that contain a locale, and a value.
IdentityIQ.Entitlement.id String Internal id of the entitlement object in IdentityIQ.
IdentityIQ.Entitlement.requestable Boolean Boolean indicates whether this entitlement is directly requestable in the IdentityIQ UI.
IdentityIQ.Entitlement.owner.value String Internal id of the owner of the entitlement in IdentityIQ.
IdentityIQ.Entitlement.owner.displayName String Display name of the owner of the entitlement in IdentityIQ.
IdentityIQ.Entitlement.aggregated String Indicates whether this entitlement was aggregated from the source system or not.
IdentityIQ.Entitlement.created Date Timestamp indicates when the entitlement was created in IdentityIQ.

Command Example

!identityiq-get-entitlements
!identityiq-get-entitlements id=8a8080824df45873014df45d9f9008a8

Human Readable Output

Results

Entitlement

id displayableName type attribute value owner application descriptions requestable aggregated created
8a8080824df45873014df45d9f9008a8 input Entitlement capability input   displayName: TRAKK
value: 8a8080824df44d48014df45444c002da
$ref: http://localhost:8088/iiq/scim/v2/Applications/8a8080824df44d48014df45444c002da
  true false  

identityiq-get-alerts


Fetch alert by id or all alerts using IdentityIQ SCIM API’s.

Base Command

identityiq-get-alerts

Input

Argument Name Description Required
id Internal id of the specific alert being requested. Optional

Context Output

Path Type Description
IdentityIQ.Alert.id String Internal id of the Alert in IdentityIQ.
IdentityIQ.Alert.lastProcessed Date Timestamp of when this alert was processed by IdentityIQ for match.
IdentityIQ.Alert.displayName String Display name of the alert in IdentityIQ.
IdentityIQ.Alert.meta.created Date Timestamp of when this alert was created in IdentityIQ
IdentityIQ.Alert.name String Name of the alert in IdentityIQ
IdentityIQ.Alert.attributes Unknown Array of attributes associated with this alert.
IdentityIQ.Alert.actions Unknown Array of actions taken on this alert after processing.
IdentityIQ.Alert.application String List of applications that are related to this alert.

Command Example

!identityiq-get-alerts
!identityiq-get-alerts id=0a000001764519c981766dbd2bd518ad

Human Readable Output

Results

Alert

id name displayName type targetId targetDisplayName targetType alertInput actions application attributes lastProcessed
0a000001764519c981766dbd2bd518ad 0000000015 Test Alert PAN XSOAR       input:
processorTaskInput:
aggregationTaskInput:
      2020-12-16T16:48:02.773-06:00

identityiq-create-alert


Create an alert using IdentityIQ SCIM API’s.

Base Command

identityiq-create-alert

Input

Argument Name Description Required
display_name Display name of the alert. Required
attributes List of JSON objects with the following structure.
{
‘key’: ‘’,
‘value’: ‘’,
‘type’: ‘‘
}.
Optional

Context Output

Path Type Description
IdentityIQ.Alert.id String Internal id of the Alert in IdentityIQ.
IdentityIQ.Alert.lastProcessed Date Timestamp of when this alert was processed by IdentityIQ for match.
IdentityIQ.Alert.displayName String Display name of the alert in IdentityIQ.
IdentityIQ.Alert.meta.created Date Timestamp of when this alert.
IdentityIQ.Alert.name String Unique name of the alert in IdentityIQ.
IdentityIQ.Alert.attributes Unknown Array of attributes associated with this alert.
IdentityIQ.Alert.actions Unknown Array of actions taken on this alert after processing.
IdentityIQ.Alert.application String List of applications that are related to this alert.

Command Example

!identityiq-create-alert display_name=Testing-Via-XSOAR

Human Readable Output

Results

Alert

id name displayName type targetId targetDisplayName targetType alertInput actions application attributes lastProcessed
0a000001764519c981767209e7491c04 0000000016 XSOAR-Alert PAN XSOAR       input:
processorTaskInput:
aggregationTaskInput:
      2020-12-17T12:50:20.369-06:00

Configuration parameters

  • identityiq_url — IdentityIQ Server URL (e.g. https://identityiq-server.com/identityiq) (required)
  • client_id — Client Id (for OAuth 2.0) (required)
  • client_secret — Client Secret (for OAuth 2.0) (required)
  • isFetch — Fetch incidents
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • incidentType — Incident type
  • max_fetch — Maximum number of incidents per fetch
  • first_fetch — First fetch time
  • incidentFetchInterval — Incidents Fetch Interval

Commands (12)

  • identityiq-create-alert

    Create an alert using IdentityIQ SCIM API's.

  • identityiq-delete-account

    Delete account by id using IdentityIQ SCIM API's.

  • identityiq-disable-account

    Disable account's active status by id using IdentityIQ SCIM API's.

  • identityiq-enable-account

    Enable account's active status by id using IdentityIQ SCIM API's.

  • identityiq-get-accounts

    Fetch accounts by search/filter parameters (id, display_name, last_refresh, native_identity, last_target_agg, identity_name & application_name) using IdentityIQ SCIM API's.

  • identityiq-get-alerts

    Fetch alert by id or all alerts using IdentityIQ SCIM API's.

  • identityiq-get-entitlements

    Fetch entitlement by id or all entitlements using IdentityIQ SCIM API's.

  • identityiq-get-policyviolations

    Fetch policy violation by id or all policy violations using IdentityIQ SCIM API's.

  • identityiq-get-roles

    Fetch role by id or all roles using IdentityIQ SCIM API's.

  • identityiq-get-taskresults

    Fetch task result by id or all task results using IdentityIQ SCIM API's.

  • identityiq-search-identities

    Search identities by search/filter parameters (id, email, risk & active) using IdentityIQ SCIM API's.

  • identitytiq-get-launched-workflows

    Fetch launched workflow by id or all launched workflows using IdentityIQ SCIM API's.

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401

""" IMPORTS """

import base64
import datetime as dt
import json
import traceback

import dateparser
import requests
import urllib3

# Disable insecure warnings
urllib3.disable_warnings()

""" CONSTANTS """

# IdentityIQ OAuth token endpoint
IIQ_OAUTH_EXT = "/oauth2/token"
IIQ_SCIM_PREFIX = "/scim/v2"

# SCIM core endpoints
IIQ_SCIM_SERVICE_PROVIDER_CONFIG_EXT = f"{IIQ_SCIM_PREFIX}/ServiceProviderConfig"
IIQ_SCIM_RESOURCE_TYPES_EXT = f"{IIQ_SCIM_PREFIX}/ResourceTypes"
IIQ_SCIM_SCHEMAS_EXT = f"{IIQ_SCIM_PREFIX}/Schemas"

# SCIM resource endpoints
IIQ_SCIM_USERS_EXT = f"{IIQ_SCIM_PREFIX}/Users"
IIQ_SCIM_ACCOUNTS_EXT = f"{IIQ_SCIM_PREFIX}/Accounts"
IIQ_SCIM_ENTITLEMENTS_EXT = f"{IIQ_SCIM_PREFIX}/Entitlements"
IIQ_SCIM_ROLES_EXT = f"{IIQ_SCIM_PREFIX}/Roles"
IIQ_SCIM_POLICY_VIOLATIONS_EXT = f"{IIQ_SCIM_PREFIX}/PolicyViolations"
IIQ_SCIM_LAUNCHED_WORKFLOWS_EXT = f"{IIQ_SCIM_PREFIX}/LaunchedWorkflows"
IIQ_SCIM_TASK_RESULTS_EXT = f"{IIQ_SCIM_PREFIX}/TaskResults"
IIQ_SCIM_ALERTS_EXT = f"{IIQ_SCIM_PREFIX}/Alerts"

# From ServiceProviderConfig (filter.maxResults) for IdentityIQ SCIM API
MAX_INCIDENTS_TO_FETCH = 1000
DATE_FORMAT = "%Y-%m-%dT%H:%M:%S"

""" CLIENT CLASS """


class Client(BaseClient):
    """
    Client class to interact with API request.
    """

    def __init__(self, base_url: str, verify: bool, proxy: bool, headers: dict, max_results: int, request_timeout: int):
        super().__init__(base_url=base_url, verify=verify, proxy=proxy, headers=headers)
        self.max_results = max_results
        self.request_timeout = request_timeout

    def send_request(self, url_suffix: str, method: str, params=None, json_data=None):
        """
        Perform a HTTP request to IdentityIQ SCIM API.

        :type url_suffix: ``str``
        :param url_suffix: IdentityIQ SCIM API endpoint ext suffix.

        :type method: ``str``
        :param method: HTTP method, e.g. 'GET', 'POST', 'PUT', 'DELETE'.

        :type params: ``JSON``
        :param params: URL parameters to specify the query.

        :type json_data: ``JSON``
        :param json_data: Data to be sent as part of 'POST' or 'PUT' request.

        :return: Response after fulfilling the request successfully, else None.
        """
        if url_suffix is None or method is None:
            return None
        return self._http_request(
            url_suffix=url_suffix,
            method=method,
            json_data=json_data,
            params=params,
            timeout=self.request_timeout,
            resp_type="response",
            ok_codes=(200, 201, 202, 204, 400, 401, 404, 409, 500),
            proxies=handle_proxy(),
        )


""" HELPER/UTILITY FUNCTIONS """


def get_headers(base_url: str, client_id: str, client_secret: str, grant_type: str, verify: bool):
    """
    Create header with OAuth 2.0 authentication information.

    :type base_url: ``str``
    :param base_url: Base URL of the IdentityIQ tenant.

    :type client_id: ``str``
    :param client_id: Client Id for OAuth 2.0.

    :type client_secret: ``str``
    :param client_secret: Client Secret for OAuth 2.0.

    :type grant_type: ``str``
    :param grant_type: Grant Type for OAuth 2.0. Defaulted to 'client_credentials' if not provided.

    :return: Header with OAuth 2.0 information if client_id & client_secret are provided, else None.
    This will return None if the client_id & client_secret were not valid (authorized).
    """
    if base_url is None or client_id is None or client_secret is None:
        return None

    if grant_type is None:
        grant_type = "client_credentials"

    auth_cred = client_id + ":" + client_secret
    iiq_oauth_body = f"grant_type={grant_type}"
    iiq_oauth_headers = {
        "Content-Type": "application/x-www-form-urlencoded",
        "Authorization": f"Basic {base64.b64encode(auth_cred.encode()).decode()}",
    }
    oauth_response = requests.request(
        "POST", url=f"{base_url}{IIQ_OAUTH_EXT}", data=iiq_oauth_body, headers=iiq_oauth_headers, verify=verify
    )
    if oauth_response is not None and 200 <= oauth_response.status_code < 300:
        return {
            "Authorization": f"Bearer {oauth_response.json().get('access_token', None)}",
            "Content-Type": "application/json",
        }
    else:
        err_msg = "Failed to get response"
        if oauth_response is not None:
            err_msg += f" {oauth_response.status_code}"
        raise DemistoException(err_msg)


def transform_object_list(object_type: str, object_list=None):
    """
    Transform list objects, i.e. - replace the scim uri to a compressed object name.
    This is done as PAN XSOAR is unable to process json keys with symbols like - '.' or ':'.

    :type object_type: ``str``
    :param object_type: Type of IdentityIQ object.

    :type object_list: ``list``
    :param object_list: List of Identity resources objects.

    :return: Transformed list object.
    """
    if not isinstance(object_list, list):
        return None

    transformed_list = []
    for object in object_list:
        transformed_list.append(transform_object(object_type, object))
    return transformed_list


def transform_object(object_type: str, object=None):
    """
    Transform objects, i.e. - replace the scim uri to a compressed object name.
    This is done as PAN XSOAR is unable to process json keys with symbols like - '.' or ':'.

    :type object_type: ``str``
    :param object_type: Type of IdentityIQ object.

    :type object: ``JSON``
    :param object: Identity resources object.

    :return: Transformed object.
    """
    if not isinstance(object, dict):
        return None

    if object_type == "IdentityIQ.Identity":
        if "urn:ietf:params:scim:schemas:sailpoint:1.0:User" in object:
            object["sailpointUser"] = object.pop("urn:ietf:params:scim:schemas:sailpoint:1.0:User")
        if "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" in object:
            object["extendedUser"] = object.pop("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User")
    elif object_type == "IdentityIQ.Workflow":
        if "urn:ietf:params:scim:schemas:sailpoint:1.0:LaunchedWorkflow" in object:
            object["launchedWorkflow"] = object.pop("urn:ietf:params:scim:schemas:sailpoint:1.0:LaunchedWorkflow")
    elif object_type == "IdentityIQ.Alert":
        if "urn:ietf:params:scim:schemas:sailpoint:1.0:AlertInput" in object:
            object["alertInput"] = object.pop("urn:ietf:params:scim:schemas:sailpoint:1.0:AlertInput")
    return object


def get_markdown(object_type: str, objects=None):
    """
    Getting markdown for object type to display the results in human readable format.

    :type object_type: ``str``
    :param object_type: Type of IdentityIQ object.

    :type objects: ``dict`` or ``list``
    :param objects: Single or list of Identity resources object/s.

    :return: Markdown for each object type.
    """
    markdown = ""
    if object_type == "IdentityIQ.Identity":
        headers = [
            "id",
            "userName",
            "displayName",
            "name",
            "emails",
            "sailpointUser",
            "extendedUser",
            "entitlements",
            "roles",
            "capabilities",
            "active",
        ]
        markdown = tableToMarkdown("Identity(Identities)", objects, headers=headers)
    elif object_type == "IdentityIQ.PolicyViolation":
        headers = ["id", "policyName", "constraintName", "status", "description", "identity", "owner"]
        markdown = tableToMarkdown("PolicyViolation(s)", objects, headers=headers)
    elif object_type == "IdentityIQ.TaskResult":
        headers = [
            "id",
            "name",
            "type",
            "host",
            "progress",
            "completionStatus",
            "launched",
            "taskDefinition",
            "pendingSignoffs",
            "launcher",
            "completed",
            "taskSchedule",
            "partitioned",
            "terminated",
            "messages",
            "attributes",
        ]
        markdown = tableToMarkdown("TaskResult(s)", objects, headers=headers)
    elif object_type == "IdentityIQ.Account":
        headers = [
            "id",
            "displayName",
            "identity",
            "hasEntitlements",
            "application",
            "nativeIdentity",
            "active",
            "lastRefresh",
            "manuallyCorrelated",
            "application",
            "locked",
        ]
        markdown = tableToMarkdown("Account(s)", objects, headers=headers)
    elif object_type == "IdentityIQ.Workflow":
        headers = [
            "id",
            "name",
            "workflowName",
            "identityRequestId",
            "workflowCaseId",
            "launched",
            "targetClass",
            "targetName",
            "type",
            "completionStatus",
            "launcher",
            "terminated",
            "attributes",
            "partitioned",
            "completed",
            "pendingSignoffs",
            "taskDefinition",
            "launchedWorkflow",
        ]
        markdown = tableToMarkdown("Workflow(s)", objects, headers=headers)
    elif object_type == "IdentityIQ.Role":
        headers = ["id", "name", "owner", "active", "displayableName", "permits", "type", "descriptions", "requirements"]
        markdown = tableToMarkdown("Role(s)", objects, headers=headers)
    elif object_type == "IdentityIQ.Entitlement":
        headers = [
            "id",
            "displayableName",
            "type",
            "attribute",
            "value",
            "owner",
            "application",
            "descriptions",
            "requestable",
            "aggregated",
            "created",
        ]
        markdown = tableToMarkdown("Entitlement(s)", objects, headers=headers)
    elif object_type == "IdentityIQ.Alert":
        headers = [
            "id",
            "name",
            "displayName",
            "type",
            "targetId",
            "targetDisplayName",
            "targetType",
            "alertInput",
            "actions",
            "application",
            "attributes",
            "lastProcessed",
        ]
        markdown = tableToMarkdown("Alert(s)", objects, headers=headers)
    return markdown


def build_results(prefix: str, key_field: str, response=None):
    """
    Build results.

    :type prefix: ``str``
    :param prefix: Prefix for CommandResults as part of the results.

    :type key_field: ``str``
    :param key_field: Key field for CommandResults as part of the results.

    :type response: ``response``
    :param response: Response object from IdentityIQ API call.

    :return: CommandResults in case of a successful response else message describing the error status.
    """
    if response is not None and 200 <= response.status_code < 300:
        data = response.json()
        if "Resources" in data:
            outputs = transform_object_list(prefix, data.get("Resources"))
            markdown = "### Results:\nTotal: " + str(data.get("totalResults")) + "\n"
        else:
            outputs = transform_object(prefix, data)
            markdown = "### Results:\n"
        markdown += get_markdown(prefix, outputs)

        return CommandResults(readable_output=markdown, outputs_prefix=prefix, outputs_key_field=key_field, outputs=outputs)
    else:
        if "status" in response.json() and "detail" in response.json():
            return "".join((response.json().get("status"), " : ", response.json().get("detail")))
        elif "status" in response.json():
            return response.json().get("status")
    return None


""" COMMAND FUNCTIONS """


def test_connection(client: Client):
    """
    Test connectivity to IdentityIQ (pings SCIM's ResourceTypes API).

    :type client: ``Client``
    :param client: SailPoint client

    :return: HTTP connectivity status for test connection.
    """
    # Service provider config url may not be behind any auth, hence test resource types URL
    response = client.send_request(IIQ_SCIM_RESOURCE_TYPES_EXT, "GET", None)
    if response is not None and 200 <= response.status_code < 300:
        return "ok"
    else:
        return "Unable to connect to IdentityIQ!"


def fetch_incidents(client: Client, last_run, first_fetch_str):
    """
    Fetch incidents [IdentityIQ Alerts]

    :type client: ``Client``
    :param client: SailPoint client

    :type last_run: ``[Dict[str, str]]``
    :param last_run:
        A dict with a key containing the latest incident created time we got
        from last fetch.

    :type first_fetch_str: ``str``
    :param first_fetch_str: First fetch time ("3 days", "1 month", etc).

    :return:
        A tuple containing two elements:
            next_run (``Dict[str, int]``): Contains the timestamp that will be
                    used in ``last_run`` on the next fetch.
            incidents (``List[dict]``): List of incidents that will be created in XSOAR
    """
    first_fetch_date = dateparser.parse(first_fetch_str)
    assert first_fetch_date is not None, f"could not parse {first_fetch_str}"
    first_fetch = first_fetch_date.strftime(DATE_FORMAT)
    last_processed = last_run.get("last_fetch", first_fetch)
    now = dt.datetime.now().strftime(DATE_FORMAT)

    incidents = []
    filter_string = "".join(('(lastProcessed gt "', last_processed, '" and lastProcessed le "', now, '")'))
    params = {"filter": filter_string}
    response = client.send_request(IIQ_SCIM_ALERTS_EXT, "GET", params, None)
    if response is not None and 200 <= response.status_code < 300:
        alerts = transform_object_list("IdentityIQ.Alert", response.json().get("Resources"))
        for alert in alerts:
            if "displayName" in alert:
                incident_name = alert.get("displayName", None)
            else:
                incident_name = alert.get("name", None)
            incident = {
                "name": incident_name,
                "details": alert.get("name", None),
                "occurred": alert.get("meta", {}).get("created", None),
                "rawJSON": json.dumps(alert),
            }
            incidents.append(incident)
    next_run = {"last_fetch": now}
    return next_run, incidents


def search_identities(client: Client, id: str, email: str, risk: int, active: bool, filter: str):
    """
    Search identities by search/filter parameters (id, email, risk & active) using IdentityIQ SCIM API's.
    Command: identityiq-search-identities

    :type client: ``Client``
    :param client: SailPoint client

    :type id: ``str``
    :param id:  Internal Id of the user being requested.

    :type email: ``str``
    :param email: Email address of the user being requested.

    :type risk: ``int``
    :param risk: Numeric value of baseline risk score, users above this will be returned.

    :type active: ``bool``
    :param active: Determines whether search will return only active users.

    :return: Identity object (JSON) corresponding to the id or list of identity objects matching search/filter
    parameters. All Identities if the search parameters are None. Empty JSON if the identity was not found in
    IdentityIQ.
    """
    params = None
    if id is not None:
        url = "".join((IIQ_SCIM_USERS_EXT, "/", id))
    else:
        url = IIQ_SCIM_USERS_EXT
        filter_list = []

        # use custom filter
        if filter is not None:
            filter_list.append(filter)
        else:
            if email is not None:
                filter_list.append("".join(('emails.value eq "', email, '"')))
            if risk is not None:
                filter_list.append("".join(("urn:ietf:params:scim:schemas:sailpoint:1.0:User:riskScore ge ", str(risk))))
            if active is not None:
                filter_list.append("".join(("active eq ", str(active).lower())))
        # Combine the filters
        if filter_list is not None and len(filter_list) > 0:
            filter_string = " and ".join(filter_list)
            params = {"filter": filter_string}
    return client.send_request(url, "GET", params, None)


def get_policy_violations(client: Client, id: str):
    """
    Get policy violation by id or all policy violations using IdentityIQ SCIM API's.
    Command: identityiq-get-policyviolations

    :type client: ``Client``
    :param client: SailPoint client

    :type id: ``str``
    :param id: Internal Id of the policy violation being requested.

    :return: Policy violation object (JSON) corresponding to the id or list of policy violation objects if id was None.
    """
    if id is not None:
        url = "".join((IIQ_SCIM_POLICY_VIOLATIONS_EXT, "/", id))
    else:
        url = IIQ_SCIM_POLICY_VIOLATIONS_EXT
    return client.send_request(url, "GET", None, None)


def get_task_results(client: Client, id: str):
    """
    Get task result by id or all task results using IdentityIQ SCIM API's.
    Command: identityiq-get-taskresults

    :type client: ``Client``
    :param client: SailPoint client

    :type id: ``str``
    :param id: Internal Id of the task result being requested.

    :return: Task result object (JSON) corresponding to the id or list of task result objects if id was None.
    """
    if id is not None:
        url = "".join((IIQ_SCIM_TASK_RESULTS_EXT, "/", id))
    else:
        url = IIQ_SCIM_TASK_RESULTS_EXT
    return client.send_request(url, "GET", None, None)


def get_accounts(
    client: Client,
    id: str,
    display_name: str,
    last_refresh: str,
    native_identity: str,
    last_target_agg: str,
    identity_name: str,
    application_name: str,
):
    """
    Get accounts by search/filter parameters (id, display_name, last_refresh, native_identity,
    last_target_agg, identity_name & application_name) using IdentityIQ SCIM API's.
    Command: identityiq-get-accounts

    :type client: ``Client``
    :param client: SailPoint client

    :type id: ``str``
    :param id: Internal Id of the account to be returned.

    :type display_name: ``str``
    :param display_name: Display name of the account to be returned.

    :type last_refresh: ``str``
    :param last_refresh: Timestamp of the last time the account(s) were refreshed from the target system.

    :type native_identity: ``str``
    :param native_identity: Unique identifier of the account on the target system.

    :type last_target_agg: ``str``
    :param last_target_agg: Timestamp of the last targeted aggregation of the account from the target system.

    :type identity_name: ``str``
    :param identity_name: Unique name of the identity for which all accounts will be returned.

    :type application_name: ``str``
    :param application_name: Unique name of the application for which all accounts will be returned.

    :return: Account object (JSON) corresponding to the id or list of identity objects matching search/filter
    parameters. All account if the search parameters are None. Empty JSON if the account was not found in IdentityIQ.
    """
    params = None
    if id is not None:
        url = "".join((IIQ_SCIM_ACCOUNTS_EXT, "/", id))
    else:
        url = IIQ_SCIM_ACCOUNTS_EXT
        filter_list = []
        if display_name is not None:
            filter_list.append("".join(('displayName eq "', display_name, '"')))
        if last_refresh is not None:
            filter_list.append("".join(('lastRefresh ge "', last_refresh, '"')))
        if native_identity is not None:
            filter_list.append("".join(('nativeIdentity eq "', native_identity, '"')))
        if last_target_agg is not None:
            filter_list.append("".join(('lastTargetAggregation ge "', last_target_agg, '"')))
        if identity_name is not None:
            filter_list.append(
                "".join(('(identity.userName eq "', identity_name, '"', ' or identity.displayName eq "', identity_name, '")'))
            )
        if application_name is not None:
            filter_list.append("".join(('application.displayName eq "', application_name, '"')))
        # Combine the filters
        if filter_list is not None and len(filter_list) > 0:
            filter_string = " and ".join(filter_list)
            params = {"filter": filter_string}
    return client.send_request(url, "GET", params, None)


def change_account_status(client: Client, id: str, status: bool):
    """
    Enable/disable account's active status by id using IdentityIQ SCIM API's.
    Command: identityiq-disable-account, identityiq-enable-account

    :type client: ``Client``
    :param client: SailPoint client

    :type id: ``str``
    :param id: (str) Internal Id of the specific account to be enabled/disabled.

    :type status: ``bool``
    :param status: True (enable) or False (disable).

    :return: Account object with active flag changed (JSON). None if the request was unsuccessful.
    """
    if id is None or status is None or type(status) is not bool:
        return None

    # Get the user account (we need several fields to update as this is not a PATCH HTTP call).
    url = "".join((IIQ_SCIM_ACCOUNTS_EXT, "/", id))
    response = client.send_request(url, "GET", None)
    if response is not None and 200 <= response.status_code < 300:
        data = response.json()
        data["active"] = str(status).lower()
        return client.send_request(url, "PUT", None, data)
    else:
        return response.json()


def delete_account(client: Client, id: str):
    """
    Delete account by id using IdentityIQ SCIM API's.
    Command: identityiq-delete-account

    :type client: ``Client``
    :param client: SailPoint client

    :type id: ``str``
    :param id: Internal Id of the specific account to be deleted.

    :return: Empty HTTP 204 response. None if the request was unsuccessful.
    """
    if id is None:
        return None
    url = "".join((IIQ_SCIM_ACCOUNTS_EXT, "/", id))
    response = client.send_request(url, "DELETE", None, None)
    if response is not None and 200 <= response.status_code < 300:
        return "Account deleted successfully!"
    else:
        if "status" in response.json() and "detail" in response.json():
            return "".join((response.json().get("status"), " : ", response.json().get("detail")))
        elif "status" in response.json():
            return response.json().get("status")
    return None


def get_launched_workflows(client: Client, id: str):
    """
    Get launched workflow by id or all launched workflows using IdentityIQ SCIM API's.
    Command: identitytiq-get-launched-workflows

    :type client: ``Client``
    :param client: SailPoint client

    :type id: ``str``
    :param id: Internal Id of the specific launched workflow being requested.

    :return: Launched workflow object (JSON) corresponding to the id or list of launched workflows objects if id was None.
    """
    if id is not None:
        url = "".join((IIQ_SCIM_LAUNCHED_WORKFLOWS_EXT, "/", id))
    else:
        url = IIQ_SCIM_LAUNCHED_WORKFLOWS_EXT
    return client.send_request(url, "GET", None, None)


def get_roles(client: Client, id: str):
    """
    Get role by id or all roles using IdentityIQ SCIM API's.
    Command: identityiq-get-roles

    :type client: ``Client``
    :param client: SailPoint client

    :type id: ``str``
    :param id: Internal Id of the specific role being requested.

    :return: Role object (JSON) corresponding to the id or list of role objects if id was None.
    """
    if id is not None:
        url = "".join((IIQ_SCIM_ROLES_EXT, "/", id))
    else:
        url = IIQ_SCIM_ROLES_EXT
    return client.send_request(url, "GET", None, None)


def get_entitlements(client: Client, id: str):
    """
    Get entitlement by id or all entitlements using IdentityIQ SCIM API's.
    Command: identityiq-get-entitlements

    :type client: ``Client``
    :param client: SailPoint client

    :type id: ``str``
    :param id: Internal Id of the specific entitlement being requested.

    :return: Entitlement object (JSON) corresponding to the id or list of entitlement objects if id was None.
    """
    if id is not None:
        url = "".join((IIQ_SCIM_ENTITLEMENTS_EXT, "/", id))
    else:
        url = IIQ_SCIM_ENTITLEMENTS_EXT
    return client.send_request(url, "GET", None, None)


def get_alerts(client: Client, id: str):
    """
    Get alert by id or all alerts using IdentityIQ SCIM API's.
    Command: identityiq-get-alerts

    :type client: ``Client``
    :param client: SailPoint client

    :type id: ``str``
    :param id: Internal Id of the specific alert being requested.

    :return: Alert object (JSON) corresponding to the id or list of alert objects if id was None.
    """
    if id is not None:
        url = "".join((IIQ_SCIM_ALERTS_EXT, "/", id))
    else:
        url = IIQ_SCIM_ALERTS_EXT
    return client.send_request(url, "GET", None, None)


def create_alert(client: Client, display_name: str, attributes=None):
    """
    Create an alert using IdentityIQ SCIM API's.
    Command: identityiq-create-alert

    :type client: ``Client``
    :param client: SailPoint client

    :type display_name: ``str``
    :param display_name: Display name of the alert.

    :type attributes: ``list``
    :param attributes: List of JSON objects with the following structure.
        [
            {
                'key': '',
                'value': '',
                'type': ''
            }
        ]

    :return: Newly created alert object (JSON).
    """
    if display_name is None:
        return None

    if attributes is None:
        attributes = []

    data = {"displayName": display_name, "type": "PAN XSOAR", "attributes": attributes}
    return client.send_request(IIQ_SCIM_ALERTS_EXT, "POST", None, data)


""" MAIN FUNCTION """


def main():
    """
    Intercept and execute commands.
    """

    # IdentityIQ Base URL (https://identityiq-server.com/identityiq)
    base_url = demisto.params().get("identityiq_url")

    # OAuth 2.0 Credentials
    client_id = demisto.params().get("client_id")
    client_secret = demisto.params().get("client_secret")
    grant_type = "client_credentials"

    # Convert the argument to an int or set to MAX_INCIDENTS_TO_FETCH
    max_results = int(demisto.params().get("max_fetch"))
    if not max_results or max_results > MAX_INCIDENTS_TO_FETCH:
        max_results = MAX_INCIDENTS_TO_FETCH

    first_fetch_str = demisto.params().get("first_fetch", "3 days")

    # Other configs
    verify_certificate = not demisto.params().get("insecure", False)
    proxy = handle_proxy()
    request_timeout = 120  # increased timeout to 2 min from 10 sec to fix timeout error.

    demisto.debug(f"Command being called is {demisto.command()}")
    try:
        headers = get_headers(base_url, client_id, client_secret, grant_type, verify_certificate)
        client = Client(
            base_url=base_url,
            verify=verify_certificate,
            proxy=proxy,
            headers=headers,
            max_results=max_results,
            request_timeout=request_timeout,
        )
        results = None
        if demisto.command() == "test-module":
            # This is the call made when pressing the integration Test button.
            results = test_connection(client)

        elif demisto.command() == "fetch-incidents":
            next_run, incidents = fetch_incidents(client, demisto.getLastRun(), first_fetch_str)
            demisto.setLastRun(next_run)
            demisto.incidents(incidents)

        elif demisto.command() == "identityiq-search-identities":
            id = demisto.args().get("id", None)
            email = demisto.args().get("email", None)
            risk = demisto.args().get("risk", 0)
            active = demisto.args().get("active", True)
            filter = demisto.args().get("filter", None)
            response = search_identities(client, id, email, risk, active, filter)
            results = build_results("IdentityIQ.Identity", "id", response)

        elif demisto.command() == "identityiq-get-policyviolations":
            id = demisto.args().get("id", None)
            response = get_policy_violations(client, id)
            results = build_results("IdentityIQ.PolicyViolation", "policyName", response)

        elif demisto.command() == "identityiq-get-taskresults":
            id = demisto.args().get("id", None)
            response = get_task_results(client, id)
            results = build_results("IdentityIQ.TaskResult", "id", response)

        elif demisto.command() == "identityiq-get-accounts":
            id = demisto.args().get("id", None)
            display_name = demisto.args().get("display_name", None)
            last_refresh = demisto.args().get("last_refresh", None)
            native_identity = demisto.args().get("native_identity", None)
            last_target_agg = demisto.args().get("last_target_agg")
            identity_name = demisto.args().get("identity_name", None)
            application_name = demisto.args().get("application_name", None)
            response = get_accounts(
                client, id, display_name, last_refresh, native_identity, last_target_agg, identity_name, application_name
            )
            results = build_results("IdentityIQ.Account", "id", response)

        elif demisto.command() == "identityiq-disable-account":
            id = demisto.args().get("id", None)
            response = change_account_status(client, id, False)
            results = build_results("IdentityIQ.Account", "id", response)

        elif demisto.command() == "identityiq-enable-account":
            id = demisto.args().get("id", None)
            response = change_account_status(client, id, True)
            results = build_results("IdentityIQ.Account", "id", response)

        elif demisto.command() == "identityiq-delete-account":
            id = demisto.args().get("id", None)
            results = delete_account(client, id)

        elif demisto.command() == "identitytiq-get-launched-workflows":
            id = demisto.args().get("id", None)
            response = get_launched_workflows(client, id)
            results = build_results("IdentityIQ.Workflow", "id", response)

        elif demisto.command() == "identityiq-get-roles":
            id = demisto.args().get("id", None)
            response = get_roles(client, id)
            results = build_results("IdentityIQ.Role", "name", response)

        elif demisto.command() == "identityiq-get-entitlements":
            id = demisto.args().get("id", None)
            response = get_entitlements(client, id)
            results = build_results("IdentityIQ.Entitlement", "id", response)

        elif demisto.command() == "identityiq-get-alerts":
            id = demisto.args().get("id", None)
            response = get_alerts(client, id)
            results = build_results("IdentityIQ.Alert", "id", response)

        elif demisto.command() == "identityiq-create-alert":
            display_name = demisto.args().get("display_name", None)
            attribute = demisto.args().get("attribute", None)
            response = create_alert(client, display_name, attribute)
            results = build_results("IdentityIQ.Alert", "id", response)

        return_results(results)

    # Log exceptions and return errors
    except Exception as e:
        demisto.error(traceback.format_exc())
        return_error(f"Failed to execute {demisto.command()} command.\nError:\n{e!s}")


""" ENTRY POINT """

if __name__ in ("__main__", "__builtin__", "builtins"):
    main()