From 7a7741e60b4a96f6b590de682ed4e539fc25ff8d Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Tue, 10 Jan 2023 01:12:45 +0100 Subject: [PATCH] Save SSH credentials with keyring module The keyring module will save the username and password of the SSH connection to the operating system password storage. --- .idea/revpicommander.iml | 1 + MANIFEST.in | 1 - requirements.txt | 3 +- setup.py | 1 + src/revpicommander/helper.py | 37 ++++---- .../locale/revpicommander_de.qm | Bin 50658 -> 51952 bytes .../locale/revpicommander_de.ts | 61 +++++++++---- .../locale/revpicommander_en.qm | Bin 0 -> 33 bytes src/revpicommander/sshauth.py | 80 +++++++++++++++--- src/revpicommander/ui/sshauth_ui.py | 24 +++--- stdeb.cfg | 6 -- translate.pro | 1 + ui_dev/sshauth.ui | 19 +++-- 13 files changed, 165 insertions(+), 69 deletions(-) create mode 100644 src/revpicommander/locale/revpicommander_en.qm delete mode 100644 stdeb.cfg diff --git a/.idea/revpicommander.iml b/.idea/revpicommander.iml index bcd0f63..0d0b203 100644 --- a/.idea/revpicommander.iml +++ b/.idea/revpicommander.iml @@ -4,6 +4,7 @@ + diff --git a/MANIFEST.in b/MANIFEST.in index 979d6ef..53cd4a6 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -9,5 +9,4 @@ include README.md include requirements.txt include setup.iss include setup.py -include stdeb.cfg include translate.pro diff --git a/requirements.txt b/requirements.txt index 5b11c16..571a1be 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ revpimodio2>=2.5.6 zeroconf>=0.24.4 setuptools>=65.6.3 wheel -paramiko>=2.12.0 \ No newline at end of file +paramiko>=2.12.0 +keyring>=23.13.1 \ No newline at end of file diff --git a/setup.py b/setup.py index 1292d52..d4263f7 100644 --- a/setup.py +++ b/setup.py @@ -15,6 +15,7 @@ setup( include_package_data=True, install_requires=[ + "keyring", "PyQt5", "revpimodio2", "zeroconf" diff --git a/src/revpicommander/helper.py b/src/revpicommander/helper.py index ce7a02e..2808edc 100644 --- a/src/revpicommander/helper.py +++ b/src/revpicommander/helper.py @@ -20,7 +20,7 @@ from paramiko.ssh_exception import AuthenticationException from . import proginit as pi from .ssh_tunneling.server import SSHLocalTunnel -from .sshauth import SSHAuth, SSHAuthType +from .sshauth import SSHAuth settings = QtCore.QSettings("revpimodio.org", "RevPiCommander") """Global application settings.""" @@ -304,11 +304,11 @@ class ConnectionManager(QtCore.QThread): self.xml_funcs.clear() self.xml_mode = -1 - def pyload_connect(self, settings: RevPiSettings, parent=None) -> bool: + def pyload_connect(self, revpi_settings: RevPiSettings, parent=None) -> bool: """ Create a new connection from settings object. - :param settings: Revolution Pi saved connection settings + :param revpi_settings: Revolution Pi saved connection settings :param parent: Qt parent window for dialog positioning :return: True, if the connection was successfully established """ @@ -322,10 +322,16 @@ class ConnectionManager(QtCore.QThread): socket.setdefaulttimeout(2) - if settings.ssh_use_tunnel: + if revpi_settings.ssh_use_tunnel: while True: - diag_ssh_auth = SSHAuth(SSHAuthType.PASS, parent) - diag_ssh_auth.username = settings.ssh_user + diag_ssh_auth = SSHAuth( + revpi_settings.ssh_user, + "{0}.{1}_{2}".format( + settings.applicationName(), + settings.organizationName(), + revpi_settings.internal_id), + parent, + ) if not diag_ssh_auth.exec() == QtWidgets.QDialog.Accepted: self._clear_settings() return False @@ -333,14 +339,15 @@ class ConnectionManager(QtCore.QThread): ssh_user = diag_ssh_auth.username ssh_pass = diag_ssh_auth.password ssh_tunnel_server = SSHLocalTunnel( - settings.port, - settings.address, - settings.ssh_port + revpi_settings.port, + revpi_settings.address, + revpi_settings.ssh_port ) try: ssh_tunnel_port = ssh_tunnel_server.connect_by_credentials(ssh_user, ssh_pass) break except AuthenticationException: + diag_ssh_auth.remove_saved_password() QtWidgets.QMessageBox.critical( parent, self.tr("Error"), self.tr( "The combination of username and password was rejected from the SSH server.\n\n" @@ -360,7 +367,7 @@ class ConnectionManager(QtCore.QThread): sp = ServerProxy("http://127.0.0.1:{0}".format(ssh_tunnel_port)) else: - sp = ServerProxy("http://{0}:{1}".format(settings.address, settings.port)) + sp = ServerProxy("http://{0}:{1}".format(revpi_settings.address, revpi_settings.port)) # Load values and test connection to Revolution Pi try: @@ -371,7 +378,7 @@ class ConnectionManager(QtCore.QThread): pi.logger.exception(e) self.connection_error_observed.emit(str(e)) - if not settings.ssh_use_tunnel: + if not revpi_settings.ssh_use_tunnel: # todo: Change message, that user can use ssh QtWidgets.QMessageBox.critical( parent, self.tr("Error"), self.tr( @@ -386,19 +393,19 @@ class ConnectionManager(QtCore.QThread): return False - self.settings = settings + self.settings = revpi_settings self.ssh_pass = ssh_pass self.pyload_version = pyload_version self.xml_funcs = xml_funcs self.xml_mode = xml_mode with self._lck_cli: - socket.setdefaulttimeout(settings.timeout) + socket.setdefaulttimeout(revpi_settings.timeout) self.ssh_tunnel_server = ssh_tunnel_server self._cli = sp self._cli_connect.put_nowait(( - "127.0.0.1" if settings.ssh_use_tunnel else settings.address, - ssh_tunnel_port if settings.ssh_use_tunnel else settings.port + "127.0.0.1" if revpi_settings.ssh_use_tunnel else revpi_settings.address, + ssh_tunnel_port if revpi_settings.ssh_use_tunnel else revpi_settings.port )) self.connection_established.emit() diff --git a/src/revpicommander/locale/revpicommander_de.qm b/src/revpicommander/locale/revpicommander_de.qm index 77e78b0ce586385c64e8c9c8fec10663e0a75c22..a8afc7e71b0f57dcdbb33cdabd73af3d2e0729bc 100644 GIT binary patch delta 2926 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 diff --git a/src/revpicommander/locale/revpicommander_de.ts b/src/revpicommander/locale/revpicommander_de.ts index f26bef3..a154800 100644 --- a/src/revpicommander/locale/revpicommander_de.ts +++ b/src/revpicommander/locale/revpicommander_de.ts @@ -101,62 +101,62 @@ Nicht gespeicherte Änderunen gehen verloren ConnectionManager - + SIMULATING SIMULATION - + NOT CONNECTED NICHT VERBUNDEN - + SERVER ERROR SERVER FEHLER - + RUNNING LÄUFT - + PLC FILE NOT FOUND SPS PROGRAMM NICHT GEFUNDEN - + NOT RUNNING (NO STATUS) LÄUFT NICHT (KEIN STATUS) - + PROGRAM KILLED PROGRAMM GETÖTET - + PROGRAM TERMED PROGRAMM BEENDET - + NOT RUNNING LÄUFT NICHT - + FINISHED WITH CODE {0} BEENDET MIT CODE {0} - + Error Fehler - + The combination of username and password was rejected from the SSH server. Try again. @@ -165,7 +165,7 @@ Try again. Bitte erneut versuchen. - + Could not establish a SSH connection to server: {0} @@ -174,7 +174,7 @@ Bitte erneut versuchen. {0} - + Can not connect to RevPi XML-RPC Service! This could have the following reasons: The RevPi is not online, the XML-RPC service is not running / bind to localhost or the ACL permission is not set for your IP!!! @@ -401,7 +401,7 @@ Dies kann aus der Textbox oben kopiert werden. Can not start the simulator! Maybe the piCtory file is corrupt or you have no write permissions for '{0}'. - Kann Simulator nicht starten! Vielleicht ist die piCtory Datei defekt oder es gibt keine Schreibberechtigung für '{0}`. + Kann Simulator nicht starten! Vielleicht ist die piCtory Datei defekt oder es gibt keine Schreibberechtigung für '{0}'. @@ -952,6 +952,27 @@ Dies ist kein Fehler, wenn das SPS Startprogramm bereits auf dem Rev Pi ist. Pr {0}. + + SSHAuth + + + Could not save password + Konnte Kennwort nicht speichern + + + + Could not save password to operating systems password save. + +Maybe your operating system does not support saving passwords. This could be due to missing libraries or programs. + +This is not an error of RevPi Commander. + Konnte das Kennwort nicht im Kennwortspeicher des Betriebssystems speichern. + +Vielleicht untersützt das Betriebssystem keine Kennwortspeicherung. Dies könnte an fehlenden Bibliotheken oder Programmen liegen. + +Dies ist kein Fehler von RevPi Commander. + + Simulator @@ -1672,6 +1693,16 @@ applicable law. SSH password: SSH Passwort: + + + Username and password will be saved in secured operating systems's password storage. + Benutzername und Kennwort werden im Passwortspeicher vom Betriebssystem gesichert. + + + + Save username and password + Benutzername und Kennwort merken + wid_debugcontrol diff --git a/src/revpicommander/locale/revpicommander_en.qm b/src/revpicommander/locale/revpicommander_en.qm new file mode 100644 index 0000000000000000000000000000000000000000..937ea3e78662d66ef3264d8fa715599d03e338ed GIT binary patch literal 33 ocmcE7ks@*G{hX<16=n7(EZlo{IRgU&YieG6XmAIR#l*-60Q^r2(EtDd literal 0 HcmV?d00001 diff --git a/src/revpicommander/sshauth.py b/src/revpicommander/sshauth.py index fd0f531..23baaa0 100644 --- a/src/revpicommander/sshauth.py +++ b/src/revpicommander/sshauth.py @@ -4,36 +4,88 @@ __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "GPLv3" -from enum import Enum +from logging import getLogger +import keyring from PyQt5 import QtWidgets +from keyring.errors import KeyringError -from revpicommander.ui.sshauth_ui import Ui_diag_sshauth +from .ui.sshauth_ui import Ui_diag_sshauth - -class SSHAuthType(Enum): - PASS = "pass" - KEYS = "keys" +log = getLogger() class SSHAuth(QtWidgets.QDialog, Ui_diag_sshauth): - """Version information window.""" - def __init__(self, auth_type: SSHAuthType, parent=None): + def __init__(self, user_name="", service_name: str = None, parent=None): + """ + Ask the user for username and password or use saved entries. + + If you want to use the operating system's password storage, you have + to set a 'service_name'. The value must be unique for your application + or for each user, if the username is the same. + + :param user_name: Preset username, also used to check password save + :param service_name: Identity to save passwords in os's password save + :param parent: Qt parent for this dialog + """ + log.debug("SSHAuth.__init__") + super(SSHAuth, self).__init__(parent) self.setupUi(self) - self.wid_password.setVisible(auth_type is SSHAuthType.PASS) - self.wid_keys.setVisible(auth_type is SSHAuthType.KEYS) + self._service_name = service_name + self.cbx_save_password.setVisible(bool(service_name)) + self.txt_username.setText(user_name) + + def accept(self) -> None: + log.debug("SSHAuth.accept") + + if self._service_name and self.cbx_save_password.isChecked(): + try: + keyring.set_password(self._service_name, self.username, self.password) + except KeyringError as e: + log.error(e) + QtWidgets.QMessageBox.warning( + self, self.tr("Could not save password"), self.tr( + "Could not save password to operating systems password save.\n\n" + "Maybe your operating system does not support saving passwords. " + "This could be due to missing libraries or programs.\n\n" + "This is not an error of RevPi Commander." + ) + ) + super().accept() + + def exec(self) -> int: + log.debug("SSHAuth.exec") + + if self._service_name: + try: + saved_password = keyring.get_password(self._service_name, self.username) + if saved_password: + self.txt_password.setText(saved_password) + return QtWidgets.QDialog.Accepted + except KeyringError as e: + log.error(e) + + return super().exec() + + def remove_saved_password(self) -> None: + """Remove saved password.""" + log.debug("SSHAuth.remove_saved_password") + + if self._service_name: + try: + keyring.delete_password(self._service_name, self.username) + except KeyringError as e: + log.error(e) @property def password(self) -> str: + """Get the saved or entered password.""" return self.txt_password.text() @property def username(self) -> str: + """Get the entered username.""" return self.txt_username.text() - - @username.setter - def username(self, value: str): - self.txt_username.setText(value) diff --git a/src/revpicommander/ui/sshauth_ui.py b/src/revpicommander/ui/sshauth_ui.py index 4df10c6..5e1f17f 100644 --- a/src/revpicommander/ui/sshauth_ui.py +++ b/src/revpicommander/ui/sshauth_ui.py @@ -15,7 +15,7 @@ class Ui_diag_sshauth(object): def setupUi(self, diag_sshauth): diag_sshauth.setObjectName("diag_sshauth") diag_sshauth.setWindowModality(QtCore.Qt.ApplicationModal) - diag_sshauth.resize(275, 170) + diag_sshauth.resize(363, 163) self.verticalLayout = QtWidgets.QVBoxLayout(diag_sshauth) self.verticalLayout.setObjectName("verticalLayout") self.wid_password = QtWidgets.QWidget(diag_sshauth) @@ -36,18 +36,18 @@ class Ui_diag_sshauth(object): self.txt_username.setObjectName("txt_username") self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.txt_username) self.verticalLayout.addWidget(self.wid_password) - self.wid_keys = QtWidgets.QWidget(diag_sshauth) - self.wid_keys.setObjectName("wid_keys") - self.verticalLayout.addWidget(self.wid_keys) - self.buttonBox = QtWidgets.QDialogButtonBox(diag_sshauth) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) - self.buttonBox.setObjectName("buttonBox") - self.verticalLayout.addWidget(self.buttonBox) + self.cbx_save_password = QtWidgets.QCheckBox(diag_sshauth) + self.cbx_save_password.setObjectName("cbx_save_password") + self.verticalLayout.addWidget(self.cbx_save_password) + self.btn_box = QtWidgets.QDialogButtonBox(diag_sshauth) + self.btn_box.setOrientation(QtCore.Qt.Horizontal) + self.btn_box.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.btn_box.setObjectName("btn_box") + self.verticalLayout.addWidget(self.btn_box) self.retranslateUi(diag_sshauth) - self.buttonBox.accepted.connect(diag_sshauth.accept) # type: ignore - self.buttonBox.rejected.connect(diag_sshauth.reject) # type: ignore + self.btn_box.accepted.connect(diag_sshauth.accept) # type: ignore + self.btn_box.rejected.connect(diag_sshauth.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(diag_sshauth) def retranslateUi(self, diag_sshauth): @@ -55,6 +55,8 @@ class Ui_diag_sshauth(object): diag_sshauth.setWindowTitle(_translate("diag_sshauth", "SSH authentication")) self.lbl_username.setText(_translate("diag_sshauth", "SSH username:")) self.lbl_password.setText(_translate("diag_sshauth", "SSH password:")) + self.cbx_save_password.setToolTip(_translate("diag_sshauth", "Username and password will be saved in secured operating systems\'s password storage.")) + self.cbx_save_password.setText(_translate("diag_sshauth", "Save username and password")) if __name__ == "__main__": diff --git a/stdeb.cfg b/stdeb.cfg deleted file mode 100644 index abae509..0000000 --- a/stdeb.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[DEFAULT] -Debian-Version=1 -Depends3=python3-pyqt5, python3-revpimodio2 (>= 2.5.0), python3-zeroconf (>= 0.24.4) -Section=universe/x11 -Suite=stable -X-Python3-Version: >=3.4 diff --git a/translate.pro b/translate.pro index 8f935a0..2f7a861 100644 --- a/translate.pro +++ b/translate.pro @@ -11,6 +11,7 @@ SOURCES = src/revpicommander/aclmanager.py \ src/revpicommander/revpiplclist.py \ src/revpicommander/revpiprogram.py \ src/revpicommander/simulator.py \ + src/revpicommander/sshauth.py \ src/revpicommander/revpicommander.py FORMS = ui_dev/aclmanager.ui \ diff --git a/ui_dev/sshauth.ui b/ui_dev/sshauth.ui index e690765..3b821e0 100644 --- a/ui_dev/sshauth.ui +++ b/ui_dev/sshauth.ui @@ -9,8 +9,8 @@ 0 0 - 275 - 170 + 363 + 163 @@ -48,10 +48,17 @@ - + + + Username and password will be saved in secured operating systems's password storage. + + + Save username and password + + - + Qt::Horizontal @@ -65,7 +72,7 @@ - buttonBox + btn_box accepted() diag_sshauth accept() @@ -81,7 +88,7 @@ - buttonBox + btn_box rejected() diag_sshauth reject()