You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Splunk_Deploiement/apps/trackme/lib/trackme_libs_soar.py

203 lines
5.7 KiB

#!/usr/bin/env python
# coding=utf-8
__author__ = "TrackMe Limited"
__copyright__ = "Copyright 2022-2026, TrackMe Limited, U.K."
__credits__ = "TrackMe Limited, U.K."
__license__ = "TrackMe Limited, all rights reserved"
__version__ = "0.1.0"
__maintainer__ = "TrackMe Limited, U.K."
__email__ = "support@trackme-solutions.com"
__status__ = "PRODUCTION"
# Standard library imports
import os
import sys
import re
# Networking and URL handling imports
from urllib.parse import urlencode
import urllib3
# Disable insecure request warnings for urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# splunk home
splunkhome = os.environ["SPLUNK_HOME"]
# append lib
sys.path.append(os.path.join(splunkhome, "etc", "apps", "trackme", "lib"))
# import Splunk libs
import splunklib.client as client
# logging:
# To avoid overriding logging destination of callers, the libs will not set on purpose any logging definition
# and rely on callers themselves
# get the soar account password
def get_soar_password(storage_passwords, soar_id):
# realm
credential_realm = (
"__REST_CREDENTIAL__#splunk_app_soar#configs/conf-ta_splunk_app_soar_account"
)
credential_name = f"{credential_realm}:{soar_id}``"
# extract as raw json
bearer_token_rawvalue = ""
for credential in storage_passwords:
if credential.content.get("realm") == str(
credential_realm
) and credential.name.startswith(credential_name):
bearer_token_rawvalue = bearer_token_rawvalue + str(
credential.content.clear_password
)
# extract a clean json object
bearer_token_rawvalue_match = re.search(
r'\{"password":\s*"(.*)"\}', bearer_token_rawvalue
)
if bearer_token_rawvalue_match:
bearer_token = bearer_token_rawvalue_match.group(1)
else:
bearer_token = None
return bearer_token
# return the list of accounts configured, or None if not any
def trackme_get_soar_accounts(reqinfo):
# get service
service = client.connect(
owner="nobody",
app="splunk_app_soar",
port=reqinfo.server_rest_port,
token=reqinfo.system_authtoken,
timeout=600,
)
# get all acounts
accounts = []
conf_file = "ta_splunk_app_soar_account"
# if there are no account, raise an exception, otherwise what we would do here?
try:
confs = service.confs[str(conf_file)]
except Exception as e:
error_msg = (
"trackmesplksoar was called but we have no SOAR account configured yet"
)
raise Exception(error_msg)
for stanza in confs:
for key, value in stanza.content.items():
if key == "custom_name":
soar_custom_name = value
accounts.append(soar_custom_name)
if accounts:
return accounts
else:
return None
# Get SOAR account credentials, designed to be used for a least privileges approach in a programmatic approach
def trackme_get_soar_account(reqinfo, account):
# get service
service = client.connect(
owner="nobody",
app="splunk_app_soar",
port=reqinfo.server_rest_port,
token=reqinfo.system_authtoken,
timeout=600,
)
# Splunk credentials store
storage_passwords = service.storage_passwords
# get all acounts
accounts = []
conf_file = "ta_splunk_app_soar_account"
# if there are no account, raise an exception, otherwise what we would do here?
try:
confs = service.confs[str(conf_file)]
except Exception as e:
error_msg = (
"trackmesplksoar was called but we have no SOAR account configured yet"
)
raise Exception(error_msg)
for stanza in confs:
for key, value in stanza.content.items():
if key == "custom_name":
soar_custom_name = value
accounts.append(soar_custom_name)
# account configuration
isfound = False
soar_id = None
soar_custom_name = None
soar_server = None
soar_username = None
# get account
if account in accounts:
isfound = True
if isfound:
for stanza in confs:
for key, value in stanza.content.items():
if key == "custom_name":
soar_custom_name = value
if soar_custom_name != account:
break
else:
soar_id = stanza.name
if key == "server":
soar_server = value
if key == "username":
soar_username = value
# end of get configuration
# Stop here if we cannot find the submitted account
if not isfound:
error_msg = f'The account="{account}" has not been configured on this instance, cannot proceed!'
raise Exception(
{
"status": "failure",
"message": error_msg,
"account": account,
}
)
# get the bearer token stored encrypted
soar_password = get_soar_password(storage_passwords, soar_id)
if not soar_password:
error_msg = f'The password for the account="{account}" could not be retrieved, cannot proceed!'
raise Exception(
{
"status": "failure",
"message": error_msg,
"account": account,
"server": soar_server,
"id": soar_id,
}
)
else:
# render
return {
"status": "success",
"message": "SOAR account is ready",
"account": account,
"custom_name": soar_custom_name,
"server": soar_server,
"username": soar_username,
"password": soar_password,
}