-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[WIP] PR: Finish support for OpenSSH client config file specification (Remote Client) #24343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 4 commits
3ddba69
8e0c598
ed3079f
f8957be
83965c7
2e55e08
4625411
89b125f
09ebedf
e45a823
59ba911
8f11ebb
c9c4097
2dbeabb
08191f0
9aae452
f1cd227
033cbc9
2038673
294e628
ad0fbe0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -65,7 +65,7 @@ class ValidationReasons(TypedDict): | |||||||||||||
| class BaseConnectionPage(SpyderConfigPage, SpyderFontsMixin): | ||||||||||||||
| """Base class to create connection pages.""" | ||||||||||||||
|
|
||||||||||||||
| MIN_HEIGHT = 450 | ||||||||||||||
| MIN_HEIGHT = 700 | ||||||||||||||
| NEW_CONNECTION = False | ||||||||||||||
| CONF_SECTION = "remoteclient" | ||||||||||||||
|
|
||||||||||||||
|
|
@@ -186,12 +186,10 @@ def create_connection_info_widget(self): | |||||||||||||
| intro_layout.addWidget(intro_tip) | ||||||||||||||
|
|
||||||||||||||
| # Authentication methods | ||||||||||||||
| # TODO: The config file method is not implemented yet, so we need to | ||||||||||||||
| # disable it for now. | ||||||||||||||
| methods = ( | ||||||||||||||
| (_('Password'), AuthenticationMethod.Password), | ||||||||||||||
| (_('Key file'), AuthenticationMethod.KeyFile), | ||||||||||||||
| # (_('Configuration file'), AuthenticationMethod.ConfigFile), | ||||||||||||||
| (_('Configuration file'), AuthenticationMethod.ConfigFile), | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| self._auth_methods = self.create_combobox( | ||||||||||||||
|
|
@@ -426,28 +424,127 @@ def _create_configfile_subpage(self): | |||||||||||||
| configfile = self.create_browsefile( | ||||||||||||||
| text=_("Configuration file *"), | ||||||||||||||
| option=f"{self.host_id}/configfile", | ||||||||||||||
| tip=_("File with the OpenSSH client configuration to use"), | ||||||||||||||
| alignment=Qt.Vertical, | ||||||||||||||
| status_icon=ima.icon("error"), | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| host = self.create_lineedit( | ||||||||||||||
| text=_("Host *"), | ||||||||||||||
| option=f"{self.host_id}/{AuthenticationMethod.ConfigFile}/address", | ||||||||||||||
| default="", | ||||||||||||||
| tip=_( | ||||||||||||||
| "This is the host (<i><b>Host</b></i> configuration keyword) " | ||||||||||||||
dalthviz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| "that encapsulates the options to use for the connection" | ||||||||||||||
| ), | ||||||||||||||
| status_icon=ima.icon("error"), | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| port = self.create_spinbox( | ||||||||||||||
| prefix=_("Port"), | ||||||||||||||
| suffix="", | ||||||||||||||
| option=f"{self.host_id}/{AuthenticationMethod.ConfigFile}/port", | ||||||||||||||
| min_=0, | ||||||||||||||
| max_=65535, | ||||||||||||||
| tip=_("Introduce a port to use for this connection. " | ||||||||||||||
| "Set <i><b>0</b></i> (<i><b>From file</b></i> value) to use " | ||||||||||||||
| "the port specified in the configuration file"), | ||||||||||||||
dalthviz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| ) | ||||||||||||||
| port.spinbox.setSpecialValueText(_("From file")) | ||||||||||||||
dalthviz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| port.spinbox.setStyleSheet("margin-left: 5px") | ||||||||||||||
|
|
||||||||||||||
| username = self.create_lineedit( | ||||||||||||||
| text=_("Username"), | ||||||||||||||
| option=f"{self.host_id}/{AuthenticationMethod.ConfigFile}/username", | ||||||||||||||
| status_icon=ima.icon("error"), | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| password = self.create_lineedit( | ||||||||||||||
| text=_("Password"), | ||||||||||||||
| option=f"{self.host_id}/password", | ||||||||||||||
| tip=( | ||||||||||||||
| _("Your password will be saved securely by Spyder") | ||||||||||||||
| if self.NEW_CONNECTION | ||||||||||||||
| else _("Your password is saved securely by Spyder") | ||||||||||||||
| ), | ||||||||||||||
| status_icon=ima.icon("error"), | ||||||||||||||
| password=True | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| keyfile = self.create_browsefile( | ||||||||||||||
| text=_("Key file"), | ||||||||||||||
| option=f"{self.host_id}/keyfile", | ||||||||||||||
| alignment=Qt.Vertical, | ||||||||||||||
| status_icon=ima.icon("error"), | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| passphrase = self.create_lineedit( | ||||||||||||||
| text=_("Passphrase"), | ||||||||||||||
| option=f"{self.host_id}/passphrase", | ||||||||||||||
| tip=( | ||||||||||||||
| _("Your passphrase will be saved securely by Spyder") | ||||||||||||||
| if self.NEW_CONNECTION | ||||||||||||||
| else _("Your passphrase is saved securely by Spyder") | ||||||||||||||
| ), | ||||||||||||||
dalthviz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| password=True | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| validation_label = MessageLabel(self) | ||||||||||||||
|
|
||||||||||||||
| # Add widgets to their required dicts | ||||||||||||||
| self._name_widgets[AuthenticationMethod.ConfigFile] = name | ||||||||||||||
| self._widgets_for_validation[AuthenticationMethod.ConfigFile] = [ | ||||||||||||||
| name, | ||||||||||||||
| host, | ||||||||||||||
|
||||||||||||||
| host, | |
| host, | |
| username, | |
| password, | |
| keyfile, | |
| passphrase, |
Add these other widgets to perform more validations:
- If a user introduces a
username, then we need to check thatpasswordis not empty, and viceversa. - If they introduce
passphrase, thenkeyfilecan't be empty, and viceversa. - They can't introduce
username/passwordandkeyfile/passphraseat the same time because only one method is necessary for authentication. - We should check that none of those fields are available in the SSH config file (if possible). Otherwise, we should show a warning about it.
Please implement those validations in the validate_page method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So thinking about these validations, I think there are a couple of cases that should work and kind of go against the validations listed:
- Providing only password when the config file provides the username
- Not providing a passphrase when the config file provides the keyfile or even when the keyfile is provided by the user inside the connections dialog but the keyfile doesn't require a passphrase.
Is there a reason to not allow such cases? Or maybe I'm not fully understanding the extra validations definitions? Also, following the config file validation item, the idea is that users should not set the info that can be provided via the connection dialog in the config file (i.e values for username and keyfile)? Or maybe the idea is to somehow add a message when this happens (values where provided via the dialog and also a value is available from the config file)? From my understanding the config file values act as a fallback to the other values so when a value is not provided (in our case no value is given via de connection dialog fields) asyncssh tries to get the missing options from the config file provided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So thinking about these validations, I think there are a couple of cases that should work and kind of go against the validations listed:
- Providing only password when the config file provides the username
- Not providing a passphrase when the config file provides the keyfile or even when the keyfile is provided by the user inside the connections dialog but the keyfile doesn't require a passphrase.
Is there a reason to not allow such cases?
Nop, I just didn't think about them. The validations I proposed should work when username/keyfile are not present in the config file.
Also, following the config file validation item, the idea is that users should not set the info that can be provided via the connection dialog in the config file (i.e values for username and keyfile)? Or maybe the idea is to somehow add a message when this happens (values where provided via the dialog and also a value is available from the config file)?
I think we need to parse the config file, fill those fields (i.e. username and keyfile) if they're present in it, and make them read-only (see below). Also, when the passphrase is not required in the config file, then we should disable that field too.
From my understanding the config file values act as a fallback to the other values so when a value is not provided (in our case no value is given via de connection dialog fields) asyncssh tries to get the missing options from the config file provided.
I understand that, but I think config files are distributed to people to make complex SSH connections. So, in that case we should load the info present in them to our UI and not allow users to edit it so they can perform a successful connection. If they want to change that info, then I'd say they should edit the config file (or request a new one from IT).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the latest commit I went with an approach where the info in the config file is shown as placeholder for fields like username and keyfile. That, to me, seems like goes more in line with the concept of the config file working as a fallback. However, if that doesn't make sense to you let me know and I will go ahead with just forcing the values in the config file into the connection dialog widgets. As an example:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think above the above way to make things work @ccordoba12 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it looks good (sorry for the delay to reply back).
As far as I can see, you decided to do the validation using SSHClientConfig from asyncssh. Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, from what I remember and checking the code here, I think I used SSHClientConfig.load to parse the selected config file and validate if it was possible to parse it. Also, if the file was parsed successfully, then use any parsed values available to set placeholders for the page widgets
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, no problem. We can add more validations later.

Uh oh!
There was an error while loading. Please reload this page.