PingOne
Integrates with the PingOne Management API to unlock, create, delete and update users.
Authentication & Identity Management · PingIdentity
Details
| ID | PingOne |
|---|---|
| Provider | Thoma Bravo |
| Category | Authentication & Identity Management |
| From Version | 6.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix Cloud Runtime Security Cloud Posture Security XSIAM EDR Cortex Cloud |
README
Integrates with the PingOne Management API to unlock, create, delete and update users.
Configure PingOne in Cortex
| Parameter | Description | Required |
|---|---|---|
| Your PingOne Environment ID | Environment ID is available under the PingOne Dashboard->Environment Properties. | True |
| PingOne Region | PingOne has 3 regions, US, EU and Asia. | True |
| Client ID | True | |
| Client Secret | True | |
| Trust any certificate (not secure) | Trust any certificate (not secure). | False |
| Use system proxy settings | Use system proxy settings. | 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.
pingone-unlock-user
Unlock a user’s account.
Base Command
pingone-unlock-user
Input
| Argument Name | Description | Required |
|---|---|---|
| username | Username to unlock. | Required |
Context Output
There is no context output for this command.
Command Example
!pingone-unlock-user username=emma.sharp
Human Readable Output
emma.sharp unlocked
pingone-deactivate-user
Deactivate a user’s account.
Base Command
pingone-deactivate-user
Input
| Argument Name | Description | Required |
|---|---|---|
| username | A username to deactivate. | Required |
Context Output
There is no context output for this command.
Command Example
!pingone-deactivate-user username=emma.sharp
Human Readable Output
User emma.sharp deactivated
pingone-activate-user
Activate a user’s account.
Base Command
pingone-activate-user
Input
| Argument Name | Description | Required |
|---|---|---|
| username | A username to activate. | Required |
Context Output
There is no context output for this command.
Command Example
!pingone-activate-user username=emma.sharp
Human Readable Output
emma.sharp is active now
pingone-set-password
Sets a user’s password. Further password details available here: https://apidocs.pingidentity.com/pingone/platform/v1/api/#put-update-password-self
Base Command
pingone-set-password
Input
| Argument Name | Description | Required |
|---|---|---|
| username | The username to change the password for. | Required |
| password | The new password. | Required |
Context Output
There is no context output for this command.
Command Example
!pingone-set-password username=emma.sharp password=OnePing123!
Human Readable Output
emma.sharp password was updated.
pingone-password-force-change
Force a user’s password change on next login.
Base Command
pingone-password-force-change
Input
| Argument Name | Description | Required |
|---|---|---|
| username | The username to force a password change for. | Required |
Context Output
There is no context output for this command.
Command Example
!pingone-password-force-change username=emma.sharp
Human Readable Output
emma.sharp password was set to force change.
pingone-read-password-state
Read a user’s password state.
Base Command
pingone-read-password-state
Input
| Argument Name | Description | Required |
|---|---|---|
| username | The username to read password state for. | Required |
Context Output
There is no context output for this command.
Command Example
!pingone-read-password-state username=emma.sharp
Human Readable Output
Password state for emma.sharp status MUST_CHANGE_PASSWORD
pingone-add-to-group
Add user to the group. One of the following has to be given username or userId and groupName or groupId.
Base Command
pingone-add-to-group
Input
| Argument Name | Description | Required |
|---|---|---|
| username | Username . | Optional |
| groupName | Group Name. | Optional |
| groupId | Group ID. | Optional |
| userId | User ID. | Optional |
Context Output
There is no context output for this command.
Command Example
!pingone-add-to-group username=richard.smith groupName=Sales
Human Readable Output
User: 9bc53389-f806-47b6-9480-ab1e3c6269b5 added to group: Sales successfully
pingone-remove-from-group
Remove user from the group. One of the following has to be given username or userId and groupName or groupId.
Base Command
pingone-remove-from-group
Input
| Argument Name | Description | Required |
|---|---|---|
| username | Username. | Optional |
| groupName | Group Name. | Optional |
| userId | User ID. | Optional |
| groupId | Group ID. | Optional |
Context Output
There is no context output for this command.
Command Example
!pingone-remove-from-group username=richard.smith groupName=Sales
Human Readable Output
User: 9bc53389-f806-47b6-9480-ab1e3c6269b5 was removed from group: Sales successfully
pingone-get-groups
Returns user’s group memberships.
Base Command
pingone-get-groups
Input
| Argument Name | Description | Required |
|---|---|---|
| username | Username. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PingOne.Account.Group | string | PingOne groups of the user. |
| PingOne.Account.ID | string | PingOne account ID. |
| PingOne.Account.Type | string | PingOne account type. |
| PingOne.Account.Group.ID | string | Group unique ID. |
| PingOne.Account.Group.Name | string | Group name. |
Command Example
!pingone-get-groups username=emma.sharp
Context Example
{
"Account": {
"Group": [
{
"ID": "a5ec8d61-6291-4ebf-8630-135c2ecf1d10",
"Name": "Marketing"
},
{
"ID": "115458a4-5460-4514-802c-df153a6dcd47",
"Name": "Standard"
}
],
"ID": "emma.sharp",
"Type": "PingOne"
}
}
Human Readable Output
PingOne groups for user: emma.sharp
Groups
ID Name a5ec8d61-6291-4ebf-8630-135c2ecf1d10 Marketing 115458a4-5460-4514-802c-df153a6dcd47 Standard
pingone-get-user
Returns a PingOne user. One of the following has to be given username or userId.
Base Command
pingone-get-user
Input
| Argument Name | Description | Required |
|---|---|---|
| username | Username. | Optional |
| userId | User ID. | Optional |
| detailed | PingOne user details. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PingOne.Account.ID | string | PingOne account ID. |
| PingOne.Account.Username | string | PingOne account username. |
| PingOne.Account.DisplayName | string | PingOne account display name. |
| PingOne.Account.Email | string | PingOne account email. |
| PingOne.Account.Enabled | boolean | PingOne account enabled status. |
| PingOne.Account.CreatedAt | date | PingOne account create date. |
| PingOne.Account.UpdatedAt | date | PingOne account updated date. |
Command Example
!pingone-get-user username=emma.sharp
Context Example
{
"Account": {
"CreatedAt": "2021-09-03T18:04:03.916Z",
"DisplayName": "Emma Testman",
"Email": "emma.sharp@example.com",
"Enabled": true,
"ID": "a8890eb9-38ea-469a-bc00-b64be7903633",
"UpdatedAt": "2021-09-23T17:18:11.747Z",
"Username": "emma.sharp"
}
}
Human Readable Output
User:emma.sharp
AccountStatus CreatedAt Enabled Environment First Name ID Last Name PopulationID UpdatedAt Username OK 2021-09-03T18:04:03.916Z emma.sharp@example.com true b4f5e266-a946-4f77-9cc5-5dc91b046431 Emma a8890eb9-38ea-469a-bc00-b64be7903633 Sharp 4cd45bdb-0eb2-42fe-8475-4bcd908269f1 2021-09-23T17:18:11.747Z emma.sharp
pingone-create-user
Create a PingOne user.
Base Command
pingone-create-user
Input
| Argument Name | Description | Required |
|---|---|---|
| username | The username to create. | Required |
| populationId | PingOne population ID where the new user will be created. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PingOne.Account.ID | string | PingOne account ID. |
| PingOne.Account.Username | string | PingOne account username. |
| PingOne.Account.DisplayName | string | PingOne account display name. |
| PingOne.Account.Email | string | PingOne account email. |
| PingOne.Account.Enabled | boolean | PingOne account enabled status. |
| PingOne.Account.CreatedAt | date | PingOne account create date. |
| PingOne.Account.UpdatedAt | date | PingOne account updated date. |
Command Example
!pingone-create-user username=richard.smith populationId=4cd45bdb-0eb2-42fe-8475-4bcd908269f1
Context Example
{
"Account": {
"CreatedAt": "2021-09-23T17:18:18.292Z",
"DisplayName": null,
"Email": null,
"Enabled": true,
"ID": "9bc53389-f806-47b6-9480-ab1e3c6269b5",
"UpdatedAt": "2021-09-23T17:18:18.292Z",
"Username": "richard.smith"
}
}
Human Readable Output
PingOne user created: richard.smith
AccountStatus CreatedAt Enabled Environment First Name ID Last Name PopulationID UpdatedAt Username OK 2021-09-23T17:18:18.292Z true b4f5e266-a946-4f77-9cc5-5dc91b046431 9bc53389-f806-47b6-9480-ab1e3c6269b5 4cd45bdb-0eb2-42fe-8475-4bcd908269f1 2021-09-23T17:18:18.292Z richard.smith
pingone-update-user
Update a PingOne user.
Base Command
pingone-update-user
Input
| Argument Name | Description | Required |
|---|---|---|
| username | The username to be updated. | Required |
| formatted | Formatted PingOne name. | Optional |
| given | Given name. | Optional |
| middle | Middle name. | Optional |
| family | Family name. | Optional |
| nickname | Nickname. | Optional |
| title | Title. | Optional |
| locale | Locale. | Optional |
| Email. | Optional | |
| primaryPhone | Primary phone number. | Optional |
| mobilePhone | Mobile phone number. | Optional |
| streetAddress | Street address. | Optional |
| locality | Locality. | Optional |
| region | Region. | Optional |
| postalCode | Zip code. | Optional |
| countryCode | Country code. | Optional |
| Type | Account type. | Optional |
Context Output
There is no context output for this command.
Command Example
!pingone-update-user username=richard.smith phoneNumber=604-998-7766
Human Readable Output
PingOne user updated: richard.smith
No entries.
pingone-delete-user
Delete a PingOne user. One of the following has to be given username or userId.
Base Command
pingone-delete-user
Input
| Argument Name | Description | Required |
|---|---|---|
| username | Username. | Optional |
| userId | User ID. | Optional |
Context Output
There is no context output for this command.
Command Example
!pingone-delete-user username=richard.smith
Human Readable Output
User: 9bc53389-f806-47b6-9480-ab1e3c6269b5 was Deleted successfully
Configuration parameters
environment_id— Your PingOne Environment ID (required)region— PingOne Region (required)credentials— Client ID (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (13)
-
pingone-activate-userActivate a user's account.
-
pingone-add-to-groupAdd user to the group. One of the following has to be given username or userId and groupName or groupId.
-
pingone-create-userCreate a PingOne user.
-
pingone-deactivate-userDeactivate a user's account.
-
pingone-delete-userDelete a PingOne user. One of the following has to be given username or userId.
-
pingone-get-groupsReturns user's group memberships.
-
pingone-get-userReturns a PingOne user. One of the following has to be given username or userId.
-
pingone-password-force-changeForce a user's password change on next login.
-
pingone-read-password-stateRead a user's password state.
-
pingone-remove-from-groupRemove user from the group. One of the following has to be given username or userId and groupName or groupId.
-
pingone-set-passwordSets a user's password. Further password details available here: https://apidocs.pingidentity.com/pingone/platform/v1/api/#put-update-password-self .
-
pingone-unlock-userUnlock a user's account.
-
pingone-update-userUpdate a PingOne user.
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 # IMPORTS # Disable insecure warnings import urllib3 urllib3.disable_warnings() PROFILE_ARGS = [ "formatted", "given", "middle", "family", "nickname", "title", "locale", "email", "primaryPhone", "mobilePhone", "streetAddress", "locality", "region", "postalCode", "countryCode", "type", ] class Client(BaseClient): """ Client will implement the service API, and should not contain any Demisto logic. Should only do requests and return data. """ def __init__(self, base_url, verify, proxy, auth_params): super().__init__(base_url=base_url, verify=verify, proxy=proxy) self.client_id = auth_params.get("client_id") self.client_secret = auth_params.get("client_secret") self.auth_url = auth_params.get("auth_url") self._headers = self._request_token() def _request_token(self): """ Handles the actual request made to retrieve the access token. :return: Access token to be used in the authorization header for each request. """ params = {"grant_type": "client_credentials", "client_id": self.client_id, "client_secret": self.client_secret} response = self._http_request( method="POST", headers={"Content-Type": "application/x-www-form-urlencoded"}, full_url=self.auth_url, data=params ) access_token = response.get("access_token") auth_header = {"Authorization": f"Bearer {access_token}"} return auth_header # Getting Group Id with a given group name def get_group_id(self, group_name): uri = "groups" query_params = {"filter": encode_string_results(f'name eq "{group_name}"')} res = self._http_request(method="GET", url_suffix=uri, params=query_params) if "_embedded" in res and len(res.get("_embedded", {}).get("groups")) == 1: return res.get("_embedded", {}).get("groups")[0].get("id") raise Exception(f"Failed to find groupID for: {group_name} group name.") # Return User Id from username def get_user_id(self, username): uri = "users" query_params = {"filter": encode_string_results(f'username eq "{username}"')} res = self._http_request(method="GET", url_suffix=uri, params=query_params) if "_embedded" in res and len(res.get("_embedded", {}).get("users")) == 1: return res.get("_embedded", {}).get("users")[0].get("id") raise Exception(f"PingOne error: Failed to find userID for: {username} username.") # Return user from username def get_user_by_username(self, username): uri = "users" query_params = {"filter": encode_string_results(f'username eq "{username}"')} res = self._http_request(method="GET", url_suffix=uri, params=query_params) if "_embedded" in res and len(res.get("_embedded", {}).get("users")) == 1: return res.get("_embedded", {}).get("users")[0] raise Exception(f"Failed to find user for {username} username.") # Return user from id def get_user_by_id(self, user_id): uri = f"users/{user_id}" res = self._http_request( method="GET", url_suffix=uri, ) if res.get("code") == "NOT_FOUND": raise Exception(f"Failed to find user for {user_id}") return res def unlock_user(self, user_id): """ sending a POST request to unlock a specific user """ uri = f"users/{user_id}" new_headers = self._headers new_headers["Content-Type"] = "application/vnd.pingidentity.account.unlock+json" return self._http_request(method="POST", url_suffix=uri, headers=new_headers) def deactivate_user(self, user_id): uri = f"users/{user_id}/enabled" body = {"enabled": False} return self._http_request(method="PUT", url_suffix=uri, json_data=body) def activate_user(self, user_id): uri = f"users/{user_id}/enabled" body = {"enabled": True} return self._http_request(method="PUT", url_suffix=uri, json_data=body) def set_password(self, user_id, password): uri = f"users/{user_id}/password" body = {"newPassword": password} new_headers = self._headers new_headers["Content-Type"] = "application/vnd.pingidentity.password.reset+json" return self._http_request(method="PUT", url_suffix=uri, headers=new_headers, json_data=body) def force_password_change(self, user_id): uri = f"users/{user_id}/password" new_headers = dict(self._headers) new_headers["Content-Type"] = "application/vnd.pingidentity.password.forceChange" return self._http_request( method="POST", url_suffix=uri, headers=new_headers, return_empty_response=True, ok_codes=(204,), ) def read_password_state(self, user_id): uri = f"users/{user_id}/password" return self._http_request(method="GET", url_suffix=uri) def add_user_to_group(self, user_id, group_id): uri = f"users/{user_id}/memberOfGroups" body = {"id": group_id} return self._http_request(method="POST", url_suffix=uri, json_data=body) def remove_user_from_group(self, user_id, group_id): uri = f"users/{user_id}/memberOfGroups/{group_id}" self._http_request( method="DELETE", url_suffix=uri, return_empty_response=True, ok_codes=(204, 404), # PingOne returns 404 if the group has already removed which results in a XSOAR error ) def get_groups_for_user(self, user_id): uri = f'users/{user_id}/memberOfGroups?expand=group&filter=type eq "DIRECT"' query_params = {"expand": "group", "filter": 'username eq "DIRECT"'} return self._http_request(method="GET", url_suffix=uri, params=query_params) @staticmethod def build_user_profile(args): profile = {} # type:ignore keys = args.keys() for key in PROFILE_ARGS: if key in keys: if key in ["formatted", "given", "middle", "family"]: if "name" not in profile: profile["name"] = {} profile["name"][key] = args[key] elif key in ["streetAddress", "locality", "region", "postalCode", "countryCode"]: if "address" not in profile: profile["address"] = {} profile["address"][key] = args[key] else: profile[key] = args[key] return profile @staticmethod def get_readable_group_membership(raw_groups): groups = [] raw_groups = raw_groups.get("_embedded", {}).get("groupMemberships", []) for group in raw_groups: if group.get("type") == "DIRECT": grp = {"ID": group.get("id"), "Name": group.get("name")} groups.append(grp) return groups @staticmethod def get_user_context(raw_user): user = { "ID": raw_user.get("id"), "Username": raw_user.get("username"), "DisplayName": raw_user.get("name", {}).get("formatted"), "Email": raw_user.get("email"), "Enabled": raw_user.get("enabled"), "CreatedAt": raw_user.get("createdAt"), "UpdatedAt": raw_user.get("updatedAt"), } return user @staticmethod def get_readable_user(raw_user): user_attrs = { "ID": raw_user.get("id"), "Username": raw_user.get("username"), "Email": raw_user.get("email"), "First Name": raw_user.get("name", {}).get("given"), "Last Name": raw_user.get("name", {}).get("family"), "Enabled": raw_user.get("enabled"), "Environment": raw_user.get("environment", {}).get("id"), "PopulationID": raw_user.get("population", {}).get("id"), "AccountStatus": raw_user.get("account", {}).get("status"), "CreatedAt": raw_user.get("createdAt"), "UpdatedAt": raw_user.get("updatedAt"), } return user_attrs def get_user(self, user_id): uri = f"users/{user_id}" return self._http_request(method="GET", url_suffix=uri) def create_user(self, username, pop_id): uri = "users" body = {"population": {"id": f"{pop_id}"}, "username": f"{username}"} res = self._http_request(method="POST", url_suffix=uri, json_data=body) return res def update_user(self, user_id, attrs): uri = f"users/{user_id}" return self._http_request(method="PATCH", url_suffix=uri, json_data=attrs) def delete_user(self, user_id): uri = f"users/{user_id}" return self._http_request( method="DELETE", url_suffix=uri, return_empty_response=True, ok_codes=(204, 404), # PingOne returns 404 if the group has already removed which results in a XSOAR error ) def test_module(client, _args): """ Returning 'ok' indicates that the integration works like it is supposed to. Connection to the service is successful. Args: client: HelloWorld client Returns: 'ok' if test passed, anything else will fail the test. """ uri = "/" client._http_request(method="GET", url_suffix=uri) return "ok", None, None def unlock_user_command(client, args): user_id = client.get_user_id(args.get("username")) raw_response = client.unlock_user(user_id) readable_output = f"### {args.get('username')} unlocked" return ( readable_output, {}, raw_response, # raw response - the original response ) def activate_user_command(client, args): user_id = client.get_user_id(args.get("username")) raw_response = client.activate_user(user_id) readable_output = f"### {args.get('username')} is active now" return (readable_output, {}, raw_response) def deactivate_user_command(client, args): user_id = client.get_user_id(args.get("username")) raw_response = client.deactivate_user(user_id) readable_output = f"### User {args.get('username')} deactivated" return ( readable_output, {}, raw_response, # raw response - the original response ) def set_password_command(client, args): user_id = client.get_user_id(args.get("username")) password = args.get("password") raw_response = client.set_password(user_id, password) readable_output = f"{args.get('username')} password was updated." return (readable_output, {}, raw_response) def force_password_change_command(client, args): user_id = client.get_user_id(args.get("username")) raw_response = client.force_password_change(user_id) readable_output = f"{args.get('username')} password was set to force change." return (readable_output, {}, raw_response) def read_password_state_command(client, args): user_id = client.get_user_id(args.get("username")) raw_response = client.read_password_state(user_id) readable_output = tableToMarkdown(f"Password state for {args.get('username')}", raw_response) return (readable_output, {}, raw_response) def add_user_to_group_command(client, args): group_id = args.get("groupId") user_id = args.get("userId") if (not (args.get("username") or user_id)) or (not (args.get("groupName") or group_id)): raise Exception("PingOne error: You must supply either 'Username' or 'userId and 'groupName' or 'groupId'.") if not user_id: user_id = client.get_user_id(args.get("username")) user_id_or_name = args.get("username") else: user_id_or_name = user_id if not group_id: group_id = client.get_group_id(args.get("groupName")) group_id_or_name = args.get("groupName") else: group_id_or_name = group_id raw_response = client.add_user_to_group(user_id, group_id) readable_output = f"User: {user_id_or_name} added to group: {group_id_or_name} successfully" return (readable_output, {}, raw_response) def remove_from_group_command(client, args): group_id = args.get("groupId") user_id = args.get("userId") if (not (args.get("username") or user_id)) or (not (args.get("groupName") or group_id)): raise Exception("PingOne error: You must supply either 'Username' or 'userId and 'groupName' or 'groupId'.") if not user_id: user_id = client.get_user_id(args.get("username")) user_id_or_name = args.get("username") else: user_id_or_name = user_id if not group_id: group_id = client.get_group_id(args.get("groupName")) group_id_or_name = args.get("groupName") else: group_id_or_name = group_id client.remove_user_from_group(user_id, group_id) readable_output = f"User: {user_id_or_name} was removed from group: {group_id_or_name} successfully" return (readable_output, {}, "") def get_groups_for_user_command(client, args): user_id = client.get_user_id(args.get("username")) raw_response = client.get_groups_for_user(user_id) groups = client.get_readable_group_membership(raw_response) context = createContext(groups, removeNull=True) outputs = {"PingOne.Account(val.ID && val.ID === obj.ID)": {"Group": context, "ID": args.get("username"), "Type": "PingOne"}} readable_output = f"PingOne groups for user: {args.get('username')}\n {tableToMarkdown('Groups', groups)}" return (readable_output, outputs, raw_response) def get_user_command(client, args): if args.get("userId"): user_id_or_name = args.get("userId") raw_response = client.get_user_by_id(args.get("userId")) elif args.get("username"): user_id_or_name = args.get("username") raw_response = client.get_user_by_username(args.get("username")) else: raise Exception("PingOne error: You must supply either 'Username' or 'userId") user_context = client.get_user_context(raw_response) user_readable = client.get_readable_user(raw_response) outputs = {"PingOne.Account(val.ID && val.ID === obj.ID)": createContext([user_context])} readable_output = f"{tableToMarkdown(f'User:{user_id_or_name}', [user_readable])} " return (readable_output, outputs, raw_response) def create_user_command(client, args): username = args.get("username") pop_id = args.get("populationId") raw_response = client.create_user(username, pop_id) user_context = client.get_user_context(raw_response) outputs = {"PingOne.Account(val.ID && val.ID === obj.ID)": createContext(user_context)} readable_output = tableToMarkdown(f"PingOne user created: {args.get('username')}", client.get_readable_user(raw_response)) return (readable_output, outputs, raw_response) def update_user_command(client, args): user_id = client.get_user_id(args.get("username")) attrs = Client.build_user_profile(args) raw_response = client.update_user(user_id, attrs) readable_output = tableToMarkdown(f"PingOne user updated: {args.get('username')}", attrs) return (readable_output, {}, raw_response) def delete_user_command(client, args): if not (args.get("username") or args.get("userId")): raise Exception("PingOne error: You must supply either 'Username' or 'userId") if args.get("username"): user = client.get_user_by_username(args.get("username")) user_id = user.get("id") # Output username when possible user_id_or_name = args.get("username") else: user_id = args.get("userId") user_id_or_name = user_id client.delete_user(user_id) readable_output = f"User: {user_id_or_name} was Deleted successfully" return (readable_output, {}, "") def main(): """ PARSE AND VALIDATE INTEGRATION PARAMS """ # get the service API URL params = demisto.params() environment_id = params.get("environment_id") region = params.get("region") tld = ".com" if region == "EU": tld = ".eu" elif region == "Asia": tld = ".asia" base_url = urljoin(f"https://api.pingone{tld}", f"/v1/environments/{environment_id}/") auth_url = urljoin(f"https://auth.pingone{tld}", f"/{environment_id}/as/token") client_id = demisto.params().get("credentials", {}).get("identifier") client_secret = demisto.params().get("credentials", {}).get("password") verify_certificate = not demisto.params().get("insecure", False) proxy = demisto.params().get("proxy", False) auth_params = { "client_id": client_id, "client_secret": client_secret, "base_url": base_url, "auth_url": auth_url, } demisto.debug(f"Command being called is {demisto.command()}") commands = { "test-module": test_module, "pingone-unlock-user": unlock_user_command, "pingone-deactivate-user": deactivate_user_command, "pingone-activate-user": activate_user_command, "pingone-set-password": set_password_command, "pingone-password-force-change": force_password_change_command, "pingone-read-password-state": read_password_state_command, "pingone-add-to-group": add_user_to_group_command, "pingone-remove-from-group": remove_from_group_command, "pingone-get-groups": get_groups_for_user_command, "pingone-get-user": get_user_command, "pingone-create-user": create_user_command, "pingone-update-user": update_user_command, "pingone-delete-user": delete_user_command, } command = demisto.command() client = Client(auth_params=auth_params, base_url=base_url, verify=verify_certificate, proxy=proxy) try: if command in commands: human_readable, outputs, raw_response = commands[command](client, demisto.args()) return_outputs(readable_output=human_readable, outputs=outputs, raw_response=raw_response) # Log exceptions except Exception as e: return_error(f"Failed to execute {command} command. Error: {str(e)}") if __name__ in ("__main__", "__builtin__", "builtins"): main()