SafewalkReports

Safewalk server integration.

Analytics & SIEM · Altipeak

Details

IDSafewalkReports
ProviderProtectimus
CategoryAnalytics & SIEM
From Version6.0.0
Docker Imagedemisto/python3:3.12.8.3296088
Supported ModulesAgentix XSIAM

README

Safewalk server integration
This integration was integrated and tested with version 3 of SafewalkReports

Configure SafewalkReports in Cortex

Parameter Description Required
Server URL (e.g. https://soar.monstersofhack.com)   True
Fetch incidents   False
Incident type   False
API Key   True
Trust any certificate (not secure)   False
Use system proxy settings   False
Fetch indicators   False
Incidents Fetch Interval   False
    False
    False
    False
Indicator Reputation Indicators from this integration instance will be marked with this reputation False
Source Reliability Reliability of the source providing the intelligence data True
    False
    False
Feed Fetch Interval   False
Bypass exclusion list When selected, the exclusion list is ignored for indicators from this feed. This means that if an indicator from this feed is on the exclusion list, the indicator might still be added to the system. False
Tags Supports CSV values. False
Traffic Light Protocol Color The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed False

Commands

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

safewalk-get-associated-users


safewalk-get-associated-users

Base Command

safewalk-get-associated-users

Input

Argument Name Description Required
devicetype devicetype. Optional

Context Output

Path Type Description
Safewalk.reports.associated_users.data.id String users data id
Safewalk.reports.associated_users.data.label String users data label

Human Readable Output

safewalk-get-authentication-methods-distribution


safewalk-get-authentication-methods-distribution

Base Command

safewalk-get-authentication-methods-distribution

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
Safewalk.reports.device_auth_distribution.data.id String device_auth_distribution.data.id
Safewalk.reports.device_auth_distribution.data.label String device_auth_distribution.data.label
Safewalk.reports.device_auth_distribution.data.type String device_auth_distribution.data.type
Safewalk.reports.device_auth_distribution.data Number device_auth_distribution.data

Human Readable Output

safewalk-get-authentication-rate-per-device


safewalk-get-authentication-rate-per-device

Base Command

safewalk-get-authentication-rate-per-device

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
Safewalk.reports.device_auth_rate.data.id String device_auth_rate.data.id
Safewalk.reports.device_auth_rate.data.label String device_auth_rate.data.label
Safewalk.reports.device_auth_rate.data.type String device_auth_rate.data.type
Safewalk.reports.device_auth_rate.data Number device_auth_rate.data

Human Readable Output

safewalk-get-least-active-users


safewalk-get-least-active-users

Base Command

safewalk-get-least-active-users

Input

Argument Name Description Required
sincedate sincedate. Optional
userinformation userinformation. Optional

Context Output

Path Type Description
Safewalk.reports.inactive_users.data.id String inactive_users.data.id
Safewalk.reports.inactive_users.data.label String inactive_users.data.label

Human Readable Output

safewalk-get-licenses-inventory


safewalk-get-licenses-inventory

Base Command

safewalk-get-licenses-inventory

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
Safewalk.reports.licensesinventory.total Number licenses inventory total
Safewalk.reports.licensesinventory.data.id String icenses inventory data id
Safewalk.reports.licensesinventory.data.label String licenses inventory data label
Safewalk.reports.licensesinventory.data.type String licenses inventory data type
Safewalk.reports.licensesinventory.data Number licenses inventory data

Human Readable Output

safewalk-get-licenses-usage


safewalk-get-licenses-usage

Base Command

safewalk-get-licenses-usage

Input

Argument Name Description Required
begindate begindate. Optional
enddate enddate. Optional

Context Output

Path Type Description
Safewalk.reports.licensesusage.total Number licenses usage total
Safewalk.reports.licensesusage.data.id String licenses usage data id
Safewalk.reports.licensesusage.data.label String licenses usage data label
Safewalk.reports.licensesusage.data.type String licenses usage data type
Safewalk.reports.licensesusage.data Number licenses usage data

Human Readable Output

safewalk-get-most-active-users


safewalk-get-most-active-users

Base Command

safewalk-get-most-active-users

Input

Argument Name Description Required
days days. Optional
limit limit. Optional
userinformation userinformation. Optional

Context Output

Path Type Description
Safewalk.reports.mostactiveusers.data.id String mostactiveusers.data.id
Safewalk.reports.mostactiveusers.data.label String mostactiveusers.data.label
Safewalk.reports.mostactiveusers.data.type String mostactiveusers.data.type
Safewalk.reports.mostactiveusers.data String mostactiveusers.data

Human Readable Output

safewalk-get-physical-tokens-inventory


safewalk-get-physical-tokens-inventory

Base Command

safewalk-get-physical-tokens-inventory

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
Safewalk.reports.physicaltokeninventory.total Number physicaltokeninventory.total
Safewalk.reports.physicaltokeninventory.data.id String physicaltokeninventory.data.id
Safewalk.reports.physicaltokeninventory.data.label String physicaltokeninventory.data.label
Safewalk.reports.physicaltokeninventory.data.type String physicaltokeninventory.data.type
Safewalk.reports.physicaltokeninventory.data Number physicaltokeninventory.data

Human Readable Output

safewalk-get-registered-devices-distribution


safewalk-get-registered-devices-distribution

Base Command

safewalk-get-registered-devices-distribution

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
Safewalk.reports.registereddevices.total Number registereddevices.total
Safewalk.reports.registereddevices.data.id String registereddevices.data.id
Safewalk.reports.registereddevices.data.label String registereddevices.data.label
Safewalk.reports.registereddevices.data.type String registereddevices.data.type
Safewalk.reports.registereddevices.data Number registereddevices.data

Human Readable Output

safewalk-get-registration


safewalk-get-registration

Base Command

safewalk-get-registration

Input

Argument Name Description Required
begindate begindate. Optional
enddate enddate. Optional
userinformation userinformation. Optional

Context Output

Path Type Description
Safewalk.reports.registration.total Number registration.total
Safewalk.reports.registration.data.id String registration.data.id
Safewalk.reports.registration.data.label String registration.data.label
Safewalk.reports.registration.data.type String registration.data.type

Human Readable Output

safewalk-get-users-associations-indicators


safewalk-get-users-associations-indicators

Base Command

safewalk-get-users-associations-indicators

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
Safewalk.reports.usersassociations.total Number usersassociations.total
Safewalk.reports.usersassociations.data.id String usersassociations.data.id
Safewalk.reports.usersassociations.data.label String usersassociations.data.label
Safewalk.reports.usersassociations.data.type String usersassociations.data.type
Safewalk.reports.usersassociations.data Number usersassociations.data

Human Readable Output

Configuration parameters

  • url — Server URL (e.g. https://soar.monstersofhack.com) (required)
  • isFetch — Fetch incidents
  • incidentType — Incident type
  • apikey — API Key (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • feed — Fetch indicators
  • incidentFetchInterval — Incidents Fetch Interval
  • first_fetch — First fetch
  • max_fetch — Maximum number of incidents per fetch
  • fetch_query_filter — Fetch Query Filter
  • feedReputation — Indicator Reputation
  • feedReliability — Source Reliability (required)
  • feedExpirationPolicy
  • feedExpirationInterval
  • feedFetchInterval — Feed Fetch Interval
  • feedBypassExclusionList — Bypass exclusion list
  • feedTags — Tags
  • tlp_color — Traffic Light Protocol Color

Commands (11)

  • safewalk-get-associated-users

    safewalk-get-associated-users.

  • safewalk-get-authentication-methods-distribution

    safewalk-get-authentication-methods-distribution.

  • safewalk-get-authentication-rate-per-device

    safewalk-get-authentication-rate-per-device.

  • safewalk-get-least-active-users

    safewalk-get-least-active-users.

  • safewalk-get-licenses-inventory

    safewalk-get-licenses-inventory.

  • safewalk-get-licenses-usage

    safewalk-get-licenses-usage.

  • safewalk-get-most-active-users

    safewalk-get-most-active-users.

  • safewalk-get-physical-tokens-inventory

    safewalk-get-physical-tokens-inventory.

  • safewalk-get-registered-devices-distribution

    safewalk-get-registered-devices-distribution.

  • safewalk-get-registration

    safewalk-get-registration.

  • safewalk-get-users-associations-indicators

    safewalk-get-users-associations-indicators.

from datetime import datetime, timedelta
import urllib3
import json
import dateparser
from typing import Any
from CommonServerPython import *


urllib3.disable_warnings()


DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
MAX_INCIDENTS_TO_FETCH = 50
HELLOWORLD_SEVERITIES = ["Low", "Medium", "High", "Critical"]


class Client(BaseClient):
    def get_associated_users(self, devicetype):
        return json.loads(
            self._http_request(method="GET", url_suffix=f"/reports/associated_users/?device_type={devicetype}", resp_type="text")
        )

    def get_authentication_methods_distribution(self):
        return json.loads(self._http_request(method="GET", url_suffix="/reports/device_auth_distribution/", resp_type="text"))

    def get_authentication_rate_per_device(self):
        return json.loads(self._http_request(method="GET", url_suffix="/reports/device_auth_rate/", resp_type="text"))

    def get_least_active_users(self, sincedate=None, userinformation=False):
        if sincedate is None:
            sincedate = (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%d")

        return json.loads(
            self._http_request(
                method="GET",
                url_suffix=f"/reports/inactive_users/?since_date={sincedate}&user_information={str(userinformation)}",
                resp_type="text",
            )
        )

    def get_licenses_inventory(self):
        return json.loads(self._http_request(method="GET", url_suffix="/reports/device_inventory/", resp_type="text"))

    def get_licenses_usage(self, begindate=None, enddate=None):
        if begindate is None:
            begindate = (datetime.now() - timedelta(days=90)).strftime("%Y-%m-%d")

        if enddate is None:
            enddate = (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%d")

        return json.loads(
            self._http_request(
                method="GET", url_suffix=f"/reports/licensesusage/?begin_date={begindate}&end_date={enddate}", resp_type="text"
            )
        )

    def get_most_active_users(self, days=10, limit=30, userinformation=False):
        return json.loads(
            self._http_request(
                method="GET",
                url_suffix=f"/reports/top_users/?days={str(days)}&limit={str(limit)}&user_information={str(userinformation)}",
                resp_type="text",
            )
        )

    def get_physical_tokens_inventory(self):
        return json.loads(self._http_request(method="GET", url_suffix="/reports/physical_tokens_inventory/", resp_type="text"))

    def get_registered_devices_distribution(self):
        return json.loads(
            self._http_request(
                method="GET", url_suffix="/reports/device_inventory/?fields=associated_and_registered", resp_type="text"
            )
        )

    def get_registration(self, begindate=None, enddate=None, userinformation=False):
        if begindate is None:
            begindate = (datetime.now() - timedelta(days=90)).strftime("%Y-%m-%d")

        if enddate is None:
            enddate = (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%d")

        return json.loads(
            self._http_request(
                method="GET",
                url_suffix=f"/reports/registrations/?begin_date={begindate}&end_date={enddate}&user_information={str(userinformation)}",
                resp_type="text",
            )
        )

    def get_users_associations_indicators(self):
        return json.loads(self._http_request(method="GET", url_suffix="/reports/users/", resp_type="text"))

    def list_incidents(self, page, search, locked, query_filter=None) -> dict[str, Any]:
        if page is None:
            page = 1

        p_search = ""
        if search is not None and search != "":
            p_search = f"&search={search}"

        p_locked = ""
        if locked is not None and locked:
            p_locked = "&locked={}".format("true")

        p_query_filter = ""
        if query_filter is not None and search != "":
            p_query_filter = f"&q={query_filter}"

        return json.loads(
            self._http_request(
                method="GET", url_suffix=f"/transactionlog/?page={page}{p_search}{p_locked}{p_query_filter}", resp_type="text"
            )
        )


def get_associated_users(client, args):
    devicetype = args.get("devicetype")
    result_raw = client.get_associated_users(devicetype)
    result = remove_empty_elements(result_raw)

    readable_output = tableToMarkdown(
        "Get Associated Users Results",
        result,
        headers=list(result.keys()),
        headerTransform=string_to_table_header,
    )
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="GetAssociatedUsers.Result",
        outputs_key_field="",
        outputs=result,
        raw_response=result_raw,
    )

    return command_results


def get_authentication_methods_distribution(client, args):
    result_raw = client.get_authentication_methods_distribution()

    result = remove_empty_elements(result_raw)

    readable_output = tableToMarkdown(
        "Get Authentication Methods Distribution Results",
        result,
        headers=list(result.keys()),
        headerTransform=string_to_table_header,
    )
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="GetAuthenticationMethodsDistribution.Result",
        outputs_key_field="",
        outputs=result,
        raw_response=result_raw,
    )

    return command_results


def get_authentication_rate_per_device(client, args):
    result_raw = client.get_authentication_rate_per_device()

    result = remove_empty_elements(result_raw)

    readable_output = tableToMarkdown(
        "Get Authentication Rate Per Device Results",
        result,
        headers=list(result.keys()),
        headerTransform=string_to_table_header,
    )
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="GetAuthenticationRatePerDevice.Result",
        outputs_key_field="",
        outputs=result,
        raw_response=result_raw,
    )

    return command_results


def get_least_active_users(client, args):
    sincedate = args.get("sincedate")
    userinformation = args.get("userinformation")

    result_raw = client.get_least_active_users(sincedate, userinformation)

    result = remove_empty_elements(result_raw)

    readable_output = tableToMarkdown(
        "Get Least Active Users Results",
        result,
        headers=list(result.keys()),
        headerTransform=string_to_table_header,
    )
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="GetLeastActiveUsers.Result",
        outputs_key_field="",
        outputs=result,
        raw_response=result_raw,
    )

    return command_results


def get_licenses_inventory(client, args):
    result_raw = client.get_licenses_inventory()

    result = remove_empty_elements(result_raw)

    readable_output = tableToMarkdown(
        "Get Licenses Inventory Results",
        result,
        headers=list(result.keys()),
        headerTransform=string_to_table_header,
    )
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="GetLicensesInventory.Result",
        outputs_key_field="",
        outputs=result,
        raw_response=result_raw,
    )

    return command_results


def get_licenses_usage(client, args):
    begindate = args.get("begindate")
    enddate = args.get("enddate")

    result_raw = client.get_licenses_usage(begindate, enddate)

    result = remove_empty_elements(result_raw)

    readable_output = tableToMarkdown(
        "Get Licenses Usage Results",
        result,
        headers=list(result.keys()),
        headerTransform=string_to_table_header,
    )
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="GetLicensesUsage.Result",
        outputs_key_field="",
        outputs=result,
        raw_response=result_raw,
    )

    return command_results


def get_most_active_users(client, args):
    days = args.get("days")
    limit = args.get("limit")
    userinformation = args.get("userinformation")

    result_raw = client.get_most_active_users(days, limit, userinformation)

    result = remove_empty_elements(result_raw)

    readable_output = tableToMarkdown(
        "Get Most Active Users Results",
        result,
        headers=list(result.keys()),
        headerTransform=string_to_table_header,
    )
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="GetMostActiveUsers.Result",
        outputs_key_field="",
        outputs=result,
        raw_response=result_raw,
    )

    return command_results


def get_physical_tokens_inventory(client, args):
    result_raw = client.get_physical_tokens_inventory()

    result = remove_empty_elements(result_raw)

    readable_output = tableToMarkdown(
        "Get Physical Tokens Inventory Results",
        result,
        headers=list(result.keys()),
        headerTransform=string_to_table_header,
    )
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="GetPhysicalTokensInventory.Result",
        outputs_key_field="",
        outputs=result,
        raw_response=result_raw,
    )

    return command_results


def get_registered_devices_distribution(client, args):
    result_raw = client.get_registered_devices_distribution()

    result = remove_empty_elements(result_raw)

    readable_output = tableToMarkdown(
        "Get Registered Devices Distribution Results",
        result,
        headers=list(result.keys()),
        headerTransform=string_to_table_header,
    )
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="GetRegisteredDevicesDistribution.Result",
        outputs_key_field="",
        outputs=result,
        raw_response=result_raw,
    )

    return command_results


def get_registration(client, args):
    begindate = args.get("begindate")
    enddate = args.get("enddate")
    userinformation = args.get("userinformation")

    result_raw = client.get_registration(begindate, enddate, userinformation)

    result = remove_empty_elements(result_raw)

    readable_output = tableToMarkdown(
        "Get Registration Results",
        result,
        headers=list(result.keys()),
        headerTransform=string_to_table_header,
    )
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="GetRegistration.Result",
        outputs_key_field="",
        outputs=result,
        raw_response=result_raw,
    )

    return command_results


def get_users_associations_indicators(client, args):
    result_raw = client.get_users_associations_indicators()

    result = remove_empty_elements(result_raw)

    readable_output = tableToMarkdown(
        "Get Users Associations Indicators Results",
        result,
        headers=list(result.keys()),
        headerTransform=string_to_table_header,
    )
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="GetUsersAssociationsIndicators.Result",
        outputs_key_field="",
        outputs=result,
        raw_response=result_raw,
    )

    return command_results


def test_module(client, is_fetch, last_run, first_fetch_str, fetch_limit):
    if argToBoolean(is_fetch):
        results, next_run = fetch_incidents(client, last_run, first_fetch_str, fetch_limit)
        if results and len(results) > 0:
            results = results[0].get("rawJSON")
            if results:
                results = json.loads(results)
                if results.get("reason_detail") == "Invalid credentials":
                    return "Failed to run test, invalid credentials."
            else:
                return "ok"
    else:
        results = client.list_incidents(None, None, None, None)

    if results:
        results = results.get("results")
        if results and len(results) > 0:
            if results[0].get("reason_detail") == "Invalid credentials":
                return "Failed to run test, invalid credentials."
            else:
                return "ok"
        return None
    else:
        return "Failed to run test."


def fetch_incidents(client, last_run, first_fetch_str, fetch_limit, query_filter=None):
    incidents = []

    first_fetch_date = dateparser.parse(first_fetch_str)
    assert first_fetch_date is not None, f"could not parse {first_fetch_str}"
    first_fetch = first_fetch_date.strftime(DATE_FORMAT)
    last_run_time = last_run.get("last_run_time", first_fetch)
    next_run_time = last_run_time

    # Last run time must be used to filter transaction log
    results = []
    if query_filter and query_filter:
        q_list = query_filter.split(",")
        for q in q_list:
            if q:
                tmp = client.list_incidents(None, None, None, q).get("results")
                results.extend([element for element in tmp if element not in results])
    else:
        results = client.list_incidents(None, None, None, query_filter).get("results")

    for result in results:
        timestamp_date = dateparser.parse(result.get("timestamp"))
        assert timestamp_date is not None
        incident_time = timestamp_date.strftime(DATE_FORMAT)

        # This condition is temporal
        if incident_time > last_run_time:
            incident = {"name": result.get("reason_detail"), "occurred": incident_time, "rawJSON": json.dumps(result)}
            incidents.append(incident)

            if incident_time > next_run_time:
                next_run_time = incident_time

    next_run = {"last_run_time": next_run_time}

    return incidents[: int(fetch_limit)], next_run


def main():
    params = demisto.params()
    command = demisto.command()
    args = demisto.args()
    base_url = params.get("url")
    if base_url:
        base_url = base_url + "/api/v1/admin/"
    demisto.info(f"BASE_URL: {base_url}")
    verify_certificate = not params.get("insecure", False)
    auth_access_token = params.get("apikey")
    proxy = params.get("proxy", False)

    is_fetch = params.get("isFetch", False)
    fetch_limit = params.get("max_fetch", 50)
    first_fetch_str = params.get("first_fetch", "0")
    fetch_query_filter = params.get("fetch_query_filter")

    demisto.debug(f"Command being called is {command}")
    try:
        client = Client(
            base_url=base_url, verify=verify_certificate, headers={"Authorization": f"Bearer {auth_access_token}"}, proxy=proxy
        )

        if command == "safewalk-get-associated-users":
            result = get_associated_users(client, args)
            return_results(result)

        if command == "safewalk-get-authentication-methods-distribution":
            result = get_authentication_methods_distribution(client, args)
            return_results(result)

        if command == "safewalk-get-authentication-rate-per-device":
            result = get_authentication_rate_per_device(client, args)
            return_results(result)

        if command == "safewalk-get-least-active-users":
            result = get_least_active_users(client, args)
            return_results(result)

        if command == "safewalk-get-licenses-inventory":
            result = get_licenses_inventory(client, args)
            return_results(result)

        if command == "safewalk-get-licenses-usage":
            result = get_licenses_usage(client, args)
            return_results(result)

        if command == "safewalk-get-most-active-users":
            result = get_most_active_users(client, args)
            return_results(result)

        if command == "safewalk-get-physical-tokens-inventory":
            result = get_physical_tokens_inventory(client, args)
            return_results(result)

        if command == "safewalk-get-registered-devices-distribution":
            result = get_registered_devices_distribution(client, args)
            return_results(result)

        if command == "safewalk-get-registration":
            result = get_registration(client, args)
            return_results(result)

        if command == "safewalk-get-users-associations-indicators":
            result = get_users_associations_indicators(client, args)
            return_results(result)

        if command == "test-module":
            result = test_module(client, is_fetch, demisto.getLastRun(), first_fetch_str, fetch_limit)
            return_results(result)

        if command == "fetch-incidents":
            last_run = demisto.getLastRun()
            incidents, next_run = fetch_incidents(client, last_run, first_fetch_str, fetch_limit, fetch_query_filter)
            demisto.incidents(incidents)
            demisto.setLastRun(next_run)

    except Exception as e:
        return_error(f"Failed to execute {command} command. Error: {str(e)}")


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