mirror of
https://gerrit.googlesource.com/git-repo
synced 2024-12-21 07:16:21 +00:00
Implement Kerberos HTTP authentication handler
This commit implements a Kerberos HTTP authentication handler. It uses credentials from a local cache to perform an HTTP authentication negotiation using the GSSAPI. The purpose of this handler is to allow the use Kerberos authentication to access review endpoints without the need to transmit the user password. Change-Id: Id2c3fc91a58b15a3e83e4bd9ca87203fa3d647c8
This commit is contained in:
parent
5db69f3f66
commit
1242e60bdd
87
main.py
87
main.py
@ -31,6 +31,11 @@ else:
|
|||||||
urllib = imp.new_module('urllib')
|
urllib = imp.new_module('urllib')
|
||||||
urllib.request = urllib2
|
urllib.request = urllib2
|
||||||
|
|
||||||
|
try:
|
||||||
|
import kerberos
|
||||||
|
except ImportError:
|
||||||
|
kerberos = None
|
||||||
|
|
||||||
from trace import SetTrace
|
from trace import SetTrace
|
||||||
from git_command import git, GitCommand
|
from git_command import git, GitCommand
|
||||||
from git_config import init_ssh, close_ssh
|
from git_config import init_ssh, close_ssh
|
||||||
@ -332,6 +337,86 @@ class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
|
|||||||
self.retried = 0
|
self.retried = 0
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
class _KerberosAuthHandler(urllib.request.BaseHandler):
|
||||||
|
def __init__(self):
|
||||||
|
self.retried = 0
|
||||||
|
self.context = None
|
||||||
|
self.handler_order = urllib.request.BaseHandler.handler_order - 50
|
||||||
|
|
||||||
|
def http_error_401(self, req, fp, code, msg, headers):
|
||||||
|
host = req.get_host()
|
||||||
|
retry = self.http_error_auth_reqed('www-authenticate', host, req, headers)
|
||||||
|
return retry
|
||||||
|
|
||||||
|
def http_error_auth_reqed(self, auth_header, host, req, headers):
|
||||||
|
try:
|
||||||
|
spn = "HTTP@%s" % host
|
||||||
|
authdata = self._negotiate_get_authdata(auth_header, headers)
|
||||||
|
|
||||||
|
if self.retried > 3:
|
||||||
|
raise urllib.request.HTTPError(req.get_full_url(), 401,
|
||||||
|
"Negotiate auth failed", headers, None)
|
||||||
|
else:
|
||||||
|
self.retried += 1
|
||||||
|
|
||||||
|
neghdr = self._negotiate_get_svctk(spn, authdata)
|
||||||
|
if neghdr is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
req.add_unredirected_header('Authorization', neghdr)
|
||||||
|
response = self.parent.open(req)
|
||||||
|
|
||||||
|
srvauth = self._negotiate_get_authdata(auth_header, response.info())
|
||||||
|
if self._validate_response(srvauth):
|
||||||
|
return response
|
||||||
|
except kerberos.GSSError:
|
||||||
|
return None
|
||||||
|
except:
|
||||||
|
self.reset_retry_count()
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self._clean_context()
|
||||||
|
|
||||||
|
def reset_retry_count(self):
|
||||||
|
self.retried = 0
|
||||||
|
|
||||||
|
def _negotiate_get_authdata(self, auth_header, headers):
|
||||||
|
authhdr = headers.get(auth_header, None)
|
||||||
|
if authhdr is not None:
|
||||||
|
for mech_tuple in authhdr.split(","):
|
||||||
|
mech, __, authdata = mech_tuple.strip().partition(" ")
|
||||||
|
if mech.lower() == "negotiate":
|
||||||
|
return authdata.strip()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _negotiate_get_svctk(self, spn, authdata):
|
||||||
|
if authdata is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
result, self.context = kerberos.authGSSClientInit(spn)
|
||||||
|
if result < kerberos.AUTH_GSS_COMPLETE:
|
||||||
|
return None
|
||||||
|
|
||||||
|
result = kerberos.authGSSClientStep(self.context, authdata)
|
||||||
|
if result < kerberos.AUTH_GSS_CONTINUE:
|
||||||
|
return None
|
||||||
|
|
||||||
|
response = kerberos.authGSSClientResponse(self.context)
|
||||||
|
return "Negotiate %s" % response
|
||||||
|
|
||||||
|
def _validate_response(self, authdata):
|
||||||
|
if authdata is None:
|
||||||
|
return None
|
||||||
|
result = kerberos.authGSSClientStep(self.context, authdata)
|
||||||
|
if result == kerberos.AUTH_GSS_COMPLETE:
|
||||||
|
return True
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _clean_context(self):
|
||||||
|
if self.context is not None:
|
||||||
|
kerberos.authGSSClientClean(self.context)
|
||||||
|
self.context = None
|
||||||
|
|
||||||
def init_http():
|
def init_http():
|
||||||
handlers = [_UserAgentHandler()]
|
handlers = [_UserAgentHandler()]
|
||||||
|
|
||||||
@ -348,6 +433,8 @@ def init_http():
|
|||||||
pass
|
pass
|
||||||
handlers.append(_BasicAuthHandler(mgr))
|
handlers.append(_BasicAuthHandler(mgr))
|
||||||
handlers.append(_DigestAuthHandler(mgr))
|
handlers.append(_DigestAuthHandler(mgr))
|
||||||
|
if kerberos:
|
||||||
|
handlers.append(_KerberosAuthHandler())
|
||||||
|
|
||||||
if 'http_proxy' in os.environ:
|
if 'http_proxy' in os.environ:
|
||||||
url = os.environ['http_proxy']
|
url = os.environ['http_proxy']
|
||||||
|
Loading…
Reference in New Issue
Block a user