psycopg/psycopg/errors.py: E125, E128, E302
# Allow concatenated string literals from async_to_sync
+ psycopg/psycopg/connection.py: E501
psycopg_pool/psycopg_pool/pool.py: E501
# Pytest's importorskip() getting in the way
(:ticket:`#1108`).
- Add support for Python 3.14 (:ticket:`#1053`).
- Fix `psycopg_binary.__version__`.
+- Raise a warning if a GSSAPI connection is obtained using the
+ ``gssencmode=prefer`` libpq default (see :ticket:`#1136`).
+
+ .. warning::
+
+ In a future Psycopg version the default in the binary package will be
+ changed to ``disable``. If you need to interact with the GSSAPI reliably
+ you should explicitly set the ``gssencmode`` parameter in the connection
+ string or the :envvar:`PGGSSENCMODE` environment variable to ``prefer`` or
+ ``require``.
Current release
except ValueError:
return False
return True
+
+
+def gssapi_requested(params: ConnDict) -> bool:
+ """Return `true` if `gssencmode` was specified explicitly."""
+ return bool(get_param(params, "gssencmode"))
from __future__ import annotations
import logging
+import warnings
from time import monotonic
from types import TracebackType
from typing import TYPE_CHECKING, Any, Generator, Iterator, cast, overload
from .transaction import Transaction
from ._capabilities import capabilities
from ._server_cursor import ServerCursor
+from ._conninfo_utils import gssapi_requested
from ._connection_base import BaseConnection, CursorRow, Notify
if TYPE_CHECKING:
lines.extend((f"- {descr}: {error}" for error, descr in conn_errors))
raise type(last_ex)("\n".join(lines)).with_traceback(None)
+ if (
+ pq.version() >= 160000
+ and rv.pgconn.used_gssapi
+ and (not gssapi_requested(params))
+ ):
+ warnings.warn(
+ "the connection was obtained using the GSSAPI relying on the 'gssencmode=prefer' libpq default. In a future psycopg[binary] version this default will be changed to 'disable'. If you wish to interact with the GSSAPI reliably please set the 'gssencmode' parameter in the connection string or the 'PGGSSENCMODE' environment variable to 'prefer' or 'require'",
+ DeprecationWarning,
+ )
+
rv._autocommit = bool(autocommit)
if row_factory:
rv.row_factory = row_factory
from __future__ import annotations
import logging
+import warnings
from time import monotonic
from types import TracebackType
from typing import TYPE_CHECKING, Any, AsyncGenerator, AsyncIterator, cast, overload
from .transaction import AsyncTransaction
from .cursor_async import AsyncCursor
from ._capabilities import capabilities
+from ._conninfo_utils import gssapi_requested
from ._connection_base import BaseConnection, CursorRow, Notify
from ._server_cursor_async import AsyncServerCursor
lines.extend(f"- {descr}: {error}" for error, descr in conn_errors)
raise type(last_ex)("\n".join(lines)).with_traceback(None)
+ if (
+ pq.version() >= 160000
+ and rv.pgconn.used_gssapi
+ and not gssapi_requested(params)
+ ):
+ warnings.warn(
+ "the connection was obtained using the GSSAPI relying on the"
+ " 'gssencmode=prefer' libpq default. In a future psycopg[binary]"
+ " version this default will be changed to 'disable'."
+ " If you wish to interact with the GSSAPI reliably please set the"
+ " 'gssencmode' parameter in the connection string or the"
+ " 'PGGSSENCMODE' environment variable to 'prefer' or 'require'",
+ DeprecationWarning,
+ )
+
rv._autocommit = bool(autocommit)
if row_factory:
rv.row_factory = row_factory
from psycopg import pq
from psycopg.rows import tuple_row
from psycopg.conninfo import conninfo_to_dict, timeout_from_conninfo
+from psycopg._conninfo_utils import get_param
from .acompat import skip_async, skip_sync, sleep
from .fix_crdb import crdb_anydb
params = conninfo_to_dict(dsn, target_session_attrs=mode)
with pytest.raises(psycopg.OperationalError, match=mode):
conn_cls.connect(**params)
+
+
+@pytest.mark.libpq(">= 16")
+@pytest.mark.skipif(pq.__impl__ != "python", reason="can't monkeypatch C module")
+def test_implicit_gssapi_warning(conn_cls, dsn, recwarn, monkeypatch):
+ if get_param(conninfo_to_dict(dsn), "gssencmode"):
+ pytest.skip("gssencmode parameter explicitly set in test connection string")
+
+ monkeypatch.setattr(pq.PGconn, "used_gssapi", lambda: True)
+ with conn_cls.connect(dsn):
+ pass
+
+ assert "gssencmode" in str(recwarn.pop(DeprecationWarning).message)
from psycopg import pq
from psycopg.rows import tuple_row
from psycopg.conninfo import conninfo_to_dict, timeout_from_conninfo
+from psycopg._conninfo_utils import get_param
from .acompat import asleep, skip_async, skip_sync
from .fix_crdb import crdb_anydb
params = conninfo_to_dict(dsn, target_session_attrs=mode)
with pytest.raises(psycopg.OperationalError, match=mode):
await aconn_cls.connect(**params)
+
+
+@pytest.mark.libpq(">= 16")
+@pytest.mark.skipif(pq.__impl__ != "python", reason="can't monkeypatch C module")
+async def test_implicit_gssapi_warning(aconn_cls, dsn, recwarn, monkeypatch):
+ if get_param(conninfo_to_dict(dsn), "gssencmode"):
+ pytest.skip("gssencmode parameter explicitly set in test connection string")
+
+ monkeypatch.setattr(pq.PGconn, "used_gssapi", lambda: True)
+ async with await aconn_cls.connect(dsn):
+ pass
+
+ assert "gssencmode" in str(recwarn.pop(DeprecationWarning).message)