From ba0d68b99182871b0ef9d554fc9804ae434f573d Mon Sep 17 00:00:00 2001 From: Gord Thompson Date: Sun, 29 May 2022 07:07:45 -0600 Subject: [PATCH] mssql login failure if password starts with "{" Fix issue where a password with a leading "{" would result in login failure. Fixes: #8062 Change-Id: If91c2c211937b5eac89b8d525c22a19b0a94c5c4 (cherry picked from commit 8ac7cb92b4972a08b8008b80b34989694510139f) --- doc/build/changelog/unreleased_14/8062.rst | 5 ++ lib/sqlalchemy/connectors/pyodbc.py | 2 +- test/dialect/mssql/test_engine.py | 54 ++++++++++++++++------ 3 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 doc/build/changelog/unreleased_14/8062.rst diff --git a/doc/build/changelog/unreleased_14/8062.rst b/doc/build/changelog/unreleased_14/8062.rst new file mode 100644 index 0000000000..ada473de9c --- /dev/null +++ b/doc/build/changelog/unreleased_14/8062.rst @@ -0,0 +1,5 @@ +.. change:: + :tags: bug, mssql + :tickets: 8062 + + Fix issue where a password with a leading "{" would result in login failure. diff --git a/lib/sqlalchemy/connectors/pyodbc.py b/lib/sqlalchemy/connectors/pyodbc.py index 7a97aa16c7..9bb67b5113 100644 --- a/lib/sqlalchemy/connectors/pyodbc.py +++ b/lib/sqlalchemy/connectors/pyodbc.py @@ -60,7 +60,7 @@ class PyODBCConnector(Connector): else: def check_quote(token): - if ";" in str(token): + if ";" in str(token) or str(token).startswith("{"): token = "{%s}" % token.replace("}", "}}") return token diff --git a/test/dialect/mssql/test_engine.py b/test/dialect/mssql/test_engine.py index 5482e26167..b5a04f1405 100644 --- a/test/dialect/mssql/test_engine.py +++ b/test/dialect/mssql/test_engine.py @@ -234,25 +234,49 @@ class ParseConnectTest(fixtures.TestBase): connection, ) - def test_pyodbc_token_injection(self): - token1 = "someuser%3BPORT%3D50001" - token2 = "some{strange}pw%3BPORT%3D50001" - token3 = "somehost%3BPORT%3D50001" - token4 = "somedb%3BPORT%3D50001" - - u = url.make_url( - "mssql+pyodbc://%s:%s@%s/%s?driver=foob" - % (token1, token2, token3, token4) - ) - dialect = pyodbc.dialect() - connection = dialect.create_connect_args(u) - eq_( - [ + @testing.combinations( + ( + "original", + ( + "someuser%3BPORT%3D50001", + "some{strange}pw%3BPORT%3D50001", + "somehost%3BPORT%3D50001", + "somedb%3BPORT%3D50001", + ), + ( [ "DRIVER={foob};Server=somehost%3BPORT%3D50001;" "Database=somedb%3BPORT%3D50001;UID={someuser;PORT=50001};" "PWD={some{strange}}pw;PORT=50001}" - ], + ] + ), + ), + ( + "issue_8062", + ( + "larry", + "{moe", + "localhost", + "mydb", + ), + ( + [ + "DRIVER={foob};Server=localhost;" + "Database=mydb;UID=larry;" + "PWD={{moe}" + ] + ), + ), + argnames="tokens, connection_string", + id_="iaa", + ) + def test_pyodbc_token_injection(self, tokens, connection_string): + u = url.make_url("mssql+pyodbc://%s:%s@%s/%s?driver=foob" % tokens) + dialect = pyodbc.dialect() + connection = dialect.create_connect_args(u) + eq_( + [ + connection_string, {}, ], connection, -- 2.47.2