KnowBe4KMSAT Deprecated

Deprecated. Use KnowBe4KMSAT instead.

Network Security · KMSAT (Deprecated)

Details

IDKnowBe4KMSAT
ProviderVista Equity Partners
CategoryNetwork Security
From Version6.5.0
Docker Imagedemisto/python3:3.10.10.48392
Supported ModulesAgentix

README

KnowBe4’s KMSAT Console is a security awareness training and simulated phishing console that you can use to improve your organization’s overall security. This integration pack allows you to push and pull your external data to and from your KMSAT console.

What Does This Pack Do?
1. Pull Risk Score history for your account
2. Pull Risk Score history for your groups
3. Pull Risk Score history for your users
4. Pull all Phishing Security Test (PST) results for your account
5. Pull Phishing Security Test (PST) results for a specific campaign
6. Pull statuses of your training campaigns
7. Pull a list of your users’ training campaign enrollments
8. Pull your users’ event data
9. Add events to User Timelines in KMSAT
10. Delete events from User Timelines in KMSAT

Configuration

Parameter Description Requirement
Instance Name Enter a name for your KMSAT instance. Required
Your Reporting Server URL Enter the Reporting Server URL for your KMSAT instance, which you can find in KnowBe4’s Reporting API documentation. Required
Reporting API Key Enter the Reporting API key to use for the connection. To generate this key, see KnowBe4’s Account Settings: API documentation. Required
Your User Events Server URL Enter the User Event URL for your KMSAT instance, which you can find in KnowBe4’s User Event API documentation. Required
User Events API Key Enter the User Event API key to use for the connection. To generate this key, see KnowBe4’s User Event API documentation. Required

Commands

Commands Description
kmsat-account-info-list Displays account information
kmsat-account-risk-score-history-list Displays your organization’s Risk Score history
kmsat-groups-list Displays all groups
kmsat-groups-risk-score-history-list Displays Risk Score history for groups
kmsat-groups-members-list Displays members of groups
kmsat-users-risk-score-history-list Displays Risk Score history for users
kmsat-phishing-security-tests-list Displays all PSTs
kmsat-phishing-security-tests-recipients-list Displays PSTs and user data for enrolled users
kmsat-phishing-security-tests-failed-recipients-list Displays failed PSTs and user data for enrolled users
kmsat-phishing-campaign-security-tests-list Displays PSTs for a phishing campaign
kmsat-training-campaigns-list Displays all training campaigns
kmsat-training-enrollments-list Displays all training enrollments
kmsat-user-event-list Displays a user event by id
kmsat-user-events-list Displays all user events
kmsat-user-event-types-list Displays types of user events
kmsat-user-event-create Creates an event on the User Timeline
kmsat-user-event-delete Deletes an event from the User Timeline
kmsat-user-event-status-list Lists the status of user event request by request id
kmsat-user-event-statuses-list Lists the statuses of user event requests

kmsat-account-info-list

Context Output

Path Type Description
KMSAT.AccountInfo.name String Account name
KMSAT.AccountInfo.type String Account type
KMSAT.AccountInfo.domains String Account domains
KMSAT.AccountInfo.admins.id Number Account admin ID
KMSAT.AccountInfo.admins.first_name String Account admin first name
KMSAT.AccountInfo.admins.last_name String Account admin last name
KMSAT.AccountInfo.admins.email String Account admin email address
KMSAT.AccountInfo.subscription_email String Account subscription level
KMSAT.AccountInfo.subscription_end_date Date Account subscription end date
KMSAT.AccountInfo.number_of_seats Number Number of account seats
KMSAT.AccountInfo.current_risk_score Number Account Risk Score

Command Example

kmsat-account-risk-score-history

Argument Name Description Required
page Page Number No
per_page Per Page Amount No

Context Output

Path Type Description
KMSAT.AccountRiskScoreHistory.risk_score String Account Risk Score and associated date
KMSAT.AccountRiskScoreHistory.date Date Account Risk Score history date

Command Example

!kmsat-account-risk-score-history-list page=1 per_page=25

Context Example


{
  "risk_score": 37.3,
  "date": "2021-02-07"
}

kmsat-groups-list

kmsat-account-risk-score-history

Argument Name Description Requirement
page Page Number Optional
per_page Per Page Amount Optional

Context Output

Path Type Description
KMSAT.Groups.id Number Group ID
KMSAT.Groups.name String Group name
KMSAT.Groups.group_type String Group type
KMSAT.Groups.provisioning_guid String Group provisioning GUID
KMSAT.Groups.member_count Number Group member count
KMSAT.Groups.current_risk_score Number Group’s current Risk Score
KMSAT.Groups.status String Groups status

Command Example

!kmsat-groups-list page=1 per_page=25

Context Example


{
  "id": 3142,
  "name": "Customer Service",
  "group_type": "console_group",
  "provisioning_guid": "abc12345-6789-abc-1234-456789abc123",
  "member_count": 42,
  "current_risk_score": 45.742,
  "status": "active"
}

kmsat-groups-risk-score-history

Argument Name Description Requirement
group_id Group ID Optional
page Page number Optional
per_page Amount per page Optional

Context Output

Path Type Description
KMSAT.GroupRiskScoreHistory.risk_score String Group Risk Score And associated date
KMSAT.GroupRiskHistory.date Date Group Risk Score history date

Command Example

!kmsat-groups-risk-score-history-list page=1 per_page=25

Context Example


{
  "risk_score": 37.3,
  "date": "2021-02-07"
}

kmsat-groups-members

Argument Name Description Requirement
group_id Group ID Required
page Page Number Optional
per_page Per Page Amount Optional

Context Output

Path Type Description
KMSAT.GroupsMembers.id Number User’s ID
KMSAT.GroupsMembers.employee_number String User’s employee number
KMSAT.GroupsMembers.first_name String User’s first name
KMSAT.GroupsMembers.last_name String User’s last name
KMSAT.GroupsMembers.job_title String User’s job title
KMSAT.GroupsMembers.email String User’s email address
KMSAT.GroupsMembers.phish_prone_percentage Number User’s Phish-prone Percentage
KMSAT.GroupsMembers.phone_number String User’s phone number
KMSAT.GroupsMembers.extension String User’s extension
KMSAT.GroupsMembers.mobile_phone_number String User’s phone number
KMSAT.GroupsMembers.location String User’s location
KMSAT.GroupsMembers.division String User’s division
KMSAT.GroupsMembers.manager_name String Name of user’s manager
KMSAT.GroupsMembers.provisioning_managed Boolean Email address of user’s manager
KMSAT.GroupsMembers.provisioning_guid Unknown User’s provisioning GUID
KMSAT.GroupsMembers.groups Number User’s groups
KMSAT.GroupsMembers.current_risk_score Number User’s current Risk Score
KMSAT.GroupsMembers.aliases String User’s aliases
KMSAT.GroupsMembers.joined_on Date User created at
KMSAT.GroupsMembers.last_sign_in Date User’s last login
KMSAT.GroupsMembers.status String User’s status
KMSAT.GroupsMembers.organization String User’s organization
KMSAT.GroupsMembers.department String User’s department
KMSAT.GroupsMembers.language String User’s language
KMSAT.GroupsMembers.comment String User comment
KMSAT.GroupsMembers.employee_start_date Date User’s employee start date
KMSAT.GroupsMembers.archived_at Date User archived at
KMSAT.GroupsMembers.custom_field_1 String User custom field 1
KMSAT.GroupsMembers.custom_field_2 String User custom field 2
KMSAT.GroupsMembers.custom_field_3 String User custom field 3
KMSAT.GroupsMembers.custom_date_1 Date User custom date 1
KMSAT.GroupsMembers.custom_date_2 Date User custom date 2

Command Example

!kmsat-groups-members-list group_id=1 page=1 per_page=25

Context Example


{
  "id": 667542,
  "employee_number": "19425",
  "first_name": "William",
  "last_name": "Marcoux",
  "job_title": "VP of Sales",
  "email": "example2@kb4-demo.com",
  "phish_prone_percentage": 14.235,
  "phone_number": "555-554-2222",
  "extension": "42",
  "mobile_phone_number": "555-553-4422",
  "location": "Office A",
  "division": "Sales",
  "manager_name": "Michael Scott",
  "manager_email": "example3@kb4-demo.com",
  "provisioning_managed": false,
  "provisioning_guid": null,
  "groups": [
    3264
  ],
  "current_risk_score": 45.742,
  "aliases": [
    "alias_email@kb4-demo.com"
  ],
  "joined_on": "2019-04-02T15:02:38.000Z",
  "last_sign_in": "2019-04-02T15:02:38.000Z",
  "status": "active",
  "organization": "KB4-Demo",
  "department": "Sales",
  "language": "English - United States",
  "comment": "Low PPP",
  "employee_start_date": "2019-04-02T15:02:38.000Z",
  "archived_at": null,
  "custom_field_1": "Building C, 4th Floor",
  "custom_field_2": null,
  "custom_field_3": null,
  "custom_field_4": null,
  "custom_date_1": "1986-11-26",
  "custom_date_2": null
}

kmsat-users-risk-score-history

Argument Name Description Requirement
user_id User ID Required
page Page number Optional
per_page Amount per page Optional

Context Output

Path Type Description
KMSAT.UsersRiskHistory.risk_score Number User’s Risk Score and associated date
KMSAT.UsersRiskHistory.date Date User’s Risk Score history date

Command Example

!kmsat-users-risk-score-history-list user_id=1 page=1 per_page=25

Context Example


{
  "risk_score": 37.3,
  "date": "2021-02-07"
}

kmsat-phishing-security-tests

Argument Name Description Requirement
page Page number Optional
per_page Amount per page Optional

Context Output

Path Type Description
KMSAT.PhishingSecurity.campaign_id Number Phishing campaign ID
KMSAT.PhishingSecurity.pst_id Number PST ID
KMSAT.PhishingSecurity.status String PST status
KMSAT.PhishingSecurity.name String PST name
KMSAT.PhishingSecurity.groups.group_id Number PST group ID
KMSAT.PhishingSecurity.groups.name String PST group name
KMSAT.PhishingSecurity.phish_prone_percentage Number PST Phish-prone Percentage
KMSAT.PhishingSecurity.started_at Date PST started date
KMSAT.PhishingSecurity.duration Number PST duration
KMSAT.PhishingSecurity.categories.category_id Number PST category ID
KMSAT.PhishingSecurity.categories.name String PST category name
KMSAT.PhishingSecurity.template.id Number PST template ID
KMSAT.PhishingSecurity.template.name String PST template Name
KMSAT.PhishingSecurity.lading_page.id Number PST landing page ID
KMSAT.PhishingSecurity.landing_page.name String PST landing page name
KMSAT.PhishingSecurity.scheduled_count Number PST scheduled count
KMSAT.PhishingSecurity.delivered_count Number PST delivered count
KMSAT.PhishingSecurity.opened_count Number PST opened count
KMSAT.PhishingSecurity.clicked_count Number PST clicked count
KMSAT.PhishingSecurity.replied_count Number PST replied count
KMSAT.PhishingSecurity.attachment_open_count Number PST attachment opened count
KMSAT.PhishingSecurity.macro_enabled_count Number PST macro enabled count
KMSAT.PhishingSecurity.data_entered_count Number PST data entered count
KMSAT.PhishingSecurity.qr_code_scanned_count Number PST QR Code scanned count
KMSAT.PhishingSecurity.reported_count Number PST reported count
KMSAT.PhishingSecurity.bounced_count Number PST bounced count

Command Example

!kmsat-phishing-security-tests-list page=1 per_page=25

Context Example


[
  {
    "campaign_id": 3423,
    "pst_id": 16142,
    "status": "Closed",
    "name": "Corporate Test",
    "groups": [
      {
        "group_id": 16342,
        "name": "Corporate Employees"
      }
    ],
    "phish_prone_percentage": 0.5,
    "started_at": "2019-04-02T15:02:38.000Z",
    "duration": 1,
    "categories": [
      {
        "category_id": 4237,
        "name": "Current Events"
      }
    ],
    "template": {
      "id": 11428,
      "name": "CNN Breaking News"
    },
    "landing_page": {
      "id": 1842,
      "name": "SEI Landing Page"
    },
    "scheduled_count": 42,
    "delivered_count": 4,
    "opened_count": 24,
    "clicked_count": 20,
    "replied_count": 0,
    "attachment_open_count": 3,
    "macro_enabled_count": 0,
    "data_entered_count": 0,
    "qr_code_scanned_count": 0,
    "reported_count": 0,
    "bounced_count": 0
  }
]

kmsat-phishing-security-tests-recipients

Argument Name Description Requirement
pst_id PST ID Required
page Page number Optional
per_page Amount per page Optional

Context Output

Path Type Description
KMSAT.PhishingSecurityPST.recipient_id Number PST recipient ID
KMSAT.PhishingSecurityPST.pst_id Number PST ID
KMSAT.PhishingSecurityPST.user String PST user
KMSAT.PhishingSecurityPST.template String PST template
KMSAT.PhishingSecurityPST.scheduled_at Date PST scheduled at
KMSAT.PhishingSecurityPST.delivered_at Date PST delivered at
KMSAT.PhishingSecurityPST.opened_at Date PST opened at
KMSAT.PhishingSecurityPST.clicked_at Date PST clicked at
KMSAT.PhishingSecurityPST.replied_at Date PST replied at
KMSAT.PhishingSecurityPST.attachment_opened_at Date PST attachment opened at
KMSAT.PhishingSecurityPST.macro_enabled_at Date PST macro enabled at
KMSAT.PhishingSecurityPST.data_entered_at Date PST data entered at
KMSAT.PhishingSecurityPST.qr_code_scanned Date PST QR code scanned at
KMSAT.PhishingSecurityPST.reported_at Date PST reported at
KMSAT.PhishingSecurityPST.bounced_at Date PST bounced at
KMSAT.PhishingSecurityPST.ip String PST IP address
KMSAT.PhishingSecurityPST.up_location String PST IP address location
KMSAT.PhishingSecurityPST.browser String PST browser
KMSAT.PhishingSecurityPST.browser_version String PST browser version
KMSAT.PhishingSecurityPST.os String PST operating system

Command Example

!kmsat-phishing-security-tests-recipients-list pst_id=1 page=1 per_page=25

Context Example


[
  {
    "recipient_id": 3077742,
    "pst_id": 14240,
    "user": {
      "id": 264215,
      "provisioning_guid": null,
      "first_name": "Bob",
      "last_name": "Ross",
      "email": "example4@kb4-demo.com"
    },
    "template": {
      "id": 2,
      "name": "Your Amazon Order"
    },
    "scheduled_at": "2019-04-02T15:02:38.000Z",
    "delivered_at": "2019-04-02T15:02:38.000Z",
    "opened_at": "2019-04-02T15:02:38.000Z",
    "clicked_at": "2019-04-02T15:02:38.000Z",
    "replied_at": null,
    "attachment_opened_at": null,
    "macro_enabled_at": null,
    "data_entered_at": "2019-04-02T15:02:38.000Z",
    "qr_code_scanned": "2022-05-12T15:29:54.000Z",
    "reported_at": null,
    "bounced_at": null,
    "ip": "XX.XX.XXX.XXX",
    "ip_location": "St.Petersburg, FL",
    "browser": "Chrome",
    "browser_version": "48.0",
    "os": "MacOSX"
  }
]

kmsat-phishing-security-tests-failed-recipients

Argument Name Description Requirement
pst_id PST ID Required

Context Output

Path Type Description
KMSAT.PhishingSecurityPST.recipient_id Number PST recipient ID
KMSAT.PhishingSecurityPST.pst_id Number PST ID
KMSAT.PhishingSecurityPST.user String PST user
KMSAT.PhishingSecurityPST.template String PST template
KMSAT.PhishingSecurityPST.scheduled_at Date PST scheduled at
KMSAT.PhishingSecurityPST.delivered_at Date PST delivered at
KMSAT.PhishingSecurityPST.opened_at Date PST opened at
KMSAT.PhishingSecurityPST.clicked_at Date PST clicked at
KMSAT.PhishingSecurityPST.replied_at Date PST replied at
KMSAT.PhishingSecurityPST.attachment_opened_at Date PST attachment opened at
KMSAT.PhishingSecurityPST.macro_enabled_at Date PST macro enabled at
KMSAT.PhishingSecurityPST.data_entered_at Date PST data entered at
KMSAT.PhishingSecurityPST.qr_code_scanned Date PST QR code scanned at
KMSAT.PhishingSecurityPST.reported_at Date PST reported at
KMSAT.PhishingSecurityPST.bounced_at Date PST bounced at
KMSAT.PhishingSecurityPST.ip String PST IP address
KMSAT.PhishingSecurityPST.up_location String PST IP address location
KMSAT.PhishingSecurityPST.browser String PST browser
KMSAT.PhishingSecurityPST.browser_version String PST browser version
KMSAT.PhishingSecurityPST.os String PST operating system

Command Example

!kmsat-phishing-security-tests-failed-recipients-list pst_id=1

Context Example


[
  {
    "recipient_id": 3077742,
    "pst_id": 14240,
    "user": {
      "id": 264215,
      "provisioning_guid": null,
      "first_name": "Bob",
      "last_name": "Ross",
      "email": "example4@kb4-demo.com"
    },
    "template": {
      "id": 2,
      "name": "Your Amazon Order"
    },
    "scheduled_at": "2019-04-02T15:02:38.000Z",
    "delivered_at": "2019-04-02T15:02:38.000Z",
    "opened_at": "2019-04-02T15:02:38.000Z",
    "clicked_at": "2019-04-02T15:02:38.000Z",
    "replied_at": null,
    "attachment_opened_at": null,
    "macro_enabled_at": null,
    "data_entered_at": "2019-04-02T15:02:38.000Z",
    "qr_code_scanned": "2022-05-12T15:29:54.000Z",
    "reported_at": null,
    "bounced_at": null,
    "ip": "XX.XX.XXX.XXX",
    "ip_location": "St.Petersburg, FL",
    "browser": "Chrome",
    "browser_version": "48.0",
    "os": "MacOSX"
  }
]

kmsat-phishing-campaign-security-tests

Argument Name Description Requirement
campaign_id Campaign ID Required
page Page number Optional
per_page Amount per page Optional

Context Output

Path Type Description
KMSAT.CampaignPST.campaign_id Number Phishing campaign ID
KMSAT.CampaignPST.pst_id Number PST ID
KMSAT.CampaignPST.status String PST status
KMSAT.CampaignPST.name String PST name
KMSAT.CampaignPST.groups.group_id Number PST group ID
KMSAT.CampaignPST.groups.name String PST group name
KMSAT.CampaignPST.phish_prone_percentage Number PST Phish-prone Percentage
KMSAT.CampaignPST.started_at Date PST started at
KMSAT.CampaignPST.duration Number PST duration
KMSAT.CampaignPST.categories.category_id Number PST category ID
KMSAT.CampaignPST.categories.name String PST category name
KMSAT.CampaignPST.template.id Number PST template ID
KMSAT.CampaignPST.template.name String PST template name
KMSAT.CampaignPST.landing_page.id Number PST landing page ID
KMSAT.CampaignPST.landing_page.name String PST landing page name
KMSAT.CampaignPST.scheduled_count Number PST scheduled count
KMSAT.CampaignPST.delivered_count Number PST delivered count
KMSAT.CampaignPST.opened_count Number PST opened count
KMSAT.CampaignPST.clicked_count Number PST clicked count
KMSAT.CampaignPST.replied_count Number PST replied count
KMSAT.CampaignPST.attachment_open_count Number PST attachment opened count
KMSAT.CampaignPST.macro_enabled_count Number PST macro enabled count
KMSAT.CampaignPST.data_entered_count Number PST data entered count
KMSAT.CampaignPST.qr_code_scanned_count Number PST QR code scanned count
KMSAT.CampaignPST.reported_count Number PST reported count
KMSAT.CampaignPST.bounced_count Number PST bounced count

Command Example

!kmsat-phishing-campaign-security-tests-list campaign_id=1 page=1 per_page=25

Context Example


[
  {
    "campaign_id": 3423,
    "pst_id": 16142,
    "status": "Closed",
    "name": "Corporate Test",
    "groups": [
      {
        "group_id": 16342,
        "name": "Corporate Employees"
      }
    ],
    "phish_prone_percentage": 0.5,
    "started_at": "2019-04-02T15:02:38.000Z",
    "duration": 1,
    "categories": [
      {
        "category_id": 4237,
        "name": "Current Events"
      }
    ],
    "template": {
      "id": 11428,
      "name": "CNN Breaking News"
    },
    "landing_page": {
      "id": 1842,
      "name": "SEI Landing Page"
    },
    "scheduled_count": 42,
    "delivered_count": 4,
    "opened_count": 24,
    "clicked_count": 20,
    "replied_count": 0,
    "attachment_open_count": 3,
    "macro_enabled_count": 0,
    "data_entered_count": 0,
    "qr_code_scanned_count": 0,
    "reported_count": 0,
    "bounced_count": 0
  }
]

kmsat-training-campaigns

Argument Name Description Requireent
page Page Number Optional
per_page Per Page Amount Optional

Context Output

Path Type Description
KMSAT.TrainingCampaigns.campaign_id Number Training campaign ID
KMSAT.TrainingCampaigns.name String Training campaign name
KMSAT.TrainingCampaigns.groups.group_id Number Training campaign group ID
KMSAT.TrainingCampaigns.groups.name String Training campaign group name
KMSAT.TrainingCampaigns.status String Training campaign Status
KMSAT.TrainingCampaigns.content.store_purchase_id Number Training campaign content store purchase ID
KMSAT.TrainingCampaigns.content.content_type String Training campaign content type
KMSAT.TrainingCampaigns.content.name String Training campaign content name
KMSAT.TrainingCampaigns.content.description String Training campaign content description
KMSAT.TrainingCampaigns.content.type String Training campaign content type
KMSAT.TrainingCampaigns.content.duration Number Training campaign content duration
KMSAT.TrainingCampaigns.content.retired Boolean Training campaign content retired
KMSAT.TrainingCampaigns.content.retirement_date Date Training campaign content retirement date
KMSAT.TrainingCampaigns.content.publish_date Date Training campaign content publish date
KMSAT.TrainingCampaigns.content.publisher String Training campaign content publisher
KMSAT.TrainingCampaigns.content.purchase_date Date Training campaign content purchase date
KMSAT.TrainingCampaigns.content.policy_url String Training campaign content policy URL
KMSAT.TrainingCampaigns.content.policy_id Number Training campaign content policy ID
KMSAT.TrainingCampaigns.content.minimum_time Number Training campaign content minimum time
KMSAT.TrainingCampaigns.content.default_language String Training campaign content default language
KMSAT.TrainingCampaigns.content.published Boolean Training campaign content published
KMSAT.TrainingCampaigns.duration_type String Training campaign duration type
KMSAT.TrainingCampaigns.start_date Date Training campaign start date
KMSAT.TrainingCampaigns.end_date Date Training campaign end date
KMSAT.TrainingCampaigns.relative_duration String Training campaign relative duration
KMSAT.TrainingCampaigns.auto_enroll Boolean Training campaign auto enrolls
KMSAT.TrainingCampaigns.allow_multiple_enrollments Boolean Training campaign allows multiple enrollments
KMSAT.TrainingCampaigns.completion_percentage Number Training campaign completion percentage

Command Example

!kmsat-training-campaigns-list campaign_id=1 page=1 per_page=25

Context Example


{
  "campaign_id": 4261,
  "name": "Annual Training",
  "groups": [
    {
      "group_id": 0,
      "name": "All Users"
    }
  ],
  "status": "Completed",
  "content": [
    [
      {
        "store_purchase_id": 7,
        "content_type": "Store Purchase",
        "name": "2019 Security Awareness Training",
        "description": "A comprehensive overview of best practices...",
        "type": "Training Module",
        "duration": 42,
        "retired": false,
        "retirement_date": null,
        "publish_date": "2019-04-02T15:02:38.000Z",
        "publisher": "KnowBe4",
        "purchase_date": "2019-04-02T15:02:38.000Z",
        "policy_url": "https://www.yourcompany.com/employees/acceptableusepolicy.html"
      },
      {
        "policy_id": 142,
        "content_type": "Uploaded Policy",
        "name": "Security Awareness Policy",
        "minimum_time": 3,
        "default_language": "en-us",
        "published": true
      }
    ]
  ],
  "duration_type": "Specific End Date",
  "start_date": "2019-04-02T15:02:38.000Z",
  "end_date": "2019-04-02T15:02:38.000Z",
  "relative_duration": "string",
  "auto_enroll": true,
  "allow_multiple_enrollments": false,
  "completion_percentage": 0
}

kmsat-training-enrollments

Argument Name Description Requirement
status Status Optional
page Page number Optional
per_page Amount per page Optional

Context Output

Path Type Description
KMSAT.TrainingEnrollments.enrollment_id Number Training enrollment ID
KMSAT.TrainingEnrollments.content_type String Training enrollment content type
KMSAT.TrainingEnrollments.module_name String Training enrollment module name
KMSAT.TrainingEnrollments.user.id Number Training enrollment user ID
KMSAT.TrainingEnrollments.user.first_name String Training enrollment user’s first name
KMSAT.TrainingEnrollments.user.last_name String Training enrollment user’s last name
KMSAT.TrainingEnrollments.user.email String Training enrollment user’s email address
KMSAT.TrainingEnrollments.campaign_name String Training enrollment campaign name
KMSAT.TrainingEnrollments.enrollment_date Date Training enrollment date
KMSAT.TrainingEnrollments.start_date Date Training enrollment start date
KMSAT.TrainingEnrollments.completion_date Date Training enrollment completion date
KMSAT.TrainingEnrollments.status String Training enrollment status
KMSAT.TrainingEnrollments.time_spent Number Training enrollment time spent
KMSAT.TrainingEnrollments.policy_acknowledged Boolean Training enrollment policy acknowledged

Command Example

!kmsat-training-enrollments-list status="Completed" page=1 per_page=25

Context Example


{
  "enrollment_id": 1425526,
  "content_type": "Uploaded Policy",
  "module_name": "Acceptable Use Policy",
  "user": {
    "id": 796742,
    "first_name": "Sarah",
    "last_name": "Thomas",
    "email": "example1@kb4-demo.com"
  },
  "campaign_name": "New Employee Policies",
  "enrollment_date": "2019-04-02T15:02:38.000Z",
  "start_date": "2019-04-02T15:02:38.000Z",
  "completion_date": "2019-04-02T15:02:38.000Z",
  "status": "Passed",
  "time_spent": 2340,
  "policy_acknowledged": false
}

kmsat-user-event-list

Argument Name Type Requirement
event_type String Optional
target_user String Optional
external_id String Optional
source string Optional
occurred_date String Optional
risk_level Number Optional
risk_decay_mode Number Optional
risk_expired_date String Optional
page Number Optional
per_page Number Optional
order_by String Optional
order_direction String Optional

Context Output

Path Type Description
KMSAT.UserEvents.id Number Event ID
KMSAT.UserEvents.user.email String User email address
KMSAT.UserEvents.user.id Number User ID
KMSAT.UserEvents.user.archived Boolean User archived
KMSAT.UserEvents.external_id String External ID of the event
KMSAT.UserEvents.source String Source of the event
KMSAT.UserEvents.description String Description of the event
KMSAT.UserEvents.occurred_date Date Date the event occurred
KMSAT.UserEvents.risk.level Number Risk level of the event
KMSAT.UserEvents.risk.factor Number Risk factor of the event
KMSAT.UserEvents.risk.decay_mode String Decay Mode of the risk level
KMSAT.UserEvents.risk.expire_date String Risk expiration date
KMSAT.UserEvents.event_type.id Number ID of event type
KMSAT.UserEvents.event_type.name String Name of event type

Command Example

!kmsat-user-event-list id=xyz

kmsat-user-events-list

Argument Name Type Requirement
event_type String Optional
target_user String Optional
external_id String Optional
source string Optional
occurred_date String Optional
risk_level Number Optional
risk_decay_mode Number Optional
risk_expired_date String Optional
page Number Optional
per_page Number Optional
order_by String Optional
order_direction String Optional

Context Output

Path Type Description
KMSAT.UserEvents.id Number Event ID
KMSAT.UserEvents.user.email String User email address
KMSAT.UserEvents.user.id Number User ID
KMSAT.UserEvents.user.archived Boolean User archived
KMSAT.UserEvents.external_id String External ID of the event
KMSAT.UserEvents.source String Source of the event
KMSAT.UserEvents.description String Description of the event
KMSAT.UserEvents.occurred_date Date Date the event occurred
KMSAT.UserEvents.risk.level Number Risk level of the event
KMSAT.UserEvents.risk.factor Number Risk factor of the event
KMSAT.UserEvents.risk.decay_mode String Decay Mode of the risk level
KMSAT.UserEvents.risk.expire_date String Risk expiration date
KMSAT.UserEvents.event_type.id Number ID of event type
KMSAT.UserEvents.event_type.name String Name of event type

Command Example

!kmsat-user-events-list target_user=1 risk_level=1 page=1 per_page=25

Context Example


{
  "data": [
    {
      "id": 0,
      "user": {
        "email": "string",
        "id": 0,
        "archived": true
      },
      "external_id": "string",
      "source": "string",
      "description": "string",
      "occurred_date": "2019-08-24",
      "risk": {
        "level": 0,
        "factor": 0,
        "decay_mode": "string",
        "expire_date": "string"
      },
      "event_type": {
        "id": 0,
        "name": "string"
      }
    }
  ]
}

kmsat-user-event-types-list

Argument Name Description Requirement
name Filter by name of the event type Optional

Context Output

Path Type Description
KMSAT.UserEventTypes.id Number ID of the event type
KMSAT.UserEventTypes.account_id Number Account ID
KMSAT.UserEventTypes.name String Name of the event type
KMSAT.UserEventTypes.description String Description of event type

Command Example

!kmsat-user-event-types-list name="John"

Context Example


{
  "data": [
    {
      "id": 0,
      "name": "string",
      "description": "string"
    }
  ]
}

kmsat-user-event-create

Argument Name Description Requirement
target_user String Required
event_type String Required
external_id String Optional
source string Optional
description String Optional
occurred_date String Optional
risk_level Number Optional
risk_decay_mode Number Optional
risk_expired_date String Optional

Context Output

Path Type Description
KMSAT.UserEventCreate.id Number Unique ID of the event

Command Example

!kmsat-user-event-create target_user="John" event_type="New Event"

Context Example


{
  "data": {
    "id": "string"
  }
}

kmsat-user-event-delete

Argument Name Description Requirement
id Event ID Required

Command Example

!kmsat-user-event-delete id=1

kmsat-user-event-status-list

Argument Name Description Requirement
id request id from kmsat- Required

Context Output

Path Type Description
KMSAT.UserEventStatus.id Number ID of the Event Type
KMSAT.UserEventTypes.details Object Details of event request including event id and any failures
KMSAT.UserEventTypes.details.events Array list of event ids
KMSAT.UserEventTypes.details.failures Array reasons for failure
KMSAT.UserEventTypes.processed Date Date and time event was processed
KMSAT.UserEventTypes.api_key String Name of api key used

Command Example

!kmsat-user-event-status-list id=xyz

Context Example

{
    "data": {
          "id": "abcdefgh-843c-4fc8-bb2f-decf89876f7b",
          "details": {
              "events": [
                  "123456-a083-42b9-b50a-fb69b8e2b185"
              ],
              "failures": []
          },
          "processed": "2023-04-1T14:39:40.132Z",
          "api_key": "Test integration"
      }
}

kmsat-user-event-statuses-list

Argument Name Description Requirement
processed date item was processed No
page Page Number No
per_page Per Page Amount No

Context Output

Path Type Description
KMSAT.UserEventStatus.id Number ID of the Event Type
KMSAT.UserEventTypes.details Object Details of event request including event id and any failures
KMSAT.UserEventTypes.details.events Array list of event ids
KMSAT.UserEventTypes.details.failures Array reasons for failure
KMSAT.UserEventTypes.processed Date Date and time event was processed
KMSAT.UserEventTypes.api_key String Name of api key used

Command Example

!kmsat-user-event-status-list id=xyz

Context Example

{
    "data": [
        {
            "id": "abcdefgh-843c-4fc8-bb2f-decf89876f7b",
            "details": {
                "events": [
                    "123456-a083-42b9-b50a-fb69b8e2b185"
                ],
                "failures": []
            },
            "processed": "2023-04-1T14:39:40.132Z",
            "api_key": "Test integration"
        },
        {
            "id": "qrstevei-843c-4fc8-bb2f-decf89876f7b",
            "details": {
                "events": [
                    "9876543-a083-42b9-b50a-fb69b8e2b185"
                ],
                "failures": []
            },
            "processed": "2023-04-1T00:39:40.132Z",
            "api_key": "Test integration"
        }
    ]
}

Configuration parameters

  • url — Your Reporting Server URL (required)
  • apikey — (required)
  • userEventsUrl — Your User Events Server URL (required)
  • userEventsApiKey — (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (19)

  • kmsat-account-info-list

    Returns KMSAT account information

  • kmsat-account-risk-score-history-list

    Returns KMSAT Account Risk Score History.

  • kmsat-groups-list

    Returns KMSAT Group Specific Risk Score History.

  • kmsat-groups-members-list

    Returns KMSAT Groups Members.

  • kmsat-groups-risk-score-history-list

    Returns KMSAT Group Specific Risk Score History.

  • kmsat-phishing-campaigns-security-tests-list

    Returns All Campaign Phishing Security Tests (PSTs).

  • kmsat-phishing-security-tests-failed-recipients-list

    Returns a Specific Failed Recipient's Results.

  • kmsat-phishing-security-tests-list

    Returns All Phishing Security Tests (PSTs)

  • kmsat-phishing-security-tests-recipients-list

    Returns a Specific Recipient's Results.

  • kmsat-training-campaigns-list

    Returns All Training Campaigns.

  • kmsat-training-enrollments-list

    Returns all Training Enrollments

  • kmsat-user-event-create

    Adds a User Event

  • kmsat-user-event-delete

    Deletes User Event by Event ID

  • kmsat-user-event-list

    Returns a KMSAT User Event.

  • kmsat-user-event-status-list

    returns the status of the User Event request

  • kmsat-user-event-statuses-list

    returns the status of the User Event request

  • kmsat-user-event-types-list

    Returns all KMSAT User Event Types

  • kmsat-user-events-list

    Returns all KMSAT User Events.

  • kmsat-users-risk-score-history-list

    Returns KMSAT User Specific Risk Score History

"""Base Integration for Cortex XSOAR (aka Demisto)

This is an empty Integration with some basic structure according
to the code conventions.

MAKE SURE YOU REVIEW/REPLACE ALL THE COMMENTS MARKED AS "TODO"

Developer Documentation: https://xsoar.pan.dev/docs/welcome
Code Conventions: https://xsoar.pan.dev/docs/integrations/code-conventions
Linting: https://xsoar.pan.dev/docs/integrations/linting

This is an empty structure file. Check an example at;
https://github.com/demisto/content/blob/master/Packs/HelloWorld/Integrations/HelloWorld/HelloWorld.py

"""
from CommonServerPython import *  # noqa # pylint: disable=unused-wildcard-import
from CommonServerUserPython import *  # noqa
import traceback
import urllib3
from typing import Dict

# Disable insecure warnings
urllib3.disable_warnings()


""" CONSTANTS """

DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"  # ISO8601 format with UTC, default in XSOAR

""" CLIENT CLASS """


class Client(BaseClient):
    """KMSAT Client class to interact with the service API

    This Client implements API calls, and does not contain any XSOAR logic.
    Should only do requests and return data.
    It inherits from BaseClient defined in CommonServer Python.
    Most calls use _http_request() that handles proxy, SSL verification, etc.
    For this  implementation, no special attributes defined
    """

    def __init__(self, base_url, verify, proxy, headers=None):
        headers["X-KB4-Integration"] = "Cortex XSOAR KMSAT"
        super().__init__(base_url=base_url, verify=verify, headers=headers, proxy=proxy)

    def kmsat_account_info(self):
        """ Returns account info

        Returns:
            dict: HTTP Response
        """
        return self._http_request(
            method="GET", url_suffix="/account", resp_type="json", ok_codes=(200,)
        )

    def kmsat_account_risk_score_history(self, params: dict):
        """ Returns account risk score history

        Args:
            params (dict): Params for account risk score history

        Returns:
            dict: HTTP Response
        """
        return self._http_request(
            method="GET",
            url_suffix="/account/risk_score_history",
            resp_type="json",
            ok_codes=(200,),
            params=params,
        )

    def kmsat_groups_list(self, params: dict):
        """ Returns groups

        Args:
            params (dict): Params for groups risk score history

        Returns:
            dict: HTTP Response
        """
        return self._http_request(
            method="GET",
            url_suffix="/groups",
            resp_type="json",
            ok_codes=(200,),
            params=params,
        )

    def kmsat_groups_risk_score_history(self, group_id: int, params: dict):
        """ Returns groups risk score history

        Args:
            group_id (int): Group ID
            params (dict): Params for groups risk score history

        Returns:
            dict: HTTP Response
        """
        return self._http_request(
            method="GET",
            url_suffix=f"/groups/{group_id}/risk_score_history",
            resp_type="json",
            ok_codes=(200, ),
            params=params,
        )

    def kmsat_groups_members(self, group_id: int, params: dict):
        """ Returns groups members

        Args:
            group_id (int): Group ID
            params (dict): Params for groups members

        Returns:
            dict: HTTP Response
        """
        return self._http_request(
            method="GET",
            url_suffix=f"/groups/{group_id}/members",
            resp_type="json",
            ok_codes=(200, ),
            params=params,
        )

    def kmsat_users_risk_score_history(self, user_id: int, params: dict):
        """ Returns user risk score history

        Args:
            user_id (int): User ID
            params (dict): Params for user risk score history

        Returns:
            dict: HTTP Response
        """
        return self._http_request(
            method="GET",
            url_suffix=f"/users/{user_id}/risk_score_history",
            resp_type="json",
            ok_codes=(200, ),
            params=params,
        )

    def kmsat_phishing_security_tests(self, params: dict):
        """ Returns phishing security tests

        Args:
            params (dict): Params for phishing security tests

        Returns:
            dict: HTTP Response
        """
        return self._http_request(
            method="GET",
            url_suffix="/phishing/security_tests",
            resp_type="json",
            ok_codes=(200,),
            params=params,
        )

    def kmsat_phishing_security_tests_recipients(self, pst_id, params):
        """ Returns recipients phishing security tests

        Args:
            pst_id (int): PST ID
            params (dict): Params for recipients phishing security tests

        Returns:
            dict: HTTP Response
        """
        return self._http_request(
            method="GET",
            url_suffix=f"/phishing/security_tests/{pst_id}/recipients",
            resp_type="json",
            ok_codes=(200, ),
            params=params,
        )

    def kmsat_phishing_campaign_security_tests(self, campaign_id: int, params: dict):
        """ Returns campaign phishing security tets

        Args:
            campaign_id (int): Campaign ID
            params (dict): Params for campaign phishing security tests

        Returns:
            dict: HTTP Response
        """
        return self._http_request(
            method="GET",
            url_suffix=f"/phishing/campaigns/{campaign_id}/security_tests",
            resp_type="json",
            ok_codes=(200, ),
            params=params,
        )

    def kmsat_training_campaigns(self, params: dict):
        """ Returns training campaigns

        Args:
            params (dict): Params for training campaigns

        Returns:
            dict: HTTP Response
        """
        return self._http_request(
            method="GET",
            url_suffix="/training/campaigns",
            resp_type="json",
            ok_codes=(200,),
            params=params,
        )

    def kmsat_training_enrollments(self, params):
        """ Returns training enrollments

        Args:
            params (dict): Params for training enrollment

        Returns:
            dict: HTTP Response
        """
        return self._http_request(
            method="GET",
            url_suffix="/training/enrollments",
            resp_type="json",
            ok_codes=(200,),
            params=params,
        )


class UserEventClient(BaseClient):
    """Client class to interact with the KMSAT User EventAPI"""

    def __init__(self, base_url, verify, proxy, headers=None):
        headers["X-KB4-Integration"] = "Cortex XSOAR KMSAT"
        super().__init__(base_url=base_url, verify=verify, headers=headers, proxy=proxy)

    def user_events(self, args: dict):
        """ Returns user events

        Args:
            args (dict): Params for API call

        Returns:
            dict: HTTP Response
        """
        params = remove_empty_elements(
            {
                "event_type": args.get("event_type"),
                "target_user": args.get("target_user"),
                "external_id": args.get("external_id"),
                "source": args.get("source"),
                "occurred_date": args.get("occurred_date"),
                "risk_level": args.get("risk_level"),
                "risk_decay_mode": args.get("risk_decay_mode"),
                "risk_expire_date": args.get("risk_expire_date"),
                "order_by": args.get("order_by"),
                "order_direction": args.get("order_direction"),
                "page": args.get("page"),
                "per_page": args.get("per_page"),
            }
        )
        return self._http_request(
            method="GET",
            url_suffix="/events",
            resp_type="json",
            ok_codes=(200,),
            params=params,
        )

    def user_event_types(self, args: dict):
        """ Returns user event types

        Args:
            args (dict): Params for API call

        Returns:
            dict: HTTP Response
        """
        params = remove_empty_elements({"name": args.get("name")})
        return self._http_request(
            method="GET",
            url_suffix="/event_types",
            resp_type="json",
            ok_codes=(200,),
            params=params,
        )

    def create_user_event(self, args: dict):
        """ Creates a user event

        Args:
            args (dict): Params for API call

        Returns:
            dict: HTTP Response
        """

        params = remove_empty_elements(
            {
                "target_user": args.get("target_user"),
                "event_type": args.get("event_type"),
                "external_id": args.get("external_id"),
                "source": args.get("source"),
                "description": args.get("description"),
                "occurred_date": args.get("occurred_date"),
                "risk_decay_mode": args.get("risk_decay_mode"),
                "risk_expire_date": args.get("risk_expire_date"),
            }
        )

        # Converts string to int if value is set
        if args.get("risk_level") is not None:
            risk_level: int = int(args["risk_level"])
            params["risk_level"] = risk_level

        return self._http_request(
            method="POST",
            url_suffix="/events",
            resp_type="json",
            ok_codes=(201,),
            json_data=params,
        )

    def delete_user_event(self, event_id: str):
        """ Deletes a user event

        Args:
            args (dict): Params for API call

        Returns:
            dict: HTTP Response
        """

        return self._http_request(
            method="DELETE",
            url_suffix=f"/events/{event_id}",
            resp_type="response",
            raise_on_status=True,
            ok_codes=(204,),
        )

    def user_event(self, event_id: str):
        """ Deletes a user event

        Args:
            args (dict): Params for API call

        Returns:
            dict: HTTP Response
        """

        return self._http_request(
            method="GET",
            url_suffix=f"/events/{event_id}",
            resp_type="json",
            raise_on_status=True,
            ok_codes=(200, ),
        )

    def user_event_status(self, request_id: str):
        """ gets a specific user event create request status

        Args:
            args (dict): Params for API call

        Returns:
            dict: HTTP Response
        """

        return self._http_request(
            method="GET",
            url_suffix=f"/statuses/{request_id}",
            resp_type="json",
            raise_on_status=True,
            ok_codes=(200, ),
        )

    def user_event_statuses(self, params: dict):
        """ gets a list of user event request statuses

        Args:
            args (dict): Params for API call

        Returns:
            dict: HTTP Response
        """

        return self._http_request(
            method="GET",
            url_suffix="/statuses",
            resp_type="json",
            raise_on_status=True,
            ok_codes=(200,),
            params=params,
        )


""" HELPER FUNCTIONS """


def get_pagination(args: dict):
    """ Returns pagination params

        Args:
            args (dict): Params for pagination

        Returns:
            list: Returns cleaned params for paging
        """

    return remove_empty_elements(
        {"page": args.get("page"), "per_page": args.get("per_page")}
    )


""" COMMAND FUNCTIONS """


def kmsat_account_info_list_command(client: Client, args: dict) -> CommandResults:
    """ Returns account information

    Args:
        client (Client): Report Client

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for account information
    """
    response = client.kmsat_account_info()
    markdown = tableToMarkdown(
        "Account Info",
        response,
        [
            "name",
            "type",
            "domains",
            "admins",
            "subscription_level",
            "subscription_end_date",
            "number_of_seats",
            "current_risk_score",
        ],
    )

    return CommandResults(
        outputs_prefix="KMSAT.AccountInfo",
        outputs_key_field="name",
        raw_response=response,
        outputs=response,
        readable_output=markdown,
    )


def kmsat_account_risk_score_history_list_command(
    client: Client, args: dict
) -> CommandResults:
    """ Lists account risk score history

    Args:
        client (Client): Report Client
        args (dict): Params for account risk score history

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for account risk score history
    """
    params = get_pagination(args)
    response = client.kmsat_account_risk_score_history(params)

    markdown = tableToMarkdown(
        "Account Risk Score History", response, ["risk_score", "date"]
    )
    return CommandResults(
        outputs_prefix="KMSAT.AccountRiskScoreHistory",
        outputs_key_field="",
        raw_response=response,
        outputs=response,
        readable_output=markdown,
    )


def kmsat_groups_list_command(client: Client, args: dict) -> CommandResults:
    params = get_pagination(args)
    response = client.kmsat_groups_list(params)

    markdown = tableToMarkdown(
        "Groups ",
        response,
        [
            "id",
            "name",
            "group_type",
            "provisioning_guid",
            "member_count",
            "current_risk_score",
            "status"
        ]
    )

    return CommandResults(
        outputs_prefix="KMSAT.Groups",
        outputs_key_field="id",
        raw_response=response,
        outputs=response,
        readable_output=markdown,
    )


def kmsat_groups_risk_score_history_list_command(
    client: Client, args: dict
) -> CommandResults:
    """ Lists groups risk score history

    Args:
        client (Client): Report Client
        args (dict): Params for group risk score history

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for training enrollments
    """
    group_id = remove_empty_elements(args.get("group_id"))
    params = get_pagination(args)
    response = client.kmsat_groups_risk_score_history(group_id, params)
    markdown = tableToMarkdown(
        "Groups Risk Score History", response, headers=["risk_score", "date"]
    )

    return CommandResults(
        outputs_prefix="KMSAT.GroupsRiskScoreHistory",
        outputs_key_field="id",
        raw_response=response,
        outputs=response,
        readable_output=markdown,
    )


def kmsat_groups_members_list_command(
    client: Client, args: dict
) -> CommandResults:
    """ Lists groups members

    Args:
        client (Client): Report Client
        args (dict): Params for groups members

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for groups members
    """
    group_id = remove_empty_elements(args.get("group_id"))
    params = get_pagination(args)
    response = client.kmsat_groups_members(group_id, params)
    markdown = tableToMarkdown(
        "Groups Members",
        response,
        [
            "id",
            "employee_number",
            "first_name",
            "last_name",
            "job_title",
            "email",
            "phish_prone_percentage",
            "phone_number",
            "extension",
            "mobile_phone_number",
            "location",
            "division",
            "manager_name",
            "manager_email",
            "provisioning_managed",
            "provisioning_guid",
            "groups",
            "current_risk_score",
            "aliases",
            "joined_on",
            "last_sign_in",
            "status",
            "organization",
            "department",
            "language",
            "comment",
            "employee_start_date",
            "archived_at",
            "custom_field_1",
            "custom_field_2",
            "custom_field_3",
            "custom_field_4",
            "custom_date_1",
            "custom_date_2",
        ]
    )

    return CommandResults(
        outputs_prefix="KMSAT.GroupsMembers",
        outputs_key_field="id",
        raw_response=response,
        outputs=response,
        readable_output=markdown,
    )


def kmsat_users_risk_score_history_list_command(
    client: Client, args: dict
) -> CommandResults:
    """ Lists user risk score history

    Args:
        client (Client): Report Client
        args (dict): Params for user risk score history

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for user risk score history
    """
    user_id = remove_empty_elements(args.get("user_id"))
    params = get_pagination(args)
    response = client.kmsat_users_risk_score_history(user_id, params)
    markdown = tableToMarkdown(
        "Users Risk Score History", response, headers=["risk_score", "date"]
    )

    return CommandResults(
        outputs_prefix="KMSAT.UsersRiskScoreHistory",
        outputs_key_field="",
        raw_response=response,
        outputs=response,
        readable_output=markdown,
    )


def kmsat_phishing_security_tests_list_command(
    client: Client, args: dict
) -> CommandResults:
    """ Lists phishing security tests

    Args:
        client (Client): Report Client
        args (dict): Params for phishing security tests

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for phishing security
    """
    params = get_pagination(args)
    response = client.kmsat_phishing_security_tests(params)
    markdown = tableToMarkdown(
        "Phishing Security Tests",
        response,
        [
            "campaign_id",
            "pst_id",
            "status",
            "name",
            "scheduled_count",
            "delivered_count",
            "opened_count",
            "clicked_count",
            "replied_count",
            "attachment_open_count",
            "macro_enabled_count",
            "data_entered_count",
            "qr_code_scanned_count",
            "reported_count",
            "bounced_count",
        ],
    )

    return CommandResults(
        outputs_prefix="KMSAT.PhishingSecurity",
        outputs_key_field="campaign_id",
        raw_response=response,
        outputs=response,
        readable_output=markdown,
    )


def kmsat_phishing_security_tests_recipients_list_command(
    client: Client, args: dict
) -> CommandResults:
    """ Lists KMSAT recipients phishing security tests

    Args:
        client (Client): Report Client
        args (_type_): Params for recipients phishing security tests

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for recipients phishing security tests
    """
    pst_id = remove_empty_elements(args.get("pst_id"))
    params = get_pagination(args)
    response = client.kmsat_phishing_security_tests_recipients(pst_id, params)
    markdown = tableToMarkdown(
        "Phishing Security Tests Recipients",
        response,
        [
            "recipient_id",
            "pst_id",
            "user",
            "delivered_at",
            "opened_at",
            "clicked_at",
            "replied_at",
            "attachment_opened_at",
            "macro_enabled_at",
            "data_entered_at",
            "qr_code_scanned",
            "reported_at",
            "bounced_at",
        ],
    )

    return CommandResults(
        outputs_prefix="KMSAT.PhishingSecurityPST",
        outputs_key_field="recipient_id",
        raw_response=response,
        outputs=response,
        readable_output=markdown,
    )


def kmsat_phishing_security_tests_failed_recipients_list_command(
    client: Client, args: dict
) -> CommandResults:
    """ Lists KMSAT recipients that have FAILED the phishing security tests

    Args:
        client (Client): Report Client
        args (dict): Params for recipients that failed security tests

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for recipients that failed phishing security tests
    """

    pst_id = remove_empty_elements(args.get("pst_id"))
    params = get_pagination(args)
    response = client.kmsat_phishing_security_tests_recipients(pst_id, params)

    filtered_items_in_page = 0

    items_total = len(response)

    # Sets paging_end False if the response count is less than the per_page
    per_page = int(params.get('per_page')) if (params.get('per_page')) else 100

    paging_end = len(response) < per_page

    data = []
    for i in range(len(response)):
        clicked_at = response[i]['clicked_at']
        replied_at = response[i]['replied_at']
        attachment_opened_at = response[i]['attachment_opened_at']
        macro_enabled_at = response[i]['macro_enabled_at']
        data_entered_at = response[i]['data_entered_at']
        qr_code_scanned = response[i]['qr_code_scanned']

        if any([clicked_at, replied_at, attachment_opened_at, macro_enabled_at, data_entered_at, qr_code_scanned]):
            data.append(response[i])
            filtered_items_in_page += 1

    # Adds meta to the result set for paging
    metadata = {
        "paging_end": paging_end,
        "filtered_items_in_page": filtered_items_in_page,
        "items_total": items_total
    }

    d = {
        "data": data,
        "meta": metadata
    }

    markdown = tableToMarkdown(
        "Phishing Security Tests Recipients",
        d["data"],
        [
            "recipient_id",
            "pst_id",
            "user",
            "delivered_at",
            "opened_at",
            "clicked_at",
            "replied_at",
            "attachment_opened_at",
            "macro_enabled_at",
            "data_entered_at",
            "qr_code_scanned",
            "reported_at",
            "bounced_at",
        ],
    )

    return CommandResults(
        outputs_prefix="KMSAT.PhishingSecurityPST",
        outputs_key_field="recipient_id",
        raw_response=d,
        outputs=d,
        readable_output=markdown,
    )


def kmsat_phishing_campaign_security_tests_list_command(client: Client, args) -> CommandResults:
    """ Lists KMSAT campaign phishing security tets

    Args:
        client (Client): Report Client
        args (_type_): Params for campaign phishing security tests

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for phishing campaign security tests
    """
    campaign_id = remove_empty_elements(args.get("campaign_id"))
    params = get_pagination(args)
    response = client.kmsat_phishing_campaign_security_tests(campaign_id, params)
    markdown = tableToMarkdown(
        "Phishing Campaign Security Tests",
        response,
        [
            "campaign_id",
            "pst_id",
            "status",
            "started_at",
            "scheduled_count",
            "delivered_count",
            "opened_count",
            "clicked_count",
            "replied_count",
            "attachment_open_count",
            "macro_enabled_count",
            "data_entered_count",
            "qr_code_scanned_count",
            "reported_count",
            "bounced_count",
        ]
    )

    return CommandResults(
        outputs_prefix="KMSAT.CampaignPST",
        outputs_key_field="",
        raw_response=response,
        outputs=response,
        readable_output=markdown,
    )


def kmsat_training_campaigns_list_command(client: Client, args: dict) -> CommandResults:
    """ Lists KMSAT training campaigns

    Args:
        client (Client): Report Client
        args (dict): Params for training campaigns

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for training campaigns
    """
    params = get_pagination(args)
    response = client.kmsat_training_campaigns(params)
    markdown = tableToMarkdown(
        "Training Campaigns",
        response,
        [
            "campaign_id",
            "name",
            "groups",
            "status",
            "content",
            "duration_type",
            "start_date",
            "end_date",
            "relative_duration",
            "auto_enroll",
            "allow_multiple_enrollments",
            "completion_percentage",
        ],
    )

    return CommandResults(
        outputs_prefix="KMSAT.TrainingCampaigns",
        outputs_key_field="campaign_id",
        raw_response=response,
        outputs=response,
        readable_output=markdown,
    )


def kmsat_training_enrollments_list_command(
    client: Client, args: dict
) -> CommandResults:
    """ Lists KMSAT training enrollments

    Args:
        client (Client): Report Client
        args (dict): Params for training enrollments

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for training enrollments
    """
    status = remove_empty_elements(args.get("status"))
    params = get_pagination(args)
    response = client.kmsat_training_enrollments(params)

    data = []
    filtered_items_in_page = 0
    items_total = len(response)

    # Sets paging_end False if the response count is less than the per_page
    per_page = int(params.get('per_page')) if (params.get('per_page')) else 100

    paging_end = len(response) < per_page

    # Adds only the filtered items to the response with counts
    if status is not None:
        for i in range(len(response)):
            if response[i]['status'] == f"{status}":
                data.append(response[i])
                filtered_items_in_page += 1
    else:
        data = client.kmsat_training_enrollments(params)

    # Adds meta to the result set for paging
    metadata = {
        "paging_end": paging_end,
        "filtered_items_in_page": filtered_items_in_page,
        "items_total": items_total
    }

    d = {
        "data": data,
        "meta": metadata
    }

    markdown = tableToMarkdown(
        "Training Enrollments",
        d["data"],
        [
            "enrollment_id",
            "content_type",
            "module_name",
            "user",
            "campaign_name",
            "enrollment_date",
            "start_date",
            "completion_date",
            "status",
            "time_spent",
            "policy_acknowledged",
        ]

    )
    return CommandResults(
        outputs_prefix="KMSAT.TrainingEnrollments",
        outputs_key_field="enrollment_id",
        raw_response=d,
        outputs=d,
        readable_output=markdown,
    )


def kmsat_user_events_list_command(
    client: UserEventClient, args: dict
) -> CommandResults:
    """ Lists the user events

    Args:
        client (UserEventClient): UserEventClient
        args (dict): Params for user events

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for user events
    """
    response = client.user_events(args)

    data: List[Dict] = response.get("data") or []
    return CommandResults(
        outputs_prefix="KMSAT.UserEvents",
        outputs_key_field="id",
        raw_response=response,
        outputs=data,
        readable_output=tableToMarkdown(name="KMSAT User Events", t=data),
    )


def kmsat_user_event_types_list_command(
    client: UserEventClient, args: dict
) -> CommandResults:
    """ Lists user event types

    Args:
        client (UserEventClient): UserEventClient
        args (dict): Params for user event types

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data for user event types
    """
    response = client.user_event_types(args)

    data: List[Dict] = response.get("data") or []
    return CommandResults(
        outputs_prefix="KMSAT.UserEventTypes",
        outputs_key_field="id",
        raw_response=response,
        outputs=data,
        readable_output=tableToMarkdown(name="KMSAT User Event Types", t=data),
    )


def kmsat_user_event_create_command(
    client: UserEventClient, args: dict
) -> CommandResults:
    """ Creates a user event

    Args:
        client (UserEventClient): UserEventClient
        args (dict): Params for user even create

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data user create event
    """
    response = client.create_user_event(args)

    data: List[Dict] = response.get("data") or []
    return CommandResults(
        outputs_prefix="KMSAT.UserEventCreate",
        outputs_key_field="id",
        raw_response=response,
        outputs=data,
        readable_output=tableToMarkdown(name="KMSAT Create User Event", t=data),
    )


def kmsat_user_event_delete_command(
    client: UserEventClient, args: dict
) -> CommandResults:
    """ Deletes a user event

    Args:
        client (UserEventClient): UserEventClient
        args (dict): Params for user even delete

    Returns:
        CommandResults: Returns message with deleted event ID
    """
    event_id: str = str(args.get("id"))
    client.delete_user_event(event_id)
    return CommandResults(
        readable_output=f"Successfully deleted event: {event_id}")


def kmsat_user_event_list_command(
    client: UserEventClient, args: dict
) -> CommandResults:
    """ list details for a user event

    Args:
        client (UserEventClient): UserEventClient
        args (dict): Params for user even create

    Raises:
        DemistoException: Raises Demisto Exception

    Returns:
        CommandResults: Returns context data user create event
    """
    event_id: str = str(args.get("id"))
    response = client.user_event(event_id)

    data: List[Dict] = response.get("data") or []
    return CommandResults(
        outputs_prefix="KMSAT.UserEvent",
        outputs_key_field="id",
        raw_response=response,
        outputs=data,
        readable_output=tableToMarkdown(name="KMSAT User Event", t=data),
    )


def kmsat_user_event_status_list_command(
    client: UserEventClient, args: dict
) -> CommandResults:
    """ returns the status of a requested user event

    Args:
        client (UserEventClient): UserEventClient
        args (dict): Params for user events status

    Returns:
        CommandResults: Returns event status
    """

    request_id: str = str(args.get("id"))
    response = client.user_event_status(request_id)
    data: List[Dict] = response.get("data") or []
    markdown = tableToMarkdown(
        "KMSAT User Event Status",
        data,
        [
            "id",
            "details",
            "processed",
        ],
    )

    return CommandResults(
        outputs_prefix="KMSAT.UserEventStatus",
        outputs_key_field="id",
        raw_response=response,
        outputs=data,
        readable_output=markdown,
    )


def kmsat_user_event_statuses_list_command(
    client: UserEventClient, args: dict
) -> CommandResults:
    """ List the status of User Events

    Args:
        client (UserEventClient): UserEventClient
        args (dict): Params for user event status list

    Returns:
        CommandResults: Returns list of event statuses
    """
    params = get_pagination(args)
    params["processed"] = args.get("processed")
    params = remove_empty_elements(params)

    response = client.user_event_statuses(params)
    data: List[Dict] = response.get("data") or []
    markdown = tableToMarkdown(
        "KMSAT User Event Statuses",
        data,
        [
            "id",
            "details",
            "processed",
        ],
    )

    return CommandResults(
        outputs_prefix="KMSAT.UserEventStatuses",
        outputs_key_field="id",
        raw_response=response,
        outputs=data,
        readable_output=markdown,
    )


def test_module(client: Client, userEventClient: UserEventClient) -> str:
    """Tests API connectivity and authentication'

    Returning 'ok' indicates that the integration works like it is supposed to.
    Connection to the service is successful.
    Raises exceptions if something goes wrong.

    :type client: ``Client``
    :param Client: client to use
    :type userEventClient: ``UserEventClient``
    :param userEventClient: event client to use


    :return: 'ok' if test passed, anything else will fail the test.
    :return type: ``str``
    """

    message: str = ""
    params: Dict = {}
    try:
        client.kmsat_account_info()
        message = "ok"
    except DemistoException as e:
        if "Forbidden" in str(e) or "Authorization" in str(e):
            message = f"Authorization Error: make sure Reporting API Key is correctly set{str(client._headers)}"
        else:
            raise e

    try:
        userEventClient.user_event_types(params)
        message = "ok"
    except DemistoException as e:
        if "Forbidden" in str(e) or "Authorization" in str(e):
            message = f"Authorization Error: make sure Reporting API Key is correctly set{str(client._headers)}"
        else:
            raise e
    return message


""" MAIN FUNCTION """


def main() -> None:
    """Main

    Raises:
        DemistoException: Raises Demisto Exception for Reporting API
        DemistoException: Raises Demisto Exception for User Events API
        NotImplementedError: Raises no command implementation
    """

    command = demisto.command()
    params = demisto.params()
    args = demisto.args()
    demisto.debug(f"Command being called is {command}")

    # get the service API url
    base_url = urljoin(params.get("url"), "/v1")
    userEvents_base_url = params.get("userEventsUrl")

    # verify api key or credentials are specified
    if not params.get("apikey") or not (
        key := params.get("apikey", {}).get("password")
    ):
        raise DemistoException(
            "Missing Reporting API Key. Fill in a valid key in the integration configuration."
        )

    # verify User Events api key or credentials are specified
    if not params.get("userEventsApiKey") or not (
        userEventsApiKey := params.get("userEventsApiKey", {}).get("password")
    ):
        raise DemistoException(
            "Missing User Events API Key. Fill in a valid key in the integration configuration."
        )

    # if your Client class inherits from BaseClient, SSL verification is
    # handled out of the box by it, just pass ``verify_certificate`` to
    # the Client constructor
    verify_certificate = not params.get("insecure", False)

    # if your Client class inherits from BaseClient, system proxy is handled
    # out of the box by it, just pass ``proxy`` to the Client constructor
    proxy = params.get("proxy", False)

    try:

        client = Client(
            base_url=base_url,
            verify=verify_certificate,
            headers={
                "Authorization": f"Bearer {key}",
                "Content-Type": "application/json",
            },
            proxy=proxy,
        )

        userEventClient = UserEventClient(
            base_url=userEvents_base_url,
            verify=verify_certificate,
            headers={
                "Authorization": f"Bearer {userEventsApiKey}",
                "Content-Type": "application/json",
            },
            proxy=proxy,
        )

        reportingCommands = {
            "kmsat-account-info-list": kmsat_account_info_list_command,
            "kmsat-account-risk-score-history-list": kmsat_account_risk_score_history_list_command,
            "kmsat-groups-list": kmsat_groups_list_command,
            "kmsat-groups-risk-score-history-list": kmsat_groups_risk_score_history_list_command,
            "kmsat-groups-members-list": kmsat_groups_members_list_command,
            "kmsat-users-risk-score-history-list": kmsat_users_risk_score_history_list_command,
            "kmsat-phishing-security-tests-list": kmsat_phishing_security_tests_list_command,
            "kmsat-phishing-security-tests-recipients-list": kmsat_phishing_security_tests_recipients_list_command,
            "kmsat-phishing-security-tests-failed-recipients-list": kmsat_phishing_security_tests_failed_recipients_list_command,
            "kmsat-phishing-campaigns-security-tests-list": kmsat_phishing_campaign_security_tests_list_command,
            "kmsat-training-campaigns-list": kmsat_training_campaigns_list_command,
            "kmsat-training-enrollments-list": kmsat_training_enrollments_list_command,
        }

        userEventCommands = {
            "kmsat-user-events-list": kmsat_user_events_list_command,
            "kmsat-user-event-list": kmsat_user_event_list_command,
            "kmsat-user-event-types-list": kmsat_user_event_types_list_command,
            "kmsat-user-event-create": kmsat_user_event_create_command,
            "kmsat-user-event-delete": kmsat_user_event_delete_command,
            "kmsat-user-event-status-list": kmsat_user_event_status_list_command,
            "kmsat-user-event-statuses-list": kmsat_user_event_statuses_list_command,
        }

        if command == "test-module":
            # This is the call made when pressing the integration Test button.
            return_results(test_module(client, userEventClient))
        elif command in list(reportingCommands.keys()):
            return_results(reportingCommands[command](client, args))
        elif command in list(userEventCommands.keys()):
            return_results(userEventCommands[command](userEventClient, args))
        else:
            raise NotImplementedError(f"command {command} is not implemented.")

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


""" ENTRY POINT """


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