diff options
author | Nicolas Chauvat <nicolas.chauvat@logilab.fr> | 2011-02-15 23:28:07 +0100 |
---|---|---|
committer | Nicolas Chauvat <nicolas.chauvat@logilab.fr> | 2011-02-15 23:28:07 +0100 |
commit | 09a81984d4057b0ffcba98b358902f01053a0c35 (patch) | |
tree | e0f1009e1bd774c5e932d723bce5877847bb70b3 | |
parent | 446260f29a8d8da8fa4021dd79cb427948fdeebd (diff) | |
download | logilab-common-09a81984d4057b0ffcba98b358902f01053a0c35.tar.gz |
[urllib2ext] new module with HTTPGssapiAuthHandler
applied patch urllib2ext.diff
-rw-r--r-- | __pkginfo__.py | 3 | ||||
-rw-r--r-- | debian/control | 2 | ||||
-rw-r--r-- | urllib2ext.py | 87 |
3 files changed, 89 insertions, 3 deletions
diff --git a/__pkginfo__.py b/__pkginfo__.py index 206a5db..fe43ff9 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -23,7 +23,7 @@ modname = 'common' subpackage_of = 'logilab' subpackage_master = True -numversion = (0, 54, 1) +numversion = (0, 55, 0) version = '.'.join([str(num) for num in numversion]) license = 'LGPL' # 2.1 or later @@ -40,4 +40,3 @@ scripts = [join('bin', 'pytest')] include_dirs = [join('test', 'data')] install_requires = ['unittest2 >= 0.5.1'] - diff --git a/debian/control b/debian/control index e2b1007..a06507c 100644 --- a/debian/control +++ b/debian/control @@ -20,7 +20,7 @@ Package: python-logilab-common Architecture: all Provides: ${python:Provides} Depends: ${python:Depends}, ${misc:Depends} -Suggests: pyro, python-unittest2 +Suggests: pyro, python-unittest2, python-kerberos Recommends: python-egenix-mxdatetime Conflicts: python-constraint ( <= 0.3.0-4), python-logilab-astng ( <= 0.16.0-1), pylint ( << 0.11.0-1), devtools ( <= 0.9.0-1), logilab-doctools ( <= 0.1.6-4), python-logilab-aspects ( <= 0.1.4-2), python2.3-logilab-common, python2.4-logilab-common, cubicweb-server ( << 3.6.0-1) Description: useful miscellaneous modules used by Logilab projects diff --git a/urllib2ext.py b/urllib2ext.py new file mode 100644 index 0000000..08797a4 --- /dev/null +++ b/urllib2ext.py @@ -0,0 +1,87 @@ +import logging +import urllib2 + +import kerberos as krb + +class GssapiAuthError(Exception): + """raised on error during authentication process""" + +import re +RGX = re.compile('(?:.*,)*\s*Negotiate\s*([^,]*),?', re.I) + +def get_negociate_value(headers): + for authreq in headers.getheaders('www-authenticate'): + match = RGX.search(authreq) + if match: + return match.group(1) + +class HTTPGssapiAuthHandler(urllib2.BaseHandler): + """Negotiate HTTP authentication using context from GSSAPI""" + + handler_order = 400 # before Digest Auth + + def __init__(self): + self._reset() + + def _reset(self): + self._retried = 0 + self._context = None + + def clean_context(self): + if self._context is not None: + krb.authGSSClientClean(self._context) + + def http_error_401(self, req, fp, code, msg, headers): + try: + if self._retried > 5: + raise urllib2.HTTPError(req.get_full_url(), 401, + "negotiate auth failed", headers, None) + self._retried += 1 + logging.debug('gssapi handler, try %s' % self._retried) + negotiate = get_negociate_value(headers) + if negotiate is None: + logging.debug('no negociate found in a www-authenticate header') + return None + logging.debug('HTTPGssapiAuthHandler: negotiate 1 is %r' % negotiate) + result, self._context = krb.authGSSClientInit("HTTP@%s" % req.get_host()) + if result < 1: + raise GssapiAuthError("HTTPGssapiAuthHandler: init failed with %d" % result) + result = krb.authGSSClientStep(self._context, negotiate) + if result < 0: + raise GssapiAuthError("HTTPGssapiAuthHandler: step 1 failed with %d" % result) + client_response = krb.authGSSClientResponse(self._context) + logging.debug('HTTPGssapiAuthHandler: client response is %s...' % client_response[:10]) + req.add_unredirected_header('Authorization', "Negotiate %s" % client_response) + server_response = self.parent.open(req) + negotiate = get_negociate_value(server_response.info()) + if negotiate is None: + logging.warning('HTTPGssapiAuthHandler: failed to authenticate server') + else: + logging.debug('HTTPGssapiAuthHandler negotiate 2: %s' % negotiate) + result = krb.authGSSClientStep(self._context, negotiate) + if result < 1: + raise GssapiAuthError("HTTPGssapiAuthHandler: step 2 failed with %d" % result) + return server_response + except GssapiAuthError, exc: + logging.error(repr(exc)) + finally: + self.clean_context() + self._reset() + +if __name__ == '__main__': + import sys + # debug + import httplib + httplib.HTTPConnection.debuglevel = 1 + httplib.HTTPSConnection.debuglevel = 1 + # debug + import logging + logging.basicConfig(level=logging.DEBUG) + # handle cookies + import cookielib + cj = cookielib.CookieJar() + ch = urllib2.HTTPCookieProcessor(cj) + # test with url sys.argv[1] + h = HTTPGssapiAuthHandler() + response = urllib2.build_opener(h, ch).open(sys.argv[1]) + print '\nresponse: %s\n--------------\n' % response.code, response.info() |