import os import sys import logging from sys import platform from urllib.parse import quote, unquote APP = "splunk_app_soar" CERT_FILE_LOCATION_DEFAULT = os.path.join( os.environ["SPLUNK_HOME"], "etc", "apps", APP, "default", "cert_bundle.pem" ) CERT_FILE_LOCATION_LOCAL = os.path.join( os.environ["SPLUNK_HOME"], "etc", "apps", APP, "local", "cert_bundle.pem" ) splunkhome = os.environ["SPLUNK_HOME"] sys.path.append(os.path.join(splunkhome, "etc", "apps", APP, "bin")) sys.path.append(os.path.join(splunkhome, "etc", "apps", APP, "lib")) # needs to happen after # required # from soar_utils import setup_logging if platform == "linux" or platform == "linux2": sys.path.append(os.path.join(splunkhome, "etc", "apps", APP, "lib", "linux")) elif platform == "darwin": sys.path.append(os.path.join(splunkhome, "etc", "apps", APP, "lib", "mac")) import splunk.entity as entity import json import requests import aiohttp import asyncio from splunk.clilib import cli_common as cli # logging: # To avoid overriding logging destination of callers, the libs will not set on purpose any logging definition # and rely on callers themselves class SOARClient: server_url = None auth_token = None verify = True def __init__(self, server_url, auth_token): self.server_url = server_url self.auth_token = auth_token self.fetch_verify_certs() def fetch_verify_certs(self): cfg = cli.getConfStanza("soar", "verify_certs") value = cfg.get("value") if value == "true" and os.path.isfile(CERT_FILE_LOCATION_LOCAL): self.verify = CERT_FILE_LOCATION_LOCAL elif value == "true" and os.path.isfile(CERT_FILE_LOCATION_DEFAULT): self.verify = CERT_FILE_LOCATION_DEFAULT else: self.verify = False def make_request( self, endpoint, method, data, page=0, page_size=100, extra_params=None, **kwargs ): if extra_params is None: extra_params = {} url = self.server_url + "/rest/" + endpoint headers = {"Accept": "application/json", "ph-auth-token": self.auth_token} params = {"page": page, "page_size": page_size} # Merge extra_params into params, with extra_params taking precedence params.update(extra_params) if data and method == "POST": return requests.request( method=method, url=url, headers=headers, verify=self.verify, data=json.dumps(data), params=params, **kwargs, ) else: return requests.request( method=method, url=url, headers=headers, verify=self.verify, params=params, **kwargs, ) async def read_url(self, session, url, record): async with session.get(url) as resp: res_json = await resp.json() record["soar_response"] = res_json return record async def make_request_async(self, records, endpoint, method="GET", **kwargs): tasks = [] headers = {"Accept": "application/json", "ph-auth-token": self.auth_token} async with aiohttp.ClientSession( headers=headers, connector=aiohttp.TCPConnector(ssl=False) ) as session: for record in records: url = self.server_url + "/rest/" + record["endpoint"] tasks.append(asyncio.create_task(self.read_url(session, url, record))) return await asyncio.gather(*tasks)