NTLM authentication in Python

29,371

Solution 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

Solution 2

I've found out what was wrong. I should keeping the connection alive. That's the goods! Now this problem is solved.

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()
Share:
29,371
Admin
Author by

Admin

Updated on July 27, 2022

Comments

  • Admin
    Admin almost 2 years

    I'm trying to implement NTLM authentication on IIS (Windows Server 2003) from Windows 7 with python. LAN Manager Authentication Level: Send NTLM response only.
    Client machine and server are in the same domain.
    Domain controller (AD) is on another server (also running Windows Server 2003).

    I receive 401.1 - Unauthorized: Access is denied due to invalid credentials. Could you please help me find out what is wrong with this code and/or show me the other possible directions to solve this problem (using NTLM or 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 is available here: https://ironpython.svn.codeplex.com/svn/IronPython_Main/External.LCA_RESTRICTED/Languages/IronPython/27/Lib/site-packages/win32/lib/sspi.py

    Thanks!

  • Bill the Lizard
    Bill the Lizard over 13 years
    You should mark this answer as accepted (click the green check mark next to it) so it doesn't get listed as an unanswered question.
  • Dimitris
    Dimitris over 12 years
    How would this work for Linux? (I believe that some libraries are not available)
  • Amit Patil
    Amit Patil about 11 years
    @Dimitris: it uses native Windows functions to authenticate against the domain - there's no way to do that from a non-Windows box. You'd have to reimplement the Netlogon protocol (MS-NRPC) natively, which involves implementing the underlying MS-RPC layer. Not a lot of fun.
  • Mike Pennington
    Mike Pennington about 10 years
    @bobince, you can authenticate linux web services against an NTLM auth store using PyAuthenNTLM2 and Apache... see this blog for an example
  • Wasp
    Wasp over 7 years
    @Svetlana you should definitely mark this as an answer, the approach works nicely
  • Ami
    Ami almost 7 years
    This answer is great. It works for me! I'm in a Windows environment and want to use domain authentication. It works!!!
  • Colonel Beauvel
    Colonel Beauvel over 6 years
    what about a POST request? I wonder how I can handle the parameter in the Open function ...
  • imolitor
    imolitor about 6 years
    how would I make this approach multi-thread proof as in a Flask environment for example?