Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Paramiko SFTP with key and username/password - " Oops, unhandled type 3" [duplicate]

I'm trying to connect through SFTP to a remote server from Python (using Paramiko) to automate the retrieval of files.

System Versions: OS: Mac OS X Lion Python: 2.7.1 Paramiko: 1.7.7.2

My smallest example:

key_file = '/absolute/path/to/.ssh/id_rsa_key'  # NOT .pub
key_passphrase = 'id_rsa_key_passphrase'

host = 'ftp.test.com'
port = 22
username = 'my_ftp_username'
password = 'my_ftp_password'

# SSH Key
my_key = paramiko.RSAKey.from_private_key_file(key_file, password=key_passphrase)

# SFTP Connection
transport = paramiko.Transport((host, port))
transport.connect(username=username, password=password, pkey=my_key)
sftp = paramiko.SFTPClient.from_transport(transport)

# Print something
print sftp.listdir()

# Close connections
sftp.close()
transport.close()

The above generates the following log output:

DEB [20120606-16:20:46.121] thr=1   paramiko.transport: starting thread (client mode): 0x8ae7dd0L
INF [20120606-16:20:46.241] thr=1   paramiko.transport: Connected (version 2.0, client All)
DEB [20120606-16:20:46.242] thr=1   paramiko.transport: kex algos:['diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1'] server key:['ssh-rsa'] client encrypt:['aes256-cbc', 'aes192-cbc'] server encrypt:['aes256-cbc', 'aes192-cbc'] client mac:['hmac-sha1', 'hmac-sha1-96'] server mac:['hmac-sha1', 'hmac-sha1-96'] client compress:['none'] server compress:['none'] client lang:[''] server lang:[''] kex follows?False
DEB [20120606-16:20:46.242] thr=1   paramiko.transport: Ciphers agreed: local=aes256-cbc, remote=aes256-cbc
DEB [20120606-16:20:46.242] thr=1   paramiko.transport: using kex diffie-hellman-group1-sha1; server key type ssh-rsa; cipher: local aes256-cbc, remote aes256-cbc; mac: local hmac-sha1, remote hmac-sha1; compression: local none, remote none
DEB [20120606-16:20:46.673] thr=1   paramiko.transport: Switch to new keys ...
DEB [20120606-16:20:46.706] thr=2   paramiko.transport: Attempting password auth...
DEB [20120606-16:20:47.112] thr=1   paramiko.transport: userauth is OK
INF [20120606-16:20:50.288] thr=1   paramiko.transport: Authentication continues...
DEB [20120606-16:20:50.288] thr=1   paramiko.transport: Methods: ['password', 'publickey']
DEB [20120606-16:20:50.305] thr=2   paramiko.transport: [chan 1] Max packet in: 34816 bytes
WAR [20120606-16:20:50.405] thr=1   paramiko.transport: Oops, unhandled type 3
INF [20120606-16:23:53.582] thr=1   paramiko.transport: Disconnect (code 11): Idle connection

Does anyone know what "Oops, unhandled type 3" in the log means? That seems to be when the whole thing falls apart. Alternatively, if anyone sees something I'm doing terribly wrong in the code that would be helpful as well.

like image 253
rebekswr Avatar asked Jun 06 '12 20:06

rebekswr


1 Answers

I realize that this question is nearly 4 years old, however I hit this same problem and found a working solution!

Referencing the doc: http://docs.paramiko.org/en/2.4/api/transport.html

In the docs, under the connect() method it mentions that:

This is a shortcut for start_client, get_remote_server_key, and Transport.auth_password or Transport.auth_publickey.

So you simply cannot use connect() if you need to do multi-factor auth, you have to negotiate it manually using the above mentioned methods and trigger BOTH authentications, using key auth first before password auth.

The below snippet works for me!

host = "some-host"
port = 22
sftp_key = "/some-key"
username = "some-user"
password = "some-pass"

sftp_key = paramiko.RSAKey.from_private_key_file(sftp_key)
transport = paramiko.Transport((host, port))
transport.start_client(event=None, timeout=15)
transport.get_remote_server_key()
transport.auth_publickey(username, sftp_key, event=None)
transport.auth_password(username, password, event=None)
sftp = paramiko.SFTPClient.from_transport(transport) 

And wrapped that whole thing in a function to handle pretty much any SFTP server you can throw at it. My error handling is omitted since it doesn't make sense here...

#Auth types: user_pass, key_only, key_and_pass
#You can pass a junk string in for password or sftp_key if not used
def connect_to_sftp(host, port, username, password, sftp_key, auth_type):
    try:
        transport = paramiko.Transport((host, port))
        if auth_type == "key_and_pass":
            sftp_key = paramiko.RSAKey.from_private_key_file(sftp_key)
            transport.start_client(event=None, timeout=15)
            transport.get_remote_server_key()
            transport.auth_publickey(username, sftp_key, event=None)
            transport.auth_password(username, password, event=None)
            #transport.connect(username = username, password = password, pkey = sftp_key)
        elif auth_type == "key_only":
            sftp_key = paramiko.RSAKey.from_private_key_file(sftp_key)
            transport.connect(username = username, pkey = sftp_key)
        elif auth_type == "user_pass":
            transport.connect(username = username, password = password)
        else:
            ## Do your own error handling :)
            print "uh-oh!"
        sftp = paramiko.SFTPClient.from_transport(transport)   
    except Exception, e:
        ## Do your own error handling :)
        print "uh-oh!"
    return sftp, transport
like image 73
emmdee Avatar answered Sep 29 '22 10:09

emmdee