Skip to content

Commit

Permalink
Added Kerberos proxy authentication based on code published here: req…
Browse files Browse the repository at this point in the history
  • Loading branch information
enzolis committed Apr 7, 2020
1 parent d9c78fc commit 3e080c3
Showing 1 changed file with 42 additions and 4 deletions.
46 changes: 42 additions & 4 deletions requests_kerberos/kerberos_.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ def _negotiate_value(response):
regex = re.compile(r'(?:.*,)*\s*Negotiate\s*([^,]*),?', re.I)
_negotiate_value.regex = regex

authreq = response.headers.get('www-authenticate', None)
if response.status_code == 407:
authreq = response.headers.get('proxy-authenticate', None)
else:
authreq = response.headers.get('www-authenticate', None)

if authreq:
match_obj = regex.search(authreq)
Expand Down Expand Up @@ -256,16 +259,24 @@ def authenticate_user(self, response, **kwargs):
"""Handles user authentication with gssapi/kerberos"""

host = urlparse(response.url).hostname
if response.status_code == 407:
if 'proxies' in kwargs and urlparse(response.url).scheme in kwargs['proxies']:
host = urlparse(kwargs['proxies'][urlparse(response.url).scheme]).hostname

try:
auth_header = self.generate_request_header(response, host)
except KerberosExchangeError:
# GSS Failure, return existing response
return response

log.debug("authenticate_user(): Authorization header: {0}".format(
auth_header))
response.request.headers['Authorization'] = auth_header
if response.status_code == 407:
log.debug("authenticate_user(): Proxy-Authorization header: {0}".format(
auth_header))
response.request.headers['Proxy-Authorization'] = auth_header
else:
log.debug("authenticate_user(): Authorization header: {0}".format(
auth_header))
response.request.headers['Authorization'] = auth_header

# Consume the content so we can reuse the connection for the next
# request.
Expand All @@ -291,6 +302,19 @@ def handle_401(self, response, **kwargs):
log.debug("handle_401(): returning {0}".format(response))
return response

def handle_407(self, response, **kwargs):
"""Handles 407's, attempts to use gssapi/kerberos authentication"""

log.debug("handle_407(): Handling: 407")
if _negotiate_value(response) is not None:
_r = self.authenticate_user(response, **kwargs)
log.debug("handle_407(): returning {0}".format(_r))
return _r
else:
log.debug("handle_407(): Kerberos is not supported")
log.debug("handle_407(): returning {0}".format(response))
return response

def handle_other(self, response):
"""Handles all responses with the exception of 401s.
Expand Down Expand Up @@ -374,6 +398,7 @@ def authenticate_server(self, response):
def handle_response(self, response, **kwargs):
"""Takes the given response and tries kerberos-auth, as needed."""
num_401s = kwargs.pop('num_401s', 0)
num_407s = kwargs.pop('num_407s', 0)

# Check if we have already tried to get the CBT data value
if not self.cbt_binding_tried and self.send_cbt:
Expand Down Expand Up @@ -407,6 +432,19 @@ def handle_response(self, response, **kwargs):
# Authentication has failed. Return the 401 response.
log.debug("handle_response(): returning 401 %s", response)
return response
elif response.status_code == 407 and num_407s < 2:
# 407 Unauthorized. Handle it, and if it still comes back as 407,
# that means authentication failed.
_r = self.handle_407(response, **kwargs)
log.debug("handle_response(): returning %s", _r)
log.debug("handle_response() has seen %d 407 responses", num_407s)
num_407s += 1
return self.handle_response(_r, num_407s=num_407s, **kwargs)
elif response.status_code == 407 and num_407s >= 2:
# Still receiving 407 responses after attempting to handle them.
# Authentication has failed. Return the 407 response.
log.debug("handle_response(): returning 407 %s", response)
return response
else:
_r = self.handle_other(response)
log.debug("handle_response(): returning %s", _r)
Expand Down

0 comments on commit 3e080c3

Please sign in to comment.