File tree Expand file tree Collapse file tree 4 files changed +38
-0
lines changed
tests/unit_tests/db_engine_specs Expand file tree Collapse file tree 4 files changed +38
-0
lines changed Original file line number Diff line number Diff line change @@ -354,6 +354,8 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
354354 # This set will give the keywords for data limit statements
355355 # to consider for the engines with TOP SQL parsing
356356 top_keywords : Set [str ] = {"TOP" }
357+ # A set of disallowed connection query parameters
358+ disallow_uri_query_params : Set [str ] = set ()
357359
358360 force_column_alias_quotes = False
359361 arraysize = 0
@@ -1724,6 +1726,19 @@ def get_public_information(cls) -> Dict[str, Any]:
17241726 "disable_ssh_tunneling" : cls .disable_ssh_tunneling ,
17251727 }
17261728
1729+ @classmethod
1730+ def validate_database_uri (cls , sqlalchemy_uri : URL ) -> None :
1731+ """
1732+ Validates a database SQLAlchemy URI per engine spec.
1733+ Use this to implement a final validation for unwanted connection configuration
1734+
1735+ :param sqlalchemy_uri:
1736+ """
1737+ if existing_disallowed := cls .disallow_uri_query_params .intersection (
1738+ sqlalchemy_uri .query
1739+ ):
1740+ raise ValueError (f"Forbidden query parameter(s): { existing_disallowed } " )
1741+
17271742
17281743# schema for adding a database by providing parameters instead of the
17291744# full SQLAlchemy URI
Original file line number Diff line number Diff line change @@ -173,6 +173,7 @@ class MySQLEngineSpec(BaseEngineSpec, BasicParametersMixin):
173173 {},
174174 ),
175175 }
176+ disallow_uri_query_params = {"local_infile" }
176177
177178 @classmethod
178179 def convert_dttm (
Original file line number Diff line number Diff line change @@ -424,6 +424,8 @@ def _get_sqla_engine(
424424 sqlalchemy_url = make_url_safe (
425425 sqlalchemy_uri if sqlalchemy_uri else self .sqlalchemy_uri_decrypted
426426 )
427+ self .db_engine_spec .validate_database_uri (sqlalchemy_url )
428+
427429 sqlalchemy_url = self .db_engine_spec .adjust_database_uri (sqlalchemy_url , schema )
428430 effective_username = self .get_effective_user (sqlalchemy_url )
429431 # If using MySQL or Presto for example, will set url.username
Original file line number Diff line number Diff line change 3333 TINYINT ,
3434 TINYTEXT ,
3535)
36+ from sqlalchemy .engine .url import make_url
3637
3738from superset .utils .core import GenericDataType
3839from tests .unit_tests .db_engine_specs .utils import (
@@ -99,6 +100,25 @@ def test_convert_dttm(
99100 assert_convert_dttm (spec , target_type , expected_result , dttm )
100101
101102
103+ @pytest .mark .parametrize (
104+ "sqlalchemy_uri,error" ,
105+ [
106+ ("mysql://user:password@host/db1?local_infile=1" , True ),
107+ ("mysql://user:password@host/db1?local_infile=0" , True ),
108+ ("mysql://user:password@host/db1" , False ),
109+ ],
110+ )
111+ def test_validate_database_uri (sqlalchemy_uri : str , error : bool ) -> None :
112+ from superset .db_engine_specs .mysql import MySQLEngineSpec
113+
114+ url = make_url (sqlalchemy_uri )
115+ if error :
116+ with pytest .raises (ValueError ):
117+ MySQLEngineSpec .validate_database_uri (url )
118+ return
119+ MySQLEngineSpec .validate_database_uri (url )
120+
121+
102122@patch ("sqlalchemy.engine.Engine.connect" )
103123def test_get_cancel_query_id (engine_mock : Mock ) -> None :
104124 from superset .db_engine_specs .mysql import MySQLEngineSpec
You can’t perform that action at this time.
0 commit comments