Genetec Security Center Event Collector

Genetec Security Center Audit Trail Event Collector.

Analytics & SIEM · Genetec Security Center

Details

IDGenetec Security Center Event Collector
ProviderGenetec
CategoryAnalytics & SIEM
From Version6.8.0
Docker Imagedemisto/xml-feed:1.0.0.10133006
Supported ModulesXSIAM

README

Security Center is the foundation of our unified security portfolio. It lets you connect your security at your own pace, starting with a single core system. Even if you’re only interested in upgrading your video surveillance or access control, taking the next step is easy.

Configure Armis Event Collector in Cortex

Parameter Description Required
Your server URL   True
Username Username and Password. True
Password   True
Application ID   True
Trust any certificate (not secure)   False
Use system proxy settings   False
Maximum number of events per fetch Alerts and activity events.  
Use system proxy settings for external requests Use this if you wish to use proxy setting for external requests (such as sending events) when running with an engine.  

Commands

You can execute these commands in the War Room in the CLI in Cortex XSIAM.

genetec-security-center-get-events


Manual command to fetch events and display them.

Base Command

genetec-security-center-get-events

Input

Argument Name Description Required
limit The maximum amount of events to retrieve. Optional
should_push_events Set this argument to True in order to create events, otherwise the command will only display them. Required
start_time The start time to fetch_from, should be in the format of YYYY-MM-DDTHH:MM:SS (e.g. 2024-02-21T23:00:00). Optional

Context Output

There is no context output for this command.

Configuration parameters

  • url — Server URL (e.g., http://192.168.10.1:52311) (required)
  • credentials — Username (required)
  • app_id — Application ID (required)
  • max_fetch — Maximum number of events per fetch
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (1)

  • genetec-security-center-get-events

    Manual execution of fetch-events. Use this for debugging purposes.

import html
import json

import demistomock as demisto
from CommonServerPython import *  # noqa # pylint: disable=unused-wildcard-import
from requests.auth import HTTPBasicAuth
from urllib3 import disable_warnings
from xmltodict import parse

from CommonServerUserPython import *  # noqa

disable_warnings()

""" CONSTANTS """

VENDOR = "Genetec"
PRODUCT = "Security center"
DATE_FORMAT_EVENT = "%Y-%m-%dT%H:%M:%S"
AUDIT_TRAIL_ENDPOINT = "/WebSdk/report/AuditTrail"
GET_EVENTS_HEADERS = [
    "Id",
    "Guid",
    "ModificationTimeStamp",
    "ModifiedBy",
    "SourceApplicationGuid",
    "Name",
    "ModifiedByAsString",
    "SourceApplicationAsString",
    "Machine",
    "SourceApplicationType",
    "OldValue",
    "NewValue",
    "CustomFieldId",
    "CustomFieldName",
    "CustomFieldValueType",
    "AuditTrailModificationType",
    "Type",
    "Description",
    "AuditTrailModificationSubTypes",
    "Value",
]


""" CLIENT CLASS """


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

    :param base_url (str): The server URL.
    :param username (str): The account username.
    :param password (str): The account password.
    :param app_id (str): The app ID.
    :param max_fetch (str): The maximum number of events to fetch per interval.
    :param verify (bool): specifies whether to verify the SSL certificate or not.
    :param proxy (bool): specifies if to use XSOAR proxy settings.
    """

    def __init__(self, base_url: str, username: str, password: str, verify: bool, proxy: bool, max_fetch: str, app_id: str):
        auth = self._encode_authorization(username, password, app_id)
        self.limit = max_fetch

        super().__init__(base_url=base_url, verify=verify, proxy=proxy, auth=auth, headers={"Accept": "text/json"})

    def _encode_authorization(self, username: str, password: str, app_id: str):
        updated_username = f"{username};{app_id}"
        return HTTPBasicAuth(updated_username, password)

    def http_request(self, url_suffix):
        response_audit = self._http_request("GET", url_suffix=url_suffix, resp_type="response")
        response = json.loads(response_audit.content)["Rsp"]
        if response["Status"] == "Fail":
            raise DemistoException(response["Result"])
        return response["Result"]


""" COMMAND FUNCTIONS """


def test_module(client: Client):
    """
    Testing we have a valid connection to Genetec security center.
    """
    time_now: datetime = datetime.utcnow()
    start_time: datetime = time_now - timedelta(minutes=1)
    time_now_str = time_now.strftime(DATE_FORMAT_EVENT)
    start_time_str = start_time.strftime(DATE_FORMAT_EVENT)
    query = f"TimeRange.SetTimeRange({start_time_str},{time_now_str})"
    url_suffix = f"{AUDIT_TRAIL_ENDPOINT}?q={query}"
    client.http_request(url_suffix=url_suffix)
    return "ok"


def fetch_events_command(
    client: Client,
    args: dict[str, str],
    last_run: dict,
) -> tuple[list[dict], dict]:
    """
    Args:
        client (Client): The client for api calls.
        args (dict[str, str]): The args.
        last_run (dict): The last run dict.

    Returns:
        tuple[list[dict], dict]: List of all event logs of all types,
                                 The updated `last_run` obj.
    """
    time_now: datetime = datetime.utcnow()
    start_time: datetime
    start_time_str: str = ""
    if args.get("start_time"):
        start_time_str = args.get("start_time", "")
    elif not last_run:
        start_time = time_now - timedelta(minutes=1)
        start_time_str = start_time.strftime(DATE_FORMAT_EVENT)
    else:
        start_time_str = last_run.get("start_time", "")
    time_now_str = time_now.strftime(DATE_FORMAT_EVENT)
    if end_time := args.get("end_time"):
        time_now_str = end_time
    time_range = f"TimeRange.SetTimeRange({start_time_str},{time_now_str})"
    limit: int = int(args.get("limit") or client.limit)
    query: str = f"{time_range},SortOrder=Ascending"
    url_suffix = f"{AUDIT_TRAIL_ENDPOINT}?q={query}"
    demisto.info(f"executing fetch events with the following query: {query}")
    response = client.http_request(url_suffix=url_suffix)
    results = response[:limit]
    for result in results:
        result["Value"] = parse(html.unescape(result.get("Value")))
        result["_time"] = result["ModificationTimeStamp"]
    cached_audits: List[str] = last_run.get("audit_cache", [])
    updated_results, updated_cached_audits = remove_duplicated_events(results, cached_audits)
    last_run["audit_cache"] = updated_cached_audits
    if updated_results:
        last_run["start_time"] = (
            datetime.strptime(updated_results[-1]["ModificationTimeStamp"], "%Y-%m-%dT%H:%M:%S.%fZ")
        ).strftime(DATE_FORMAT_EVENT)
    else:
        demisto.info("No new events were fetched. Therefore, setting last_run object to point to now.")
        last_run["start_time"] = time_now_str
    return updated_results, last_run


def remove_duplicated_events(results: List[dict], cached_audits: List[str]) -> tuple[List[dict], List[str]]:
    updated_results: List[dict] = []
    updated_cached_audits: List[str] = []
    removed_events: List[str] = []
    for result in results:
        if (event_guid := result.get("Guid", "")) in cached_audits:
            removed_events.append(str(event_guid))
        else:
            updated_results.append(result)
            updated_cached_audits.append(event_guid)
    if removed_events:
        demisto.info(f"The following events were deduplicated: {', '.join(removed_events)}.")
    return updated_results, updated_cached_audits


def main() -> None:  # pragma: no cover
    params = demisto.params()
    args = demisto.args()

    base_url = params["url"].strip("/")
    username = params["credentials"]["identifier"]
    password = params["credentials"]["password"]
    app_id = params["app_id"]
    max_fetch = params.get("max_fetch", "1000")
    verify = not params.get("insecure", False)
    proxy = params.get("proxy", False)
    should_push_events = argToBoolean(args.get("should_push_events", False))
    should_save_last_run = False

    command = demisto.command()
    try:
        client = Client(
            base_url=base_url,
            username=username,
            password=password,
            max_fetch=max_fetch,
            app_id=app_id,
            verify=verify,
            proxy=proxy,
        )

        if command == "test-module":
            return_results(test_module(client))

        elif command == "genetec-security-center-get-events":
            events, _ = fetch_events_command(client, args, {})
            return_results(CommandResults(readable_output=tableToMarkdown("Events:", events, headers=GET_EVENTS_HEADERS)))

        elif command == "fetch-events":
            should_push_events, should_save_last_run = True, True
            last_run = demisto.getLastRun()
            events, last_run = fetch_events_command(client, params, last_run=last_run)
        else:
            raise NotImplementedError(f"Command {command} is not implemented.")
        if should_push_events:
            send_events_to_xsiam(events=events, vendor=VENDOR, product=PRODUCT, add_proxy_to_request=proxy)
            demisto.info(f"{len(events)} events were pushed to XSIAM")

        if should_save_last_run:
            demisto.setLastRun(last_run)
            demisto.info(f"set last run time: {last_run.get('start_time')}")

    except Exception as e:
        return_error(f"Failed to execute {command} command. Error in Genetec Security Center Event Collector Integration [{e}].")


""" ENTRY POINT """

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