summaryrefslogtreecommitdiff
path: root/urllib2ext.py
diff options
context:
space:
mode:
authorNicolas Chauvat <nicolas.chauvat@logilab.fr>2011-02-15 23:28:07 +0100
committerNicolas Chauvat <nicolas.chauvat@logilab.fr>2011-02-15 23:28:07 +0100
commit09a81984d4057b0ffcba98b358902f01053a0c35 (patch)
treee0f1009e1bd774c5e932d723bce5877847bb70b3 /urllib2ext.py
parent446260f29a8d8da8fa4021dd79cb427948fdeebd (diff)
downloadlogilab-common-09a81984d4057b0ffcba98b358902f01053a0c35.tar.gz
[urllib2ext] new module with HTTPGssapiAuthHandler
applied patch urllib2ext.diff
Diffstat (limited to 'urllib2ext.py')
-rw-r--r--urllib2ext.py87
1 files changed, 87 insertions, 0 deletions
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()