diff --git a/docs/en_US/release_notes_3_2.rst b/docs/en_US/release_notes_3_2.rst index 33246e369..bfc5d9546 100644 --- a/docs/en_US/release_notes_3_2.rst +++ b/docs/en_US/release_notes_3_2.rst @@ -26,3 +26,4 @@ Bug fixes | `Bug #3446 `_ - Various procedure/function related fixes for EPAS/PG 11. | `Bug #3448 `_ - Exclude system columns in Import/Export. | `Bug #3457 `_ - Fix debugging of procedures in EPAS packages. +| `Bug #3468 `_ - Support SSH tunneling with keys that don't have a passphrase. \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py index 2b9c642f2..fdf645402 100644 --- a/web/pgadmin/browser/server_groups/servers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/__init__.py @@ -782,7 +782,7 @@ class ServerNode(PGChildNodeView): have_password = False password = None passfile = None - tunnel_password = None + tunnel_password = '' if 'password' in data and data["password"] != '': # login with password have_password = True @@ -973,7 +973,7 @@ class ServerNode(PGChildNodeView): return self.get_response_for_password(server, 428) else: tunnel_password = data['tunnel_password'] if 'tunnel_password'\ - in data else None + in data else '' # Encrypt the password before saving with user's login # password key. try: diff --git a/web/pgadmin/utils/driver/psycopg2/connection.py b/web/pgadmin/utils/driver/psycopg2/connection.py index 1b4d2a3f2..3b0321633 100644 --- a/web/pgadmin/utils/driver/psycopg2/connection.py +++ b/web/pgadmin/utils/driver/psycopg2/connection.py @@ -224,10 +224,10 @@ class Connection(BaseConnection): encpass = kwargs['password'] if 'password' in kwargs else None passfile = kwargs['passfile'] if 'passfile' in kwargs else None tunnel_password = kwargs['tunnel_password'] if 'tunnel_password' in \ - kwargs else None + kwargs else '' # Check SSH Tunnel needs to be created - if manager.use_ssh_tunnel == 1 and tunnel_password is not None: + if manager.use_ssh_tunnel == 1 and not manager.tunnel_created: status, error = manager.create_ssh_tunnel(tunnel_password) if not status: return False, error diff --git a/web/pgadmin/utils/driver/psycopg2/server_manager.py b/web/pgadmin/utils/driver/psycopg2/server_manager.py index a31319d67..3a2fdd621 100644 --- a/web/pgadmin/utils/driver/psycopg2/server_manager.py +++ b/web/pgadmin/utils/driver/psycopg2/server_manager.py @@ -40,6 +40,7 @@ class ServerManager(object): self.local_bind_host = '127.0.0.1' self.local_bind_port = None self.tunnel_object = None + self.tunnel_created = False self.update(server) @@ -378,20 +379,21 @@ WHERE db.oid = {0}""".format(did)) if user is None: return False, gettext("Unauthorized request.") - try: - tunnel_password = decrypt(tunnel_password, user.password) - # Handling of non ascii password (Python2) - if hasattr(str, 'decode'): - tunnel_password = \ - tunnel_password.decode('utf-8').encode('utf-8') - # password is in bytes, for python3 we need it in string - elif isinstance(tunnel_password, bytes): - tunnel_password = tunnel_password.decode() + if tunnel_password is not None and tunnel_password != '': + try: + tunnel_password = decrypt(tunnel_password, user.password) + # Handling of non ascii password (Python2) + if hasattr(str, 'decode'): + tunnel_password = \ + tunnel_password.decode('utf-8').encode('utf-8') + # password is in bytes, for python3 we need it in string + elif isinstance(tunnel_password, bytes): + tunnel_password = tunnel_password.decode() - except Exception as e: - current_app.logger.exception(e) - return False, "Failed to decrypt the SSH tunnel " \ - "password.\nError: {0}".format(str(e)) + except Exception as e: + current_app.logger.exception(e) + return False, "Failed to decrypt the SSH tunnel " \ + "password.\nError: {0}".format(str(e)) try: # If authentication method is 1 then it uses identity file @@ -413,6 +415,7 @@ WHERE db.oid = {0}""".format(did)) ) self.tunnel_object.start() + self.tunnel_created = True except BaseSSHTunnelForwarderError as e: current_app.logger.exception(e) return False, "Failed to create the SSH tunnel." \ @@ -427,6 +430,7 @@ WHERE db.oid = {0}""".format(did)) # Check SSH Tunnel is alive or not. if it is not then # raise the ConnectionLost exception. if self.tunnel_object is None or not self.tunnel_object.is_active: + self.tunnel_created = False raise SSHTunnelConnectionLost(self.tunnel_host) def stop_ssh_tunnel(self): @@ -435,3 +439,4 @@ WHERE db.oid = {0}""".format(did)) self.tunnel_object.stop() self.local_bind_port = None self.tunnel_object = None + self.tunnel_created = False