Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion web/pgadmin/browser/server_groups/servers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
KEY_RING_DESKTOP_USER, SSL_MODES, RESTRICTION_TYPE_DATABASES,
RESTRICTION_TYPE_SQL)
from pgadmin.utils.crypto import encrypt, decrypt
from pgadmin.model import db, Server
from pgadmin.model import db, Server, SharedServer
from flask import current_app
from pgadmin.utils.master_password import set_masterpass_check_text
from pgadmin.utils.driver import get_driver
Expand Down Expand Up @@ -472,6 +472,31 @@ def reencrpyt_server_passwords(user_id, old_key, new_key):
db.session.commit()
manager.update_session()

# Ensure saved shared server passwords are re-encrypted.
for server in SharedServer.query.filter_by(user_id=user_id).all():
manager = driver.connection_manager(server.id)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's find and examine the utils.py file and the context around line 477
cat -n web/pgadmin/browser/server_groups/servers/utils.py | sed -n '470,500p'

Repository: pgadmin-org/pgadmin4

Length of output: 1471


🏁 Script executed:

# Find SharedServer model definition
find . -type f -name "*.py" | xargs grep -l "class SharedServer" 2>/dev/null | head -5

Repository: pgadmin-org/pgadmin4

Length of output: 167


🏁 Script executed:

# Examine SharedServer model definition
grep -A 30 "class SharedServer" web/pgadmin/model/__init__.py

Repository: pgadmin-org/pgadmin4

Length of output: 967


🏁 Script executed:

# Search for connection_manager method definition
grep -r "def connection_manager" --include="*.py" web/pgadmin/ | head -5

Repository: pgadmin-org/pgadmin4

Length of output: 153


🏁 Script executed:

# Examine connection_manager method
grep -A 20 "def connection_manager" web/pgadmin/utils/driver/psycopg3/__init__.py

Repository: pgadmin-org/pgadmin4

Length of output: 716


🏁 Script executed:

# Search for how connection_manager is called elsewhere
grep -B3 "connection_manager" web/pgadmin/browser/server_groups/servers/utils.py | head -30

Repository: pgadmin-org/pgadmin4

Length of output: 927


🏁 Script executed:

# Let's verify by checking if there are any other places where connection_manager 
# is called with a SharedServer and see if there's a pattern
grep -r "SharedServer" web/pgadmin/browser/server_groups/servers/utils.py -A 5 -B 5 | grep -A 2 -B 2 "connection_manager"

Repository: pgadmin-org/pgadmin4

Length of output: 310


Use server.osid instead of server.id for SharedServer connection manager lookup.

The connection_manager method expects the actual PostgreSQL server ID from the Server table. For SharedServer entries, this is stored in the osid foreign key field, not the id field (which is SharedServer's primary key). Using server.id will cause connection manager lookup failures or incorrect behavior.

-        manager = driver.connection_manager(server.id)
+        manager = driver.connection_manager(server.osid)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
manager = driver.connection_manager(server.id)
manager = driver.connection_manager(server.osid)
🤖 Prompt for AI Agents
In web/pgadmin/browser/server_groups/servers/utils.py around line 477, the call
uses server.id to look up the connection manager but SharedServer entries store
the actual PostgreSQL server id in server.osid; update the lookup to use
server.osid for SharedServer entries (or when server.osid is present and not
None) and fall back to server.id otherwise so the connection_manager call
receives the correct underlying server id.

_password_check(server, manager, old_key, new_key)

if server.tunnel_password is not None:
tunnel_password = decrypt(server.tunnel_password, old_key)
if isinstance(tunnel_password, bytes):
tunnel_password = tunnel_password.decode()

tunnel_password = encrypt(tunnel_password, new_key)
setattr(server, 'tunnel_password', tunnel_password)
manager.tunnel_password = tunnel_password
elif manager.tunnel_password is not None:
tunnel_password = decrypt(manager.tunnel_password, old_key)

if isinstance(tunnel_password, bytes):
tunnel_password = tunnel_password.decode()

tunnel_password = encrypt(tunnel_password, new_key)
manager.tunnel_password = tunnel_password

db.session.commit()
manager.update_session()


def remove_saved_passwords(user_id):
"""
Expand Down
Loading