I'm interested in a python implementation of http ntlm authentication without using the 3rd-party python ntlm library.
Asked
Active
Viewed 2,581 times
1 Answers
1
This works as long as the username is not part of a domain. You may need to pass ntlm='NTLM'
instead of Negotiate
in some cases.
def ntlm_authenticate_message(nonce, username, password):
# http://davenport.sourceforge.net/ntlm.html#theLmv2Response
import hashlib
import hmac
import os
ntlm_hash = hashlib.new('md4', password.encode('utf-16le')).digest()
ntlm_v2 = hmac.new(ntlm_hash, username.upper().encode('utf-16le')).digest()
rand = os.urandom(8)
lm = hmac.new(ntlm_v2, nonce + rand).digest() + rand
return ('NTLMSSP\0\3\0\0\0' + '\x18\0\x18\0\x40\0\0\0' + '\0' * 8 + '\0' * 8 +
chr(len(username)) + '\0' + chr(len(username)) + '\0' + '\x58\0\0\0' +
'\0' * 8 + '\0' * 8 + '\0' * 4 + lm + username).encode('base64').replace('\n', '')
def http_ntlm_auth(url, data, headers, username, password, ntlm='Negotiate'):
# http://davenport.sourceforge.net/ntlm.html#ntlmHttpAuthentication
u = urlparse(url)
h = HTTPSConnection(u.netloc)
# h.set_debuglevel(1)
h.request('GET', u.path, None, {'Authorization': ntlm + ' ' + 'NTLMSSP\0\1\0\0\0\2\0\0\0'.encode('base64')}) # 1
resp = h.getresponse()
error = resp.read()
assert resp.status == 401 and not error, (resp.status, resp.reason, error)
nonce = resp.getheader('WWW-Authenticate').split()[1].decode('base64')[24:32] # type 2
headers['Authorization'] = ntlm + ' ' + ntlm_authenticate_message(nonce, username, password) # type 3
h.request('POST' if data else 'GET', u.path, data, headers)
return h.getresponse()

Collin Anderson
- 14,787
- 6
- 68
- 57