diff options
| author | David Pursehouse <david.pursehouse@sonymobile.com> | 2014-02-05 00:58:52 +0000 |
|---|---|---|
| committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-02-05 00:58:53 +0000 |
| commit | f1027e23b4e59e6d67899562bbd24d3d0d82a9fc (patch) | |
| tree | db0de3353de1a92af0c3439c4dd58302d58f6e01 /main.py | |
| parent | 1b46cc9b6d366a34a37dd475730574979ff9b739 (diff) | |
| parent | 1242e60bdd250dd31f49a181dd326af96427f300 (diff) | |
| download | git-repo-f1027e23b4e59e6d67899562bbd24d3d0d82a9fc.tar.gz | |
Merge "Implement Kerberos HTTP authentication handler"
Diffstat (limited to 'main.py')
| -rwxr-xr-x | main.py | 87 |
1 files changed, 87 insertions, 0 deletions
| @@ -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 | ||
| 34 | try: | ||
| 35 | import kerberos | ||
| 36 | except ImportError: | ||
| 37 | kerberos = None | ||
| 38 | |||
| 34 | from trace import SetTrace | 39 | from trace import SetTrace |
| 35 | from git_command import git, GitCommand | 40 | from git_command import git, GitCommand |
| 36 | from git_config import init_ssh, close_ssh | 41 | from 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 | ||
| 340 | class _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 | |||
| 335 | def init_http(): | 420 | def 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'] |
