From 7c9be2d03d3b76ef4fff8e0f06363a997e57ac29 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Wed, 1 Apr 2026 23:12:42 +0200 Subject: [PATCH 1/3] Read password from PassFile when connecting. Use PassFile to retrieve a password when one is not retrieved by other means. The PassFile setting was already passed to connect() but was never read. --- web/pgadmin/utils/driver/psycopg3/connection.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/web/pgadmin/utils/driver/psycopg3/connection.py b/web/pgadmin/utils/driver/psycopg3/connection.py index 47ab25b7660..b29b8e615ec 100644 --- a/web/pgadmin/utils/driver/psycopg3/connection.py +++ b/web/pgadmin/utils/driver/psycopg3/connection.py @@ -17,8 +17,8 @@ import secrets import datetime import asyncio -import copy from collections import deque +from pathlib import Path import psycopg from flask import g, current_app from flask_babel import gettext @@ -281,7 +281,6 @@ def connect(self, **kwargs): password, encpass, is_update_password = \ self._check_user_password(kwargs) - passfile = kwargs['passfile'] if 'passfile' in kwargs else None tunnel_password = kwargs['tunnel_password'] if 'tunnel_password' in \ kwargs else '' @@ -313,6 +312,15 @@ def connect(self, **kwargs): if is_error: return False, errmsg + # Retrieve password from passfile, if one has not been set yet. + passfile = Path(kwargs['passfile']) if 'passfile' in kwargs else None + if not password and passfile: + try: + password = passfile.read_text(encoding='utf-8').strip() + except (OSError, UnicodeDecodeError) as e: + error = _("Failed to read PassFile.\nError: {0}").format(str(e)) + return False, error + # If no password credential is found then connect request might # come from Query tool, ViewData grid, debugger etc tools. # we will check for pgpass file availability from connection manager From 5db808c0b9d3ae817f363d4f778eb9eed6447128 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Thu, 2 Apr 2026 15:05:28 +0200 Subject: [PATCH 2/3] Revert "Read password from PassFile when connecting." This reverts commit 7c9be2d03d3b76ef4fff8e0f06363a997e57ac29. --- web/pgadmin/utils/driver/psycopg3/connection.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/web/pgadmin/utils/driver/psycopg3/connection.py b/web/pgadmin/utils/driver/psycopg3/connection.py index b29b8e615ec..47ab25b7660 100644 --- a/web/pgadmin/utils/driver/psycopg3/connection.py +++ b/web/pgadmin/utils/driver/psycopg3/connection.py @@ -17,8 +17,8 @@ import secrets import datetime import asyncio +import copy from collections import deque -from pathlib import Path import psycopg from flask import g, current_app from flask_babel import gettext @@ -281,6 +281,7 @@ def connect(self, **kwargs): password, encpass, is_update_password = \ self._check_user_password(kwargs) + passfile = kwargs['passfile'] if 'passfile' in kwargs else None tunnel_password = kwargs['tunnel_password'] if 'tunnel_password' in \ kwargs else '' @@ -312,15 +313,6 @@ def connect(self, **kwargs): if is_error: return False, errmsg - # Retrieve password from passfile, if one has not been set yet. - passfile = Path(kwargs['passfile']) if 'passfile' in kwargs else None - if not password and passfile: - try: - password = passfile.read_text(encoding='utf-8').strip() - except (OSError, UnicodeDecodeError) as e: - error = _("Failed to read PassFile.\nError: {0}").format(str(e)) - return False, error - # If no password credential is found then connect request might # come from Query tool, ViewData grid, debugger etc tools. # we will check for pgpass file availability from connection manager From c1ffe0d46d328779ae026c9e502f19fc7c7f0324 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Thu, 2 Apr 2026 15:55:59 +0200 Subject: [PATCH 3/3] Clarify passfile logic in Connection::connect(). Checking for a passfile is done by using the value returned by the ServerManager, which will also be used when constructing the connection string. An extra check is added, to warn if passfile is also provided as a kwarg to Connection::connect() and differs from the passfile picked up by ServerManager. --- .../utils/driver/psycopg3/connection.py | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/web/pgadmin/utils/driver/psycopg3/connection.py b/web/pgadmin/utils/driver/psycopg3/connection.py index 47ab25b7660..5562fc07885 100644 --- a/web/pgadmin/utils/driver/psycopg3/connection.py +++ b/web/pgadmin/utils/driver/psycopg3/connection.py @@ -17,7 +17,6 @@ import secrets import datetime import asyncio -import copy from collections import deque import psycopg from flask import g, current_app @@ -281,7 +280,6 @@ def connect(self, **kwargs): password, encpass, is_update_password = \ self._check_user_password(kwargs) - passfile = kwargs['passfile'] if 'passfile' in kwargs else None tunnel_password = kwargs['tunnel_password'] if 'tunnel_password' in \ kwargs else '' @@ -313,14 +311,22 @@ def connect(self, **kwargs): if is_error: return False, errmsg - # If no password credential is found then connect request might - # come from Query tool, ViewData grid, debugger etc tools. - # we will check for pgpass file availability from connection manager - # if it's present then we will use it - if not password and not encpass and not passfile: - passfile = manager.get_connection_param_value('passfile') - if manager.passexec: - password = manager.passexec.get() + # If no password credential is found then connect request might come + # from Query tool, ViewData grid, debugger, etc. In that case, fall + # back to using the password returned from manager.passexec. + passfile = manager.get_connection_param_value('passfile') + if not password and not encpass and not passfile and manager.passexec: + password = manager.passexec.get() + + # create_connection_string() automatically picks up the passfile from + # connection parameters. Warn if that differs from the passfile kwarg. + passfile_kwarg = kwargs.get('passfile', None) + if passfile_kwarg and passfile_kwarg != passfile: + current_app.logger.warning( + "Using the first of two specified passfiles: {!r}, {!r}".format( + passfile, passfile_kwarg + ) + ) try: database = self.db