Skip to content

Commit 236febf

Browse files
hovaescoebyhr
authored andcommitted
Add certificate auth support via connection string in SQLAlchemy
1 parent 3203d7d commit 236febf

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ The OAuth2 token will be cached either per `trino.auth.OAuth2Authentication` ins
241241
from sqlalchemy import create_engine
242242
from trino.auth import CertificateAuthentication
243243

244+
engine = create_engine("trino://<username>@<host>:<port>/<catalog>/<schema>?cert=<cert>&key=<key>")
245+
246+
# or
244247
engine = create_engine(
245248
"trino://<username>@<host>:<port>/<catalog>",
246249
connect_args={

tests/unit/sqlalchemy/test_dialect.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@
77

88
from trino.auth import BasicAuthentication
99
from trino.dbapi import Connection
10-
from trino.sqlalchemy.dialect import TrinoDialect
10+
from trino.sqlalchemy.dialect import CertificateAuthentication, JWTAuthentication, TrinoDialect
1111
from trino.transaction import IsolationLevel
1212

1313

1414
class TestTrinoDialect:
1515
def setup(self):
1616
self.dialect = TrinoDialect()
1717

18-
# TODO: Test more authentication methods and URL params (https://github.com/trinodb/trino-python-client/issues/106)
1918
@pytest.mark.parametrize(
2019
"url, expected_args, expected_kwargs",
2120
[
@@ -72,3 +71,40 @@ def test_isolation_level(self):
7271

7372
isolation_level = self.dialect.get_isolation_level(dbapi_conn)
7473
assert isolation_level == "SERIALIZABLE"
74+
75+
76+
def test_trino_connection_basic_auth():
77+
dialect = TrinoDialect()
78+
username = 'trino-user'
79+
password = 'trino-bunny'
80+
url = make_url(f'trino://{username}:{password}@host')
81+
_, cparams = dialect.create_connect_args(url)
82+
83+
assert cparams['http_scheme'] == "https"
84+
assert isinstance(cparams['auth'], BasicAuthentication)
85+
assert cparams['auth']._username == username
86+
assert cparams['auth']._password == password
87+
88+
89+
def test_trino_connection_jwt_auth():
90+
dialect = TrinoDialect()
91+
access_token = 'sample-token'
92+
url = make_url(f'trino://host/?access_token={access_token}')
93+
_, cparams = dialect.create_connect_args(url)
94+
95+
assert cparams['http_scheme'] == "https"
96+
assert isinstance(cparams['auth'], JWTAuthentication)
97+
assert cparams['auth'].token == access_token
98+
99+
100+
def test_trino_connection_certificate_auth():
101+
dialect = TrinoDialect()
102+
cert = '/path/to/cert.pem'
103+
key = '/path/to/key.pem'
104+
url = make_url(f'trino://host/?cert={cert}&key={key}')
105+
_, cparams = dialect.create_connect_args(url)
106+
107+
assert cparams['http_scheme'] == "https"
108+
assert isinstance(cparams['auth'], CertificateAuthentication)
109+
assert cparams['auth']._cert == cert
110+
assert cparams['auth']._key == key

trino/sqlalchemy/dialect.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from sqlalchemy.engine.url import URL
1919

2020
from trino import dbapi as trino_dbapi, logging
21-
from trino.auth import BasicAuthentication, JWTAuthentication
21+
from trino.auth import BasicAuthentication, CertificateAuthentication, JWTAuthentication
2222
from trino.dbapi import Cursor
2323
from trino.exceptions import TrinoUserError
2424
from trino.sqlalchemy import compiler, datatype, error
@@ -96,6 +96,10 @@ def create_connect_args(self, url: URL) -> Tuple[Sequence[Any], Mapping[str, Any
9696
kwargs["http_scheme"] = "https"
9797
kwargs["auth"] = JWTAuthentication(url.query["access_token"])
9898

99+
if "cert" and "key" in url.query:
100+
kwargs["http_scheme"] = "https"
101+
kwargs["auth"] = CertificateAuthentication(url.query['cert'], url.query['key'])
102+
99103
if "source" in url.query:
100104
kwargs["source"] = url.query["source"]
101105
else:

0 commit comments

Comments
 (0)