-
Notifications
You must be signed in to change notification settings - Fork 16
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
asyncssh API change breaks parsing of config #54
Comments
@ronf can we by chance make these new arguments into |
If you want to preload some configuration options, the preferred approach is to use "options" rather than "config". If you do use config, the only supported mechanism is to pass in a list of path names of config files to load (which is handled as part of setting "options"). If I were to make these keyword args with default values, the new functionality of "match canonical" and "match final" would be broken as a result of not setting these values correctly. Calls to this "load" function really need to be coming from Do you know why sshfs felt the need for this wrapper? How is it used? |
thanks, @ronf
can you point me to the class / code please?
I think it's an utility function that was needed for DVC (to preload some config indeed) https://github.com/iterative/dvc-ssh/blob/main/dvc_ssh/__init__.py#L44 |
From what I can see, that Generally speaking, the expectation is that you'll pass AsyncSSH a I think it would be possible to take the existing keyword args in the DVC code and convert those to AsyncSSH "options" arguments (see the SSHClientConnectionOptions class), and allow one of those arguments for the user config to be passed in as a In OpenSSH 2.15.0 and later, there's a class method called You could also convert the keyword args to a new dictionary of AsyncSSH keyword args and just pass those in as keyword args to |
Conclusion:
|
I have provided the PR. Haha, test case is to be updated. The string is returned for config.get("ProxyCommand") but is compared against a list by using split(). After this I think it should work, :) |
I strongly recommend against pinning a specific version of AsyncSSH here. That would mean that anyone using this package would not be able to pick up any security vulnerability fixes, or other bug fixes. |
@ronf thanks for the detailed response. I also don't see an immediate need (see some questions / caveats below) to DVC to try to build an effective config itself. The logic seems to go back many years ago to this ticket: and this PR: It was using back then Now, we might not need all of this. A few caveats that I can immediately see:
login_info["username"] = (
config.get("user")
or config.get("username")
or user_ssh_config.get("User")
or getpass.getuser()
) will
if config.get("keyfile"):
raw_keys.append(config.get("keyfile"))
elif user_ssh_config.get("IdentityFile"):
raw_keys.extend(user_ssh_config.get("IdentityFile")) Can we pass an additional key file to @ronf if you have quick suggestions / thoughts on these items ^^ I would appreciate any help. |
Starting with the easiest, the username is gotten from one of the following (in order of precedence):
Really, there's a value As for ProxyCommand, it shouldn't need to be special-cased. It can come from keyword args, options, or config, with a similar precedence to the above, but with the default being unset. I'm guessing the "login_info" you show here is related to trying to convert from SSH config values to Paramiko values you mentioned above. As for showing user/host/port, there are really two different sets of values here. There's the requested user, host, and port and there's the rewritten version of those after parsing config files, if you decide to support those. If your application passes values to connect() via keyword arguments or options, that will take precedence over any config files, which may or may not be what you want. As for keys, you can have multiple IdentityFile lines in a config file that can be conditionally matched, building up a set of keys to load for all the config lines which match. If you specify keys via keyword arguments or options, though, you have to specify the complete list (doing any conditional logic yourself to build that list). Note that you can load multiple config files. However, there isn't an easy way right now to state that you want to load the system default config if it exists and then some config file of your own (or vice-versa in the ordering). You'd have to check yourself to see if the system config file existed and then specify the complete list of files to load, being careful to pick the order, as most config settings will lock on the first config rule which matches, ignoring later lines that match. IdentityFile is an exception in that regard. |
thanks @ronf !
in what case then the
it means we can't replicate the existing logic if we don't want to use
is it for example to override / add certain values? e.g. by creating a temporary file with an |
If you want to see the final values of host, port, and username after all the configuration has been applied (keyword arguments, options, and the result of parsing user-specific or default config options), you can use If you have your own SSHClient class with a callback for Note that passing in a port number or username as explicit arguments in a
Yes - this should be possible. For things other than IdentityFile, you'd probably want to list your temporary file first and '~/.ssh/config' after that if you want your config to override the user's default config. For IdentityFile, it will append values set in either config file. This also applied to 'CertificateFile' and 'SendEnv', but that's not the case for other config settings. For those, the first thing that matches will be used and any later matching rules will be ignored. Using your own config file like this should be a way to leverage the existing AsyncSSH logic and not have to replicate that yourself. However, if you just need to override a value and never want to use the version of that set in the user's config file, you can just pass it as a keyword argument to |
yes, it seems to be fine and expected. If someone explicitly sets port in DVC config I think we should be using that exact value. And it is expected that hostname can be changed.
it seems we are not using callbacks atm. We just ask explicitly passphrase / password before I'll look into callbacks and if it's easy to migrate to it.
yep, but sounds very complicated to me ...
the current logic is setup in a way that we are using all the available key files (?) ... so, it's better to keep it that way. Though I don't see an easy way to do this. |
If you don't mind displaying the hostname before any config file changes are applied to it, prompting for password first should work fine. It means you would be prompting even when a password might not be required, if some target hosts are using something else such as public key auth. If you provide callbacks via an SSHClient subclass, you can avoid prompting when authentication with public key succeeds, and you'd have access to both the original host passed in as well as the rewritten host after the default config is applied, though I actually think displaying just the original host might be better in this case. Often, the rewritten host ends up being an IP address or an internal hostname that the user might not recognize. Other than host, port, username, and client keys, is there anything you'd want to be able to override from the defaults? You should be able to specify host, port, and username directly on the As for client keys, you could write your own temporary config file where you add keys you'd like to use and also pick up keys explicitly specified in the user's default config file by adding an "include config" directive at the end of your temporary config to load the user's ~/.ssh/config. However, if either your config or the user's config specify keys, only those keys will be loaded. There's no easy way right now to get all the default key files in ~/.ssh (id_rsa, id_ecdsa, id_ed25519, etc.) and also add other keys to that. The assumption is that if you are specifying keys you don't want to also use the default keys, especially given that there's a VERY small number of attempts allowed before auth fails, and each key counts against that. Nothing would stop you from keeping your own list of default key filenames and loading them explicitly, of course, but AsyncSSH will only do this for you when no client keys are specified in the keyword args, options, or config files, and you'd still have to deal with the limited number of auth attempts servers allow. |
The v2.19.0 release of
asyncssh
has added support for hostname canonicalization. With this change, two new arguments were added toSSHClientConfig.load
:canonical
andfinal
. We should also pass these parameters insshfs
, because right now thelocal_user
anduser
are passed in their places, which breaks parsing the config inconfig.py
:sshfs/sshfs/config.py
Lines 23 to 31 in 34b52b2
https://github.com/ronf/asyncssh/blob/95756fa4eb54826adb9156b87443d945fd1ed4f8/asyncssh/config.py#L428-L430
The text was updated successfully, but these errors were encountered: