I have successfully used this code to connect to a few different SFTP servers:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname, port=port, username=username, password=password)
sftp = ssh.open_sftp()
However, there is one other SFTP server that when I try to use that code gives an error ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host. For that server (and I think the others as well), the following code successfully connects with no error:
transport = paramiko.Transport((hostname, port))
transport.connect(username=username, password=password)
sftp = paramiko.SFTPClient.from_transport(transport)
Why might the behavior be different / how would I figure out what's causing the error? I'd like to be able to use the same code for all the SFTP servers I connect to. Should I just always use the Transport connection, or is there a way to modify the SSHClient connection to make it work in this case?
The problem turns out to be a bug in paramiko, that paramiko is trying to authenticate with a key from an SSH key file and is ignoring the supplied password. The workaround is to pass look_for_keys=False to the SSHClient.connect method.
The issue and workaround are described in paramiko GitHub Issue #391.
I figured this out by setting the loglevel to DEBUG and comparing the two ways of connecting - when using the SSHClient, I saw these lines:
Adding ssh-rsa host key for sftp.example.com: b'examplekey'
Trying discovered key b'someotherkey' in C:\Users\myusername/.ssh/id_ed25519
Authentication (publickey) failed.
Whereas when using the Transport, I saw this line:
Authentication (password) successful!
Interestingly, for the other SFTP servers where I didn't get this error, the logs include both of those sets of lines, suggesting it's trying public-key authentication but then still trying the password afterward, and I don't know what causes the difference.