Description
- asyncpg version: 0.23.0 - 0.25.0
- PostgreSQL version: 13.3, and 9.6.22 for additional testing
- Do you use a PostgreSQL SaaS? If so, which? Can you reproduce
the issue with a local PostgreSQL install?: Using RDS primarily. Issue happens anywhere. - Python version: 3.8.11, also reproduced in 3.6.8
- Platform: CentOS 7
- Do you use pgbouncer?: No
- Did you install asyncpg with pip?: Yes
- If you built asyncpg locally, which version of Cython did you use?: n/a
- Can the issue be reproduced under both asyncio and
uvloop?: Yes
With FIPS mode enabled, md5 is not allowed. And if asyncpg attempts to connect to a DB using md5 authentication if produced a timeout error. Obviously there is an issue connection with a db configured to use md5, and I was able to connect once it was updated to use SCRAM
instead, but it took forever to figure out what the issue was due to how the error is handled.
Simple script:
import asyncio
import asyncpg
async def main():
print("start")
c = await asyncpg.connect("postgresql://...")
print("end")
asyncio.get_event_loop().run_until_complete(main())
In 0.25.0 it says 'start' then hangs for a minute and then produces this stack trace:
Traceback (most recent call last):
File "test_async.py", line 9, in <module>
asyncio.get_event_loop().run_until_complete(main())
File "/opt/rh/rh-python38/root/lib64/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "test_async.py", line 6, in main
c = await asyncpg.connect("postgresql://...")
File "/home/maintuser/venv/lib64/python3.8/site-packages/asyncpg/connection.py", line 2085, in connect
return await connect_utils._connect(
File "/home/maintuser/venv/lib64/python3.8/site-packages/asyncpg/connect_utils.py", line 895, in _connect
raise last_error
File "/home/maintuser/venv/lib64/python3.8/site-packages/asyncpg/connect_utils.py", line 881, in _connect
return await _connect_addr(
File "/home/maintuser/venv/lib64/python3.8/site-packages/asyncpg/connect_utils.py", line 781, in _connect_addr
return await __connect_addr(params, timeout, True, *args)
File "/home/maintuser/venv/lib64/python3.8/site-packages/asyncpg/connect_utils.py", line 831, in __connect_addr
await compat.wait_for(connected, timeout=timeout)
File "/home/maintuser/venv/lib64/python3.8/site-packages/asyncpg/compat.py", line 66, in wait_for
return await asyncio.wait_for(fut, timeout)
File "/opt/rh/rh-python38/root/lib64/python3.8/asyncio/tasks.py", line 501, in wait_for
raise exceptions.TimeoutError()
asyncio.exceptions.TimeoutError
The use of md5 is https://github.com/MagicStack/asyncpg/blob/master/asyncpg/protocol/coreproto.pyx#L637 unfortunately I don't know where that is getting wrapped up and ending up a timeout.
For reference this is the error you get if you try to use hashlib.md5 on a FIPS enabled machine:
$ python
Python 3.8.11 (default, Sep 1 2021, 12:33:46)
[GCC 9.3.1 20200408 (Red Hat 9.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import hashlib
>>> hashlib.md5()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
I would expect that ValueError, or something along those lines, should be making it back to me, but somehow it gets caught in a loop inside until it hits the timeout. I am guessing there is an an except in there is catching too much, but without being familiar with the codebase I haven't found it yet.