Cisco ISE

Next-generation secure network access.

Network Security · Cisco ISE

Details

IDCisco ISE
ProviderCisco Systems
CategoryNetwork Security
From Version5.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Use the Cisco ISE integration to get endpoint data, and to manage and update endpoints and ANC policies.

 

Configure Cisco ISE on Cortex XSOAR

 

  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for Cisco ISE.
  3. Click Add instance to create and configure a new integration instance.
    • Name: a textual name for the integration instance.
    • Cisco ISE server URL (e.g., https://123.123.123.65 )
    • Server port (e.g., 9060)
    • Cisco ISE username
    • Use system proxy settings
    • Trust any certificate (not secure)
  4. Click Test to validate the URLs, token, and connection.

 

Commands

You can execute these commands from the Cortex XSOAR 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.

 

  1. Get an endpoint ID: cisco-ise-get-endpoint-id
  2. Get information for an endpoint: cisco-ise-get-endpoint-details
  3. Re-authenticate an endpoint: cisco-ise-reauthenticate-endpoint
  4. Get data for all existing endpoints: cisco-ise-get-endpoints
  5. Update custom attributes of an endpoint: cisco-ise-update-endpoint-custom-attribute
  6. Update the group of an endpoint: cisco-ise-update-endpoint-group
  7. Get a collection of endpoint identity groups: cisco-ise-get-groups
  8. Get all ANC policies: cisco-ise-get-policies
  9. Get a single ANC policy: cisco-ise-get-policy
  10. Create an ANC policy: cisco-ise-create-policy
  11. Assign an ANC policy to an endpoint: cisco-ise-assign-policy
  12. Get all endpoints on block list: cisco-ise-get-blacklist-endpoints

1. Get an endpoint ID


Returns an endpoint ID, by its MAC address.

Base Command

cisco-ise-get-endpoint-id

Input
Argument Name Description Required
macAddress MAC address of the endpoint (format: 11:22:33:44:55:66). Required

 

Context Output
Path Type Description
Endpoint.ID string Endpoint ID.
Endpoint.MACAddress string Endpoint MAC address.

 

Command Example
!cisco-ise-get-endpoint-id macAddress=00:0E:35:D4:D8:51
Human Readable Output

The endpoint ID is: 327b0120-4ba1-11e8-93bd-000c296ec148

2. Get information for an endpoint


Returns details for a specified endpoint.

Base Command

cisco-ise-get-endpoint-details

Input

 

Argument Name Description Required
endpointID The ID of the endpoint for which to return details. Optional
macAddress MAC address of the endpoint (format 11:22:33:44:55:66). Optional

 

Context Output

 

Path Type Description
CiscoISE.Endpoint.ID string Endpoint ID.
CiscoISE.Endpoint.Description string Endpoint description.
CiscoISE.Endpoint.MACAddress string Endpoint MAC address.
CiscoISE.Endpoint.Group string Endpoint group name
Endpoint.ID string Endpoint ID.
Endpoint.MACAddress string Endpoint MAC address.
CiscoISE.Endpoint.CustomAttributes string Endpoint custom attributes.
CiscoISE.Endpoint.StaticGroupAssignment boolean True if the endpoint has a static group assignment.
CiscoISE.Endpoint.StaticProfileAssignment boolean Whether the endpoint has a static profile assignment.
CiscoISE.Endpoint.User string Profile of the user associated with the endpoint.

 

Command Example

 

!cisco-ise-get-endpoint-details endpointID=327b0120-4ba1-11e8-93bd-000c296ec148

 

Context Example

 

{
    "CiscoISE.Endpoint": {
        "MACAddress": "00:0E:35:D4:D8:51",
        "Group": "Internal Dev",
        "ID": "327b0120-4ba1-11e8-93bd-000c296ec148",
        "StaticProfileAssignment": false,
        "StaticGroupAssignment": false
    },
    "Endpoint": {
        "MACAddress": "00:0E:35:D4:D8:51",
        "ID": "327b0120-4ba1-11e8-93bd-000c296ec148"
    }
}
Human Readable Output

Endpoint details - 327b0120-4ba1-11e8-93bd-000c296ec148

Group ID MACAddress StaticGroupAssignment StaticProfileAssignment
Internal Dev 327b0120-4ba1-11e8-93bd-000c296ec148 00:0E:35:D4:D8:51 false false

 

3. Re-authenticate an endpoint


Re-authenticates an endpoint (Change of Authorization - CoA).

Base Command

cisco-ise-reauthenticate-endpoint

Input
Argument Name Description Required
macAddress MAC address of the endpoint (format 11:22:33:44:55:66). Required

 

Context Output

 

Path Type Description
CiscoISE.Endpoint.MACAddress string MAC address of the endpoint.
CiscoISE.Endpoint.reauthenticateResult boolean Re-authentication result.

 

Command Example
!cisco-ise-reauthenticate-endpoint macAddress=00:0E:35:D4:D8:51
Human Readable Output

'Activation result was : True

4. Get data for all existing endpoints


Returns data for existing endpoints.

Base Command

cisco-ise-get-endpoints

Input

There are no arguments for this command.

Context Output
Path Type Description
Endpoint.ID string Endpoint ID.
Endpoint.MACAddress string Endpoint MAC address.
CiscoISE.Endpoint.ID string Endpoint ID.
CiscoISE.Endpoint.MACAddress string Endpoint MAC address.

 

Command Example
!cisco-ise-get-endpoints
Context Example
{
    "CiscoISE.Endpoint": [
        {
            "MACAddress": "00:0A:35:11:A9:00",
            "ID": "50080fc0-a07a-11e8-808e-000c295fdd32"
        },
        {
            "MACAddress": "00:0E:35:D4:D8:51",
            "ID": "327b0120-4ba1-11e8-93bd-000c296ec148"
        },
        {
            "MACAddress": "11:22:33:AA:BB:CC",
            "ID": "7d5e0530-133c-11e9-a5db-02420d3c5249"
        }
    ],
    "Endpoint": [
        {
            "MACAddress": "00:0A:35:11:A9:00",
            "ID": "50080fc0-a07a-11e8-808e-000c295fdd32"
        },
        {
            "MACAddress": "00:0E:35:D4:D8:51",
            "ID": "327b0120-4ba1-11e8-93bd-000c296ec148"
        },
        {
            "MACAddress": "11:22:33:AA:BB:CC",
            "ID": "7d5e0530-133c-11e9-a5db-02420d3c5249"
        }
    ]
}
Human Readable Output

Cisco ISE Endpoints

ID MACAddress
50080fc0-a07a-11e8-808e-000c295fdd32 00:0A:35:11:A9:00
327b0120-4ba1-11e8-93bd-000c296ec148 00:0E:35:D4:D8:51
7d5e0530-133c-11e9-a5db-02420d3c5249 11:22:33:AA:BB:CC

 

5. Update custom attributes of an endpoint


Updates the custom attributes of an endpoint.

Base Command

cisco-ise-update-endpoint-custom-attribute

Input

 

Argument Name Description Required
id Endpoint ID. Optional
macAddress MAC address of the endpoint (format 11:22:33:44:55:66). Optional
attributeName A CSV list of attributes, for example, "attributeName=firstAttribute,secondAttribute". Required
attributeValue A CSV list of attribute values, for example, "attributeValue=firstValue,secondValue". Required

 

Context Output

There is no context output for this command.

Command Example
!cisco-ise-update-endpoint-custom-attribute macAddress=00:0E:35:D4:D8:51 attributeName=mytest attributeValue=test1=testing
Human Readable Output

Successfully updated endpoint 327b0120-4ba1-11e8-93bd-000c296ec148, the new custom fields are: "{test1=testing}"

6. Update the group of an endpoint


Updates the group of an endpoint.

Base Command

cisco-ise-update-endpoint-group

Input
Argument Name Description Required
groupId The group ID to assign to this endpoint, e.g. 1 Optional
macAddress MAC address of the endpoint (format 11:22:33:44:55:66). Optional
id Endpoint ID of the endpoint to update. Optional
groupName Name of the group to update for the endpoint. Optional

 

Context Output

There is no context output for this command.

Command Example
!cisco-ise-update-endpoint-group groupName=Blacklist id=7d5e0530-133c-11e9-a5db-02420d3c5249
Human Readable Output

Endpoint 7d5e0530-133c-11e9-a5db-02420d3c5249 updated successfully

7. Get a collection of endpoint identity groups


Retrieves a collection of endpoint identity groups.

Base Command

cisco-ise-get-groups

Input

There are no arguments for this command.

Context Output
Path Type Description
CiscoISE.Group.Description String The description of the endpoint identity groups.
CiscoISE.Group.ID String The ID of the endpoint identity groups.
CiscoISE.Group.Name String The name of the endpoint identity groups.

 

Command Example
!cisco-ise-get-groups
Context Example
{
    "CiscoISE.Group": [
        {
            "Name": "Sony-Device",
            "Description": "Identity Group for Profile: Sony-Device",
            "ID": "38a73670-8c00-11e6-996c-525400b48521"
        },
        {
            "Name": "Cisco-Meraki-Device",
            "Description": "Identity Group for Profile: Cisco-Meraki-Device",
            "ID": "1e2700a0-8c00-11e6-996c-525400b48521"
        },
        {
            "Name": "Apple-iDevice",
            "Description": "Identity Group for Profile: Apple-iDevice",
            "ID": "0a4a50f0-8c00-11e6-996c-525400b48521"
        },
        {
            "Name": "BlackBerry",
            "Description": "Identity Group for Profile: BlackBerry",
            "ID": "0cc7ad00-8c00-11e6-996c-525400b48521"
        },
        {
            "Name": "Android",
            "Description": "Identity Group for Profile: Android",
            "ID": "ffa36b00-8bff-11e6-996c-525400b48521"
        },
        {
            "Name": "Axis-Device",
            "Description": "Identity Group for Profile: Axis-Device",
            "ID": "0c4eac70-8c00-11e6-996c-525400b48521"
        },
        {
            "Name": "Juniper-Device",
            "Description": "Identity Group for Profile: Juniper-Device",
            "ID": "2b07d100-8c00-11e6-996c-525400b48521"
        },
        {
            "Name": "Epson-Device",
            "Description": "Identity Group for Profile: Epson-Device",
            "ID": "22c6c780-8c00-11e6-996c-525400b48521"
        },
        {
            "Name": "Profiled",
            "Description": "Profiled Identity Group",
            "ID": "aa10ae00-8bff-11e6-996c-525400b48521"
        },
        {
            "Name": "Blacklist",
            "Description": "Blacklist Identity Group",
            "ID": "aa000c30-8bff-11e6-996c-525400b48521"
        },
        {
            "Name": "GuestEndpoints",
            "Description": "Guest Endpoints Identity Group",
            "ID": "aa178bd0-8bff-11e6-996c-525400b48521"
        },
        {
            "Name": "Synology-Device",
            "Description": "Identity Group for Profile: Synology-Device",
            "ID": "3a1b38d0-8c00-11e6-996c-525400b48521"
        },
        {
            "Name": "Vizio-Device",
            "Description": "Identity Group for Profile: Vizio-Device",
            "ID": "3b113190-8c00-11e6-996c-525400b48521"
        },
        {
            "Name": "Trendnet-Device",
            "Description": "Identity Group for Profile: Trendnet-Device",
            "ID": "3a88eec0-8c00-11e6-996c-525400b48521"
        },
        {
            "Name": "RegisteredDevices",
            "Description": "Asset Registered Endpoints Identity Group",
            "ID": "aa13bb40-8bff-11e6-996c-525400b48521"
        },
        {
            "Name": "Cisco-IP-Phone",
            "Description": "Identity Group for Profile: Cisco-IP-Phone",
            "ID": "14f5cac0-8c00-11e6-996c-525400b48521"
        },
        {
            "Name": "Unknown",
            "Description": "Unknown Identity Group",
            "ID": "aa0e8b20-8bff-11e6-996c-525400b48521"
        },
        {
            "Name": "Workstation",
            "Description": "Identity Group for Profile: Workstation",
            "ID": "3b76f840-8c00-11e6-996c-525400b48521"
        }
    ]
}
Human Readable Output

Cisco pxGrid ISE Groups

ID Name Description
38a73670-8c00-11e6-996c-525400b48521 Sony-Device Identity Group for Profile: Sony-Device
1e2700a0-8c00-11e6-996c-525400b48521 Cisco-Meraki-Device Identity Group for Profile: Cisco-Meraki-Device
0a4a50f0-8c00-11e6-996c-525400b48521 Apple-iDevice Identity Group for Profile: Apple-iDevice
0cc7ad00-8c00-11e6-996c-525400b48521 BlackBerry Identity Group for Profile: BlackBerry
ffa36b00-8bff-11e6-996c-525400b48521 Android Identity Group for Profile: Android
0c4eac70-8c00-11e6-996c-525400b48521 Axis-Device Identity Group for Profile: Axis-Device
2b07d100-8c00-11e6-996c-525400b48521 Juniper-Device Identity Group for Profile: Juniper-Device
22c6c780-8c00-11e6-996c-525400b48521 Epson-Device Identity Group for Profile: Epson-Device
aa10ae00-8bff-11e6-996c-525400b48521 Profiled Profiled Identity Group
aa000c30-8bff-11e6-996c-525400b48521 Blacklist Blacklist Identity Group
aa178bd0-8bff-11e6-996c-525400b48521 GuestEndpoints Guest Endpoints Identity Group
3a1b38d0-8c00-11e6-996c-525400b48521 Synology-Device Identity Group for Profile: Synology-Device
3b113190-8c00-11e6-996c-525400b48521 Vizio-Device Identity Group for Profile: Vizio-Device
3a88eec0-8c00-11e6-996c-525400b48521 Trendnet-Device Identity Group for Profile: Trendnet-Device
aa13bb40-8bff-11e6-996c-525400b48521 RegisteredDevices Asset Registered Endpoints Identity Group
14f5cac0-8c00-11e6-996c-525400b48521 Cisco-IP-Phone Identity Group for Profile: Cisco-IP-Phone
aa0e8b20-8bff-11e6-996c-525400b48521 Unknown Unknown Identity Group
3b76f840-8c00-11e6-996c-525400b48521 Workstation Identity Group for Profile: Workstation

 

8. Get all ANC policies


Returns all Adaptive Network Control policies.

Base Command

cisco-ise-get-policies

Input

There are no arguments for this command.

Context Output
Path Type Description
CiscoISE.Policy.Description String The description of the ANC policy.
CiscoISE.Policy.ID String The ID of the ANC policy.
CiscoISE.Policy.Name String The name of the ANC policy.

 

Command Example
!cisco-ise-get-policies
Context Example
{
    "CiscoISE.Policy": [
        {
            "ID": "ANCPortBounce",
            "Name": "ANCPortBounce"
        },
        {
            "ID": "ANCQuarantine",
            "Name": "ANCQuarantine"
        },
        {
            "ID": "ANCShutdown",
            "Name": "ANCShutdown"
        },
        {
            "ID": "azoce",
            "Name": "azoce"
        },
        {
            "ID": "dpkef",
            "Name": "dpkef"
        },
        {
            "ID": "dvgoy",
            "Name": "dvgoy"
        },
        {
            "ID": "gfibg",
            "Name": "gfibg"
        },
        {
            "ID": "jzbhh",
            "Name": "jzbhh"
        },
        {
            "ID": "last-test",
            "Name": "last-test"
        },
        {
            "ID": "ljnba",
            "Name": "ljnba"
        },
        {
            "ID": "mhxab",
            "Name": "mhxab"
        },
        {
            "ID": "mxiiw",
            "Name": "mxiiw"
        },
        {
            "ID": "ncxer",
            "Name": "ncxer"
        },
        {
            "ID": "phzbe",
            "Name": "phzbe"
        },
        {
            "ID": "pjrgp",
            "Name": "pjrgp"
        },
        {
            "ID": "policy0",
            "Name": "policy0"
        },
        {
            "ID": "policy09",
            "Name": "policy09"
        },
        {
            "ID": "policy1",
            "Name": "policy1"
        },
        {
            "ID": "policy2",
            "Name": "policy2"
        },
        {
            "ID": "policy3",
            "Name": "policy3"
        }
    ]
}
Human Readable Output

CiscoISE Adaptive Network Control Policies

ID Name
ANCPortBounce ANCPortBounce
ANCQuarantine ANCQuarantine
ANCShutdown ANCShutdown
azoce azoce
dpkef dpkef
dvgoy dvgoy
gfibg gfibg
jzbhh jzbhh
last-test last-test
ljnba ljnba
mhxab mhxab
mxiiw mxiiw
ncxer ncxer
phzbe phzbe
pjrgp pjrgp
policy0 policy0
policy09 policy09
policy1 policy1
policy2 policy2
policy3 policy3

 

9. Get a single ANC policy


Returns a single Adaptive Network Control policy.

Base Command

cisco-ise-get-policy

Input
Argument Name Description Required
policy_name The name of the ANC policy to return. Optional

 

Context Output

 

Path Type Description
CiscoISE.Policy.Action String The action of the policy. Can be "QUARANTINE", "PORTBOUNCE", or "SHUTDOWN".
CiscoISE.Policy.ID String The ID of the ANC policy.
CiscoISE.Policy.Link String The link for the ANC policy (GUI).
CiscoISE.Policy.Name String The name of the ANC policy.

 

Command Example
!cisco-ise-get-policy policy_name=policy3
Context Example
{
    "CiscoISE.Policy": [
        {
            "Action": [
                "QUARANTINE"
            ],
            "Name": "policy3"
        }
    ]
}
Human Readable Output

CiscoISE Policy

Action Name
QUARANTINE policy3

 

10. Create an ANC policy


Creates an ANC policy.

Base Command

cisco-ise-create-policy

Input
Argument Name Description Required
policy_actions The actions of the policy. Can be "QUARANTINE", "PORTBOUNCE", or "SHUTDOWN". Required
policy_name The name of the new adaptive network control policy. Required

 

Context Output
Path Type Description
CiscoISE.Policy.Action String The actions of the ANC policy.
CiscoISE.Policy.Name String The name of the new ANC policy.

 

Command Example
!cisco-ise-create-policy policy_name=quarantinePolicy policy_actions=QUARANTINE
Context Example
{
    "CiscoISE.Policy": {
        "Action": [
            "QUARANTINE"
        ],
        "Name": "quarantinePolicy"
    }
}
Human Readable Output

The policy "quarantinePolicy" has been created successfully

11. Assign an ANC policy to an endpoint


Assigns an Adapative Network Control policy to an endpoint.

Base Command

cisco-ise-assign-policy

Input
Argument Name Description Required
mac_address The MAC address to which to apply the policy. Required
policy_name The name of the policy to assign to the endpoint. Required

 

Context Output
Path Type Description
CiscoISE.Endpoint.MACAddress String The MAC address of the endpoint.
CiscoISE.Endpoint.PolicyName String The policy name that was applied to the endpoint.

 

Command Example
!cisco-ise-assign-policy mac_address=50080fc0-a07a-11e8-808e-000c295fdd32 policy_name=policy3
Human Readable Output

The policy "policy3" has been applied successfully

12. Get all endpoints on block list.


Returns all blacklisted endpoints.

Base Command

cisco-ise-get-blacklist-endpoints

Input

There are no arguments for this command.

Context Output
Path Type Description
CiscoISE.Endpoint.ID String The endpoint ID.
CiscoISE.Endpoint.Name String The name of the endpoint.
CiscoISE.Endpoint.Description String The endpoint description.
CiscoISE.Endpoint.Link String The link for the endpoint

 

Command Example
!cisco-ise-get-blacklist-endpoints
Context Example
{
    "CiscoISE.Endpoint": [
        {
            "GroupName": "Blacklist",
            "ID": "327b0120-4ba1-11e8-93bd-000c296ec148",
            "Name": "00:0E:35:D4:D8:51"
        }
    ]
}
Human Readable Output

CiscoISE Blacklist Endpoints

GroupName ID Name
Blacklist 327b0120-4ba1-11e8-93bd-000c296ec148 00:0E:35:D4:D8:51

cisco-ise-create-endpoint


Creates a new endpoint on Cisco ISE according to the passed MAC address and custom attribute list.

Base Command

cisco-ise-create-endpoint

Input

Argument Name Description Required
mac_address MAC address of the endpoint (format: 11:22:33:44:55:66). Required
attributes_map A list of custom attributes. Optional

Context Output

Path Type Description
CiscoISE.Endpoint.MACAddress string MAC address of the new endpoint.

cisco-ise-get-nodes


Returns data for all Cisco ISE nodes in the deployment.

Base Command

cisco-ise-get-nodes

Input

There are no input arguments for this command.

Context Output

Path Type Description
CiscoISE.NodesData unknown Details of all deployment ISE nodes.

cisco-ise-get-endpoint-id-by-name


Returns an EndpointID using its name (Available on ISE 2.3 and later versions).

Base Command

cisco-ise-get-endpoint-id-by-name

Input

Argument Name Description Required
mac_address MAC address of the endpoint (format: 11:22:33:44:55:66). Required

Context Output

Path Type Description
Endpoint.ID string Endpoint ID.
Endpoint.MACAddress string Endpoint MAC address.

cisco-ise-remove-policy


Removes an Adapative Network Control policy from an endpoint.

Base Command

cisco-ise-remove-policy

Input

Argument Name Description Required
mac_address The MAC address from which to remove the policy. Required
policy_name The name of the policy to remove from the endpoint. Required

Context Output

Path Type Description
CiscoISE.Endpoint.MACAddress string The MAC address of the endpoint.
CiscoISE.Endpoint.PolicyName string The policy name that was removed from the endpoint.

cisco-ise-get-session-data-by-ip


Queries an IP address and returns its session data from an active endpoint.

Base Command

cisco-ise-get-session-data-by-ip

Input

Argument Name Description Required
ip_address IP address to query in the ISE platform. Required

Context Output

There is no context output for this command.

Configuration parameters

  • serverURL — Cisco ISE server URL (e.g., https://123.123.123.65) (required)
  • serverPort — Server port (e.g., 9060)
  • credentials — Cisco ISE username (required)
  • proxy — Use system proxy settings
  • insecure — Trust any certificate (not secure)

Commands (17)

  • cisco-ise-assign-policy

    Assigns an Adapative Network Control policy to an endpoint.

  • cisco-ise-create-endpoint

    Creates a new endpoint on Cisco ISE according to the passed MAC address and custom attribute list.

  • cisco-ise-create-policy

    Creates an Adapative Network Control policy.

  • cisco-ise-get-blacklist-endpoints

    Returns all block listed endpoints.

  • cisco-ise-get-endpoint-details

    Returns details for a specified endpoint.

  • cisco-ise-get-endpoint-id

    Returns an endpoint ID, by its MAC address.

  • cisco-ise-get-endpoint-id-by-name

    Returns an EndpointID using its name (Available on ISE 2.3 and later versions).

  • cisco-ise-get-endpoints

    Returns data for existing endpoints.

  • cisco-ise-get-groups

    Retrieves a collection of endpoint identity groups.

  • cisco-ise-get-nodes

    Returns data for all Cisco ISE nodes in the deployment.

  • cisco-ise-get-policies

    Returns all Adaptive Network Control policies.

  • cisco-ise-get-policy

    Returns a single Adaptive Network Control policy.

  • cisco-ise-get-session-data-by-ip

    Queries an IP address and returns its session data from an active endpoint.

  • cisco-ise-reauthenticate-endpoint

    Re-authenticates an endpoint (Change of Authorization - CoA).

  • cisco-ise-remove-policy

    Removes an Adapative Network Control policy from an endpoint.

  • cisco-ise-update-endpoint-custom-attribute

    Updates the custom attributes of an endpoint.

  • cisco-ise-update-endpoint-group

    Updates the group of an endpoint.

import demistomock as demisto
from CommonServerPython import *
from CommonServerUserPython import *

""" IMPORTS """
import requests
from urllib.parse import urlparse
import urllib3

# disable insecure warnings
urllib3.disable_warnings()

""" GLOBAL VARS """

BASE_URL = re.sub(r"/+$", "", demisto.params().get("serverURL"))
SERVER_PORT = demisto.params().get("serverPort")
SERVER_URL = BASE_URL + ":" + SERVER_PORT
SERVER_ADMIN_URL = BASE_URL

USERNAME = demisto.params().get("credentials").get("identifier")
PASSWORD = demisto.params().get("credentials").get("password")

USE_SSL = not demisto.params().get("insecure", False)

DEFAULT_HEADERS = {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "Connection": "keep_alive",
}

DEFAULT_ADMIN_HEADERS = {
    "Content-Type": "application/json",
    "Accept": "application/xml",
    "Connection": "keep_alive",
}
""" HELPER FUNCTIONS """


def http_request(method, url_suffix, params=None, data=None, headers=None, is_admin_api=False):
    params = params if params is not None else {}
    if headers is None:
        headers = DEFAULT_ADMIN_HEADERS if is_admin_api else DEFAULT_HEADERS

    if is_admin_api:
        url = SERVER_ADMIN_URL + url_suffix
    else:
        url = SERVER_URL + url_suffix

    try:
        LOG(f"running {method} request with url={url}")

        response = requests.request(
            method, url, auth=(USERNAME, PASSWORD), headers=headers, verify=USE_SSL, params=params, data=data
        )
    except requests.exceptions.SSLError:
        err_msg = "Could not connect to Cisco ISE: Could not verify certificate."
        return_error(err_msg)
    except requests.exceptions.ConnectionError:
        err_msg = "Connection Error. Verify that the Server URL and port are correct, and that the port is open."
        return_error(err_msg)

    # handle request failure
    if response.status_code not in {200, 201, 202, 204}:
        message = parse_error_response(response)
        err_msg = f"Error in API call to Cisco ISE Integration [{response.status_code}] - {response.reason}, {message}"
        return_error(err_msg)

    if response.status_code in (201, 204):
        return None

    if is_admin_api:
        return response.content

    try:
        response = response.json()
    except ValueError:
        return_error(response.content)

    return response


def parse_error_response(response):
    try:
        res = response.json()
        msg = res.get("ERSResponse").get("messages")
        err = msg[0].get("title", "")
    except Exception:
        return response.text
    return err


def translate_group_id(group_id):
    """
    Translates group ID to group name
    """

    api_endpoint = f"/ers/config/identitygroup/{group_id}"
    identity_group = http_request("GET", api_endpoint)["IdentityGroup"]
    return identity_group["name"]


""" COMMANDS FUNCTIONS """


def get_groups_request():
    api_endpoint = "/ers/config/endpointgroup"
    return http_request("GET", api_endpoint)


def get_groups():
    """
    Retrieve a collection of endpoint identity groups.
    """

    groups_data: dict = get_groups_request().get("SearchResult", {})

    if groups_data.get("total", 0) < 1:
        return "No groups were found."

    groups = groups_data.get("resources", [])
    context = []
    humanreadable = []

    for group in groups:
        context_dict = {"ID": group.get("id"), "Name": group.get("name"), "Description": group.get("description")}
        hr_dict = dict(context_dict)
        context.append(context_dict)
        humanreadable.append(hr_dict)

    entry_context = {"CiscoISE.Group(val.ID === obj.ID)": context}

    return_outputs(
        tableToMarkdown("Cisco ISE Groups", humanreadable, ["ID", "Name", "Description"], removeNull=True),
        entry_context,
        groups_data,
    )
    return None


def get_endpoint_id(mac_address=None):
    """
    Returns endpoint id by specific mac address
    """

    api_endpoint = f"/ers/config/endpoint?filter=mac.EQ.{mac_address}" if mac_address is not None else ""
    return http_request("GET", api_endpoint, "")


def get_endpoint_id_command():
    """
    corresponds to 'cisco-ise-get-endpoint-id' command. Returns endpoint's id
    """
    mac_address = demisto.args().get("macAddress")

    if not is_mac_address(mac_address):
        return_error("Given MAC address is invalid")

    endpoint_data = get_endpoint_id(mac_address)

    resources = endpoint_data.get("SearchResult", {}).get("resources", [])
    if resources:
        endpoint_id = resources[0].get("id", None)
    else:
        endpoint_id = None

    entry_context = {"Endpoint(val.ID === obj.ID)": {"ID": endpoint_id, "MACAddress": mac_address}}

    return_outputs(f"The endpoint ID is: {endpoint_id}", entry_context, endpoint_id)


def get_endpoint_details(endpoint_id):
    """
    Gets endpoint details by specific id
    """

    api_endpoint = f"/ers/config/endpoint/{endpoint_id}"
    response = http_request("GET", api_endpoint)
    if response:
        return response
    else:
        return_error("Endpoint was not found.")
        return None


def get_endpoint_details_command():
    """
    corresponds to 'cisco-ise-get-endpoint-details' command. Returns information about a specific endpoint
    """

    endpoint_id = demisto.args().get("endpointID")
    endpoint_mac_address = demisto.args().get("macAddress")

    if endpoint_mac_address and not is_mac_address(endpoint_mac_address):
        return_error("Given MAC address is invalid")

    if not endpoint_id and not endpoint_mac_address:
        return_error("Either endpoint ID or MAC address should be provided")

    if endpoint_mac_address and not endpoint_id:
        resources = get_endpoint_id(endpoint_mac_address).get("SearchResult", {}).get("resources", [])
        if resources:
            endpoint_id = resources[0].get("id", None)

    endpoint_data = get_endpoint_details(endpoint_id)

    endpoint_details = endpoint_data.get("ERSEndPoint")

    if endpoint_details:
        custom_attributes = endpoint_details.get("customAttributes")
        if custom_attributes:
            custom_attributes = custom_attributes.get("customAttributes")
        portal_user = endpoint_details.get("portalUser")
        description = endpoint_details.get("description")
        group_name = translate_group_id(endpoint_details["groupId"])
        hr = {
            "ID": endpoint_details["id"],
            "MACAddress": endpoint_details["mac"],
            "Group": group_name,
            "CustomAttributes": custom_attributes,
            "StaticGroupAssignment": endpoint_details["staticGroupAssignment"],
            "StaticProfileAssignment": endpoint_details["staticProfileAssignment"],
        }
        detailed_ec = {
            "ID": endpoint_details["id"],
            "MACAddress": endpoint_details["mac"],
            "Group": group_name,
            "StaticGroupAssignment": endpoint_details["staticGroupAssignment"],
            "StaticProfileAssignment": endpoint_details["staticProfileAssignment"],
        }
        if custom_attributes:
            detailed_ec["CustomAttributes"] = {}
            for attribute in custom_attributes:
                detailed_ec["CustomAttributes"][attribute] = custom_attributes[attribute]
        if portal_user:
            hr["User"] = portal_user
            detailed_ec["User"] = portal_user
        if description:
            hr["Description"] = description
            detailed_ec["Description"] = description
        ec = {
            "Endpoint(val.ID === obj.ID)": {"ID": endpoint_details["id"], "MACAddress": endpoint_details["mac"]},
            "CiscoISE.Endpoint(val.ID === obj.ID)": detailed_ec,
        }

        title = "Endpoint details - " + (endpoint_id or endpoint_mac_address)
        return_outputs(tableToMarkdown(title, hr, removeNull=True), ec, endpoint_details)
    else:
        demisto.results("No results found")


def reauthenticate_endpoint(mac_address, psn_address):
    """
    Reauthenticates an endpoint
    """
    api_endpoint = f"/admin/API/mnt/CoA/Reauth/{psn_address}/{mac_address}/1"
    response = http_request("GET", api_endpoint)
    return response


def get_psn_for_mac(mac_address):
    """
    Retrieves psn for an endpoint
    """
    api_endpoint = f"/admin/API/mnt/AuthStatus/MACAddress/{mac_address}/86400/0/0"
    response = http_request("GET", api_endpoint)
    if response:
        return response
    else:
        return_error("Could not reauthenticate the endpoint")
        return None


def reauthenticate_endpoint_command():
    """
    corresponds to 'cisco-ise-reauthenticate-endpoint' command. Reauthenticates an endpoint
    """
    mac_address = demisto.args().get("macAddress").upper()
    if not is_mac_address(mac_address):
        return "Please enter a valid mac address"
    mac_address = mac_address.upper()
    mac_address_psn = get_psn_for_mac(mac_address)
    if not mac_address_psn:
        return "Couldn't find psn address for mac: " + mac_address
    psn_address = (
        json.loads(xml2json(mac_address_psn))
        .get("restAuthStatusOutputList", {})
        .get("authStatusList", {})
        .get("authStatusElements", {})[0]
        .get("acs_server")
    )
    if not psn_address:
        return (
            "Couldn't find psn address for mac: "
            + mac_address
            + " response from psn endpoint was: "
            + json.dumps(mac_address_psn)
        )
    activation_result = reauthenticate_endpoint(mac_address, psn_address).text
    json_activation_result = json.loads(xml2json(activation_result)).get("remoteCoA").get("results")
    activation_result_boolean = "true" in json_activation_result

    entry_context = {
        "CiscoISE.Endpoint(val.MACAddress==obj.MACAddress)": {
            "MACAddress": json_activation_result,
            "reauthenticateResult": activation_result_boolean,
        }
    }

    return_outputs("Activation result was : " + str(activation_result_boolean), entry_context, activation_result)
    return None


def get_endpoints():
    """
    Gets data about existing endpoints
    """

    api_endpoint = "/ers/config/endpoint"
    return http_request("GET", api_endpoint)


def get_endpoints_command(return_bool: bool = False):
    """
    corresponds to 'ise-get-endpoints' command. Get data about the existing endpoints
    """

    endpoints_data = get_endpoints().get("SearchResult", {})

    if endpoints_data.get("total", 0) < 1:
        return "No endpoints were found."

    endpoints = endpoints_data.get("resources", [])

    context = []
    hr = []

    for endpoint in endpoints:
        context_dict = {"ID": endpoint.get("id"), "MACAddress": endpoint.get("name")}
        hr_dict = dict(context_dict)
        context.append(context_dict)
        hr.append(hr_dict)
    if return_bool:
        return True
    entry_context = {"Endpoint(val.ID == obj.ID)": context, "CiscoISE.Endpoint(val.ID == obj.ID)": context}

    return_outputs(tableToMarkdown("Cisco ISE Endpoints", hr, ["ID", "MACAddress"], removeNull=True), entry_context, endpoints)
    return None


def update_endpoint_by_id(endpoint_id, endpoint_details):
    """
    Updates endpoint status
    """
    api_endpoint = f"/ers/config/endpoint/{endpoint_id}"
    response = http_request("PUT", api_endpoint, data=json.dumps(endpoint_details))
    return response


def update_endpoint_custom_attribute_command():
    """
    corresponds to 'cisco-ise-update-endpoint-custom-attribute' command.
    Blocks endpoint using predefined custom fields
    """

    endpoint_id = demisto.args().get("id")
    endpoint_mac_address = demisto.args().get("macAddress")

    if endpoint_mac_address and not is_mac_address(endpoint_mac_address):
        return_error("Please enter a valid mac address")

    if not endpoint_id and not endpoint_mac_address:
        return_error("Please enter either endpoint id or endpoint mac address")

    if endpoint_mac_address and not endpoint_id:
        endpoint_id = get_endpoint_id(endpoint_mac_address).get("SearchResult", {}).get("resources", [])[0].get("id", None)

    endpoint_details = get_endpoint_details(endpoint_id)

    if "ERSEndPoint" not in endpoint_details:
        return_error(f"Failed to get endpoint {endpoint_id}")

    attribute_names = demisto.args().get("attributeName").split(",")
    attribute_values = demisto.args().get("attributeValue").split(",")

    attributes_dic = {}
    for couple in zip(attribute_names, attribute_values):
        attributes_dic[couple[0]] = couple[1]
    try:
        del endpoint_details["ERSEndPoint"]["link"]
        if endpoint_details["ERSEndPoint"].get("customAttributes"):
            endpoint_details["ERSEndPoint"]["customAttributes"]["customAttributes"] = attributes_dic
        else:
            endpoint_details["ERSEndPoint"]["customAttributes"] = {"customAttributes": attributes_dic}

        update_result = update_endpoint_by_id(endpoint_id, endpoint_details)
        if not update_result:
            demisto.results(
                "Update failed for endpoint " + endpoint_id + ". Please check if the custom "
                "fields are defined in the system. "
                "Got the following response: " + update_result.get("ERSResponse", {}).get("messages", [])
            )

        updated_fields_dict_list = update_result.get("UpdatedFieldsList", {}).get("updatedField", [])

        if len(updated_fields_dict_list) > 0:
            updated_fields_string = " the new custom fields are: " + json.dumps(updated_fields_dict_list[0].get("newValue"))
        else:
            updated_fields_string = ", but the fields that you've tried to update already had that specific value or do not exist"
        demisto.results(f"Successfully updated endpoint {endpoint_id + updated_fields_string}")

    except Exception as e:
        raise Exception(f"Exception: Failed to update endpoint {endpoint_id}: " + str(e))


def update_endpoint_group_command():
    """
    corresponds to 'cisco-ise-update-endpoint-group' command. Updates endpoint status
    """

    endpoint_group_name = demisto.args().get("groupName")
    endpoint_group_id = demisto.args().get("groupId")
    if not endpoint_group_name and not endpoint_group_id:
        return_error("Please enter either group id or group name")

    if endpoint_group_name and not endpoint_group_id:
        endpoint_group_data = get_endpoint_id(endpoint_group_name).get("SearchResult", {})
        if endpoint_group_data.get("total", 0) < 1:
            return_error("No endpoints were found. Please make sure you entered the correct group name")
        else:
            endpoint_group_id = endpoint_group_data.get("resources")[0].get("id")

    endpoint_id = demisto.args().get("id")
    endpoint_mac_address = demisto.args().get("macAddress")

    if endpoint_mac_address and not is_mac_address(endpoint_mac_address):
        return_error("Please enter a valid mac address")

    if not endpoint_id and not endpoint_mac_address:
        return_error("Please enter either endpoint id or endpoint mac address")

    if endpoint_mac_address and not endpoint_id:
        endpoint_id = get_endpoint_id(endpoint_mac_address).get("SearchResult", {}).get("resources", [])[0].get("id", None)
    endpoint_details = get_endpoint_details(endpoint_id)

    if "ERSEndPoint" not in endpoint_details:
        return_error(f"Failed to get endpoint {endpoint_id}")

    try:
        updated_endpoint_details = {"ERSEndPoint": {}}  # type: Dict[str, Any]
        updated_endpoint_details["ERSEndPoint"]["groupId"] = endpoint_group_id
        updated_endpoint_details["ERSEndPoint"]["id"] = endpoint_details.get("ERSEndPoint", {}).get("id")
        updated_endpoint_details["ERSEndPoint"]["mac"] = endpoint_details.get("ERSEndPoint", {}).get("mac")
        updated_endpoint_details["ERSEndPoint"]["name"] = endpoint_details.get("ERSEndPoint", {}).get("name")

        update_result = update_endpoint_by_id(endpoint_id, updated_endpoint_details)
        if update_result:
            # Create result
            msg = "Endpoint " + endpoint_id + " updated successfully"
        else:
            msg = (
                "Update failed for endpoint "
                + endpoint_id
                + ", got the following response: "
                + update_result.get("ERSResponse", {}).get("messages", [])
            )

    except Exception as e:
        raise Exception(f"Exception: Failed to update endpoint {endpoint_id}: " + str(e))

    demisto.results(msg)


def list_number_of_active_sessions():
    """
    This function is used for test-module to check connectivity
    """
    api_endpoint = "/admin/API/mnt/Session/ActiveCount"

    response = http_request("GET", api_endpoint)

    return response


def get_policies_request():
    api_endpoint = "/ers/config/ancpolicy"

    response = http_request("GET", api_endpoint)

    return response


def get_policies():
    """
    Return all ANC policies
    """
    data = []

    policies_data = get_policies_request().get("SearchResult", {})

    if policies_data.get("total", 0) < 1:
        return "No policies were found."

    policies = policies_data.get("resources", [])

    for policy in policies:
        data.append({"ID": policy.get("id"), "Name": policy.get("name")})

    context = {"CiscoISE.Policy(val.ID && val.ID === obj.ID)": data}

    return_outputs(tableToMarkdown("CiscoISE Adaptive Network Control Policies", data, removeNull=True), context, policies_data)
    return None


def get_policy_by_name(policy_name):
    api_endpoint = f"/ers/config/ancpolicy/name/{policy_name}"

    response = http_request("GET", api_endpoint)
    return response


def get_policy():
    """
    Returns: the specific ANC policy
    """

    data = []
    policy_name = demisto.args().get("policy_name")

    if not policy_name:
        return_error("Please enter either policy name or policy id")

    policy_data = get_policy_by_name(policy_name).get("ErsAncPolicy", {}) if policy_name else None

    if policy_data:
        data.append({"Name": policy_data.get("name"), "Action": policy_data.get("actions")})

    context = {"CiscoISE.Policy(val.ID && val.ID === obj.ID)": data}

    return_outputs(tableToMarkdown("CiscoISE Policy", data, removeNull=True), context, policy_data)


def create_policy_request(data):
    api_endpoint = "/ers/config/ancpolicy"

    http_request("POST", api_endpoint, data=json.dumps(data))


def create_policy():
    """
    Create ANC Policy
    """
    policy_name = demisto.args().get("policy_name")
    policy_actions = demisto.args().get("policy_actions", "")

    data = {"ErsAncPolicy": {"name": policy_name, "actions": [policy_actions]}}
    create_policy_request(data)
    policy_context = {"Name": policy_name, "Action": [policy_actions]}

    context = {"CiscoISE.Policy(val.Name && val.Name === obj.Name)": policy_context}

    return_outputs(f'The policy "{policy_name}" has been created successfully', context)


def assign_policy_request(data):
    api_endpoint = "/ers/config/ancendpoint/apply"

    http_request("PUT", api_endpoint, data=json.dumps(data))


def assign_policy_to_endpoint():
    """
    Apply ANC policy to an endpoint
    """

    policy_name = demisto.args().get("policy_name")
    mac_address = demisto.args().get("mac_address")
    if not is_mac_address(mac_address):
        return_error("Please enter a valid mac address")

    data = {
        "OperationAdditionalData": {
            "additionalData": [{"name": "macAddress", "value": mac_address}, {"name": "policyName", "value": policy_name}]
        }
    }
    assign_policy_request(data)

    endpoint_context = {"MACAddress": mac_address, "PolicyName": policy_name}

    context = {"CiscoISE.Endpoint(val.ID && val.ID === obj.ID)": endpoint_context}

    return_outputs(f'The policy "{policy_name}" has been assigned successfully', context)


def remove_policy_request(data):
    api_endpoint = "/ers/config/ancendpoint/clear"

    http_request("PUT", api_endpoint, data=json.dumps(data))


def remove_policy_from_endpoint():
    """
    Remove ANC policy from an endpoint
    """

    policy_name = demisto.args().get("policy_name")
    mac_address = demisto.args().get("mac_address")
    if not is_mac_address(mac_address):
        return_error("Please enter a valid mac address")

    data = {
        "OperationAdditionalData": {
            "additionalData": [{"name": "macAddress", "value": mac_address}, {"name": "policyName", "value": policy_name}]
        }
    }
    remove_policy_request(data)

    endpoint_context = {"MACAddress": mac_address, "PolicyName": policy_name}

    context = {"CiscoISE.Endpoint(val.ID && val.ID === obj.ID)": endpoint_context}

    return_outputs(f'The policy "{policy_name}" has been removed successfully', context)


def get_blacklist_group_id():
    api_endpoint = "/ers/config/endpointgroup?filter=name.EQ.Blacklist"

    response = http_request("GET", api_endpoint)

    return response


def get_blacklist_endpoints_request():
    blacklist = get_blacklist_group_id().get("SearchResult", {})

    resources = blacklist.get("resources", [])
    blacklist_id = {}
    if resources:
        blacklist_id = resources[0]
    else:
        return_error("No blacklist endpoint were found.")

    black_id = blacklist_id.get("id")

    api_endpoint = f"/ers/config/endpoint?filter=groupId.EQ.{black_id}"
    blacklist_response = http_request("GET", api_endpoint)

    return blacklist_response


def get_blacklist_endpoints():
    data = []
    blacklist_endpoints = get_blacklist_endpoints_request().get("SearchResult", {})

    if blacklist_endpoints.get("total", 0) < 1:
        demisto.results("No endpoints were found.")

    endpoints = blacklist_endpoints.get("resources", [])

    for endpoint in endpoints:
        data.append({"ID": endpoint.get("id"), "Name": endpoint.get("name"), "GroupName": "Blacklist"})

    context = {"CiscoISE.Endpoint(val.ID && val.ID === obj.ID)": data}

    return_outputs(tableToMarkdown("CiscoISE Blacklist Endpoints", data, removeNull=True), context, endpoints)


def get_endpoint_id_by_name(mac_address=None):
    """
    Returns endpoint id by specific mac address
    Only compatible with Cisco ISE versions 2.3
    """
    if not is_mac_address(mac_address):
        return_error("Given MAC address is invalid")

    api_endpoint = f"/ers/config/endpoint/name/{mac_address}"
    return http_request("GET", api_endpoint, "")


def get_endpoint_id_by_name_command():
    mac_address = demisto.args().get("mac_address")

    if not is_mac_address(mac_address):
        return_error("Given MAC address is invalid")

    endpoint_data = get_endpoint_id_by_name(mac_address)
    endpoint_id = endpoint_data.get("ERSEndPoint", {}).get("id", None)

    entry_context = {"Endpoint(val.ID === obj.ID)": {"ID": endpoint_id, "MACAddress": mac_address}}

    return_outputs(f"The endpoint ID is: {endpoint_id}", entry_context, endpoint_id)


def get_node_details(name=None):
    """
    Returns details for the given Cisco ISE node
    """
    if not name:
        return_error("Given Cisco ISE node is invalid")

    api_endpoint = f"/ers/config/node/name/{name}"
    return http_request("GET", api_endpoint, "")


def get_all_nodes_command():
    """
    Returns all nodes in the Cisco ISE Deployment
    Also sets isLocalIstance in the output
    """

    instance_ip = urlparse(BASE_URL).netloc
    try:
        instance_ip = socket.gethostbyname(instance_ip)
    except Exception as e:
        err_msg = f"Failed to get ip address of configured Cisco ISE instance - {e}"
        raise Exception(err_msg)

    data = []
    api_endpoint = "/ers/config/node"
    response = http_request("GET", api_endpoint)
    results = response.get("SearchResult", {})

    if results.get("total", 0) < 1:
        demisto.results("No Nodes were found")

    node_data = results.get("resources", [])
    for node in node_data:
        is_local_istance = False
        name = node.get("name")
        node_details = get_node_details(name).get("Node", {})
        ip = node_details.get("ipAddress")
        if ip == instance_ip:
            is_local_istance = True

        data.append(
            {
                "Name": name,
                "ip": ip,
                "isLocalIstance": is_local_istance,
                # if false then standalone mode.. ie single node
                "inDeployment": node_details.get("inDeployment"),
                # primary means active node
                "primaryPapNode": node_details.get("primaryPapNode"),
            }
        )

    context = {"CiscoISE.NodesData": data}

    return_outputs(tableToMarkdown("CiscoISE deployment nodes", data, removeNull=True), context)


def create_new_endpoint_command():
    """
    Creates a new Endpoint in Cisco ISE with the given
    Mac address and Custom attributes
    """

    attr_map = demisto.args().get("attributes_map")
    mac_address = demisto.args().get("mac_address")
    if not is_mac_address(mac_address):
        return_error("Please enter a valid mac address")
    if attr_map is not None:
        attr_map = json.loads(attr_map)
    data = {"ERSEndPoint": {"mac": mac_address, "customAttributes": {"customAttributes": attr_map}}}

    api_endpoint = "/ers/config/endpoint"
    http_request("POST", api_endpoint, data=json.dumps(data))
    endpoint_context = {
        "MACAddress": mac_address,
    }

    context = {"CiscoISE.Endpoint(val.Name && val.Name === obj.Name)": endpoint_context}
    return_outputs(f'Endpoint "{mac_address}" has been created successfully', context)


def get_session_data_by_ip_request(ip):
    ip_address = f"/admin/API/mnt/Session/EndPointIPAddress/{ip}"
    response = http_request("GET", ip_address, is_admin_api=True)
    byte_conversion = str(response, "utf-8")
    json_data = xml2json(byte_conversion)
    session_data = json.loads(json_data)

    context = {"CiscoISE.Endpoint(val.ID && val.ID === obj.ID)": session_data}

    return_outputs("The targeted users session xml is being returned.", context)


def get_session_data_by_ip():
    """
    Returns: the session data given an ip address
    """
    ip = demisto.args().get("ip_address")
    if not ip:
        return_error("Please enter the ip")

    get_session_data_by_ip_request(ip)


""" EXECUTION CODE """


def main():
    LOG(f"Command being called is {demisto.command()}")
    try:
        handle_proxy()
        if demisto.command() == "test-module":
            if get_endpoints_command(True):
                demisto.results("ok")
            else:
                demisto.results("test failed")
        elif demisto.command() == "cisco-ise-get-endpoint-id":
            get_endpoint_id_command()
        elif demisto.command() == "cisco-ise-get-endpoint-details":
            get_endpoint_details_command()
        elif demisto.command() == "cisco-ise-reauthenticate-endpoint":
            reauthenticate_endpoint_command()
        elif demisto.command() == "cisco-ise-get-endpoints":
            get_endpoints_command()
        elif demisto.command() == "cisco-ise-update-endpoint-custom-attribute":
            update_endpoint_custom_attribute_command()
        elif demisto.command() == "cisco-ise-update-endpoint-group":
            update_endpoint_group_command()
        elif demisto.command() == "cisco-ise-get-groups":
            get_groups()
        elif demisto.command() == "cisco-ise-get-policies":
            get_policies()
        elif demisto.command() == "cisco-ise-get-policy":
            get_policy()
        elif demisto.command() == "cisco-ise-create-policy":
            create_policy()
        elif demisto.command() == "cisco-ise-assign-policy":
            assign_policy_to_endpoint()
        elif demisto.command() == "cisco-ise-remove-policy":
            remove_policy_from_endpoint()
        elif demisto.command() == "cisco-ise-get-blacklist-endpoints":
            get_blacklist_endpoints()
        elif demisto.command() == "cisco-ise-create-endpoint":
            create_new_endpoint_command()
        elif demisto.command() == "cisco-ise-get-nodes":
            get_all_nodes_command()
        elif demisto.command() == "cisco-ise-get-endpoint-id-by-name":
            get_endpoint_id_by_name_command()
        elif demisto.command() == "cisco-ise-get-session-data-by-ip":
            get_session_data_by_ip()

    except Exception as e:
        return_error(str(e))


# python2 uses __builtin__ python3 uses builtins
if __name__ == "__builtin__" or __name__ == "builtins":
    main()