From 754896368af9acf96f6c20dfb1d91ada2170fafd Mon Sep 17 00:00:00 2001 From: Arihant Surana Date: Thu, 20 Feb 2020 13:32:51 +1100 Subject: [PATCH 1/7] feat: provide ssl options for Cassandra data source --- redash/query_runner/cass.py | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/redash/query_runner/cass.py b/redash/query_runner/cass.py index 4725101b1e..b5c60f5a81 100644 --- a/redash/query_runner/cass.py +++ b/redash/query_runner/cass.py @@ -1,4 +1,7 @@ import logging +import ssl +from base64 import b64decode +from pathlib import Path from redash.query_runner import BaseQueryRunner, register from redash.utils import JSONEncoder, json_dumps, json_loads @@ -45,14 +48,51 @@ def configuration_schema(cls): "default": 3, }, "timeout": {"type": "number", "title": "Timeout", "default": 10}, + "useSsl": {"type": "boolean", "title": "Use SSL", "default": False}, + "sslCertificateFile": { + "type": "string", + "title": "SSL Certificate File" + }, + "sslProtocol": { + "type": "string", + "title": "SSL Protocol", + "default": "PROTOCOL_TLSv1_2" + }, }, "required": ["keyspace", "host"], + "secret": ["sslCertificateFile"], } @classmethod def type(cls): return "Cassandra" + def _get_certifiacte(self): + ssl_cert = b64decode(self.configuration.get("sslCertificateFile", None)) + print(ssl_cert) + cert_path = None + logger.error(f"certificate is found to be {ssl_cert}") + if ssl_cert is not None: + cert_dir = f"./tmp/cassandra_certificate/{self.configuration.get('host', '')}" + cert_path = f"{cert_dir}/cert.pem" + # Ensure the path exists + Path(cert_dir).mkdir(parents=True, exist_ok=True) + with open(cert_path, 'w') as objFile: + objFile.write(ssl_cert.decode("utf-8")) + return cert_path + + def _get_ssl_options(self): + ssl_options = None + if self.configuration.get("useSsl", False): + ssl_version = self.configuration.get("sslProtocol") + ssl_options = { + 'ssl_version': getattr(ssl, ssl_version) + } + if self.configuration.get("sslCertificateFile", None) is not None: + ssl_options['ca_certs'] = self._get_certifiacte() + ssl_options['cert_reqs'] = ssl.CERT_REQUIRED + return ssl_options + def get_schema(self, get_stats=False): query = """ select release_version from system.local; @@ -106,12 +146,14 @@ def run_query(self, query, user): auth_provider=auth_provider, port=self.configuration.get("port", ""), protocol_version=self.configuration.get("protocol", 3), + ssl_options=self._get_ssl_options(), ) else: connection = Cluster( [self.configuration.get("host", "")], port=self.configuration.get("port", ""), protocol_version=self.configuration.get("protocol", 3), + ssl_options=self._get_ssl_options(), ) session = connection.connect() session.set_keyspace(self.configuration["keyspace"]) From eae5ce68b8c0bedaef9c2541403df9b0e0ecad44 Mon Sep 17 00:00:00 2001 From: Arihant Surana Date: Thu, 20 Feb 2020 13:50:14 +1100 Subject: [PATCH 2/7] remove Log and prints --- redash/query_runner/cass.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/redash/query_runner/cass.py b/redash/query_runner/cass.py index b5c60f5a81..29ef41b1f0 100644 --- a/redash/query_runner/cass.py +++ b/redash/query_runner/cass.py @@ -69,9 +69,7 @@ def type(cls): def _get_certifiacte(self): ssl_cert = b64decode(self.configuration.get("sslCertificateFile", None)) - print(ssl_cert) cert_path = None - logger.error(f"certificate is found to be {ssl_cert}") if ssl_cert is not None: cert_dir = f"./tmp/cassandra_certificate/{self.configuration.get('host', '')}" cert_path = f"{cert_dir}/cert.pem" From 864768474adfb710a72731cc38d676bd42aebb41 Mon Sep 17 00:00:00 2001 From: Arihant Surana Date: Thu, 20 Feb 2020 14:33:24 +1100 Subject: [PATCH 3/7] Refactor to create module methods and unit tests --- redash/query_runner/cass.py | 50 +++++++++++++++++++++------------ tests/query_runner/test_cass.py | 42 +++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 tests/query_runner/test_cass.py diff --git a/redash/query_runner/cass.py b/redash/query_runner/cass.py index 29ef41b1f0..1b3aee2f14 100644 --- a/redash/query_runner/cass.py +++ b/redash/query_runner/cass.py @@ -25,6 +25,26 @@ def default(self, o): return super(CassandraJSONEncoder, self).default(o) +def generate_cert_file(ssl_cert, host): + cert_dir = f"./tmp/cassandra_certificate/{host}" + cert_path = f"{cert_dir}/cert.pem" + # Ensure the path exists + Path(cert_dir).mkdir(parents=True, exist_ok=True) + with open(cert_path, 'w') as objFile: + objFile.write(ssl_cert.decode("utf-8")) + return cert_path + + +def generate_ssl_options_dict(protocol, cert_path=None): + ssl_options = { + 'ssl_version': getattr(ssl, protocol) + } + if cert_path is not None: + ssl_options['ca_certs'] = cert_path + ssl_options['cert_reqs'] = ssl.CERT_REQUIRED + return ssl_options + + class Cassandra(BaseQueryRunner): noop_query = "SELECT dateof(now()) FROM system.local" @@ -67,28 +87,22 @@ def configuration_schema(cls): def type(cls): return "Cassandra" - def _get_certifiacte(self): - ssl_cert = b64decode(self.configuration.get("sslCertificateFile", None)) - cert_path = None - if ssl_cert is not None: - cert_dir = f"./tmp/cassandra_certificate/{self.configuration.get('host', '')}" - cert_path = f"{cert_dir}/cert.pem" - # Ensure the path exists - Path(cert_dir).mkdir(parents=True, exist_ok=True) - with open(cert_path, 'w') as objFile: - objFile.write(ssl_cert.decode("utf-8")) - return cert_path + def _get_certifiacte_path(self): + cert_bytes = b64decode(self.configuration.get("sslCertificateFile", None)) + if cert_bytes is None: + return None + return generate_cert_file( + ssl_cert=cert_bytes, + host=self.configuration.get('host', '') + ) def _get_ssl_options(self): ssl_options = None if self.configuration.get("useSsl", False): - ssl_version = self.configuration.get("sslProtocol") - ssl_options = { - 'ssl_version': getattr(ssl, ssl_version) - } - if self.configuration.get("sslCertificateFile", None) is not None: - ssl_options['ca_certs'] = self._get_certifiacte() - ssl_options['cert_reqs'] = ssl.CERT_REQUIRED + ssl_options = generate_ssl_options_dict( + protocol=self.configuration.get("sslProtocol"), + cert_path=self._get_certifiacte_path() + ) return ssl_options def get_schema(self, get_stats=False): diff --git a/tests/query_runner/test_cass.py b/tests/query_runner/test_cass.py new file mode 100644 index 0000000000..b578b87e26 --- /dev/null +++ b/tests/query_runner/test_cass.py @@ -0,0 +1,42 @@ +import shutil +import ssl +from pathlib import Path +from unittest import TestCase + +from redash.query_runner.cass import generate_cert_file, generate_ssl_options_dict + + +class TestCassandra(TestCase): + + def tearDownClass(): + shutil.rmtree("./tmp", ignore_errors=True) + + def test_generate_cert_file_creates_a_file_with_right_path(self): + expected = "./tmp/cassandra_certificate/test_host/cert.pem" + actual = generate_cert_file(b"test_cert_string", "test_host") + self.assertEqual(expected, actual) + + def test_generate_cert_file_creates_a_file_that_exists(self): + actual = generate_cert_file(b"test_cert_string", "another_host") + self.assertEqual(True, Path(actual).exists()) + + def test_generate_cert_file_creates_a_file_with_right_content(self): + expected = "test_cert_string" + actual_path = generate_cert_file(b"test_cert_string", "content_host") + with open(actual_path, "r") as f: + actual = f.read() + self.assertEqual(expected, actual) + + def test_generate_ssl_options_dict_creates_plain_protocol_dict(self): + expected = {'ssl_version': ssl.PROTOCOL_TLSv1_2} + actual = generate_ssl_options_dict("PROTOCOL_TLSv1_2") + self.assertDictEqual(expected, actual) + + def test_generate_ssl_options_dict_creates_certificate_dict(self): + expected = { + 'ssl_version': ssl.PROTOCOL_TLSv1_2, + 'ca_certs': 'some/path', + 'cert_reqs': ssl.CERT_REQUIRED, + } + actual = generate_ssl_options_dict("PROTOCOL_TLSv1_2", "some/path") + self.assertDictEqual(expected, actual) From ead4e5d1b90e0209d6ec63c3e74c9b19a138fc1e Mon Sep 17 00:00:00 2001 From: Arihant Surana Date: Thu, 5 Mar 2020 14:22:50 +1100 Subject: [PATCH 4/7] Switch to using Enumerator and temp file --- redash/query_runner/cass.py | 126 +++++++++++++++++--------------- tests/query_runner/test_cass.py | 22 +----- 2 files changed, 67 insertions(+), 81 deletions(-) diff --git a/redash/query_runner/cass.py b/redash/query_runner/cass.py index 1b3aee2f14..876690c681 100644 --- a/redash/query_runner/cass.py +++ b/redash/query_runner/cass.py @@ -1,7 +1,7 @@ import logging import ssl from base64 import b64decode -from pathlib import Path +from tempfile import NamedTemporaryFile from redash.query_runner import BaseQueryRunner, register from redash.utils import JSONEncoder, json_dumps, json_loads @@ -18,23 +18,6 @@ enabled = False -class CassandraJSONEncoder(JSONEncoder): - def default(self, o): - if isinstance(o, sortedset): - return list(o) - return super(CassandraJSONEncoder, self).default(o) - - -def generate_cert_file(ssl_cert, host): - cert_dir = f"./tmp/cassandra_certificate/{host}" - cert_path = f"{cert_dir}/cert.pem" - # Ensure the path exists - Path(cert_dir).mkdir(parents=True, exist_ok=True) - with open(cert_path, 'w') as objFile: - objFile.write(ssl_cert.decode("utf-8")) - return cert_path - - def generate_ssl_options_dict(protocol, cert_path=None): ssl_options = { 'ssl_version': getattr(ssl, protocol) @@ -45,6 +28,13 @@ def generate_ssl_options_dict(protocol, cert_path=None): return ssl_options +class CassandraJSONEncoder(JSONEncoder): + def default(self, o): + if isinstance(o, sortedset): + return list(o) + return super(CassandraJSONEncoder, self).default(o) + + class Cassandra(BaseQueryRunner): noop_query = "SELECT dateof(now()) FROM system.local" @@ -76,10 +66,27 @@ def configuration_schema(cls): "sslProtocol": { "type": "string", "title": "SSL Protocol", - "default": "PROTOCOL_TLSv1_2" + # "extendedEnum": [ + # {"value": "PROTOCOL_SSLv23", "name": "SSLv23"}, + # {"value": "PROTOCOL_TLS", "name": "TLS"}, + # {"value": "PROTOCOL_TLS_CLIENT", "name": "TLS_CLIENT"}, + # {"value": "PROTOCOL_TLS_SERVER", "name": "TLS_SERVER"}, + # {"value": "PROTOCOL_TLSv1", "name": "TLSv1"}, + # {"value": "PROTOCOL_TLSv1_1", "name": "TLSv1_1"}, + # {"value": "PROTOCOL_TLSv1_2", "name": "TLSv1_2"}, + # ], + "enum": [ + "PROTOCOL_SSLv23", + "PROTOCOL_TLS", + "PROTOCOL_TLS_CLIENT", + "PROTOCOL_TLS_SERVER", + "PROTOCOL_TLSv1", + "PROTOCOL_TLSv1_1", + "PROTOCOL_TLSv1_2", + ], }, }, - "required": ["keyspace", "host"], + "required": ["keyspace", "host", "useSsl"], "secret": ["sslCertificateFile"], } @@ -87,24 +94,6 @@ def configuration_schema(cls): def type(cls): return "Cassandra" - def _get_certifiacte_path(self): - cert_bytes = b64decode(self.configuration.get("sslCertificateFile", None)) - if cert_bytes is None: - return None - return generate_cert_file( - ssl_cert=cert_bytes, - host=self.configuration.get('host', '') - ) - - def _get_ssl_options(self): - ssl_options = None - if self.configuration.get("useSsl", False): - ssl_options = generate_ssl_options_dict( - protocol=self.configuration.get("sslProtocol"), - cert_path=self._get_certifiacte_path() - ) - return ssl_options - def get_schema(self, get_stats=False): query = """ select release_version from system.local; @@ -146,28 +135,29 @@ def get_schema(self, get_stats=False): def run_query(self, query, user): connection = None try: - if self.configuration.get("username", "") and self.configuration.get( - "password", "" - ): - auth_provider = PlainTextAuthProvider( - username="{}".format(self.configuration.get("username", "")), - password="{}".format(self.configuration.get("password", "")), - ) - connection = Cluster( - [self.configuration.get("host", "")], - auth_provider=auth_provider, - port=self.configuration.get("port", ""), - protocol_version=self.configuration.get("protocol", 3), - ssl_options=self._get_ssl_options(), - ) - else: - connection = Cluster( - [self.configuration.get("host", "")], - port=self.configuration.get("port", ""), - protocol_version=self.configuration.get("protocol", 3), - ssl_options=self._get_ssl_options(), - ) - session = connection.connect() + with NamedTemporaryFile(mode='w') as cert_file: + if self.configuration.get("username", "") and self.configuration.get( + "password", "" + ): + auth_provider = PlainTextAuthProvider( + username="{}".format(self.configuration.get("username", "")), + password="{}".format(self.configuration.get("password", "")), + ) + connection = Cluster( + [self.configuration.get("host", "")], + auth_provider=auth_provider, + port=self.configuration.get("port", ""), + protocol_version=self.configuration.get("protocol", 3), + ssl_options=self._get_ssl_options(cert_file), + ) + else: + connection = Cluster( + [self.configuration.get("host", "")], + port=self.configuration.get("port", ""), + protocol_version=self.configuration.get("protocol", 3), + ssl_options=self._get_ssl_options(cert_file), + ) + session = connection.connect() session.set_keyspace(self.configuration["keyspace"]) session.default_timeout = self.configuration.get("timeout", 10) logger.debug("Cassandra running query: %s", query) @@ -189,6 +179,22 @@ def run_query(self, query, user): return json_data, error + def _generate_cert_file(self, cert_file): + cert_bytes = b64decode(self.configuration.get("sslCertificateFile", None)) + if cert_bytes is None: + return None + cert_file.write(cert_bytes.decode("utf-8")) + return cert_file.name + + def _get_ssl_options(self, cert_file): + ssl_options = None + if self.configuration.get("useSsl", False): + ssl_options = generate_ssl_options_dict( + protocol=self.configuration["sslProtocol"], + cert_path=self._generate_cert_file(cert_file) + ) + return ssl_options + class ScyllaDB(Cassandra): @classmethod diff --git a/tests/query_runner/test_cass.py b/tests/query_runner/test_cass.py index b578b87e26..6f7fcca78d 100644 --- a/tests/query_runner/test_cass.py +++ b/tests/query_runner/test_cass.py @@ -1,32 +1,12 @@ import shutil import ssl -from pathlib import Path from unittest import TestCase -from redash.query_runner.cass import generate_cert_file, generate_ssl_options_dict +from redash.query_runner.cass import generate_ssl_options_dict class TestCassandra(TestCase): - def tearDownClass(): - shutil.rmtree("./tmp", ignore_errors=True) - - def test_generate_cert_file_creates_a_file_with_right_path(self): - expected = "./tmp/cassandra_certificate/test_host/cert.pem" - actual = generate_cert_file(b"test_cert_string", "test_host") - self.assertEqual(expected, actual) - - def test_generate_cert_file_creates_a_file_that_exists(self): - actual = generate_cert_file(b"test_cert_string", "another_host") - self.assertEqual(True, Path(actual).exists()) - - def test_generate_cert_file_creates_a_file_with_right_content(self): - expected = "test_cert_string" - actual_path = generate_cert_file(b"test_cert_string", "content_host") - with open(actual_path, "r") as f: - actual = f.read() - self.assertEqual(expected, actual) - def test_generate_ssl_options_dict_creates_plain_protocol_dict(self): expected = {'ssl_version': ssl.PROTOCOL_TLSv1_2} actual = generate_ssl_options_dict("PROTOCOL_TLSv1_2") From 53e7520158e1d312c8ecc0100f39038a39336191 Mon Sep 17 00:00:00 2001 From: Arihant Surana Date: Thu, 5 Mar 2020 15:18:23 +1100 Subject: [PATCH 5/7] Fix temporary file lifecycle for cert --- redash/query_runner/cass.py | 75 ++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/redash/query_runner/cass.py b/redash/query_runner/cass.py index 876690c681..d143fc1ae8 100644 --- a/redash/query_runner/cass.py +++ b/redash/query_runner/cass.py @@ -1,4 +1,5 @@ import logging +import os import ssl from base64 import b64decode from tempfile import NamedTemporaryFile @@ -66,15 +67,6 @@ def configuration_schema(cls): "sslProtocol": { "type": "string", "title": "SSL Protocol", - # "extendedEnum": [ - # {"value": "PROTOCOL_SSLv23", "name": "SSLv23"}, - # {"value": "PROTOCOL_TLS", "name": "TLS"}, - # {"value": "PROTOCOL_TLS_CLIENT", "name": "TLS_CLIENT"}, - # {"value": "PROTOCOL_TLS_SERVER", "name": "TLS_SERVER"}, - # {"value": "PROTOCOL_TLSv1", "name": "TLSv1"}, - # {"value": "PROTOCOL_TLSv1_1", "name": "TLSv1_1"}, - # {"value": "PROTOCOL_TLSv1_2", "name": "TLSv1_2"}, - # ], "enum": [ "PROTOCOL_SSLv23", "PROTOCOL_TLS", @@ -134,30 +126,30 @@ def get_schema(self, get_stats=False): def run_query(self, query, user): connection = None + cert_path = self._generate_cert_file() try: - with NamedTemporaryFile(mode='w') as cert_file: - if self.configuration.get("username", "") and self.configuration.get( - "password", "" - ): - auth_provider = PlainTextAuthProvider( - username="{}".format(self.configuration.get("username", "")), - password="{}".format(self.configuration.get("password", "")), - ) - connection = Cluster( - [self.configuration.get("host", "")], - auth_provider=auth_provider, - port=self.configuration.get("port", ""), - protocol_version=self.configuration.get("protocol", 3), - ssl_options=self._get_ssl_options(cert_file), - ) - else: - connection = Cluster( - [self.configuration.get("host", "")], - port=self.configuration.get("port", ""), - protocol_version=self.configuration.get("protocol", 3), - ssl_options=self._get_ssl_options(cert_file), - ) - session = connection.connect() + if self.configuration.get("username", "") and self.configuration.get( + "password", "" + ): + auth_provider = PlainTextAuthProvider( + username="{}".format(self.configuration.get("username", "")), + password="{}".format(self.configuration.get("password", "")), + ) + connection = Cluster( + [self.configuration.get("host", "")], + auth_provider=auth_provider, + port=self.configuration.get("port", ""), + protocol_version=self.configuration.get("protocol", 3), + ssl_options=self._get_ssl_options(cert_path), + ) + else: + connection = Cluster( + [self.configuration.get("host", "")], + port=self.configuration.get("port", ""), + protocol_version=self.configuration.get("protocol", 3), + ssl_options=self._get_ssl_options(cert_path), + ) + session = connection.connect() session.set_keyspace(self.configuration["keyspace"]) session.default_timeout = self.configuration.get("timeout", 10) logger.debug("Cassandra running query: %s", query) @@ -176,22 +168,27 @@ def run_query(self, query, user): except KeyboardInterrupt: error = "Query cancelled by user." json_data = None + finally: + # Cleanup the cert file + if cert_path: + os.remove(cert_path) return json_data, error - def _generate_cert_file(self, cert_file): - cert_bytes = b64decode(self.configuration.get("sslCertificateFile", None)) - if cert_bytes is None: - return None - cert_file.write(cert_bytes.decode("utf-8")) + def _generate_cert_file(self): + with NamedTemporaryFile(mode='w', delete=False) as cert_file: + cert_bytes = b64decode(self.configuration.get("sslCertificateFile", None)) + if cert_bytes is None: + return None + cert_file.write(cert_bytes.decode("utf-8")) return cert_file.name - def _get_ssl_options(self, cert_file): + def _get_ssl_options(self, cert_path): ssl_options = None if self.configuration.get("useSsl", False): ssl_options = generate_ssl_options_dict( protocol=self.configuration["sslProtocol"], - cert_path=self._generate_cert_file(cert_file) + cert_path=cert_path ) return ssl_options From efb85b69d68df0667196d2a66ea819613d83d7ec Mon Sep 17 00:00:00 2001 From: Arihant Surana Date: Thu, 5 Mar 2020 15:25:40 +1100 Subject: [PATCH 6/7] Align with changes on master --- redash/query_runner/cass.py | 89 +++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 47 deletions(-) diff --git a/redash/query_runner/cass.py b/redash/query_runner/cass.py index d143fc1ae8..c5eb424f40 100644 --- a/redash/query_runner/cass.py +++ b/redash/query_runner/cass.py @@ -127,53 +127,44 @@ def get_schema(self, get_stats=False): def run_query(self, query, user): connection = None cert_path = self._generate_cert_file() - try: - if self.configuration.get("username", "") and self.configuration.get( - "password", "" - ): - auth_provider = PlainTextAuthProvider( - username="{}".format(self.configuration.get("username", "")), - password="{}".format(self.configuration.get("password", "")), - ) - connection = Cluster( - [self.configuration.get("host", "")], - auth_provider=auth_provider, - port=self.configuration.get("port", ""), - protocol_version=self.configuration.get("protocol", 3), - ssl_options=self._get_ssl_options(cert_path), - ) - else: - connection = Cluster( - [self.configuration.get("host", "")], - port=self.configuration.get("port", ""), - protocol_version=self.configuration.get("protocol", 3), - ssl_options=self._get_ssl_options(cert_path), - ) - session = connection.connect() - session.set_keyspace(self.configuration["keyspace"]) - session.default_timeout = self.configuration.get("timeout", 10) - logger.debug("Cassandra running query: %s", query) - result = session.execute(query) - - column_names = result.column_names - - columns = self.fetch_columns([(c, "string") for c in column_names]) - - rows = [dict(zip(column_names, row)) for row in result] - - data = {"columns": columns, "rows": rows} - json_data = json_dumps(data, cls=CassandraJSONEncoder) - - error = None - except KeyboardInterrupt: - error = "Query cancelled by user." - json_data = None - finally: - # Cleanup the cert file - if cert_path: - os.remove(cert_path) - - return json_data, error + if self.configuration.get("username", "") and self.configuration.get( + "password", "" + ): + auth_provider = PlainTextAuthProvider( + username="{}".format(self.configuration.get("username", "")), + password="{}".format(self.configuration.get("password", "")), + ) + connection = Cluster( + [self.configuration.get("host", "")], + auth_provider=auth_provider, + port=self.configuration.get("port", ""), + protocol_version=self.configuration.get("protocol", 3), + ssl_options=self._get_ssl_options(cert_path), + ) + else: + connection = Cluster( + [self.configuration.get("host", "")], + port=self.configuration.get("port", ""), + protocol_version=self.configuration.get("protocol", 3), + ssl_options=self._get_ssl_options(cert_path), + ) + session = connection.connect() + session.set_keyspace(self.configuration["keyspace"]) + session.default_timeout = self.configuration.get("timeout", 10) + logger.debug("Cassandra running query: %s", query) + result = session.execute(query) + self._cleanup_cert_file(cert_path) + + column_names = result.column_names + + columns = self.fetch_columns([(c, "string") for c in column_names]) + + rows = [dict(zip(column_names, row)) for row in result] + + data = {"columns": columns, "rows": rows} + json_data = json_dumps(data, cls=CassandraJSONEncoder) + + return json_data, None def _generate_cert_file(self): with NamedTemporaryFile(mode='w', delete=False) as cert_file: @@ -183,6 +174,10 @@ def _generate_cert_file(self): cert_file.write(cert_bytes.decode("utf-8")) return cert_file.name + def _cleanup_cert_file(self, cert_path): + if cert_path: + os.remove(cert_path) + def _get_ssl_options(self, cert_path): ssl_options = None if self.configuration.get("useSsl", False): From 452b7139009443b438fda7a139d90bb1d56568e0 Mon Sep 17 00:00:00 2001 From: Arihant Surana Date: Thu, 5 Mar 2020 15:38:36 +1100 Subject: [PATCH 7/7] Fix non certificate but ssl enabled usecase --- redash/query_runner/cass.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/redash/query_runner/cass.py b/redash/query_runner/cass.py index c5eb424f40..4a49c0d9b1 100644 --- a/redash/query_runner/cass.py +++ b/redash/query_runner/cass.py @@ -167,12 +167,13 @@ def run_query(self, query, user): return json_data, None def _generate_cert_file(self): - with NamedTemporaryFile(mode='w', delete=False) as cert_file: - cert_bytes = b64decode(self.configuration.get("sslCertificateFile", None)) - if cert_bytes is None: - return None - cert_file.write(cert_bytes.decode("utf-8")) - return cert_file.name + cert_encoded_bytes = self.configuration.get("sslCertificateFile", None) + if cert_encoded_bytes: + with NamedTemporaryFile(mode='w', delete=False) as cert_file: + cert_bytes = b64decode(cert_encoded_bytes) + cert_file.write(cert_bytes.decode("utf-8")) + return cert_file.name + return None def _cleanup_cert_file(self, cert_path): if cert_path: