Skip to content

Commit

Permalink
Apply bulk black and isort changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jborean93 committed Jun 7, 2024
1 parent 5f71c99 commit 986a8ad
Show file tree
Hide file tree
Showing 6 changed files with 347 additions and 260 deletions.
2 changes: 1 addition & 1 deletion requests_ntlm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .requests_ntlm import HttpNtlmAuth

__all__ = ('HttpNtlmAuth',)
__all__ = ("HttpNtlmAuth",)
10 changes: 5 additions & 5 deletions requests_ntlm/requests_ntlm.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
from __future__ import annotations

import warnings
import base64
import typing as t

import warnings
from urllib.parse import urlparse

import requests
import spnego

from cryptography import x509
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.exceptions import UnsupportedAlgorithm
from requests.auth import AuthBase
from requests.packages.urllib3.response import HTTPResponse

Expand Down Expand Up @@ -170,7 +168,9 @@ def retry_using_http_NTLM_auth(
)

if not ntlm_header_value:
raise PermissionError("Access denied: Server did not respond with NTLM challenge token")
raise PermissionError(
"Access denied: Server did not respond with NTLM challenge token"
)

# Parse the challenge in the ntlm context and perform
# the second step of authentication
Expand Down
27 changes: 15 additions & 12 deletions tests/functional/test_functional.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import requests

import requests_ntlm

"""
Expand All @@ -7,47 +8,49 @@
with the 4 scenarios tested below if you wish to run a sanity check
"""

username = '.\\User'
password = 'Password01'
http_with_cbt = 'http://127.0.0.1:81/contents.txt'
http_without_cbt = 'http://127.0.0.1:82/contents.txt'
https_with_cbt = 'https://127.0.0.1:441/contents.txt'
https_without_cbt = 'https://127.0.0.1:442/contents.txt'
expected = 'contents'
username = ".\\User"
password = "Password01"
http_with_cbt = "http://127.0.0.1:81/contents.txt"
http_without_cbt = "http://127.0.0.1:82/contents.txt"
https_with_cbt = "https://127.0.0.1:441/contents.txt"
https_without_cbt = "https://127.0.0.1:442/contents.txt"
expected = "contents"


class Test_Functional():
class Test_Functional:
def test_ntlm_http_with_cbt(self):
actual = send_request(http_with_cbt, username, password)
actual_content = actual.content.decode('utf-8')
actual_content = actual.content.decode("utf-8")
actual_code = actual.status_code

assert actual_code == 200
assert actual_content == expected

def test_ntlm_http_without_cbt(self):
actual = send_request(http_without_cbt, username, password)
actual_content = actual.content.decode('utf-8')
actual_content = actual.content.decode("utf-8")
actual_code = actual.status_code

assert actual_code == 200
assert actual_content == expected

def test_ntlm_https_with_cbt(self):
actual = send_request(https_with_cbt, username, password)
actual_content = actual.content.decode('utf-8')
actual_content = actual.content.decode("utf-8")
actual_code = actual.status_code

assert actual_code == 200
assert actual_content == expected

def test_ntlm_https_without_cbt(self):
actual = send_request(https_without_cbt, username, password)
actual_content = actual.content.decode('utf-8')
actual_content = actual.content.decode("utf-8")
actual_code = actual.status_code

assert actual_code == 200
assert actual_content == expected


def send_request(url, username, password):
"""
Sends a request to the url with the credentials specified. Returns the final response
Expand Down
59 changes: 38 additions & 21 deletions tests/test_server.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,90 @@
import base64
import struct

from flask import Flask,request
from tests.test_utils import domain, username, password
from flask import Flask, request

from tests.test_utils import domain, password, username

app = Flask(__name__)


@app.route("/ntlm")
def ntlm_auth():
return get_auth_response('NTLM')
return get_auth_response("NTLM")


@app.route("/negotiate")
def negotiate_auth():
return get_auth_response('Negotiate')
return get_auth_response("Negotiate")


@app.route("/both")
def negotiate_and_ntlm_auth():
return get_auth_response('NTLM', advertise_nego_and_ntlm=True)
return get_auth_response("NTLM", advertise_nego_and_ntlm=True)


@app.route("/no_challenge")
def no_challenge():
return get_auth_response('Negotiate', no_challenge=True)
return get_auth_response("Negotiate", no_challenge=True)


def get_auth_response(auth_type, advertise_nego_and_ntlm=False, no_challenge=False):
# Get the actual header that is returned by requests_ntlm
actual_header = request.headers.get('Authorization', '')
actual_header = request.headers.get("Authorization", "")

# Check what the message type is from the header
if actual_header == '':
if actual_header == "":
# This is the initial connection, need to return a 401
response_headers = {'WWW-Authenticate': auth_type if not advertise_nego_and_ntlm else 'Negotiate, NTLM'}
response_headers = {
"WWW-Authenticate": (
auth_type if not advertise_nego_and_ntlm else "Negotiate, NTLM"
)
}
status_code = 401
response = "auth with '%s\\%s':'%s'" % (domain, username, password)
else:
# Set human readable names for message types
# see https://msdn.microsoft.com/en-us/library/cc236639.aspx for more details
expected_signature = b'NTLMSSP\x00'
expected_signature = b"NTLMSSP\x00"
negotiate_message_type = 1
authenticate_message_type = 3

msg = base64.b64decode(actual_header[len(auth_type):])
msg = base64.b64decode(actual_header[len(auth_type) :])
signature = msg[0:8]
if signature != expected_signature:
raise ValueError("Mismatch on NTLM message signature, expecting: %s, actual: %s" % (expected_signature,
signature))
raise ValueError(
"Mismatch on NTLM message signature, expecting: %s, actual: %s"
% (expected_signature, signature)
)
# Get the NTLM version number (bytes 9 - 12)
message_type = struct.unpack("<I", msg[8:12])[0]

if no_challenge:
response_headers = {'WWW-Authenticate': auth_type}
response_headers = {"WWW-Authenticate": auth_type}
response = "access denied"
status_code = 401
elif message_type == negotiate_message_type:
# Initial NTLM message from client, attach challenge token
challenge_response = ('TlRMTVNTUAACAAAAAwAMADgAAAAzgoriASNFZ4mrze8AAAA'
'AAAAAACQAJABEAAAABgBwFwAAAA9TAGUAcgB2AGUAcgACAA'
'wARABvAG0AYQBpAG4AAQAMAFMAZQByAHYAZQByAAAAAAA=')
challenge_header = auth_type + ' ' + challenge_response
response_headers = {'WWW-Authenticate': challenge_header}
challenge_response = (
"TlRMTVNTUAACAAAAAwAMADgAAAAzgoriASNFZ4mrze8AAAA"
"AAAAAACQAJABEAAAABgBwFwAAAA9TAGUAcgB2AGUAcgACAA"
"wARABvAG0AYQBpAG4AAQAMAFMAZQByAHYAZQByAAAAAAA="
)
challenge_header = auth_type + " " + challenge_response
response_headers = {"WWW-Authenticate": challenge_header}
response = "auth with '%s\\%s':'%s'" % (domain, username, password)
status_code = 401
elif message_type == authenticate_message_type:
# Received final NTLM message, return 200
response_headers = {}
status_code = 200
response = 'authed'
response = "authed"
else:
# Should only ever receive a negotiate (1) or auth (3) message from requests_ntlm
raise ValueError("Mismatch on NTLM message type, expecting: 1 or 3, actual: %d" % message_type)
raise ValueError(
"Mismatch on NTLM message type, expecting: 1 or 3, actual: %d"
% message_type
)

return response, status_code, response_headers

Expand Down
8 changes: 4 additions & 4 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Default variables used for the ntlm_context
username = 'username'
domain = 'domain'
password = 'password'
username = "username"
domain = "domain"
password = "password"

# Genearated online as hashlib.md4 may not be available anymore
password_md4 = '8a9d093f14f8701df17732b2bb182c74'
password_md4 = "8a9d093f14f8701df17732b2bb182c74"
Loading

0 comments on commit 986a8ad

Please sign in to comment.