【问题标题】:Paramiko SFTP with key and username/password - " Oops, unhandled type 3" [duplicate]带有密钥和用户名/密码的 Paramiko SFTP -“糟糕,未处理的类型 3”[重复]
【发布时间】:2012-06-06 20:53:55
【问题描述】:

我正在尝试通过 SFTP 从 Python(使用 Paramiko)连接到远程服务器以自动检索文件。

系统版本: 操作系统:Mac OS X Lion 蟒蛇:2.7.1 帕拉米科:1.7.7.2

我最小的例子:

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()

以上生成如下日志输出:

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

有谁知道日志中的“糟糕,未处理的类型 3”是什么意思?那似乎是整个事情崩溃的时候。或者,如果有人看到我在代码中做的非常错误的事情也会有帮助。

【问题讨论】:

标签: python authentication sftp paramiko


【解决方案1】:

我意识到这个问题已经有将近 4 年的历史了,但是我遇到了同样的问题并找到了一个可行的解决方案!

参考文档:http://docs.paramiko.org/en/2.4/api/transport.html

在文档中,在 connect() 方法下它提到:

这是 start_client、get_remote_server_key 和 Transport.auth_password 或 Transport.auth_publickey 的快捷方式。

因此,如果您需要进行多因素身份验证,则根本不能使用connect(),您必须使用上述方法手动协商并触发两个身份验证,在密码身份验证之前先使用密钥身份验证。

下面的 sn-p 对我有用!

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) 

然后将整个东西包装在一个函数中,以处理几乎任何你可以扔给它的 SFTP 服务器。我的错误处理被省略了,因为它在这里没有意义......

#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

【讨论】:

  • Paramiko 可以自己处理两个因素密钥和密码身份验证,如果您正确使用其高级 API,SSHClient。请参阅我对Multi-factor authentication (password and key) with Paramiko 的回答。 + 此外,使用低级Transport 类,上述答案显示绕过主机密钥验证的方式,导致连接不安全。
【解决方案2】:

您正在对服务器使用密码和密钥身份验证,这看起来像是冲突。尝试使用Transport.auth_publickey 方法进行连接。如果失败,文档会说使用transport.get_exception 函数来收集更多详细信息。

编辑:

根据this,多重身份验证意味着同时使用密码密钥。所以,你应该可以使用auth_publickey函数,然后使用auth_password方法进入。

或者,如果您有足够的访问权限,您可以将 ftp 设置调整为只需要密钥身份验证。

您是否尝试过使用 ftp 客户端登录,例如 filezilla

【讨论】:

  • 有趣。当我尝试您建议的路径时,我看到一个从 auth_publickey 返回的数组。该数组是 ['password', 'publickey']。然后,当我查看您链接的文档时(谢谢),我看到返回的数据是“下一阶段身份验证允许的身份验证类型列表(通常为空)”。您不会碰巧知道有关多阶段身份验证过程的文档在哪里,甚至是示例/教程,对吗?
  • @rebekswr 好的,我已经用多阶段身份验证的一些内容更新了我的答案。
  • 我尝试了两种调用,两种可能的顺序,它们总是给出相同的输出,当我之后调用 is_authenticated 时,我从来没有。我将继续从命令行调用 sftp,因为我不需要它是可移植的。非常感谢您的帮助。
【解决方案3】:

问题在于您使用 rsa 密钥格式 (key_file = '/absolute/path/to/.ssh/id_rsa_key')。

确保使用 putty 密钥生成器将其转换为 SSH RSA。我做了并使用了相同的代码:它正在工作。

【讨论】:

    【解决方案4】:

    Big Sam 在一个 for 循环中打开了许多连接并且从未关闭连接后最终遇到了这个错误。

    确切的错误消息是Oops, unhandled type 3 ('unimplemented')

    您应该始终确保如果您有:

    client.connect(...)
    

    你还有:

    client.close()
    

    【讨论】: