summaryrefslogtreecommitdiffstats
path: root/main.py
diff options
context:
space:
mode:
authorCarlos Aguado <caguadosa@gmail.com>2014-02-03 13:48:47 +0100
committerCarlos Aguado <caguadosa@gmail.com>2014-02-04 09:22:42 +0100
commit1242e60bdd250dd31f49a181dd326af96427f300 (patch)
tree2763d80fb63960c934965606ea2e436e6cfd8777 /main.py
parent5db69f3f6616ea199a7840f0602b988f8d5504b9 (diff)
downloadgit-repo-1242e60bdd250dd31f49a181dd326af96427f300.tar.gz
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
Diffstat (limited to 'main.py')
-rwxr-xr-xmain.py87
1 files changed, 87 insertions, 0 deletions
diff --git a/main.py b/main.py
index 6ec7158d..36617762 100755
--- a/main.py
+++ b/main.py
@@ -31,6 +31,11 @@ else:
31 urllib = imp.new_module('urllib') 31 urllib = imp.new_module('urllib')
32 urllib.request = urllib2 32 urllib.request = urllib2
33 33
34try:
35 import kerberos
36except ImportError:
37 kerberos = None
38
34from trace import SetTrace 39from trace import SetTrace
35from git_command import git, GitCommand 40from git_command import git, GitCommand
36from git_config import init_ssh, close_ssh 41from git_config import init_ssh, close_ssh
@@ -332,6 +337,86 @@ class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
332 self.retried = 0 337 self.retried = 0
333 raise 338 raise
334 339
340class _KerberosAuthHandler(urllib.request.BaseHandler):
341 def __init__(self):
342 self.retried = 0
343 self.context = None
344 self.handler_order = urllib.request.BaseHandler.handler_order - 50
345
346 def http_error_401(self, req, fp, code, msg, headers):
347 host = req.get_host()
348 retry = self.http_error_auth_reqed('www-authenticate', host, req, headers)
349 return retry
350
351 def http_error_auth_reqed(self, auth_header, host, req, headers):
352 try:
353 spn = "HTTP@%s" % host
354 authdata = self._negotiate_get_authdata(auth_header, headers)
355
356 if self.retried > 3:
357 raise urllib.request.HTTPError(req.get_full_url(), 401,
358 "Negotiate auth failed", headers, None)
359 else:
360 self.retried += 1
361
362 neghdr = self._negotiate_get_svctk(spn, authdata)
363 if neghdr is None:
364 return None
365
366 req.add_unredirected_header('Authorization', neghdr)
367 response = self.parent.open(req)
368
369 srvauth = self._negotiate_get_authdata(auth_header, response.info())
370 if self._validate_response(srvauth):
371 return response
372 except kerberos.GSSError:
373 return None
374 except:
375 self.reset_retry_count()
376 raise
377 finally:
378 self._clean_context()
379
380 def reset_retry_count(self):
381 self.retried = 0
382
383 def _negotiate_get_authdata(self, auth_header, headers):
384 authhdr = headers.get(auth_header, None)
385 if authhdr is not None:
386 for mech_tuple in authhdr.split(","):
387 mech, __, authdata = mech_tuple.strip().partition(" ")
388 if mech.lower() == "negotiate":
389 return authdata.strip()
390 return None
391
392 def _negotiate_get_svctk(self, spn, authdata):
393 if authdata is None:
394 return None
395
396 result, self.context = kerberos.authGSSClientInit(spn)
397 if result < kerberos.AUTH_GSS_COMPLETE:
398 return None
399
400 result = kerberos.authGSSClientStep(self.context, authdata)
401 if result < kerberos.AUTH_GSS_CONTINUE:
402 return None
403
404 response = kerberos.authGSSClientResponse(self.context)
405 return "Negotiate %s" % response
406
407 def _validate_response(self, authdata):
408 if authdata is None:
409 return None
410 result = kerberos.authGSSClientStep(self.context, authdata)
411 if result == kerberos.AUTH_GSS_COMPLETE:
412 return True
413 return None
414
415 def _clean_context(self):
416 if self.context is not None:
417 kerberos.authGSSClientClean(self.context)
418 self.context = None
419
335def init_http(): 420def init_http():
336 handlers = [_UserAgentHandler()] 421 handlers = [_UserAgentHandler()]
337 422
@@ -348,6 +433,8 @@ def init_http():
348 pass 433 pass
349 handlers.append(_BasicAuthHandler(mgr)) 434 handlers.append(_BasicAuthHandler(mgr))
350 handlers.append(_DigestAuthHandler(mgr)) 435 handlers.append(_DigestAuthHandler(mgr))
436 if kerberos:
437 handlers.append(_KerberosAuthHandler())
351 438
352 if 'http_proxy' in os.environ: 439 if 'http_proxy' in os.environ:
353 url = os.environ['http_proxy'] 440 url = os.environ['http_proxy']