Paramiko SFTPClient class throws "Authentication failed", but Transport class and WinSCP work

Question:

I have an issue using Paramiko and connecting to an SFTP server.

The connecting work fine using same credentials in WinSCP.
I am also able to use pysftp.
But I would prefer to be able to use Paramiko, which gives access to better control of timeouts (removed in the example below).

I get the following error in the last Paramiko example:

paramiko.ssh_exception.AuthenticationException: Authentication failed.

What is even more strange, the exact same code, works for my colleague.
So anyone have a clue what I should look into?

import pysftp
from base64 import decodebytes
import paramiko

username = "my_username"
password = "my_secret_password"
hostname = "ftp.hostname.tld"
directory = "/protected/directory"
port = 22
keydata = b"""AAAAB...TuQ=="""
key = paramiko.RSAKey(data=decodebytes(keydata))

# PYSFTP is working!
cnopts = pysftp.CnOpts()
cnopts.hostkeys.add(hostname, 'ssh-rsa', key)
with pysftp.Connection(host=hostname, username=username, password=password, cnopts=cnopts) as sftp:
    files = sftp.listdir_attr(directory)
    test = "test"

# This pure Paramiko is also working!
with paramiko.Transport((hostname,port)) as transport:
    transport.connect(
        hostkey=key,
        username=username,
        password=password
    )
    with paramiko.SFTPClient.from_transport(transport) as sftp:
        files = sftp.listdir_attr(directory)
        test = "test"

# This version where the transport is established using sshclient, does not work.
ssh_client = paramiko.SSHClient()
ssh_client.get_host_keys().add(hostname=hostname, keytype="ssh-rsa", key=key)
ssh_client.connect(
    hostname=hostname, 
    username=username,
    password=password,
    port=port
)
sftp = ssh_client.open_sftp()
files = sftp.listdir_attr(directory)
test = "test"

Paramiko log from a failed session:

DEBUG:paramiko.transport:starting thread (client mode): 0x5dad0e50
DEBUG:paramiko.transport:Local version/idstring: SSH-2.0-paramiko_3.1.0
DEBUG:paramiko.transport:Remote version/idstring: SSH-2.0-srtSSHServer_11.00
INFO:paramiko.transport:Connected (version 2.0, client srtSSHServer_11.00)
DEBUG:paramiko.transport:=== Key exchange possibilities ===
DEBUG:paramiko.transport:kex algos: diffie-hellman-group14-sha256, diffie-hellman-group-exchange-sha256, diffie-hellman-group14-sha1, diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1, [email protected]
DEBUG:paramiko.transport:server key: ssh-rsa
DEBUG:paramiko.transport:client encrypt: aes256-ctr, aes128-ctr, aes256-cbc, twofish256-cbc, aes128-cbc, twofish256-ctr, aes192-ctr, twofish192-ctr, twofish128-ctr, twofish128-cbc
DEBUG:paramiko.transport:server encrypt: aes256-ctr, aes128-ctr, aes256-cbc, twofish256-cbc, aes128-cbc, twofish256-ctr, aes192-ctr, twofish192-ctr, twofish128-ctr, twofish128-cbc
DEBUG:paramiko.transport:client mac: hmac-sha3-512, hmac-sha3-384, hmac-sha3-256, hmac-sha3-224, hmac-sha2-512, hmac-sha2-384, hmac-sha2-256, hmac-sha2-224, hmac-sha1
DEBUG:paramiko.transport:server mac: hmac-sha3-512, hmac-sha3-384, hmac-sha3-256, hmac-sha3-224, hmac-sha2-512, hmac-sha2-384, hmac-sha2-256, hmac-sha2-224, hmac-sha1
DEBUG:paramiko.transport:client compress: none
DEBUG:paramiko.transport:server compress: none
DEBUG:paramiko.transport:client lang: <none>
DEBUG:paramiko.transport:server lang: <none>
DEBUG:paramiko.transport:kex follows: False
DEBUG:paramiko.transport:=== Key exchange agreements ===
DEBUG:paramiko.transport:Kex: diffie-hellman-group-exchange-sha256
DEBUG:paramiko.transport:HostKey: ssh-rsa
DEBUG:paramiko.transport:Cipher: aes128-ctr
DEBUG:paramiko.transport:MAC: hmac-sha2-256
DEBUG:paramiko.transport:Compression: none
DEBUG:paramiko.transport:=== End of kex handshake ===
DEBUG:paramiko.transport:Got server p (2048 bits)
DEBUG:paramiko.transport:kex engine KexGexSHA256 specified hash_algo <built-in function openssl_sha256>
DEBUG:paramiko.transport:Switch to new keys ...
DEBUG:paramiko.transport:Trying discovered key b'f28c2e56806b573d7fc45b9722242e5b' in C:Usersmy-user/.ssh/id_rsa
DEBUG:paramiko.transport:userauth is OK
DEBUG:paramiko.transport:Finalizing pubkey algorithm for key of type 'ssh-rsa'
DEBUG:paramiko.transport:Our pubkey algorithm list: ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-rsa']
DEBUG:paramiko.transport:Server did not send a server-sig-algs list; defaulting to our first preferred algo ('rsa-sha2-512')
DEBUG:paramiko.transport:NOTE: you may use the 'disabled_algorithms' SSHClient/Transport init kwarg to disable that or other algorithms if your server does not support them!
INFO:paramiko.transport:Authentication (publickey) failed.
INFO:paramiko.transport:Disconnect (code 2): unexpected service request
Asked By: jakobdo

||

Answers:

Adding this setting to the connect() call:

look_for_keys=False,

Makes the above code work.
Thanks for pointing me in the right direction @martin-prikryl

Answered By: jakobdo

The SSHClient is automatically trying the ~/.ssh/id_* keys. You have id_rsa there.

DEBUG:paramiko.transport:Trying discovered key b'f28c2e56806b573d7fc45b9722242e5b' in C:Usersmy-user/.ssh/id_rsa

Normally, it would do not harm, as it would fail and Paramiko will then try the password.

But recent versions of Paramiko are too strict by default about use of SHA-256 signatures:
Paramiko authentication fails with "Agreed upon 'rsa-sha2-512' pubkey algorithm" (and "unsupported public key algorithm: rsa-sha2-512" in sshd log)

As your server does not support it, Paramiko fails when trying the key. And the password authentication never happens.

Use look_for_keys=False to ignore the keys in ~/.ssh. See:
Force password authentication (ignore keys in .ssh folder) in Paramiko in Python

Answered By: Martin Prikryl
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.