Skip to content
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
Expand Up @@ -50,7 +50,7 @@ repos:
- repo: https://github.com/returntocorp/semgrep
rev: v1.89.0
hooks:
- id: semgrep
- id: semgrep-docker
- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks:
Expand Down
1,002 changes: 501 additions & 501 deletions NOTICE

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION
**username** | required | string | Username |
**password** | required | password | Password |
**port** | optional | numeric | Database Service Port |
**encryption** | optional | string | TLS encryption mode for the database connection |

### Supported Actions

Expand Down
11 changes: 11 additions & 0 deletions microsoftsqlserver.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@
"data_type": "numeric",
"default": 1433,
"order": 4
},
"encryption": {
"description": "TLS encryption mode for the database connection",
"data_type": "string",
"value_list": [
"off",
"request",
"require"
],
"default": "request",
"order": 5
}
},
"actions": [
Expand Down
41 changes: 41 additions & 0 deletions microsoftsqlserver_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
import csv
import datetime
import json
import os
import struct
import tempfile
import traceback

import phantom.app as phantom
Expand All @@ -42,6 +44,7 @@ def __init__(self):
super().__init__()
self._state = None
self._cursor = None
self._freetds_conf_path = None

def _initialize_error(self, msg, exception=None):
if self.get_action_identifier() == "test_connectivity":
Expand Down Expand Up @@ -250,6 +253,31 @@ def _handle_test_connectivity(self, param):
self.save_progress("Test Connectivity Passed")
return action_result.set_status(phantom.APP_SUCCESS)

def _configure_freetds(self, encryption):
# Workaround for https://github.com/pymssql/pymssql/issues/924:
# The `encryption` parameter passed to pymssql.connect() is silently ignored due to a
# known bug in pymssql. As a workaround, we write a temporary FreeTDS config file with
# the desired encryption setting and point the FREETDSCONF environment variable at it
# before opening the connection. The temp file is cleaned up in finalize().
encryption = (encryption or MSSQLSERVER_ENCRYPTION_DEFAULT).lower()
if encryption not in MSSQLSERVER_ENCRYPTION_VALID_VALUES:
encryption = MSSQLSERVER_ENCRYPTION_DEFAULT

lines = [
"[global]",
f"encryption = {encryption}",
]

temp_conf = tempfile.NamedTemporaryFile(mode="w", prefix="mssql_freetds_", suffix=".conf", delete=False)
self._freetds_conf_path = temp_conf.name
try:
temp_conf.write("\n".join(lines) + "\n")
temp_conf.flush()
finally:
temp_conf.close()

os.environ["FREETDSCONF"] = self._freetds_conf_path

def _handle_list_columns(self, param):
self.save_progress(f"In action handler for: {self.get_action_identifier()}")
action_result = self.add_action_result(ActionResult(dict(param)))
Expand Down Expand Up @@ -412,6 +440,7 @@ def _connect_sql(self, param):
username = config["username"]
password = config["password"]
port = config.get("port", 1433)
encryption = config.get("encryption", MSSQLSERVER_ENCRYPTION_DEFAULT)
host = param.get("host", config["host"])
database = param.get("database", config["database"])
param["host"] = host
Expand All @@ -424,6 +453,9 @@ def _connect_sql(self, param):

self._cursor = None
try:
# `encryption` is passed via the FreeTDS config rather than as a pymssql.connect() argument
# see _configure_freetds() for details.
self._configure_freetds(encryption)
self._connection = pymssql.connect(host, username, password, database, port=port) # pylint: disable=no-member
self._cursor = self._connection.cursor()
except Exception as ex:
Expand All @@ -440,6 +472,15 @@ def initialize(self):
return phantom.APP_SUCCESS

def finalize(self):
if self._freetds_conf_path:
try:
os.unlink(self._freetds_conf_path)
except OSError:
self.debug_print(f"Error deleting FreeTDS config file: {self._freetds_conf_path}")
self._freetds_conf_path = None

os.environ.pop("FREETDSCONF", None)

self.save_state(self._state)
return phantom.APP_SUCCESS

Expand Down
4 changes: 4 additions & 0 deletions microsoftsqlserver_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@
# responses
MSSQLSERVER_ERROR_MESSAGE_UNAVAILABLE = "Error message unavailable. Please check the asset configuration and|or action parameters"
DEFAULT_TIMEOUT = 30

# encryption config
MSSQLSERVER_ENCRYPTION_DEFAULT = "request"
MSSQLSERVER_ENCRYPTION_VALID_VALUES = {"off", "request", "require"}
3 changes: 3 additions & 0 deletions release_notes/unreleased.md
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
**Unreleased**

* Added an `encryption` configuration parameter to control the TLS encryption mode for database connections;
* fixed encryption not being applied due to a known pymssql bug (pymssql/pymssql#924) by configuring it via a FreeTDS config file instead
Loading