Python Paramiko(客户端)多重身份验证

标签 python python-2.7 paramiko

我正在尝试使用 Paramiko(在 Python 2.7 上)连接到使用多重身份验证(用户名 + 密码 + 一次性密码)的主机。 transport.auth_interactive函数似乎是执行此操作的方法(根据我从文档中理解的内容),但执行从未达到该点 - client.connect 上的身份验证失败线。

我好像漏掉了一些东西。

这是代码:

#!/usr/bin/env python

import paramiko
import getpass
import os
import logging

user = ""
pw = ""
mfa = ""

def inter_handler(title, instructions, prompt_list):
    resp = []

    for pr in prompt_list:
        if pr[0].strip() == "Username:":
            resp.append(user)
        elif pr[0].strip() == "Password:":
            resp.append(pw)
        elif pr[0].strip() == "OTP Code:":
            resp.append(mfa)
        
    return tuple(resp)


#Main Entry Point
if __name__ == "__main__":

    paramiko.util.log_to_file(os.path.expanduser('~/paramiko.log'), logging.DEBUG)

    user = raw_input("Username: ")
    pw = getpass.getpass("Password: ")
    mfa = raw_input("OTP Code:")

    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())   #Don't care about host keys
    client.connect("mfahost.example.com", port=22, username=user, password=pw, look_for_keys=False)
    client.get_transport().auth_interactive(user, inter_handler) 

    client.exec_command("touch ~/paramikotestfile")

最佳答案

回答我自己的问题,因为我设法解决了这个问题,并认为我会分享。

简单的回答是,必须创建一个套接字,在其上创建一个 Paramiko 客户端 Transport,调用 auth_interactive,然后打开一个 session 。 session 提供了一个 Paramiko Channel 对象,可以像 SSHClient 对象一样接受 exec_command 调用。

下面的代码是完整的引用实现:

 #!/usr/bin/env python

import paramiko #Provides SSH functionality import getpass #Allows for secure prompting and collection of the user password import os #Used to setup the Paramiko log file import logging #Used to setup the Paramiko log file import socket #This method requires that we create our own socket #Global variables are used to store these data because they're sent to the server by a callback user = "" pw = "" mfa = "" def inter_handler(title, instructions, prompt_list): """ inter_handler: the callback for paramiko.transport.auth_interactive The prototype for this function is defined by Paramiko, so all of the arguments need to be there, even though we don't use 'title' or 'instructions'. The function is expected to return a tuple of data containing the responses to the provided prompts. Experimental results suggests that there will be one call of this function per prompt, but the mechanism allows for multiple prompts to be sent at once, so it's best to assume that that can happen. Since tuples can't really be built on the fly, the responses are collected in a list which is then converted to a tuple when it's time to return a value. Experiments suggest that the username prompt never happens. This makes sense, but the Username prompt is included here just in case. """ resp = [] #Initialize the response container #Walk the list of prompts that the server sent that we need to answer for pr in prompt_list: #str() used to to make sure that we're dealing with a string rather than a unicode string #strip() used to get rid of any padding spaces sent by the server if str(pr[0]).strip() == "Username:": resp.append(user) elif str(pr[0]).strip() == "Password:": resp.append(pw) elif str(pr[0]).strip() == "OTP Code:": resp.append(mfa) return tuple(resp) #Convert the response list to a tuple and return it #Main Entry Point if __name__ == "__main__": #Setup Paramiko logging; this is useful for troubleshooting paramiko.util.log_to_file(os.path.expanduser('~/paramiko.log'), logging.DEBUG) #Get the username, password, and MFA token code from the user user = raw_input("Username: ") pw = getpass.getpass("Password: ") mfa = raw_input("OTP Code: ") #Create a socket and connect it to port 22 on the host sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("mfahost.example.com", 22)) #Make a Paramiko Transport object using the socket ts = paramiko.Transport(sock) #Tell Paramiko that the Transport is going to be used as a client ts.start_client(timeout=10) #Begin authentication; note that the username and callback are passed ts.auth_interactive(user, inter_handler) #Opening a session creates a channel along the socket to the server chan = ts.open_session(timeout=10) #Now the channel can be used to execute commands chan.exec_command("touch ~/paramikotestfile")

关于Python Paramiko(客户端)多重身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43903875/

相关文章:

python - 在Python循环内动态创建变量

python - 如何使用 dfs 进行拓扑排序?

使用 cmake 和 pybind11 构建示例应用程序时找不到 Python.h

python - 值错误 : Invalid placeholder in string

python - 使用 add_cookie 时 WebDrive 出现奇怪的异常

python - 使用 BeautifulSoup 获取属性值

python - 获取 "socket.error: [Errno 61] Connection refused"python paramiko

Python Multiprocessing.Pool 工作人员在使用 pool.map 时挂起

python - IntegrityError Question_question.pub_date 不能为 NULL

python - 无法通过 python 中的 ssh 为 X11 自动启动没有 $DISPLAY 的 dbus-daemon