diff --git a/TA-egnyte-connect/app.manifest b/TA-egnyte-connect/app.manifest index 6113b51..01e91c6 100644 --- a/TA-egnyte-connect/app.manifest +++ b/TA-egnyte-connect/app.manifest @@ -5,7 +5,7 @@ "id": { "group": null, "name": "TA-egnyte-connect", - "version": "1.0.6" + "version": "1.0.7" }, "author": [ { diff --git a/TA-egnyte-connect/appserver/static/js/build/globalConfig.json b/TA-egnyte-connect/appserver/static/js/build/globalConfig.json index be669ae..e632875 100644 --- a/TA-egnyte-connect/appserver/static/js/build/globalConfig.json +++ b/TA-egnyte-connect/appserver/static/js/build/globalConfig.json @@ -2,7 +2,7 @@ "meta": { "name": "TA-egnyte-connect", "displayName": "Egnyte Collaborate Add-on for Splunk", - "version": "1.0.3", + "version": "1.0.7", "apiVersion": "3.0.0", "restRoot": "TA_egnyte_connect" }, diff --git a/TA-egnyte-connect/bin/input_module_egnyte_connect.py b/TA-egnyte-connect/bin/input_module_egnyte_connect.py index 43910f1..d537f09 100644 --- a/TA-egnyte-connect/bin/input_module_egnyte_connect.py +++ b/TA-egnyte-connect/bin/input_module_egnyte_connect.py @@ -4,14 +4,14 @@ import time import datetime import json -from solnlib.splunkenv import get_splunkd_uri -from solnlib.credentials import (CredentialManager, CredentialNotExistException) from datetime import datetime, timedelta from ta_egnyte_connect_utility import * import ta_egnyte_connect_constants as tec import splunk.rest as rest APP_NAME = os.path.abspath(__file__).split(os.sep)[-3] +import splunklib.client as client + ''' IMPORTANT Edit only the validate_input and collect_events functions. @@ -82,12 +82,15 @@ def collect_events(helper, ew): auth_url = str(egnyte_domain_url) + "/puboauth/token" mapping_data_type={"FILE_AUDIT": "file", "PERMISSION_AUDIT": "permission", "LOGIN_AUDIT": "login", "USER_AUDIT": "user", "WG_SETTINGS_AUDIT": "wg_settings", "GROUP_AUDIT": "group", "WORKFLOW_AUDIT": "workflow"} checkpoint = get_checkpoint(helper, key=account_name, start_date=start_date) or dict() + + service = client.connect(host='localhost', port=8089, + username='admin', password='admin123') + # Going to take access/refresh token if it is not available in the checkpoint if not checkpoint or str(checkpoint.get("code")) != str(code): helper.log_info("Checkpoint is not available or code changed from setup page. Hence requesting new access token.") try: response = generate_or_refresh_token(helper=helper, auth_url=auth_url, clientid=clientid, client_secret=client_secret, code=code, redirect_uri=REDIRECT_URI) - helper.log_info("Checkpoint is not available or code changed from setup page. Hence requested new access token.") if response.status_code == 400: helper.log_error("Error while getting access/refresh token error") helper.log_error("Please generate new code and update the input with new code.") @@ -101,9 +104,17 @@ def collect_events(helper, ew): return else: response = response.json() - checkpoint["access_token"] = response.get("access_token") checkpoint["code"] = code set_checkpoint(helper, key=account_name, checkpoint=checkpoint) + + storage_passwords = service.storage_passwords + try: + # Retrieve existing password. This is safeguard in case of any racing condition. + # updating token is not necessary as it is deterministic based on client_id, secret & domain + body = storage_passwords.get(account_name + "/" + code)["body"] + except HTTPError: + storage_passwords.create(response.get("access_token"), account_name + "/" + code) + helper.log_debug("New storage password entry created for {}".format(response.get("access_token"))) except Exception as e: raise e @@ -116,6 +127,9 @@ def collect_events(helper, ew): params = {} if checkpoint_for_input.get("nextCursor"): params['nextCursor']=checkpoint_for_input.get("nextCursor") + + token = get_token_from_secure_password(account_name, code, service, helper, checkpoint, checkpoint_for_input) + while start_date_done: try: # collecting issues from the Egnyte server @@ -126,7 +140,8 @@ def collect_events(helper, ew): params.pop("startDate") params.pop("endDate") data_url = str(egnyte_domain_url) + "/pubapi/v2/audit/stream" - data, response_text = collect_issues(helper, checkpoint.get('access_token'), data_url, params) + + data, response_text = collect_issues(helper, token, data_url, params) if data == 401: helper.log_error("Please generate new code and update the input with new code.") diff --git a/TA-egnyte-connect/bin/ta_egnyte_connect_utility.py b/TA-egnyte-connect/bin/ta_egnyte_connect_utility.py index 7c3c6bf..140b701 100755 --- a/TA-egnyte-connect/bin/ta_egnyte_connect_utility.py +++ b/TA-egnyte-connect/bin/ta_egnyte_connect_utility.py @@ -1,4 +1,8 @@ import requests +from splunklib.binding import HTTPError, ResponseReader +import xml.etree.ElementTree as ET + + def generate_or_refresh_token(helper=None, auth_url=None, clientid=None, client_secret=None, code=None, refresh_token=None, redirect_uri=None): if code: payload = {"client_id": clientid, "client_secret": client_secret, "grant_type": "authorization_code", @@ -13,6 +17,44 @@ def generate_or_refresh_token(helper=None, auth_url=None, clientid=None, client_ return response +def get_token_from_secure_password(account_name, code, service, helper, checkpoint, checkpoint_for_input): + storage_passwords = service.storage_passwords + try: + response = storage_passwords.get(account_name + "/" + code) + reader: ResponseReader = ResponseReader(response["body"]) + + xml_response_str: str = reader.read().decode("UTF-8") + start_tag = "" + end_tag = "" + # getting index of substrings + idx1 = xml_response_str.index(start_tag) + + xml_data_substr = xml_response_str[idx1:] + idx2_from_substring = xml_data_substr.index(end_tag) + idx2 = idx1 + idx2_from_substring + + token: str = '' + # getting elements in between + for idx in range(idx1 + len(start_tag), idx2): + token = token + xml_response_str[idx] + + helper.log_debug("Access token in StoragePassword already exist. Erasing eventual access token from checkpoint.") + checkpoint_for_input.pop("access_token", None) + + return token + + except HTTPError: + helper.log_debug("Unable to find access token in StoragePassword engine. Performing one time " + "migration from checkpoint.") + token = checkpoint.get('access_token') + try: + storage_passwords.create(token, account_name + "/" + code) + helper.log_debug("Access token migrated.") + except HTTPError: + helper.log_debug("Access token already exist. Erasing access token from checkpoint.") + checkpoint_for_input.pop("access_token", None) + + def collect_issues(helper, access_token, data_url, params): headers = {"Authorization": "Bearer " + str(access_token)} response_data = helper.send_http_request(data_url, "GET", parameters=params, payload=None, diff --git a/TA-egnyte-connect/default/app.conf b/TA-egnyte-connect/default/app.conf index fef5a58..c0c4c0c 100644 --- a/TA-egnyte-connect/default/app.conf +++ b/TA-egnyte-connect/default/app.conf @@ -6,7 +6,7 @@ state = enabled build = 1 [launcher] -version = 1.0.6 +version = 1.0.7 author = Egnyte Inc description = This TA provides interface to ingest events from Egnyte Collaborate into Splunk.