Skip to content

Commit 9994628

Browse files
committed
Added option to skip the password dialog when using an identity file. #6996
1 parent c6af61a commit 9994628

File tree

12 files changed

+117
-10
lines changed

12 files changed

+117
-10
lines changed
28.1 KB
Loading

docs/en_US/release_notes_9_9.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This release contains a number of bug fixes and new features since the release o
88

99
Supported Database Servers
1010
**************************
11-
**PostgreSQL**: 13, 14, 15, 16 and 17
11+
**PostgreSQL**: 13, 14, 15, 16, 17 and 18
1212

1313
**EDB Advanced Server**: 13, 14, 15, 16 and 17
1414

@@ -20,8 +20,10 @@ Bundled PostgreSQL Utilities
2020
New features
2121
************
2222

23+
| `Issue #6385 <https://github.com/pgadmin-org/pgadmin4/issues/6385>`_ - Add support of DEPENDS/NO DEPENDS ON EXTENSION for ALTER FUNCTION.
2324
| `Issue #6394 <https://github.com/pgadmin-org/pgadmin4/issues/6394>`_ - Added "MULTIRANGE_TYPE_NAME" option while creating a Range Type.
2425
| `Issue #6395 <https://github.com/pgadmin-org/pgadmin4/issues/6395>`_ - Added "SUBSCRIPT" option while creating a External Type.
26+
| `Issue #6996 <https://github.com/pgadmin-org/pgadmin4/issues/6996>`_ - Added option to skip the password dialog when using an identity file.
2527
| `Issue #8932 <https://github.com/pgadmin-org/pgadmin4/issues/8932>`_ - Added 'failover' and 'two_phase' parameter support in CREATE/ALTER SUBSCRIPTION for PostgreSQL v17+.
2628
2729
Housekeeping

docs/en_US/server_dialog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ not be able to connect directly.
177177
*Identity file* field to specify the location of the key file.
178178
* If the SSH host is expecting a password of the user name or an identity file
179179
if being used, use the *Password* field to specify the password.
180+
* Check the box next to *Prompt for password?* to to have pgAdmin prompt for
181+
a password if the identity file includes one. This setting applies only when
182+
using an identity file, which may or may not require a password.
180183
* Check the box next to *Save password?* to instruct pgAdmin to save the
181184
password for future use. Use
182185
:ref:`Clear SSH Tunnel Password <clear_saved_passwords>` to remove the saved
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
##########################################################################
2+
#
3+
# pgAdmin 4 - PostgreSQL Tools
4+
#
5+
# Copyright (C) 2013 - 2025, The pgAdmin Development Team
6+
# This software is released under the PostgreSQL Licence
7+
#
8+
##########################################################################
9+
10+
"""
11+
Revision ID: efbbe5d5862f
12+
Revises: e6ed5dac37c2
13+
Create Date: 2025-09-29 18:40:30.248908
14+
15+
"""
16+
from alembic import op, context
17+
import sqlalchemy as sa
18+
19+
20+
# revision identifiers, used by Alembic.
21+
revision = 'efbbe5d5862f'
22+
down_revision = 'e6ed5dac37c2'
23+
branch_labels = None
24+
depends_on = None
25+
26+
27+
def upgrade():
28+
with op.batch_alter_table(
29+
"server",
30+
table_kwargs={'sqlite_autoincrement': True}) as batch_op:
31+
batch_op.add_column(sa.Column('tunnel_prompt_password',
32+
sa.Integer(), server_default='0'))
33+
with op.batch_alter_table(
34+
"sharedserver",
35+
table_kwargs={'sqlite_autoincrement': True}) as batch_op:
36+
batch_op.add_column(sa.Column('tunnel_prompt_password',
37+
sa.Integer(), server_default='0'))
38+
39+
40+
def downgrade():
41+
# pgAdmin only upgrades, downgrade not implemented.
42+
pass

web/pgadmin/browser/server_groups/servers/__init__.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ def get_shared_server_properties(server, sharedserver):
167167
server.tunnel_password = sharedserver.tunnel_password
168168
server.save_password = sharedserver.save_password
169169
server.tunnel_identity_file = sharedserver.tunnel_identity_file
170+
server.tunnel_prompt_password = sharedserver.tunnel_prompt_password
170171
if hasattr(server, 'connection_params') and \
171172
hasattr(sharedserver, 'connection_params') and \
172173
'passfile' in server.connection_params and \
@@ -413,6 +414,7 @@ def create_shared_server(data, gid):
413414
tunnel_authentication=0,
414415
tunnel_identity_file=None,
415416
tunnel_keep_alive=0,
417+
tunnel_prompt_password=0,
416418
shared=True,
417419
connection_params=data.connection_params,
418420
prepare_threshold=data.prepare_threshold
@@ -790,6 +792,7 @@ def update(self, gid, sid):
790792
'tunnel_username': 'tunnel_username',
791793
'tunnel_authentication': 'tunnel_authentication',
792794
'tunnel_identity_file': 'tunnel_identity_file',
795+
'tunnel_prompt_password': 'tunnel_prompt_password',
793796
'tunnel_keep_alive': 'tunnel_keep_alive',
794797
'shared': 'shared',
795798
'shared_username': 'shared_username',
@@ -1086,6 +1089,8 @@ def properties(self, gid, sid):
10861089
'tunnel_username': tunnel_username,
10871090
'tunnel_identity_file': server.tunnel_identity_file
10881091
if server.tunnel_identity_file else None,
1092+
'tunnel_prompt_password': server.tunnel_prompt_password
1093+
if server.tunnel_identity_file else 0,
10891094
'tunnel_authentication': tunnel_authentication,
10901095
'tunnel_keep_alive': tunnel_keep_alive,
10911096
'kerberos_conn': bool(server.kerberos_conn),
@@ -1212,6 +1217,8 @@ def create(self, gid):
12121217
tunnel_authentication=1 if data.get('tunnel_authentication',
12131218
False) else 0,
12141219
tunnel_identity_file=data.get('tunnel_identity_file', None),
1220+
tunnel_prompt_password=1 if data.get('tunnel_prompt_password',
1221+
True) else 0,
12151222
tunnel_keep_alive=data.get('tunnel_keep_alive', 0),
12161223
shared=data.get('shared', None),
12171224
shared_username=data.get('shared_username', None),
@@ -1419,6 +1426,18 @@ def connect_status(self, gid, sid):
14191426
}
14201427
)
14211428

1429+
def is_prompt_tunnel_password(self, server):
1430+
"""
1431+
This function will check whether to prompt tunnel password or not.
1432+
"""
1433+
prompt_tunnel_password = True
1434+
# In case of identity file check the value of tunnel_prompt_password.
1435+
if server.tunnel_identity_file is not None and \
1436+
server.tunnel_prompt_password != 1:
1437+
prompt_tunnel_password = False
1438+
1439+
return prompt_tunnel_password
1440+
14221441
def connect(self, gid, sid, is_qt=False, server=None):
14231442
"""
14241443
Connect the Server and return the connection object.
@@ -1502,11 +1521,12 @@ def connect(self, gid, sid, is_qt=False, server=None):
15021521

15031522
# If server using SSH Tunnel
15041523
if server.use_ssh_tunnel:
1505-
if 'tunnel_password' not in data:
1506-
if server.tunnel_password is None:
1507-
prompt_tunnel_password = True
1508-
else:
1509-
tunnel_password = server.tunnel_password
1524+
if 'tunnel_password' not in data and \
1525+
server.tunnel_password is None:
1526+
prompt_tunnel_password = self.is_prompt_tunnel_password(server)
1527+
elif 'tunnel_password' not in data and \
1528+
server.tunnel_password is not None:
1529+
tunnel_password = server.tunnel_password
15101530
else:
15111531
tunnel_password = data['tunnel_password'] \
15121532
if 'tunnel_password' in data else ''
@@ -1562,6 +1582,10 @@ def connect(self, gid, sid, is_qt=False, server=None):
15621582
return self.get_response_for_password(
15631583
server, 428, prompt_password, prompt_tunnel_password)
15641584

1585+
# Check whether to prompt for the tunnel password in case if
1586+
# password is saved in server object or in data.
1587+
prompt_tunnel_password = self.is_prompt_tunnel_password(server)
1588+
15651589
try:
15661590
status, errmsg = conn.connect(
15671591
password=password,
@@ -1571,7 +1595,7 @@ def connect(self, gid, sid, is_qt=False, server=None):
15711595
)
15721596
except Exception as e:
15731597
return self.get_response_for_password(
1574-
server, 401, True, True,
1598+
server, 401, True, prompt_tunnel_password,
15751599
getattr(e, 'message', str(e)))
15761600

15771601
if not status:
@@ -1583,7 +1607,7 @@ def connect(self, gid, sid, is_qt=False, server=None):
15831607
return internal_server_error(errmsg)
15841608

15851609
return self.get_response_for_password(
1586-
server, 401, True, True, errmsg)
1610+
server, 401, True, prompt_tunnel_password, errmsg)
15871611
else:
15881612
if save_password and config.ALLOW_SAVE_PASSWORD:
15891613
try:

web/pgadmin/browser/server_groups/servers/static/js/server.ui.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ export default class ServerSchema extends BaseUISchema {
211211
tunnel_port: 22,
212212
tunnel_username: undefined,
213213
tunnel_identity_file: undefined,
214+
tunnel_prompt_password: false,
214215
tunnel_password: undefined,
215216
tunnel_authentication: false,
216217
tunnel_keep_alive: 0,
@@ -496,7 +497,22 @@ export default class ServerSchema extends BaseUISchema {
496497
maxLength: null
497498
},
498499
readonly: obj.isConnected,
499-
}, {
500+
},
501+
{
502+
id: 'tunnel_prompt_password', label: gettext('Prompt for password?'),
503+
type: 'switch', group: gettext('SSH Tunnel'), mode: ['properties', 'edit', 'create'],
504+
deps: ['tunnel_authentication', 'use_ssh_tunnel'],
505+
depChange: (state)=>{
506+
if (!state.tunnel_authentication) {
507+
return {tunnel_prompt_password: false};
508+
}
509+
},
510+
disabled: function(state) {
511+
return !state.tunnel_authentication || !state.use_ssh_tunnel;
512+
},
513+
helpMessage: gettext('This setting applies only when using an identity file. An identity file may or may not have a password. If set to true the system will prompt for the password.')
514+
},
515+
{
500516
id: 'save_tunnel_password', label: gettext('Save password?'),
501517
type: 'switch', group: gettext('SSH Tunnel'), mode: ['create'],
502518
deps: ['connect_now', 'use_ssh_tunnel'],

web/pgadmin/browser/server_groups/servers/tests/servers_test_data.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,7 @@
633633
"tunnel_password": "user123",
634634
"tunnel_identity_file": "pkey_rsa",
635635
"tunnel_keep_alive": 0,
636+
"tunnel_prompt_password": 0,
636637
"service": null,
637638
"server_info": {
638639
"id": 1,

web/pgadmin/browser/server_groups/servers/tests/test_check_ssh_mock_connect.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def __init__(self, name, id, username, use_ssh_tunnel,
7777
self.service = service
7878
self.save_password = 0
7979
self.shared = None
80+
self.tunnel_prompt_password = 0
8081

8182
mock_server_obj = TestMockServer(
8283
self.mock_data['name'],

web/pgadmin/model/__init__.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
#
3434
##########################################################################
3535

36-
SCHEMA_VERSION = 47
36+
SCHEMA_VERSION = 48
3737

3838
##########################################################################
3939
#
@@ -246,6 +246,11 @@ class Server(db.Model):
246246
nullable=False
247247
)
248248
tunnel_identity_file = db.Column(db.String(64), nullable=True)
249+
tunnel_prompt_password = db.Column(
250+
db.Integer(), db.CheckConstraint(
251+
'tunnel_prompt_password >= 0 AND tunnel_prompt_password <= 1'),
252+
nullable=False
253+
)
249254
tunnel_password = db.Column(PgAdminDbBinaryString())
250255
tunnel_keep_alive = db.Column(db.Integer(), nullable=True, default=0)
251256
shared = db.Column(db.Boolean(), nullable=False)
@@ -483,6 +488,11 @@ class SharedServer(db.Model):
483488
nullable=False
484489
)
485490
tunnel_identity_file = db.Column(db.String(64), nullable=True)
491+
tunnel_prompt_password = db.Column(
492+
db.Integer(), db.CheckConstraint(
493+
'tunnel_prompt_password >= 0 AND tunnel_prompt_password <= 1'),
494+
nullable=False
495+
)
486496
tunnel_password = db.Column(PgAdminDbBinaryString())
487497
tunnel_keep_alive = db.Column(db.Integer(), nullable=True)
488498
shared = db.Column(db.Boolean(), nullable=False)

web/pgadmin/setup/tests/servers.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"TunnelPort": "22",
3737
"TunnelUsername": "username",
3838
"TunnelAuthentication": 0,
39+
"TunnelPromptPassword": 0,
3940
"PasswordExecCommand": "echo 'test'",
4041
"PasswordExecExpiration": 100
4142
}

0 commit comments

Comments
 (0)