You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by be...@apache.org on 2021/05/18 04:28:52 UTC

[superset] branch master updated: feat: add SSL to new DB parameters (#14673)

This is an automated email from the ASF dual-hosted git repository.

beto pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 971f588  feat: add SSL to new DB parameters (#14673)
971f588 is described below

commit 971f5883f0f5187c14345de95de5c65d967be44f
Author: Beto Dealmeida <ro...@dealmeida.net>
AuthorDate: Mon May 17 21:27:43 2021 -0700

    feat: add SSL to new DB parameters (#14673)
    
    * feat: add SSL to new DB parameters
    
    * Fix test
    
    * Raise if cls.encryption_parameters is empty
---
 superset/db_engine_specs/base.py        | 24 +++++++++++++++++++++---
 superset/db_engine_specs/postgres.py    |  2 ++
 tests/databases/api_tests.py            |  4 ++++
 tests/db_engine_specs/postgres_tests.py | 11 ++++++++---
 4 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py
index 3289b4a..158162e 100644
--- a/superset/db_engine_specs/base.py
+++ b/superset/db_engine_specs/base.py
@@ -1304,6 +1304,9 @@ class BasicParametersSchema(Schema):
     query = fields.Dict(
         keys=fields.Str(), values=fields.Raw(), description=__("Additional parameters")
     )
+    encryption = fields.Boolean(
+        required=False, description=__("Use an encrypted connection to the database")
+    )
 
 
 class BasicParametersType(TypedDict, total=False):
@@ -1313,6 +1316,7 @@ class BasicParametersType(TypedDict, total=False):
     port: int
     database: str
     query: Dict[str, Any]
+    encryption: bool
 
 
 class BasicParametersMixin:
@@ -1339,8 +1343,18 @@ class BasicParametersMixin:
         "drivername://user:password@host:port/dbname[?key=value&key=value...]"
     )
 
+    # query parameter to enable encryption in the database connection
+    # for Postgres this would be `{"sslmode": "verify-ca"}`, eg.
+    encryption_parameters: Dict[str, str] = {}
+
     @classmethod
     def build_sqlalchemy_uri(cls, parameters: BasicParametersType) -> str:
+        query = parameters.get("query", {})
+        if parameters.get("encryption"):
+            if not cls.encryption_parameters:
+                raise Exception("Unable to build a URL with encryption enabled")
+            query.update(cls.encryption_parameters)
+
         return str(
             URL(
                 cls.drivername,
@@ -1349,13 +1363,16 @@ class BasicParametersMixin:
                 host=parameters["host"],
                 port=parameters["port"],
                 database=parameters["database"],
-                query=parameters.get("query", {}),
+                query=query,
             )
         )
 
-    @staticmethod
-    def get_parameters_from_uri(uri: str) -> BasicParametersType:
+    @classmethod
+    def get_parameters_from_uri(cls, uri: str) -> BasicParametersType:
         url = make_url(uri)
+        encryption = all(
+            item in url.query.items() for item in cls.encryption_parameters.items()
+        )
         return {
             "username": url.username,
             "password": url.password,
@@ -1363,6 +1380,7 @@ class BasicParametersMixin:
             "port": url.port,
             "database": url.database,
             "query": url.query,
+            "encryption": encryption,
         }
 
     @classmethod
diff --git a/superset/db_engine_specs/postgres.py b/superset/db_engine_specs/postgres.py
index b00a27a..5c8ff40 100644
--- a/superset/db_engine_specs/postgres.py
+++ b/superset/db_engine_specs/postgres.py
@@ -163,6 +163,8 @@ class PostgresEngineSpec(PostgresBaseEngineSpec, BasicParametersMixin):
     sqlalchemy_uri_placeholder = (
         "postgresql+psycopg2://user:password@host:port/dbname[?key=value&key=value...]"
     )
+    # https://www.postgresql.org/docs/9.1/libpq-ssl.html#LIBQ-SSL-CERTIFICATES
+    encryption_parameters = {"sslmode": "verify-ca"}
 
     max_column_name_length = 63
     try_remove_schema_from_table_name = False
diff --git a/tests/databases/api_tests.py b/tests/databases/api_tests.py
index 69f98cb..d7404f5 100644
--- a/tests/databases/api_tests.py
+++ b/tests/databases/api_tests.py
@@ -1392,6 +1392,10 @@ class TestDatabaseApi(SupersetTestCase):
                                 "description": "Database name",
                                 "type": "string",
                             },
+                            "encryption": {
+                                "description": "Use an encrypted connection to the database",
+                                "type": "boolean",
+                            },
                             "host": {
                                 "description": "Hostname or IP address",
                                 "type": "string",
diff --git a/tests/db_engine_specs/postgres_tests.py b/tests/db_engine_specs/postgres_tests.py
index e166726..6f6fa54 100644
--- a/tests/db_engine_specs/postgres_tests.py
+++ b/tests/db_engine_specs/postgres_tests.py
@@ -430,11 +430,12 @@ def test_base_parameters_mixin():
         "port": 5432,
         "database": "dbname",
         "query": {"foo": "bar"},
+        "encryption": True,
     }
     sqlalchemy_uri = PostgresEngineSpec.build_sqlalchemy_uri(parameters)
-    assert (
-        sqlalchemy_uri
-        == "postgresql+psycopg2://username:password@localhost:5432/dbname?foo=bar"
+    assert sqlalchemy_uri == (
+        "postgresql+psycopg2://username:password@localhost:5432/dbname?"
+        "foo=bar&sslmode=verify-ca"
     )
 
     parameters_from_uri = PostgresEngineSpec.get_parameters_from_uri(sqlalchemy_uri)
@@ -458,6 +459,10 @@ def test_base_parameters_mixin():
                 "additionalProperties": {},
             },
             "database": {"type": "string", "description": "Database name"},
+            "encryption": {
+                "type": "boolean",
+                "description": "Use an encrypted connection to the database",
+            },
         },
         "required": ["database", "host", "port", "username"],
     }