Skip to content

Commit a3443d7

Browse files
committed
Fix for Python 3.6, win32 and lack of TLSv1.1
1 parent 3ffdde5 commit a3443d7

File tree

2 files changed

+41
-29
lines changed

2 files changed

+41
-29
lines changed

asyncpg/connect_utils.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ def _parse_hostlist(hostlist, port, *, unquote=False):
222222

223223

224224
def _parse_tls_version(tls_version):
225+
if not hasattr(ssl_module, 'TLSVersion'):
226+
raise ValueError(
227+
"TLSVersion is not supported in this version of Python"
228+
)
225229
if tls_version.startswith('SSL'):
226230
raise ValueError(
227231
f"Unsupported TLS version: {tls_version}"
@@ -234,6 +238,10 @@ def _parse_tls_version(tls_version):
234238
)
235239

236240

241+
def _dot_postgresql_path(filename) -> pathlib.Path:
242+
return (pathlib.Path.home() / '.postgresql' / filename).resolve()
243+
244+
237245
def _parse_connect_dsn_and_args(*, dsn, host, port, user,
238246
password, passfile, database, ssl,
239247
connect_timeout, server_settings):
@@ -485,7 +493,7 @@ def _parse_connect_dsn_and_args(*, dsn, host, port, user,
485493
ssl.load_verify_locations(cafile=sslrootcert)
486494
ssl.verify_mode = ssl_module.CERT_REQUIRED
487495
else:
488-
sslrootcert = os.path.expanduser('~/.postgresql/root.crt')
496+
sslrootcert = _dot_postgresql_path('root.crt')
489497
try:
490498
ssl.load_verify_locations(cafile=sslrootcert)
491499
except FileNotFoundError:
@@ -509,7 +517,7 @@ def _parse_connect_dsn_and_args(*, dsn, host, port, user,
509517
ssl.load_verify_locations(cafile=sslcrl)
510518
ssl.verify_flags |= ssl_module.VERIFY_CRL_CHECK_CHAIN
511519
else:
512-
sslcrl = os.path.expanduser('~/.postgresql/root.crl')
520+
sslcrl = _dot_postgresql_path('root.crl')
513521
try:
514522
ssl.load_verify_locations(cafile=sslcrl)
515523
except FileNotFoundError:
@@ -520,8 +528,8 @@ def _parse_connect_dsn_and_args(*, dsn, host, port, user,
520528
if sslkey is None:
521529
sslkey = os.getenv('PGSSLKEY')
522530
if not sslkey:
523-
sslkey = os.path.expanduser('~/.postgresql/postgresql.key')
524-
if not os.path.exists(sslkey):
531+
sslkey = _dot_postgresql_path('postgresql.key')
532+
if not sslkey.exists():
525533
sslkey = None
526534
if not sslpassword:
527535
sslpassword = ''
@@ -532,7 +540,7 @@ def _parse_connect_dsn_and_args(*, dsn, host, port, user,
532540
sslcert, keyfile=sslkey, password=lambda: sslpassword
533541
)
534542
else:
535-
sslcert = os.path.expanduser('~/.postgresql/postgresql.crt')
543+
sslcert = _dot_postgresql_path('postgresql.crt')
536544
try:
537545
ssl.load_cert_chain(
538546
sslcert, keyfile=sslkey, password=lambda: sslpassword
@@ -552,13 +560,17 @@ def _parse_connect_dsn_and_args(*, dsn, host, port, user,
552560
ssl.options &= ~ssl_module.OP_NO_COMPRESSION
553561

554562
if ssl_min_protocol_version is None:
555-
ssl_min_protocol_version = os.getenv(
556-
'PGSSLMINPROTOCOLVERSION', 'TLSv1.2'
557-
)
563+
ssl_min_protocol_version = os.getenv('PGSSLMINPROTOCOLVERSION')
558564
if ssl_min_protocol_version:
559565
ssl.minimum_version = _parse_tls_version(
560566
ssl_min_protocol_version
561567
)
568+
else:
569+
try:
570+
ssl.minimum_version = _parse_tls_version('TLSv1.2')
571+
except ValueError:
572+
# Python 3.6 does not have ssl.TLSVersion
573+
pass
562574

563575
if ssl_max_protocol_version is None:
564576
ssl_max_protocol_version = os.getenv('PGSSLMAXPROTOCOLVERSION')

tests/test_connect.py

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
import contextlib
1010
import ipaddress
1111
import os
12+
import pathlib
1213
import platform
1314
import shutil
1415
import ssl
1516
import stat
17+
import sys
1618
import tempfile
1719
import textwrap
1820
import unittest
@@ -46,31 +48,26 @@
4648
@contextlib.contextmanager
4749
def mock_dot_postgresql(*, ca=True, crl=False, client=False, protected=False):
4850
with tempfile.TemporaryDirectory() as temp_dir:
49-
pg_home = os.path.join(temp_dir, '.postgresql')
50-
os.mkdir(pg_home)
51+
home = pathlib.Path(temp_dir)
52+
pg_home = home / '.postgresql'
53+
pg_home.mkdir()
5154
if ca:
52-
shutil.copyfile(
53-
SSL_CA_CERT_FILE, os.path.join(pg_home, 'root.crt')
54-
)
55+
shutil.copyfile(SSL_CA_CERT_FILE, pg_home / 'root.crt')
5556
if crl:
56-
shutil.copyfile(
57-
SSL_CA_CRL_FILE, os.path.join(pg_home, 'root.crl')
58-
)
57+
shutil.copyfile(SSL_CA_CRL_FILE, pg_home / 'root.crl')
5958
if client:
60-
shutil.copyfile(
61-
CLIENT_SSL_CERT_FILE, os.path.join(pg_home, 'postgresql.crt')
62-
)
59+
shutil.copyfile(CLIENT_SSL_CERT_FILE, pg_home / 'postgresql.crt')
6360
if protected:
6461
shutil.copyfile(
65-
CLIENT_SSL_PROTECTED_KEY_FILE,
66-
os.path.join(pg_home, 'postgresql.key'),
62+
CLIENT_SSL_PROTECTED_KEY_FILE, pg_home / 'postgresql.key'
6763
)
6864
else:
6965
shutil.copyfile(
70-
CLIENT_SSL_KEY_FILE,
71-
os.path.join(pg_home, 'postgresql.key'),
66+
CLIENT_SSL_KEY_FILE, pg_home / 'postgresql.key'
7267
)
73-
with unittest.mock.patch.dict('os.environ', {'HOME': temp_dir}):
68+
with unittest.mock.patch(
69+
'pathlib.Path.home', unittest.mock.Mock(return_value=home)
70+
):
7471
yield
7572

7673

@@ -1340,13 +1337,13 @@ async def verify_fails(sslmode, *, host='localhost', exn_type):
13401337
await verify_works('allow')
13411338
await verify_works('prefer')
13421339
await verify_fails('require',
1343-
exn_type=ssl.CertificateError)
1340+
exn_type=ssl.SSLError)
13441341
await verify_fails('verify-ca',
1345-
exn_type=ssl.CertificateError)
1342+
exn_type=ssl.SSLError)
13461343
await verify_fails('verify-ca', host='127.0.0.1',
1347-
exn_type=ssl.CertificateError)
1344+
exn_type=ssl.SSLError)
13481345
await verify_fails('verify-full',
1349-
exn_type=ssl.CertificateError)
1346+
exn_type=ssl.SSLError)
13501347

13511348
async def test_ssl_connection_default_context(self):
13521349
# XXX: uvloop artifact
@@ -1410,6 +1407,9 @@ async def test_executemany_uvloop_ssl_issue_700(self):
14101407
finally:
14111408
await con.close()
14121409

1410+
@unittest.skipIf(
1411+
sys.version_info < (3, 7), "Python < 3.7 doesn't have ssl.TLSVersion"
1412+
)
14131413
async def test_tls_version(self):
14141414
# XXX: uvloop artifact
14151415
old_handler = self.loop.get_exception_handler()
@@ -1420,7 +1420,7 @@ async def test_tls_version(self):
14201420
dsn='postgresql://ssl_user@localhost/postgres'
14211421
'?sslmode=require&ssl_min_protocol_version=TLSv1.3'
14221422
)
1423-
with self.assertRaisesRegex(ssl.SSLError, 'protocol version'):
1423+
with self.assertRaises(ssl.SSLError):
14241424
await self.connect(
14251425
dsn='postgresql://ssl_user@localhost/postgres'
14261426
'?sslmode=require'

0 commit comments

Comments
 (0)