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 json
from unittest import mock
from unittest.mock import patch

import pytest
import SailPointIdentityIQ
from CommonServerPython import *

""" TEST CONSTANTS """

MOCK_IDENTITYIQ_BASE_URL = "https://identityiq-server.com/identityiq"
MOCK_BEARER_TOKEN = "RXAxTEQ0ZkhUVm94dmhIWDd1M2Q0TjU3NDRnQUYzN2ouZXVlV2h1WUk4OW9jMi95Zml"
MOCK_HEADERS = {"Authorization": f"Bearer {MOCK_BEARER_TOKEN}", "Content-Type": "application/json"}
MOCK_CLIENT = SailPointIdentityIQ.Client(
    base_url=MOCK_IDENTITYIQ_BASE_URL, verify=False, proxy=False, headers=MOCK_HEADERS, max_results=1000, request_timeout=10
)

""" HELPER/UTILITY FUNCTIONS """


def util_load_json(path: str):
    """
    Utility to load json data from a local folder.
    """
    with open(path, encoding="utf-8") as file:
        return json.loads(file.read())


def util_mock_http_resp(status: int, json_data=None):
    """
    Utility to mock http response.
    """
    response = mock.Mock()
    response.status_code = status
    if json_data is not None:
        response.json = mock.Mock(return_value=json_data)
    return response


def verify_scim_list_response(response, total_results):
    """
    Verify SCIM structure for list response.
    """
    assert response["totalResults"] == total_results
    assert len(response["Resources"]) == total_results

    if "startIndex" in response:
        assert response["startIndex"] == 1

    if "schemas" in response:
        assert "urn:ietf:params:scim:api:messages:2.0:ListResponse" in response["schemas"]


def verify_user(user):
    """
    Verify SCIM structure for IdentityIQ User.
    """
    assert user["id"] is not None
    assert user["userName"] is not None
    assert user["active"] is True
    assert user["displayName"] is not None
    assert "urn:ietf:params:scim:schemas:core:2.0:User" in user["schemas"]


def verify_policy_violation(policy_violation):
    """
    Verify SCIM structure for IdentityIQ PolicyViolation.
    """
    assert policy_violation["id"] is not None
    assert policy_violation["constraintName"] is not None
    assert policy_violation["status"] in ["Open", "Closed", "Mitigated"]
    assert policy_violation["policyName"] is not None
    assert "urn:ietf:params:scim:schemas:sailpoint:1.0:PolicyViolation" in policy_violation["schemas"]
    assert policy_violation["identity"]["displayName"] is not None
    assert policy_violation["identity"]["value"] is not None


def verify_task_result(task_result):
    """
    Verify SCIM structure for IdentityIQ TaskResult.
    """
    assert task_result["id"] is not None
    assert task_result["taskDefinition"] is not None
    assert task_result["name"] is not None
    assert task_result["host"] is not None
    assert task_result["type"] is not None
    assert task_result["pendingSignoffs"] is not None
    assert task_result["completionStatus"] in ["Success", "Error"]
    assert task_result["launcher"] is not None
    assert task_result["completed"] is not None


def verify_account(account):
    """
    Verify SCIM structure for IdentityIQ Account response.
    """
    assert account["id"] is not None
    assert account["nativeIdentity"] is not None
    assert account["identity"]["displayName"] is not None
    assert account["identity"]["value"] is not None
    assert account["application"]["displayName"] is not None
    assert account["application"]["value"] is not None
    assert account["hasEntitlements"] is not None
    assert account["active"] is not None


def verify_launched_workflow(launched_workflow):
    """
    Verify SCIM structure for IdentityIQ Launched Workflow response.
    """
    assert launched_workflow["id"] is not None
    assert launched_workflow["name"] is not None
    assert launched_workflow["launcher"] is not None
    assert launched_workflow["type"] is not None
    assert launched_workflow["completionStatus"] in ["Success", "Error"]
    assert launched_workflow["terminated"] is not None
    assert launched_workflow["targetClass"] is not None


def verify_role(role):
    """
    Verify SCIM structure for IdentityIQ Role response.
    """
    assert role["id"] is not None
    assert role["name"] is not None
    assert role["displayableName"] is not None
    assert role["active"] is not None
    assert role["owner"]["displayName"] is not None
    assert role["owner"]["value"] is not None
    assert role["type"]["name"] is not None
    assert role["type"]["autoAssignment"] is not None
    assert role["type"]["displayName"] is not None
    assert role["type"]["manualAssignment"] is not None


def verify_entitlement(entitlement):
    """
    Verify SCIM structure for IdentityIQ Entitlement response.
    """
    assert entitlement["id"] is not None
    assert entitlement["type"] is not None
    assert entitlement["requestable"] is not None
    assert entitlement["aggregated"] is not None
    assert entitlement["application"]["displayName"] is not None
    assert entitlement["application"]["value"] is not None
    assert entitlement["owner"]["displayName"] is not None
    assert entitlement["owner"]["value"] is not None


def verify_alert(alert):
    """
    Verify SCIM structure for IdentityIQ Alert response.
    """
    assert alert["id"] is not None
    assert alert["name"] is not None
    assert alert["displayName"] is not None
    assert alert["meta"]["created"] is not None


""" TESTS (UTILITY)"""


def test_get_headers_all_none():
    headers = SailPointIdentityIQ.get_headers(None, None, None, None, False)
    assert headers is None


def test_get_headers_base_url_none():
    headers = SailPointIdentityIQ.get_headers(None, "test", "test", "client_credentials", False)
    assert headers is None


def test_get_headers_client_id_none():
    headers = SailPointIdentityIQ.get_headers(MOCK_IDENTITYIQ_BASE_URL, None, "test", "client_credentials", False)
    assert headers is None


def test_get_headers_client_secret_none():
    headers = SailPointIdentityIQ.get_headers(MOCK_IDENTITYIQ_BASE_URL, "test", None, "client_credentials", False)
    assert headers is None


@patch("SailPointIdentityIQ.get_headers")
def test_get_headers_grant_type(mock_header):
    mock_header.return_value = {
        "Authorization": "Bearer RXAxTEQ0ZkhUVm94dmhIWDd1M2Q0TjU3NDRnQUYzN2ouZXVlV2h1WUk4OW9jMi95Zml",
        "Content-Type": "application/json",
    }
    headers = SailPointIdentityIQ.get_headers(MOCK_IDENTITYIQ_BASE_URL, "test", "test", None)
    assert headers["Authorization"] == "Bearer RXAxTEQ0ZkhUVm94dmhIWDd1M2Q0TjU3NDRnQUYzN2ouZXVlV2h1WUk4OW9jMi95Zml"
    assert headers["Content-Type"] == "application/json"


@patch("SailPointIdentityIQ.get_headers")
def test_get_headers_success(mock_header):
    mock_header.return_value = {
        "Authorization": "Bearer RXAxTEQ0ZkhUVm94dmhIWDd1M2Q0TjU3NDRnQUYzN2ouZXVlV2h1WUk4OW9jMi95Zml",
        "Content-Type": "application/json",
    }
    headers = SailPointIdentityIQ.get_headers(MOCK_IDENTITYIQ_BASE_URL, "test", "test", "client_credentials")
    assert headers["Authorization"] == "Bearer RXAxTEQ0ZkhUVm94dmhIWDd1M2Q0TjU3NDRnQUYzN2ouZXVlV2h1WUk4OW9jMi95Zml"
    assert headers["Content-Type"] == "application/json"


@patch("SailPointIdentityIQ.Client.send_request")
def test_send_request_all_none(mock_response):
    mock_response.return_value = None
    response = MOCK_CLIENT.send_request(None, None, None, None)
    assert response is None


@patch("SailPointIdentityIQ.Client.send_request")
def test_send_request_url_suffix_none(mock_response):
    mock_response.return_value = None
    response = MOCK_CLIENT.send_request(None, "GET", None, None)
    assert response is None


@patch("SailPointIdentityIQ.Client.send_request")
def test_send_request_method_none(mock_response):
    mock_response.return_value = None
    response = MOCK_CLIENT.send_request(MOCK_IDENTITYIQ_BASE_URL, None, None, None)
    assert response is None


@patch("SailPointIdentityIQ.Client.send_request")
def test_send_request_non_200_status(mock_response):
    """
    Send request should return None in case of 3XX, 4XX or 5XX HTTP status from IdentityIQ.
    """
    json_data = util_load_json("test_data/404_Not_Found.json")
    mock_response.return_value = util_mock_http_resp(404, json_data)
    response = MOCK_CLIENT.send_request(MOCK_IDENTITYIQ_BASE_URL, "GET", None)
    assert response.status_code == 404
    assert "urn:ietf:params:scim:api:messages:2.0:Error" in response.json()["schemas"]
    assert response.json()["status"] == "404"


@patch("SailPointIdentityIQ.Client.send_request")
def test_send_request_success(mock_response):
    """
    Send request should return response json in case of 2XX HTTP status from IdentityIQ.
    """
    json_data = util_load_json("test_data/ResourceTypes.json")
    mock_response.return_value = util_mock_http_resp(200, json_data)
    response = MOCK_CLIENT.send_request(MOCK_IDENTITYIQ_BASE_URL, "GET", None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), response.json()["totalResults"])


def test_transform_object_list_none_all():
    data_list = SailPointIdentityIQ.transform_object_list(None, None)
    assert data_list is None


def test_transform_object_list_type_none():
    json_data = util_load_json("test_data/Users.json")
    data_list = SailPointIdentityIQ.transform_object_list(None, json_data["Resources"])
    assert data_list == json_data["Resources"]


def test_transform_object_list_none():
    data_list = SailPointIdentityIQ.transform_object_list("IdentityIQ.Identity", None)
    assert data_list is None


def test_transform_object_list():
    json_data = util_load_json("test_data/Users.json")
    data_list = SailPointIdentityIQ.transform_object_list("IdentityIQ.Identity", json_data["Resources"])
    assert data_list == json_data["Resources"]

    for data in data_list:
        assert "sailpointUser" in data

    for resource in json_data["Resources"]:
        assert "sailpointUser" in resource


def test_transform_object_none_all():
    data = SailPointIdentityIQ.transform_object(None, None)
    assert data is None


def test_transform_object_type_none():
    json_data = util_load_json("test_data/User.json")
    data = SailPointIdentityIQ.transform_object(None, json_data)
    assert data == json_data


def test_transform_object_none():
    data = SailPointIdentityIQ.transform_object("IdentityIQ.Identity", None)
    assert data is None


def test_transform_object():
    json_data = util_load_json("test_data/User.json")
    data = SailPointIdentityIQ.transform_object("IdentityIQ.Identity", json_data)
    assert data == json_data
    assert "sailpointUser" in data
    assert "sailpointUser" in json_data


def test_get_markdown_none():
    markdown = SailPointIdentityIQ.get_markdown(None, None)
    assert markdown == ""


def test_get_markdown_object_type_none():
    json_data = util_load_json("test_data/User.json")
    markdown = SailPointIdentityIQ.get_markdown(None, json_data)
    assert markdown == ""


def test_get_markdown_objects_none():
    markdown = SailPointIdentityIQ.get_markdown("IdentityIQ.Identity", None)
    headers = [
        "id",
        "userName",
        "displayName",
        "name",
        "emails",
        "sailpointUser",
        "extendedUser",
        "entitlements",
        "roles",
        "capabilities",
        "active",
    ]
    assert markdown == tableToMarkdown("Identity(Identities)", None, headers=headers)


def test_get_markdown():
    json_data = util_load_json("test_data/User.json")
    markdown = SailPointIdentityIQ.get_markdown("IdentityIQ.Identity", json_data)
    headers = [
        "id",
        "userName",
        "displayName",
        "name",
        "emails",
        "sailpointUser",
        "extendedUser",
        "entitlements",
        "roles",
        "capabilities",
        "active",
    ]
    assert markdown == tableToMarkdown("Identity(Identities)", json_data, headers=headers)


def test_build_results_none():
    response = util_mock_http_resp(500, None)
    with pytest.raises(TypeError):
        SailPointIdentityIQ.build_results(None, None, response)


def test_build_results_non_2xx_status():
    json_data = util_load_json("test_data/404_Not_Found.json")
    response = util_mock_http_resp(404, json_data)
    results = SailPointIdentityIQ.build_results("Test.prefix", "Test.key_field", response)
    assert results == "404 : Resource 7f000001705911b4817059d30cf50348 not found."


def test_build_results_2xx_status():
    json_data = util_load_json("test_data/User.json")
    response = util_mock_http_resp(200, json_data)
    results = SailPointIdentityIQ.build_results("IdentityIQ.Identity", "IdentityIQ.Identity", response)
    assert results.readable_output == "### Results:\n" + SailPointIdentityIQ.get_markdown("IdentityIQ.Identity", json_data)
    assert results.outputs_prefix == "IdentityIQ.Identity"
    assert results.outputs_key_field == "IdentityIQ.Identity"
    verify_user(results.outputs)


""" TESTS (COMMAND)"""


@patch("SailPointIdentityIQ.Client.send_request")
def test_connection_fail(mock_response):
    mock_response.return_value = util_mock_http_resp(404, None)
    test_connection = SailPointIdentityIQ.test_connection(MOCK_CLIENT)
    assert test_connection == "Unable to connect to IdentityIQ!"


@patch("SailPointIdentityIQ.Client.send_request")
def test_connection_success(mock_response):
    mock_response.return_value = util_mock_http_resp(200, None)
    test_connection = SailPointIdentityIQ.test_connection(MOCK_CLIENT)
    assert test_connection == "ok"


@patch("SailPointIdentityIQ.Client.send_request")
def test_search_identities_no_resources(mock_search_identities_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_search_identities_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.search_identities(MOCK_CLIENT, None, None, 0, False, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_search_identities_id_not_found(mock_search_identities_response):
    json_data = util_load_json("test_data/404_Not_Found.json")
    mock_search_identities_response.return_value = util_mock_http_resp(404, json_data)
    response = SailPointIdentityIQ.search_identities(MOCK_CLIENT, "7f000001705911b4817059d30cf50348", None, 0, True, None)
    assert response.status_code == 404
    assert response.json()["status"] == "404"
    assert response.json()["detail"] == "Resource 7f000001705911b4817059d30cf50348 not found."


@patch("SailPointIdentityIQ.Client.send_request")
def test_search_identities_id_found(mock_search_identities_response):
    json_data = util_load_json("test_data/User.json")
    mock_search_identities_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.search_identities(MOCK_CLIENT, "7f00000174441779817444c8842b0017", None, 0, True, None)
    assert response.status_code == 200
    verify_user(response.json())
    assert response.json()["id"] == "7f00000174441779817444c8842b0017"


@patch("SailPointIdentityIQ.Client.send_request")
def test_search_identities_email_not_found(mock_search_identities_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_search_identities_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.search_identities(MOCK_CLIENT, None, "test@sailpointdemo.com", 0, True, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_search_identities_email_found(mock_search_identities_response):
    json_data = util_load_json("test_data/User_Filtered.json")
    mock_search_identities_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.search_identities(MOCK_CLIENT, None, "serviceaccount@sailpointdemo.com", 0, True, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 1)
    user = response.json()["Resources"][0]
    verify_user(user)
    assert user["id"] == "7f000001705914d1817059d59e18000e"
    has_email = False
    for email in user["emails"]:
        if email["value"] == "serviceaccount@sailpointdemo.com":
            has_email = True
    assert has_email is True


@patch("SailPointIdentityIQ.Client.send_request")
def test_search_identities_risk_score_not_matched(mock_search_identities_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_search_identities_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.search_identities(MOCK_CLIENT, None, None, 1600, True, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_search_identities_risk_score_invalid(mock_search_identities_response):
    json_data = util_load_json("test_data/400_Bad_Request.json")
    mock_search_identities_response.return_value = util_mock_http_resp(400, json_data)
    response = SailPointIdentityIQ.search_identities(MOCK_CLIENT, None, None, -1, True, None)
    assert response.status_code == 400
    assert response.json()["status"] == "400"
    assert response.json()["detail"] == "Invalid filter:urn:ietf:params:scim:schemas:sailpoint:1.0:User:riskScore eq -1"
    assert "urn:ietf:params:scim:api:messages:2.0:Error" in response.json()["schemas"]


@patch("SailPointIdentityIQ.Client.send_request")
def test_search_identities_risk_score_matched(mock_search_identities_response):
    json_data = util_load_json("test_data/User_Filtered.json")
    mock_search_identities_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.search_identities(MOCK_CLIENT, None, None, 100, True, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 1)
    user = response.json()["Resources"][0]
    verify_user(user)
    assert user["id"] == "7f000001705914d1817059d59e18000e"
    assert user["urn:ietf:params:scim:schemas:sailpoint:1.0:User"]["riskScore"] >= 100


@patch("SailPointIdentityIQ.Client.send_request")
def test_search_identities_active_false(mock_search_identities_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_search_identities_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.search_identities(MOCK_CLIENT, None, None, 0, True, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_search_identities_active_true(mock_search_identities_response):
    json_data = util_load_json("test_data/Users.json")
    mock_search_identities_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.search_identities(MOCK_CLIENT, None, None, 0, True, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 5)
    for user in response.json()["Resources"]:
        verify_user(user)
        assert user["active"] is True


@patch("SailPointIdentityIQ.Client.send_request")
def test_search_identities_custom_filter_found(mock_search_identities_response):
    json_data = util_load_json("test_data/User_Filtered.json")
    mock_search_identities_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.search_identities(
        MOCK_CLIENT, None, None, 0, True, 'emails.value eq "serviceaccount@sailpointdemo.com"'
    )
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 1)
    user = response.json()["Resources"][0]
    verify_user(user)
    assert user["id"] == "7f000001705914d1817059d59e18000e"
    has_email = False
    for email in user["emails"]:
        if email["value"] == "serviceaccount@sailpointdemo.com":
            has_email = True
    assert has_email is True


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_policy_violations_id_not_found(mock_policy_violations_response):
    json_data = util_load_json("test_data/404_Not_Found.json")
    mock_policy_violations_response.return_value = util_mock_http_resp(404, json_data)
    response = SailPointIdentityIQ.get_policy_violations(MOCK_CLIENT, "8a8080824df45873014df46036521343")
    assert response.status_code == 404
    assert "urn:ietf:params:scim:api:messages:2.0:Error" in response.json()["schemas"]
    assert response.json()["status"] == "404"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_policy_violations_id_found(mock_policy_violations_response):
    json_data = util_load_json("test_data/PolicyViolation.json")
    mock_policy_violations_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_policy_violations(MOCK_CLIENT, "8a8080824df45873014df46036521328")
    assert response.status_code == 200
    verify_policy_violation(response.json())
    assert response.json()["id"] == "8a8080824df45873014df46036521328"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_policy_violations_no_resources(mock_policy_violations_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_policy_violations_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_policy_violations(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_policy_violations(mock_policy_violations_response):
    json_data = util_load_json("test_data/PolicyViolations.json")
    mock_policy_violations_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_policy_violations(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 2)
    for policy_violation in response.json()["Resources"]:
        verify_policy_violation(policy_violation)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_task_results_id_not_found(mock_task_results_response):
    json_data = util_load_json("test_data/404_Not_Found.json")
    mock_task_results_response.return_value = util_mock_http_resp(404, json_data)
    response = SailPointIdentityIQ.get_task_results(MOCK_CLIENT, "7f00000175891f4b81763bd218de1d64")
    assert response.status_code == 404
    assert "urn:ietf:params:scim:api:messages:2.0:Error" in response.json()["schemas"]
    assert response.json()["status"] == "404"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_task_results_id_found(mock_task_results_response):
    json_data = util_load_json("test_data/TaskResult.json")
    mock_task_results_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_task_results(MOCK_CLIENT, "7f00000175891f4b81763bd2181c1d5f")
    assert response.status_code == 200
    verify_task_result(response.json())


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_task_results_no_resources(mock_task_results_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_task_results_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_task_results(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_task_results(mock_task_results_response):
    json_data = util_load_json("test_data/TaskResults.json")
    mock_task_results_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_task_results(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 5)
    for task_result in response.json()["Resources"]:
        verify_task_result(task_result)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_no_resources(mock_accounts_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, None, None, None, None, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_id_not_found(mock_accounts_response):
    json_data = util_load_json("test_data/404_Not_Found.json")
    mock_accounts_response.return_value = util_mock_http_resp(404, json_data)
    response = SailPointIdentityIQ.get_accounts(
        MOCK_CLIENT, "7f00000174441779817444c8837c5373", None, None, None, None, None, None
    )
    assert response.status_code == 404
    assert "urn:ietf:params:scim:api:messages:2.0:Error" in response.json()["schemas"]
    assert response.json()["status"] == "404"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_id_found(mock_accounts_response):
    json_data = util_load_json("test_data/Account.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(
        MOCK_CLIENT, "7f00000174441779817444c8837c0014", None, None, None, None, None, None
    )
    assert response.status_code == 200
    verify_account(response.json())


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_display_name_not_found(mock_accounts_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, "Black Jack", None, None, None, None, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_display_name_found(mock_accounts_response):
    json_data = util_load_json("test_data/Account_Filtered.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, "bjack", None, None, None, None, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 1)
    account = response.json()["Resources"][0]
    verify_account(account)
    assert account["id"] == "7f00000174441779817444c883c30016"
    assert account["displayName"] == "bjack"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_last_refresh_not_matched(mock_accounts_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, "2020-12-10T08:50:25Z", None, None, None, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_last_refresh_matched(mock_accounts_response):
    json_data = util_load_json("test_data/Account_Filtered.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, "2020-08-31T00:00:00Z", None, None, None, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 1)
    account = response.json()["Resources"][0]
    verify_account(account)
    assert account["id"] == "7f00000174441779817444c883c30016"
    assert account["lastRefresh"] >= "2020-08-31T00:00:00Z"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_native_identity_not_found(mock_accounts_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, None, "Black Jack", None, None, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_native_identity_found(mock_accounts_response):
    json_data = util_load_json("test_data/Account_Filtered.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, None, "bjack", None, None, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 1)
    account = response.json()["Resources"][0]
    verify_account(account)
    assert account["id"] == "7f00000174441779817444c883c30016"
    assert account["nativeIdentity"] == "bjack"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_last_target_agg_not_matched(mock_accounts_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, None, None, "2020-12-10T00:00:00Z", None, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_last_target_agg_matched(mock_accounts_response):
    json_data = util_load_json("test_data/Account_Filtered.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, None, None, "2020-08-31T00:00:00Z", None, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 1)
    account = response.json()["Resources"][0]
    verify_account(account)
    assert account["id"] == "7f00000174441779817444c883c30016"
    assert account["lastTargetAggregation"] == "2020-09-05T09:22:45.432-05:00"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_identity_name_not_matched(mock_accounts_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, None, None, None, "Black Jack", None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_identity_name_matched(mock_accounts_response):
    json_data = util_load_json("test_data/Account_Filtered.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, None, None, None, "bjack", None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 1)
    account = response.json()["Resources"][0]
    verify_account(account)
    assert account["id"] == "7f00000174441779817444c883c30016"
    assert account["identity"]["displayName"] == "bjack"
    assert account["identity"]["userName"] == "bjack"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_application_name_not_matched(mock_accounts_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, None, None, None, None, "SCIM Server")
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts_application_name_matched(mock_accounts_response):
    json_data = util_load_json("test_data/Account_Filtered.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, None, None, None, None, "SCIM SDK")
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 1)
    account = response.json()["Resources"][0]
    verify_account(account)
    assert account["id"] == "7f00000174441779817444c883c30016"
    assert account["application"]["displayName"] == "SCIM SDK"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_accounts(mock_accounts_response):
    json_data = util_load_json("test_data/Accounts.json")
    mock_accounts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_accounts(MOCK_CLIENT, None, None, "2020-05-01T00:00:00Z", None, None, None, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 3)
    for account in response.json()["Resources"]:
        verify_account(account)


@patch("SailPointIdentityIQ.change_account_status")
def test_change_account_id_not_found(mock_account):
    mock_account.return_value = util_load_json("test_data/404_Not_Found.json")
    accounts = SailPointIdentityIQ.change_account_status(MOCK_CLIENT, "7f00000174441779817444c8837c5373", True)
    assert "urn:ietf:params:scim:api:messages:2.0:Error" in accounts["schemas"]
    assert accounts["status"] == "404"


@patch("SailPointIdentityIQ.change_account_status")
def test_change_account_enable(mock_account):
    mock_account.return_value = util_load_json("test_data/Account.json")
    account = SailPointIdentityIQ.change_account_status(MOCK_CLIENT, "7f00000174441779817444c883c30016", True)
    verify_account(account)
    assert account["active"] is True


@patch("SailPointIdentityIQ.change_account_status")
def test_change_account_disable(mock_account):
    mock_account.return_value = util_load_json("test_data/Account_Disabled.json")
    account = SailPointIdentityIQ.change_account_status(MOCK_CLIENT, "7f00000174441779817444c883c30016", False)
    verify_account(account)
    assert account["active"] is False


@patch("SailPointIdentityIQ.delete_account")
def test_delete_account_id_none(mock_account_response):
    mock_account_response.return_value = "405"
    response = SailPointIdentityIQ.delete_account(MOCK_CLIENT, None)
    assert response == "405"


@patch("SailPointIdentityIQ.delete_account")
def test_delete_account_id_not_found(mock_account_response):
    mock_account_response.return_value = "404 : Resource 7f00000174441779817444c8837c5373 not found."
    response = SailPointIdentityIQ.delete_account(MOCK_CLIENT, "7f00000174441779817444c8837c5373")
    assert response == "404 : Resource 7f00000174441779817444c8837c5373 not found."


@patch("SailPointIdentityIQ.delete_account")
def test_delete_account_deleted(mock_account_response):
    mock_account_response.return_value = "404 : Resource 7f00000174441779817444c8837c5373 not found."
    response = SailPointIdentityIQ.delete_account(MOCK_CLIENT, "7f00000174441779817444c8837c5373")
    assert response == "404 : Resource 7f00000174441779817444c8837c5373 not found."


@patch("SailPointIdentityIQ.delete_account")
def test_delete_account(mock_account_response):
    mock_account_response.return_value = "Account deleted successfully!"
    response = SailPointIdentityIQ.delete_account(MOCK_CLIENT, "7f00000174441779817444c8837c5373")
    assert response == "Account deleted successfully!"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_launched_workflows_id_not_found(mock_launched_workflows_response):
    json_data = util_load_json("test_data/404_Not_Found.json")
    mock_launched_workflows_response.return_value = util_mock_http_resp(404, json_data)
    response = SailPointIdentityIQ.get_launched_workflows(MOCK_CLIENT, "7f00000173de18fa8173deb1064e0453")
    assert response.status_code == 404
    assert "urn:ietf:params:scim:api:messages:2.0:Error" in response.json()["schemas"]
    assert response.json()["status"] == "404"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_launched_workflows_id_found(mock_launched_workflows_response):
    json_data = util_load_json("test_data/LaunchedWorkflow.json")
    mock_launched_workflows_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_launched_workflows(MOCK_CLIENT, "7f00000173de18fa8173deb1064e001c")
    assert response.status_code == 200
    verify_launched_workflow(response.json())


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_launched_workflows_no_resources(mock_launched_workflows_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_launched_workflows_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_launched_workflows(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_launched_workflows(mock_launched_workflows_response):
    json_data = util_load_json("test_data/LaunchedWorkflows.json")
    mock_launched_workflows_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_launched_workflows(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 5)
    for launched_workflow in response.json()["Resources"]:
        verify_launched_workflow(launched_workflow)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_roles_id_not_found(mock_roles_response):
    json_data = util_load_json("test_data/404_Not_Found.json")
    mock_roles_response.return_value = util_mock_http_resp(404, json_data)
    response = SailPointIdentityIQ.get_roles(MOCK_CLIENT, "7f000001705911b4817059d312394432")
    assert response.status_code == 404
    assert "urn:ietf:params:scim:api:messages:2.0:Error" in response.json()["schemas"]
    assert response.json()["status"] == "404"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_roles_id_found(mock_roles_response):
    json_data = util_load_json("test_data/Role.json")
    mock_roles_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_roles(MOCK_CLIENT, "7f000001705911b4817059d31239035f")
    assert response.status_code == 200
    verify_role(response.json())


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_roles_no_resources(mock_roles_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_roles_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_roles(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_roles(mock_roles_response):
    json_data = util_load_json("test_data/Roles.json")
    mock_roles_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_roles(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 5)
    for role in response.json()["Resources"]:
        verify_role(role)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_entitlements_id_not_found(mock_entitlements_response):
    json_data = util_load_json("test_data/404_Not_Found.json")
    mock_entitlements_response.return_value = util_mock_http_resp(404, json_data)
    response = SailPointIdentityIQ.get_entitlements(MOCK_CLIENT, "7f000001705911b4817059d355844443")
    assert response.status_code == 404
    assert "urn:ietf:params:scim:api:messages:2.0:Error" in response.json()["schemas"]
    assert response.json()["status"] == "404"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_entitlements_id_found(mock_entitlements_response):
    json_data = util_load_json("test_data/Entitlement.json")
    mock_entitlements_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_entitlements(MOCK_CLIENT, "7f000001705911b4817059d355840657")
    assert response.status_code == 200
    verify_entitlement(response.json())


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_entitlements_no_resources(mock_entitlements_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_entitlements_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_entitlements(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_entitlements(mock_entitlements_response):
    json_data = util_load_json("test_data/Entitlements.json")
    mock_entitlements_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_entitlements(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 5)
    for entitlement in response.json()["Resources"]:
        verify_entitlement(entitlement)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_alerts_id_not_found(mock_alerts_response):
    json_data = util_load_json("test_data/404_Not_Found.json")
    mock_alerts_response.return_value = util_mock_http_resp(404, json_data)
    response = SailPointIdentityIQ.get_alerts(MOCK_CLIENT, "0a000001758a173e81763f81205e6453")
    assert response.status_code == 404
    assert "urn:ietf:params:scim:api:messages:2.0:Error" in response.json()["schemas"]
    assert response.json()["status"] == "404"


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_alerts_id_found(mock_alerts_response):
    json_data = util_load_json("test_data/Alert.json")
    mock_alerts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_alerts(MOCK_CLIENT, "0a000001758a173e81763f81205e0062")
    assert response.status_code == 200
    verify_alert(response.json())


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_alerts_no_resources(mock_alerts_response):
    json_data = util_load_json("test_data/NoResources.json")
    mock_alerts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_alerts(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 0)


@patch("SailPointIdentityIQ.Client.send_request")
def test_get_alerts(mock_alerts_response):
    json_data = util_load_json("test_data/Alerts.json")
    mock_alerts_response.return_value = util_mock_http_resp(200, json_data)
    response = SailPointIdentityIQ.get_alerts(MOCK_CLIENT, None)
    assert response.status_code == 200
    verify_scim_list_response(response.json(), 3)
    for alert in response.json()["Resources"]:
        verify_alert(alert)


@patch("SailPointIdentityIQ.Client.send_request")
def test_create_alert(mock_alerts_response):
    json_data = util_load_json("test_data/Alert.json")
    mock_alerts_response.return_value = util_mock_http_resp(201, json_data)
    response = SailPointIdentityIQ.create_alert(MOCK_CLIENT, "Test Alert")
    assert response.status_code == 201
    verify_alert(response.json())