Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended logging around connecting to the server #33

Merged
merged 1 commit into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/phantomcyber/dev-cicd-tools
rev: v1.19
rev: v1.24
hooks:
- id: org-hook
- id: package-app-dependencies
Expand Down
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Connector Version: 3.3.0
Product Vendor: Generic
Product Name: SMTP
Product Version Supported (regex): ".\*"
Minimum Product Version: 6.2.1
Minimum Product Version: 6.3.0

This app provides the ability to send email using SMTP

Expand Down Expand Up @@ -257,15 +257,14 @@ This app provides the ability to send email using SMTP
Recipients Test\\n\\nThis is test data.


### Configuration Variables
The below configuration variables are required for this Connector to operate. These variables are specified when configuring a SMTP asset in SOAR.
### Configuration variables
This table lists the configuration variables required to operate SMTP. These variables are specified when configuring a SMTP asset in Splunk SOAR.

VARIABLE | REQUIRED | TYPE | DESCRIPTION
-------- | -------- | ---- | -----------
**server** | required | string | Server IP/Hostname
**port** | optional | numeric | Port
**auth_type** | optional | string | Authentication type to use for connectivity
**ph_0** | optional | ph | Place holder
**username** | optional | string | Username (or email address)
**password** | optional | password | Password (For Basic Auth)
**client_id** | optional | string | OAuth Client ID (For OAuth)
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ verbose = true

[tool.isort]
line_length = 145
profile = "black"
1 change: 1 addition & 0 deletions release_notes/unreleased.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
**Unreleased**
* Extended logging [SOARHELP-4116]
2 changes: 1 addition & 1 deletion smtp.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"product_vendor": "Generic",
"product_name": "SMTP",
"product_version_regex": ".*",
"min_phantom_version": "6.2.1",
"min_phantom_version": "6.3.0",
"rest_handler": "request_handler.handle_request",
"license": "Copyright (c) 2016-2024 Splunk Inc.",
"logo": "logo_splunk.svg",
Expand Down
36 changes: 21 additions & 15 deletions smtp_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ def _with_oauth_type(self, action_result):
return self.set_status(phantom.APP_ERROR, SMTP_DECRYPTION_ERROR)

if phantom.is_fail(self._connect_to_server_helper(action_result)):
self.debug_print("OAuth authentication failed")
return action_result.get_status()

return phantom.APP_SUCCESS
Expand Down Expand Up @@ -173,29 +174,28 @@ def _process_auth_type(self, action_result):
if auth_type == SMTP_PASSWORD_LESS_AUTH_TYPE:
if action_id != SMTP_TEST_CONNECTIVITY:
msg = "Authentication failed for connecting to server with {} types \
of authentication.{}".format(
SMTP_ALLOWED_AUTH_TYPES[1:], SMTP_FAILED_CONNECTIVITY_TEST
of authentication. Message: {}.{}".format(
SMTP_ALLOWED_AUTH_TYPES[1:], msg, SMTP_FAILED_CONNECTIVITY_TEST
)
return action_result.set_status(phantom.APP_ERROR, msg)
else:
return action_result.set_status(phantom.APP_ERROR)
return action_result.set_status(phantom.APP_ERROR)
else:
return phantom.APP_SUCCESS

# Check specific auth type as per input given by user in auth_type parameter
self.save_progress(SMTP_AUTH_MESSAGE.format(auth_type)) # nosemgrep
auth = eval(f"self._with_{auth_type.lower()}_type(action_result)")
if phantom.is_fail(auth):
self.debug_print(f"Authentication failed using {auth_type}")
msg = action_result.get_message()
if action_id != SMTP_TEST_CONNECTIVITY:
msg = "Authentication failed for connecting to server with {} \
authentication.{}".format(
auth_type, SMTP_FAILED_CONNECTIVITY_TEST
msg = "Authentication failed for connecting to server with {} authentication. Message: {}.{}".format(
auth_type, msg, SMTP_FAILED_CONNECTIVITY_TEST
)
return action_result.set_status(phantom.APP_ERROR, msg)
else:
return action_result.set_status(phantom.APP_ERROR, msg)
return action_result.set_status(phantom.APP_ERROR, msg)

self.debug_print(f"Authentication succeeded using {auth_type}")
return phantom.APP_SUCCESS

def finalize(self):
Expand All @@ -211,7 +211,7 @@ def finalize(self):
self._state["oauth_token"]["refresh_token"] = self._refresh_token
self._state[SMTP_STATE_IS_ENCRYPTED] = True
except Exception as e:
self.debug_print("{}: {}".format(SMTP_ENCRYPTION_ERROR, self._get_error_message_from_exception(e)))
self.error_print("{}: {}".format(SMTP_ENCRYPTION_ERROR, self._get_error_message_from_exception(e)))
return self.set_status(phantom.APP_ERROR, SMTP_ENCRYPTION_ERROR)

self.save_state(self._state)
Expand Down Expand Up @@ -388,7 +388,7 @@ def _interactive_auth_initial(self, client_id, rsh, client_secret):
return phantom.APP_SUCCESS, ""

def _interactive_auth_refresh(self):

self.debug_print("Attempting to refresh OAuth token")
config = self.get_config()
client_id = config.get("client_id")
client_secret = config.get("client_secret")
Expand Down Expand Up @@ -426,10 +426,11 @@ def _interactive_auth_refresh(self):
self._refresh_token = oauth_token.get("refresh_token")

self._state["oauth_token"] = oauth_token
self.debug_print("OAuth token refresh succeeded")
return phantom.APP_SUCCESS, ""

def _set_interactive_auth(self, action_result):

self.debug_print("Setting interactive auth")
config = self.get_config()
client_id = config.get("client_id")
client_secret = config.get("client_secret")
Expand Down Expand Up @@ -551,7 +552,6 @@ def handle_exception(self, e):
self._cleanup()

def _connect_to_server(self, action_result, first_try=True):

config = self.get_config()
is_oauth = self._auth_mechanism == SMTP_OAUTH_AUTH_TYPE

Expand Down Expand Up @@ -590,11 +590,12 @@ def _connect_to_server(self, action_result, first_try=True):
self._smtp_conn.ehlo()
# Login
try:
self.debug_print("Attempting to login")
if self._auth_mechanism == SMTP_OAUTH_AUTH_TYPE:
if config.get(phantom.APP_JSON_USERNAME) is None:
return action_result.set_status(
phantom.APP_ERROR,
"A username must be specified to run test connectivity using OAuth. " "Please check your asset configuration.",
"A username must be specified to run test connectivity using OAuth. Please check your asset configuration.",
)
auth_string = self._generate_oauth_string(config[phantom.APP_JSON_USERNAME], self._access_token)
# self._smtp_conn.ehlo(config.get("client_id"))
Expand All @@ -605,8 +606,12 @@ def _connect_to_server(self, action_result, first_try=True):
elif self._auth_mechanism == SMTP_PASSWORD_LESS_AUTH_TYPE:
self.debug_print(SMTP_MESSAGE_SKIP_AUTH_NO_USERNAME_PASSWORD)
response_code, response_message = (None, None)
else:
self.debug_print(f"Unsupported auth_mechanism: {self._auth_mechanism}")
return action_result.set_status(phantom.APP_ERROR, "Login failed due to an unsupported auth mechanism. This shouldn't happen.")

except Exception as e:
self.debug_print(f"Exception occurred while attempting to login using OAuth. Details: {e}")
# If token is expired, use the refresh token to re-new the access token
error_text = self._get_error_message_from_exception(e)
if first_try and is_oauth and "Invalid credentials" in error_text:
Expand All @@ -618,6 +623,7 @@ def _connect_to_server(self, action_result, first_try=True):
raise e

if response_code is not None:
self.debug_print(f"Response to login attempt received. Response code: {response_code}")
# 334 status code for smtp signifies that the requested security mechanism is accepted
if response_code == 334:
decoded_bytes = base64.b64decode(response_message)
Expand Down Expand Up @@ -939,7 +945,7 @@ def _generate_oauth_string(self, username, access_token):

def _connect_to_server_helper(self, action_result):
"""Redirect the flow based on auth type"""

self.debug_print("Connecting to SMTP server")
if self._auth_mechanism == SMTP_OAUTH_AUTH_TYPE:
if self._refresh_token and self._access_token == "":
self.debug_print("Try to generate token from refresh token")
Expand Down
5 changes: 1 addition & 4 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
[flake8]
max-line-length = 145
max-complexity = 28
extend-ignore = F403,E128,E126,E121,E127,E731,E201,E202,F405,E722,D

[isort]
line_length = 145
extend-ignore = F403,E128,E126,E121,E127,E731,E201,E202,E203,E701,F405,E722,D,W503
Loading