TeamViewer Event Collector

TeamViewer event collector integration for Cortex XSIAM.

Analytics & SIEM · TeamViewer

Details

IDTeamViewer Event Collector
ProviderTeamViewer
CategoryAnalytics & SIEM
From Version6.8.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesXSIAM

README

TeamViewer event collector integration for Cortex XSIAM.
This integration was integrated and tested with version 15.40 of TeamViewer.
User access token scope: Event logging - Allow requesting all event logs.
A Tensor license is required.

Configure TeamViewer Event Collector in Cortex

Parameter Description Required
Your server URL   True
Script Token The script token to use for connection True
Trust any certificate (not secure)   False
Use system proxy settings   False
First fetch time   False
The maximum number of alerts per fetch   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.

teamviewer-get-events


Gets events from TeamViewer.

Base Command

teamviewer-get-events

Input

Argument Name Description Required
should_push_events If true, the command will create events, otherwise it will only display them. Possible values are: true, false. Default is false. Required
limit Maximum number of results to return. Optional

Context Output

There is no context output for this command.

Configuration parameters

  • url — Server URL (required)
  • credentials — (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • first_fetch — First fetch time (<number> <time unit>, e.g., 12 hours, 7 days) - within the last 12 months. Recommended time is 3 days.
  • max_fetch — The maximum number of alerts per fetch

Commands (1)

  • teamviewer-get-events

    Gets events from TeamViewer.

from datetime import datetime
from typing import Any

import demistomock as demisto
import urllib3
from CommonServerPython import *  # noqa # pylint: disable=unused-wildcard-import

from CommonServerUserPython import *  # noqa

# Disable insecure warnings
urllib3.disable_warnings()


""" CONSTANTS """

DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"  # ISO8601 format with UTC, default in XSOAR
DEFAULT_LIMIT = 300
VENDOR = "teamviewer"
PRODUCT = "tensor"

""" CLIENT CLASS """


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

    def __init__(self, base_url, verify, proxy, headers):
        super().__init__(base_url=base_url, verify=verify, proxy=proxy, headers=headers)

    def get_if_token_valid(self):
        return self._http_request(method="GET", url_suffix="/api/v1/ping", headers=self._headers)

    def get_events(self, params=None, body=None):
        return self._http_request(
            method="POST", url_suffix="/api/v1/EventLogging", headers=self._headers, params=params, data=body
        )


""" HELPER FUNCTIONS """


def search_events(client: Client, limit: int, body: dict[str, Any] | None = None) -> tuple[list[dict[str, Any]], CommandResults]:
    """
    Searches for T alerts.
    Args:
        client: Client, client to use.
        limit: int, the limit of the results to return.
        body: dict, contains the time parameters.
    Returns:
        list: A list containing the events
    """
    results: list[dict] = []
    token_next_page = None
    next_page = True
    if limit <= 0:
        raise DemistoException("the limit argument cannot be negative or zero.")
    while next_page:
        response = client.get_events(body=body)
        demisto.debug(f"http response:\n {response}")
        results += response.get("AuditEvents", [])
        next_page = response.get("ContinuationToken")
        if token_next_page := response.get("ContinuationToken"):
            if not body:
                body = {}
            body["ContinuationToken"] = token_next_page
        else:
            next_page = False
            demisto.debug("finished fetching http response")
    events: list[dict[str, Any]] = sorted(results, key=lambda x: x["Timestamp"])
    if limit < len(events):
        events = events[-limit:]
    hr = tableToMarkdown(name="Events", t=events) if events else "No events found."
    return events, CommandResults(readable_output=hr)


""" COMMAND FUNCTIONS """


def test_module(client: Client, first_fetch_time: datetime) -> 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

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

    message: str = "Authorization Error: make sure bearer token format is correctly set"
    try:
        res = client.get_if_token_valid()
        if argToBoolean(res.get("token_valid")):
            message = "ok"
    except DemistoException as e:
        raise e
    return message


def fetch_events_command(
    client: Client, max_fetch: int, last_run: dict[str, Any], first_fetch_time: datetime
) -> tuple[dict[str, Any], list[dict[str, Any]]]:
    """
    Args:
        client (Client): TeamViewer client to use.
        max_fetch (int): The maximum number of events to fetch per log type.
        last_run (dict): A dict with a keys containing the first event id to fetch for each log type.
        first_fetch_time (str): In case of first fetch, fetch events from this date.
    Returns:
        dict: Next run dictionary containing the ids of the next events to fetch.
        list: List of events that will be created in XSIAM.
    """
    last_fetch = last_run.get("last_fetch")
    last_fetch = first_fetch_time if last_fetch is None else datetime.strptime(last_fetch, DATE_FORMAT)
    demisto.debug(f"last fetch :\n {last_fetch}")
    body = {
        "StartDate": (last_fetch + timedelta(seconds=1)).strftime(DATE_FORMAT),
        "EndDate": datetime.utcnow().strftime(DATE_FORMAT),
    }
    demisto.debug(f"TeamViewer starting fetch events with time params:\n {body}")
    events, _ = search_events(client=client, limit=max_fetch, body=body)
    next_run = {"last_fetch": events[-1].get("Timestamp")} if events else last_run
    demisto.debug(f"TeamViewer Returning {len(events)} events in total")
    return next_run, events


def add_time_key_to_events(events: list[dict[str, Any]]) -> list[dict[str, Any]]:
    """
    Adds the _time key to the events.
    Args:
        events: list, the events to add the time key to.
    Returns:
        list: The events with the _time key.
    """
    for event in events:
        if event.get("Timestamp"):
            event["_time"] = event.get("Timestamp")
    return events


""" MAIN FUNCTION """


def main() -> None:
    """
    main function, parses params and runs command functions
    """
    params = demisto.params()
    args = demisto.args()
    command = demisto.command()
    api_key = params.get("credentials", {}).get("password")
    base_url = params.get("url")
    verify_certificate = not params.get("insecure", True)
    proxy = params.get("proxy", False)
    first_fetch_time: datetime = arg_to_datetime(
        arg=params.get("first_fetch", "3 days"),
        arg_name="First fetch time",
        required=True,
    )  # type: ignore
    demisto.debug(f"Command being called is {command}")
    try:
        headers = {"Authorization": f"Bearer {api_key}"}
        client = Client(base_url=base_url, verify=verify_certificate, headers=headers, proxy=proxy)
        if command == "test-module":
            # This is the call made when pressing the integration Test button.
            result = test_module(client, first_fetch_time)
            return_results(result)

        elif command in ("teamviewer-get-events", "fetch-events"):
            if command == "teamviewer-get-events":
                should_push_events = argToBoolean(args.get("should_push_events"))
                events, results = search_events(
                    client=client,
                    limit=arg_to_number(args.get("limit")) or DEFAULT_LIMIT,
                    body={
                        "StartDate": first_fetch_time.strftime(DATE_FORMAT),
                        "EndDate": datetime.utcnow().strftime(DATE_FORMAT),
                    },  # type: ignore
                )
                if should_push_events:
                    send_events_to_xsiam(events, vendor=VENDOR, product=PRODUCT)
                return_results(results)

            else:
                # the command is fetch-events
                should_push_events = True
                last_run = demisto.getLastRun()
                next_run, events = fetch_events_command(
                    client=client,
                    max_fetch=arg_to_number(params.get("max_fetch")) or DEFAULT_LIMIT,
                    last_run=last_run,
                    first_fetch_time=first_fetch_time,
                )
                demisto.debug(f"TeamViewer last run: {last_run} \n next run: {next_run}")
                demisto.debug(f"Number of events: {len(events)}")
                events = add_time_key_to_events(events)
                send_events_to_xsiam(events, vendor=VENDOR, product=PRODUCT)
                if next_run:
                    # saves next_run for the time fetch-events is invoked
                    demisto.setLastRun(next_run)
        # Log exceptions and return errors
    except Exception as e:
        return_error(f"Failed to execute {command} command.\nError:\n{e!s}")


""" ENTRY POINT """


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