Package logilab :: Package common :: Module urllib2ext

[frames] | no frames]

# Source Code for Module logilab.common.urllib2ext

     1  from __future__ import print_function
     2
     3  import logging
     4  import urllib2
     5
     6  import kerberos as krb
     7
     8 -class GssapiAuthError(Exception):
     9      """raised on error during authentication process"""
    10
    11  import re
    12  RGX = re.compile('(?:.*,)*\s*Negotiate\s*([^,]*),?', re.I)
    13
    14 -def get_negociate_value(headers):
    15      for authreq in headers.getheaders('www-authenticate'):
    16          match = RGX.search(authreq)
    17          if match:
    18              return match.group(1)
    19
    20 -class HTTPGssapiAuthHandler(urllib2.BaseHandler):
    21      """Negotiate HTTP authentication using context from GSSAPI"""
    22
    23      handler_order = 400 # before Digest Auth
    24
    25 -    def __init__(self):
    26          self._reset()
    27
    28 -    def _reset(self):
    29          self._retried = 0
    30          self._context = None
    31
    32 -    def clean_context(self):
    33          if self._context is not None:
    34              krb.authGSSClientClean(self._context)
    35
    36 -    def http_error_401(self, req, fp, code, msg, headers):
    37          try:
    38              if self._retried > 5:
    39                  raise urllib2.HTTPError(req.get_full_url(), 401,
    40                                          "negotiate auth failed", headers, None)
    41              self._retried += 1
    42              logging.debug('gssapi handler, try %s' % self._retried)
    43              negotiate = get_negociate_value(headers)
    44              if negotiate is None:
    45                  logging.debug('no negociate found in a www-authenticate header')
    46                  return None
    47              logging.debug('HTTPGssapiAuthHandler: negotiate 1 is %r' % negotiate)
    48              result, self._context = krb.authGSSClientInit("HTTP@%s" % req.get_host())
    49              if result < 1:
    50                  raise GssapiAuthError("HTTPGssapiAuthHandler: init failed with %d" % result)
    51              result = krb.authGSSClientStep(self._context, negotiate)
    52              if result < 0:
    53                  raise GssapiAuthError("HTTPGssapiAuthHandler: step 1 failed with %d" % result)
    54              client_response = krb.authGSSClientResponse(self._context)
    55              logging.debug('HTTPGssapiAuthHandler: client response is %s...' % client_response[:10])
    56              req.add_unredirected_header('Authorization', "Negotiate %s" % client_response)
    57              server_response = self.parent.open(req)
    58              negotiate = get_negociate_value(server_response.info())
    59              if negotiate is None:
    60                  logging.warning('HTTPGssapiAuthHandler: failed to authenticate server')
    61              else:
    62                  logging.debug('HTTPGssapiAuthHandler negotiate 2: %s' % negotiate)
    63                  result = krb.authGSSClientStep(self._context, negotiate)
    64                  if result < 1:
    65                      raise GssapiAuthError("HTTPGssapiAuthHandler: step 2 failed with %d" % result)
    66              return server_response
    67          except GssapiAuthError as exc:
    68              logging.error(repr(exc))
    69          finally:
    70              self.clean_context()
    71              self._reset()
    72
    73  if __name__ == '__main__':
    74      import sys
    75      # debug
    76      import httplib
    77      httplib.HTTPConnection.debuglevel = 1
    78      httplib.HTTPSConnection.debuglevel = 1
    79      # debug
    80      import logging
    81      logging.basicConfig(level=logging.DEBUG)
    82      # handle cookies
    83      import cookielib
    84      cj = cookielib.CookieJar()
    85      ch = urllib2.HTTPCookieProcessor(cj)
    86      # test with url sys.argv[1]
    87      h = HTTPGssapiAuthHandler()
    88      response = urllib2.build_opener(h, ch).open(sys.argv[1])
    89      print('\nresponse: %s\n--------------\n' % response.code, response.info())
    90