diff --git a/src/fides/api/service/connectors/mysql_connector.py b/src/fides/api/service/connectors/mysql_connector.py index 4428125e2d0..80d01d3f949 100644 --- a/src/fides/api/service/connectors/mysql_connector.py +++ b/src/fides/api/service/connectors/mysql_connector.py @@ -1,4 +1,5 @@ from typing import Dict, List +from urllib.parse import quote from sqlalchemy.engine import Engine, LegacyCursorResult, create_engine # type: ignore @@ -24,13 +25,15 @@ class MySQLConnector(SQLConnector): secrets_schema = MySQLSchema def build_uri(self) -> str: - """Build URI of format mysql+pymysql://[user[:password]@][netloc][:port][/dbname]""" + """Build URI of format mysql+pymysql://[user[:password]@][netloc][:port][/dbname]. + Username and password are URL-encoded so that reserved characters (e.g. @, :) do not + break URI parsing.""" config = self.secrets_schema(**self.configuration.secrets or {}) user_password = "" if config.username: - user = config.username - password = f":{config.password}" if config.password else "" + user = quote(str(config.username), safe="") + password = f":{quote(str(config.password), safe='')}" if config.password else "" user_password = f"{user}{password}@" netloc = config.host @@ -40,13 +43,15 @@ def build_uri(self) -> str: return url def build_ssh_uri(self, local_address: tuple) -> str: - """Build URI of format mysql+pymysql://[user[:password]@][ssh_host][:ssh_port][/dbname]""" + """Build URI of format mysql+pymysql://[user[:password]@][ssh_host][:ssh_port][/dbname]. + Username and password are URL-encoded so that reserved characters (e.g. @, :) do not + break URI parsing.""" config = self.secrets_schema(**self.configuration.secrets or {}) user_password = "" if config.username: - user = config.username - password = f":{config.password}" if config.password else "" + user = quote(str(config.username), safe="") + password = f":{quote(str(config.password), safe='')}" if config.password else "" user_password = f"{user}{password}@" local_host, local_port = local_address diff --git a/src/fides/api/service/connectors/postgres_connector.py b/src/fides/api/service/connectors/postgres_connector.py index 86b57cae127..d0c075e1318 100644 --- a/src/fides/api/service/connectors/postgres_connector.py +++ b/src/fides/api/service/connectors/postgres_connector.py @@ -1,3 +1,5 @@ +from urllib.parse import quote + from loguru import logger from sqlalchemy import text from sqlalchemy.engine import Connection, Engine, create_engine # type: ignore @@ -25,13 +27,15 @@ def requires_primary_keys(self) -> bool: return False def build_uri(self) -> str: - """Build URI of format postgresql://[user[:password]@][netloc][:port][/dbname]""" + """Build URI of format postgresql://[user[:password]@][netloc][:port][/dbname]. + Username and password are URL-encoded so that reserved characters (e.g. @, :) do not + break URI parsing.""" config = self.secrets_schema(**self.configuration.secrets or {}) user_password = "" if config.username: - user = config.username - password = f":{config.password}" if config.password else "" + user = quote(str(config.username), safe="") + password = f":{quote(str(config.password), safe='')}" if config.password else "" user_password = f"{user}{password}@" netloc = config.host @@ -41,13 +45,15 @@ def build_uri(self) -> str: return f"postgresql://{user_password}{netloc}{port}{dbname}{query}" def build_ssh_uri(self, local_address: tuple) -> str: - """Build URI of format postgresql://[user[:password]@][ssh_host][:ssh_port][/dbname]""" + """Build URI of format postgresql://[user[:password]@][ssh_host][:ssh_port][/dbname]. + Username and password are URL-encoded so that reserved characters (e.g. @, :) do not + break URI parsing.""" config = self.secrets_schema(**self.configuration.secrets or {}) user_password = "" if config.username: - user = config.username - password = f":{config.password}" if config.password else "" + user = quote(str(config.username), safe="") + password = f":{quote(str(config.password), safe='')}" if config.password else "" user_password = f"{user}{password}@" local_host, local_port = local_address diff --git a/src/fides/api/service/connectors/redshift_connector.py b/src/fides/api/service/connectors/redshift_connector.py index 14e149770a4..f3dd7457b9a 100644 --- a/src/fides/api/service/connectors/redshift_connector.py +++ b/src/fides/api/service/connectors/redshift_connector.py @@ -1,5 +1,5 @@ from typing import Dict, Union -from urllib.parse import quote_plus +from urllib.parse import quote from loguru import logger from sqlalchemy import text @@ -22,25 +22,32 @@ class RedshiftConnector(SQLConnector): secrets_schema = RedshiftSchema def build_ssh_uri(self, local_address: tuple) -> str: - """Build SSH URI of format redshift+psycopg2://[user[:password]@][ssh_host][:ssh_port][/dbname]""" + """Build SSH URI of format redshift+psycopg2://[user[:password]@][ssh_host][:ssh_port][/dbname]. + Username and password are URL-encoded so that reserved characters (e.g. @, :) do not + break URI parsing.""" local_host, local_port = local_address config = self.secrets_schema(**self.configuration.secrets or {}) port = f":{local_port}" if local_port else "" database = f"/{config.database}" if config.database else "" - url = f"redshift+psycopg2://{config.user}:{config.password}@{local_host}{port}{database}" + user = quote(str(config.user), safe="") + password = quote(str(config.password), safe="") + url = f"redshift+psycopg2://{user}:{password}@{local_host}{port}{database}" return url # Overrides BaseConnector.build_uri def build_uri(self) -> str: - """Build URI of format redshift+psycopg2://user:password@[host][:port][/database]""" + """Build URI of format redshift+psycopg2://user:password@[host][:port][/database]. + Username and password are URL-encoded so that reserved characters (e.g. @, :) do not + break URI parsing.""" config = self.secrets_schema(**self.configuration.secrets or {}) - url_encoded_password = quote_plus(config.password) + user = quote(str(config.user), safe="") + password = quote(str(config.password), safe="") port = f":{config.port}" if config.port else "" database = f"/{config.database}" if config.database else "" - url = f"redshift+psycopg2://{config.user}:{url_encoded_password}@{config.host}{port}{database}" + url = f"redshift+psycopg2://{user}:{password}@{config.host}{port}{database}" return url # Overrides SQLConnector.create_client