Currently, Env.db_url_config uses _cast_urlstr to url unquote the username and password from database connection URIs. The underlying problem occurs when you try to use a + in your postgres password.
_cast_urlstr uses unquote_plus, (introduced in this PR here), which which will turn plus signs into spaces when unquoted. This is undesired, as plus signs should only be replaced for spaces in HTML form values that are URL encoded, not in connection URIs.
Unquote docs
unquote vs unquote_plus
This bug was discovered when using CrunchyData's PGO on kubernetes. The PGO autogenerates postgres URIs for users and stores them inside of a kubernetes secret. An example URI is shown below:
postgresql://myuser:Le-%7BFsIaYnaQw%7Da2B%2F%5BV8bS+@postgres-pgbouncer.postgres-operator.svc:5432/mydb
Using the different unquotes to decode the password:
>>> unquote('Le-%7BFsIaYnaQw%7Da2B%2F%5BV8bS+')
'Le-{FsIaYnaQw}a2B/[V8bS+'
>>> unquote_plus('Le-%7BFsIaYnaQw%7Da2B%2F%5BV8bS+')
'Le-{FsIaYnaQw}a2B/[V8bS '
The first one can be used to sign into the database using both psql and psycopg2.connect, while the second gives an auth error.
I ran the test suite for django-environ using both unquote_plus and unquote and all tests passed, regardless of which implementation is used, so I believe moving to unquote shouldn't be a huge change. I'll open a PR with changes and link them to this issue.
Currently,
Env.db_url_configuses_cast_urlstrto url unquote the username and password from database connection URIs. The underlying problem occurs when you try to use a+in your postgres password._cast_urlstrusesunquote_plus, (introduced in this PR here), which which will turn plus signs into spaces when unquoted. This is undesired, as plus signs should only be replaced for spaces in HTML form values that are URL encoded, not in connection URIs.Unquote docs
unquote vs unquote_plus
This bug was discovered when using CrunchyData's PGO on kubernetes. The PGO autogenerates postgres URIs for users and stores them inside of a kubernetes secret. An example URI is shown below:
Using the different unquotes to decode the password:
The first one can be used to sign into the database using both
psqlandpsycopg2.connect, while the second gives an auth error.I ran the test suite for
django-environusing bothunquote_plusandunquoteand all tests passed, regardless of which implementation is used, so I believe moving tounquoteshouldn't be a huge change. I'll open a PR with changes and link them to this issue.