Возможно, это не так уж и элегантно, но работает (импорт / отображение в представлениях):
import base64
def get_msg_str(msg,start):
msg_len, _, msg_off = struct.unpack("<HHH", msg[start:start + 6])
return msg[msg_off:msg_off + msg_len].replace("\0", '')
def ntlm_auth(request):
"""Goes through ntlm stages...
Return user_name, response.
While response is not none, keep sending it.
Then use the user.
"""
username = None
response = None
auth = request.META.get('HTTP_AUTHORIZATION')
if not auth:
response = HttpResponse(status=401)
response['WWW-Authenticate'] = "NTLM"
elif auth[:4] == "NTLM":
msg = base64.b64decode(auth[4:])
# print repr(msg)
ntlm_fmt = "<8sb" #string, length 8, 4 - op
NLTM_SIG = "NTLMSSP\0"
signature, op = struct.unpack(ntlm_fmt, msg[:9])
if signature != NLTM_SIG:
print "error header not recognized"
else:
print "recognized"
# print signature, op
# print repr(msg)
if op == 1:
out_msg_fmt = ntlm_fmt + "2I4B2Q2H"
out_msg = struct.pack(out_msg_fmt,
NLTM_SIG, #Signature
2, #Op
0, #target name len
0, #target len off
1, 2, 0x81, 1, #flags
0, #challenge
0, #context
0, #target info len
0x30, #target info offset
)
response = HttpResponse(status=401)
response['WWW-Authenticate'] = "NTLM " + base64.b64encode(out_msg).strip()
elif op == 3:
username = get_msg_str(msg, 36)
return username, response
Использование:
def my_view(request):
username, response = ntlm_auth(request)
if response:
return response
Я уверен, что это можно сделать более элегантно, как декоратор, и могут быть другие способы - но я использовал это, и это работает.