]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
feat: add support for libpq PQconnectionUsedGSSAPI()
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Mon, 25 Aug 2025 16:35:30 +0000 (18:35 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 26 Aug 2025 12:50:30 +0000 (14:50 +0200)
We will not advertise its presence as PGconn.used_gssapi until Psycopg
3.3. However we can use it internally to implement a warning to check
the implicit usage of gssencmode=prefer.

See #1136

psycopg/psycopg/errors.py
psycopg/psycopg/pq/_pq_ctypes.py
psycopg/psycopg/pq/_pq_ctypes.pyi
psycopg/psycopg/pq/abc.py
psycopg/psycopg/pq/pq_ctypes.py
psycopg_c/psycopg_c/pq/libpq.pxd
psycopg_c/psycopg_c/pq/pgconn.pyx
tests/pq/test_pgconn.py

index fe410fa67434f687218dd7f29dad1b0f758e6e25..b71c56dd65e57385cc06751f7c9cd475df464061 100644 (file)
@@ -66,6 +66,7 @@ class FinishedPGconn:
     backend_pid: int = 0
     needs_password: bool = False
     used_password: bool = False
+    used_gssapi: bool = False
     ssl_in_use: bool = False
 
     nonblocking: int = 0
index 99e49357c7c59d66e0958167754350c0fc07e492..b02812c7103753480f555f71ccc1d7e1d01ef312 100644 (file)
@@ -259,6 +259,13 @@ PQconnectionUsedPassword = pq.PQconnectionUsedPassword
 PQconnectionUsedPassword.argtypes = [PGconn_ptr]
 PQconnectionUsedPassword.restype = c_int
 
+if libpq_version >= 160000:
+    PQconnectionUsedGSSAPI = pq.PQconnectionUsedGSSAPI
+    PQconnectionUsedGSSAPI.argtypes = [PGconn_ptr]
+    PQconnectionUsedGSSAPI.restype = c_int
+else:
+    PQconnectionUsedGSSAPI = not_supported_before("PQconnectionUsedGSSAPI", 160000)
+
 PQsslInUse = pq.PQsslInUse
 PQsslInUse.argtypes = [PGconn_ptr]
 PQsslInUse.restype = c_int
index 091ef6be7335202c76aea23bb2ac192d30ce6826..fda7f1559a8c74089576500e919890719b7380b8 100644 (file)
@@ -170,6 +170,7 @@ def PQsocket(arg1: PGconn_struct | None) -> int: ...
 def PQbackendPID(arg1: PGconn_struct | None) -> int: ...
 def PQconnectionNeedsPassword(arg1: PGconn_struct | None) -> int: ...
 def PQconnectionUsedPassword(arg1: PGconn_struct | None) -> int: ...
+def PQconnectionUsedGSSAPI(arg1: PGconn_struct | None) -> int: ...
 def PQsslInUse(arg1: PGconn_struct | None) -> int: ...
 def PQexec(arg1: PGconn_struct | None, arg2: bytes) -> PGresult_struct: ...
 def PQexecParams(arg1: PGconn_struct | None, arg2: bytes, arg3: int, arg4: _Pointer[c_uint], arg5: _Pointer[c_char_p], arg6: _Pointer[c_int], arg7: _Pointer[c_int], arg8: int) -> PGresult_struct: ...
index 5fbe112b95ca752ab57f27a23556bae48ff83191..65932840251de4cc81899c266abe53a79a77104a 100644 (file)
@@ -103,6 +103,9 @@ class PGconn(Protocol):
     @property
     def used_password(self) -> bool: ...
 
+    @property
+    def used_gssapi(self) -> bool: ...
+
     @property
     def ssl_in_use(self) -> bool: ...
 
index cf9684f5e2b5c4ec450bb634d9fc8aa0f6fb3fe0..059f0ae45b88a7eb317f204625267ae41375b949 100644 (file)
@@ -268,6 +268,10 @@ class PGconn:
         """
         return bool(impl.PQconnectionUsedPassword(self._pgconn_ptr))
 
+    @property
+    def used_gssapi(self) -> bool:
+        return bool(impl.PQconnectionUsedGSSAPI(self._pgconn_ptr))
+
     @property
     def ssl_in_use(self) -> bool:
         return self._call_bool(impl.PQsslInUse)
index ada48d67487dce59edd7fd38b422a090508c911a..dc7fb54cf3519e60c20407b0905bfcabf30e2154 100644 (file)
@@ -144,6 +144,7 @@ cdef extern from "libpq-fe.h":
     int PQbackendPID(const PGconn *conn)
     int PQconnectionNeedsPassword(const PGconn *conn)
     int PQconnectionUsedPassword(const PGconn *conn)
+    int PQconnectionUsedGSSAPI(const PGconn *conn)
     int PQsslInUse(PGconn *conn)   # TODO: const in PG 12 docs - verify/report
     # TODO: PQsslAttribute, PQsslAttributeNames, PQsslStruct, PQgetssl
 
@@ -343,6 +344,10 @@ typedef enum {
 #define PQsetTraceFlags(conn, stream) do {} while (0)
 #endif
 
+#if PG_VERSION_NUM < 160000
+#define PQconnectionUsedGSSAPI(conn) 0
+#endif
+
 #if PG_VERSION_NUM < 170000
 typedef struct pg_cancel_conn PGcancelConn;
 #define PQchangePassword(conn, user, passwd) NULL
index f8e23d4f3397f5822cfdafffb282c3ebf05ee70e..81f1aaecd88a1c1e01568cb2b4b65f8e7e90c167 100644 (file)
@@ -219,6 +219,11 @@ cdef class PGconn:
     def used_password(self) -> bool:
         return bool(libpq.PQconnectionUsedPassword(self._pgconn_ptr))
 
+    @property
+    def used_gssapi(self) -> bool:
+        _check_supported("PQconnectionUsedGSSAPI", 160000)
+        return bool(libpq.PQconnectionUsedGSSAPI(self._pgconn_ptr))
+
     @property
     def ssl_in_use(self) -> bool:
         return bool(_call_int(self, <conn_int_f>libpq.PQsslInUse))
index 75f74c46370c2d27aac7c623a8a62f721821fb59..900e06c9d835fcd84e84e91ee3d57d9991a0e16a 100644 (file)
@@ -377,6 +377,17 @@ def test_used_password(pgconn, dsn, monkeypatch):
     pgconn.used_password
 
 
+@pytest.mark.libpq(">= 16")
+def test_used_gssapi(pgconn):
+    assert isinstance(pgconn.used_gssapi, bool)
+
+
+@pytest.mark.libpq("< 16")
+def test_used_gssapi_not_suppored(pgconn):
+    with pytest.raises(psycopg.NotSupportedError):
+        pgconn.used_gssapi
+
+
 def test_ssl_in_use(pgconn):
     assert isinstance(pgconn.ssl_in_use, bool)