【问题标题】:NTLM authentication in PythonPython 中的 NTLM 身份验证
【发布时间】:2011-02-27 12:12:41
【问题描述】:

我正在尝试使用 python 从 Windows 7 在 IIS (Windows Server 2003) 上实现 NTLM 身份验证。 LAN Manager 身份验证级别:仅发送 NTLM 响应。
客户端机器和服务器在同一个域中。
域控制器 (AD) 位于另一台服务器上(也运行 Windows Server 2003)。

我收到 401.1 - 未经授权:由于凭据无效,访问被拒绝。 您能否帮我找出这段代码有什么问题和/或向我展示解决此问题的其他可能方向(使用 NTLM 或 Kerberos)?

import sys, httplib, base64, string
import urllib2
import win32api
import sspi 
import pywintypes
import socket

class WindoewNtlmMessageGenerator:
    def __init__(self,user=None):
        import win32api,sspi
        if not user:
            user = win32api.GetUserName()
        self.sspi_client = sspi.ClientAuth("NTLM",user)   

    def create_auth_req(self):
        import pywintypes
        output_buffer = None
        error_msg = None
        try:
            error_msg, output_buffer = self.sspi_client.authorize(None)            
        except pywintypes.error:
            return None
        auth_req = output_buffer[0].Buffer
        auth_req = base64.encodestring(auth_req)
        auth_req = string.replace(auth_req,'\012','')
        return auth_req 

    def create_challenge_response(self,challenge):
        import pywintypes
        output_buffer = None
        input_buffer = challenge
        error_msg = None        
        try:
            error_msg, output_buffer = self.sspi_client.authorize(input_buffer)
        except pywintypes.error:
            return None
        response_msg = output_buffer[0].Buffer       
        response_msg = base64.encodestring(response_msg)
        response_msg = string.replace(response_msg,'\012','')
        return response_msg 


fname='request.xml'
request = file(fname).read()
ip_host = '10.0.3.112'

ntlm_gen = WindoewNtlmMessageGenerator()
auth_req_msg = ntlm_gen.create_auth_req()
auth_req_msg_dec = base64.decodestring(auth_req_msg)
auth_req_msg = string.replace(auth_req_msg,'\012','')
webservice = httplib.HTTPConnection(ip_host) 
webservice.putrequest("POST", "/idc/idcplg")
webservice.putheader("Content-length", "%d" % len(request)) 
webservice.putheader('Authorization', 'NTLM'+' '+auth_req_msg) 
webservice.endheaders()
resp = webservice.getresponse()
resp.read()

challenge = resp.msg.get('WWW-Authenticate')
challenge_dec = base64.decodestring(challenge.split()[1])

msg3 = ntlm_gen.create_challenge_response(challenge_dec)
webservice = httplib.HTTP(ip_host) 
webservice.putrequest("POST", "/idc/idcplg?IdcService=LOGIN&Auth=Intranet")
webservice.putheader("Host", SHOD)
webservice.putheader("Content-length", "%d" % len(request))
webservice.putheader('Authorization', 'NTLM'+' '+msg3) 
webservice.putheader("Content-type", "text/xml; charset=\"UTF-8\"")
webservice.putheader("SOAPAction", "\"\"")
webservice.endheaders()
webservice.send(request)
statuscode, statusmessage, header = webservice.getreply()
res = webservice.getfile().read()
res_file = file('result.txt','wb')
res_file.write(res)
res_file.close()

sspi.py 在这里可用: https://ironpython.svn.codeplex.com/svn/IronPython_Main/External.LCA_RESTRICTED/Languages/IronPython/27/Lib/site-packages/win32/lib/sspi.py

谢谢!

【问题讨论】:

    标签: python authentication ntlm


    【解决方案1】:
    import win32com.client
    
    url = 'https://....'
    
    h = win32com.client.Dispatch('WinHTTP.WinHTTPRequest.5.1')
    h.SetAutoLogonPolicy(0)
    h.Open('GET', url, False)
    h.Send()
    result = h.responseText
    result
    

    【讨论】:

    • 这个答案很棒。这个对我有用!我在 Windows 环境中,想使用域身份验证。它有效!!!
    • POST 请求怎么样?我想知道如何处理 Open 函数中的参数...
    • 如何让这种方法在 Flask 环境中进行多线程证明?
    【解决方案2】:

    我发现出了什么问题。 我应该保持连接活跃。 那就是货! 现在这个问题解决了。

    class WindoewNtlmMessageGenerator:
       def __init__(self,user=None):
           import win32api,sspi
           if not user:
               user = win32api.GetUserName()
           self.sspi_client = sspi.ClientAuth("NTLM",user)   
    
       def create_auth_req(self):
           import pywintypes
           output_buffer = None
           error_msg = None
           try:
               error_msg, output_buffer = self.sspi_client.authorize(None)             
           except pywintypes.error:           
                return None
           auth_req = output_buffer[0].Buffer
           auth_req = base64.b64encode(auth_req)
           return auth_req 
    
    
      def create_challenge_response(self,challenge):
          import pywintypes
          output_buffer = None
          input_buffer = challenge
          error_msg = None
          try:
              error_msg, output_buffer = self.sspi_client.authorize(input_buffer)
          except pywintypes.error:
              return None
          response_msg = output_buffer[0].Buffer        
          response_msg = base64.b64encode(response_msg) 
          return response_msg 
    
    
    SHOD='qqq.yyy.dev'
    answer='result.xml'
    fname='request.xml'
    try:
        a_file = open(fname, 'r')
        f=open(fname, 'r')
    except IOError:
        sys.exit()
    size = os.path.getsize(fname)
    i=0
    for line in f:
        i=i+1
    count_string=i
    f.close()
    size=size-count_string+1
    
    
    print '1' 
    
    try:
        webservice = httplib.HTTPConnection(SHOD)     
        webservice.putrequest("POST", "/idc/idcplg?IdcService=LOGIN&Auth=Intranet")
        webservice.putheader("Content-length", "%d" % 0)
        webservice.putheader("Content-type", "text/xml")
        #webservice.putheader("User-Agent", 'Python-urllib/2.6')
        webservice.endheaders()
        res=webservice.getresponse()
    except:
        msg= "unable to connect to URL:  "+ SHOD
        sys.exit()
    if res.status == 401:
        auth_methods = [s.strip() for s in 
                        res.msg.get('WWW-Authenticate').split(",")]
        print auth_methods
    if res.status <> 401:
        msg= "unable to connect to URL:  "+ SHOD_
        log_error(msg,answer)
        sys.exit()
    
    
    
    print '2' 
    
    ntlm_gen = WindoewNtlmMessageGenerator()
    auth_req_msg = ntlm_gen.create_auth_req()
    webservice.putrequest("POST", "/idc/idcplg?IdcService=LOGIN&Auth=Intranet")
    webservice.putheader("Content-length", "%d" % 0)
    webservice.putheader("Connection", "Keep-Alive")
    #webservice.putheader("User-Agent", 'Python-urllib/2.6')
    webservice.putheader('Authorization', 'NTLM'+' '+auth_req_msg) 
    webservice.endheaders()
    resp = webservice.getresponse()
    resp.read()
    print resp.status
    challenge = resp.msg.get('WWW-Authenticate')
    challenge_dec = base64.b64decode(challenge.split()[1])
    
    
    
    print '3' 
    
    msg3 = ntlm_gen.create_challenge_response(challenge_dec)
    webservice.putrequest("POST", "/idc/idcplg?IdcService=LOGIN&Auth=Intranet")
    webservice.putheader("Content-type", "text/xml; charset=UTF-8")
    webservice.putheader("Content-length", "%d" %(size))
    webservice.putheader("Connection", "Close")
    webservice.putheader('Authorization', 'NTLM'+' '+msg3)
    #webservice.putheader("User-Agent", 'Python-urllib/2.6') 
    webservice.endheaders()
    sable = a_file.read()     
    webservice.send(sable)
    resp = webservice.getresponse()
    res=resp.read()
    

    【讨论】:

    • 您应该将此答案标记为已接受(单击旁边的绿色复选标记),这样它就不会被列为未回答的问题。
    • 这对 Linux 有什么作用? (相信有些库不可用)
    • @Dimitris:它使用本地 Windows 函数对域进行身份验证 - 没有办法从非 Windows 机器上做到这一点。您必须在本地重新实现 Netlogon 协议 (MS-NRPC),这涉及实现底层 MS-RPC 层。不是很有趣。
    • @bobince,您可以使用 PyAuthenNTLM2 和 Apache 针对 NTLM 身份验证存储区对 linux Web 服务进行身份验证...参见 this blog 示例
    • @Svetlana 您绝对应该将此标记为答案,该方法效果很好
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-06
    • 2017-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多