diff options
-rw-r--r-- | http_kerberos_auth_handler.py | 139 | ||||
-rw-r--r-- | urllib2_kerberos.py | 141 |
2 files changed, 40 insertions, 240 deletions
diff --git a/http_kerberos_auth_handler.py b/http_kerberos_auth_handler.py deleted file mode 100644 index 2b50154..0000000 --- a/http_kerberos_auth_handler.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/python - -# urllib2 with kerberos proof of concept -# Copyright 2008 Lime Spot LLC - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import re -import logging -import sys -import urllib2 as u2 - -import kerberos as k - -def getLogger(): - log = logging.getLogger("http_kerberos_auth_handler") - handler = logging.StreamHandler() - formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') - handler.setFormatter(formatter) - log.addHandler(handler) - return log - -log = getLogger() - -class HTTPKerberosAuthHandler(u2.BaseHandler): - """auth handler for urllib2 that does Kerberos HTTP Negotiate Authentication - """ - - rx = re.compile('(?:.*,)*\s*Negotiate\s*([^,]*),?', re.I) - handler_order = 480 # before Digest auth - - def negotiate_value(self, headers): - authreq = headers.get('www-authenticate', None) - - if authreq: - mo = HTTPKerberosAuthHandler.rx.search(authreq) - if mo: - return mo.group(1) - else: - log.debug("regex failed on: %s" % authreq) - - else: - log.debug("www-authenticate header not found") - - return None - - def __init__(self): - self.retried = 0 - self.context = None - - def generate_request_header(self, req, headers): - neg_value = self.negotiate_value(headers) - if neg_value is None: - self.retried = 0 - return None - - if self.retried > 5: - raise HTTPError(req.get_full_url(), 401, "kerberos negotiate auth failed", - headers, None) - - self.retried += 1 - - log.debug("req.get_host() returned %s" % req.get_host()) - result, self.context = k.authGSSClientInit("HTTP@%s" % req.get_host()) - - if result < 1: - log.warning("authGSSClientInit returned result %d" % result) - return None - - log.debug("authGSSClientInit() succeeded") - - result = k.authGSSClientStep(self.context, neg_value) - - if result < 0: - log.warning("authGSSClientStep returned result %d" % result) - return None - - log.debug("authGSSClientStep() succeeded") - - response = k.authGSSClientResponse(self.context) - log.debug("authGSSClientResponse() succeeded") - - return "Negotiate %s" % response - - def authenticate_server(self, headers): - neg_value = self.negotiate_value(headers) - if neg_value is None: - log.critical("mutual auth failed. No negotiate header") - return None - - if k.authGSSClientStep(self.context, neg_value) < 1: - log.critical("mutual auth failed: authGSSClientStep returned result %d" % result) - - def clean_context(self): - if self.context is not None: - k.authGSSClientClean(self.context) - - def http_error_401(self, req, fp, code, msg, headers): - log.debug("inside http_error_401") - try: - neg_hdr = self.generate_request_header(req, headers) - - if neg_hdr is None: - log.debug("neg_hdr was None") - return None - - req.add_unredirected_header('Authorization', neg_hdr) - resp = self.parent.open(req) - - self.authenticate_server(resp.info()) - - return resp - - finally: - self.clean_context() - -def test(): - log.setLevel(logging.DEBUG) - log.info("starting test") - opener = u2.build_opener() - opener.add_handler(HTTPKerberosAuthHandler()) - resp = opener.open(sys.argv[1]) - print dir(resp), resp.info(), resp.code - - -if __name__ == '__main__': - test() - diff --git a/urllib2_kerberos.py b/urllib2_kerberos.py index 84542bd..bf08042 100644 --- a/urllib2_kerberos.py +++ b/urllib2_kerberos.py @@ -1,21 +1,20 @@ #!/usr/bin/python # urllib2 with kerberos proof of concept - -# Copyright 2008 Lime Nest LLC # Copyright 2008 Lime Spot LLC -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. -# http://www.apache.org/licenses/LICENSE-2.0 +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. import re import logging @@ -24,7 +23,6 @@ import urllib2 as u2 import kerberos as k - def getLogger(): log = logging.getLogger("http_kerberos_auth_handler") handler = logging.StreamHandler() @@ -34,30 +32,26 @@ def getLogger(): return log log = getLogger() -log.setLevel(logging.DEBUG) - -class AbstractKerberosAuthHandler: - """auth handler for urllib2 that does Kerberos HTTP Negotiate - Authentication +class HTTPKerberosAuthHandler(u2.BaseHandler): + """auth handler for urllib2 that does Kerberos HTTP Negotiate Authentication """ + rx = re.compile('(?:.*,)*\s*Negotiate\s*([^,]*),?', re.I) + handler_order = 480 # before Digest auth + def negotiate_value(self, headers): - """checks for "Negotiate" in proper auth header - """ - authreq = headers.get(self.auth_header, None) - log.debug('authreq = {}'.format(authreq)) + authreq = headers.get('www-authenticate', None) if authreq: - rx = re.compile(r'(?:.*,)*\s*Negotiate\s*([^,]*),?', re.I) - mo = rx.search(authreq) + mo = HTTPKerberosAuthHandler.rx.search(authreq) if mo: return mo.group(1) else: log.debug("regex failed on: %s" % authreq) else: - log.debug("%s header not found" % self.auth_header) + log.debug("www-authenticate header not found") return None @@ -65,16 +59,20 @@ class AbstractKerberosAuthHandler: self.retried = 0 self.context = None - def generate_request_header(self, req, headers, neg_value): - self.retried += 1 - log.debug("retry count: %d" % self.retried) + def generate_request_header(self, req, headers): + neg_value = self.negotiate_value(headers) + if neg_value is None: + self.retried = 0 + return None - host = req.get_host() - log.debug("req.get_host() returned %s" % host) + if self.retried > 5: + raise HTTPError(req.get_full_url(), 401, "kerberos negotiate auth failed", + headers, None) - domain = host.rsplit(':', 1)[0] + self.retried += 1 - result, self.context = k.authGSSClientInit("HTTP@%s" % domain) + log.debug("req.get_host() returned %s" % req.get_host()) + result, self.context = k.authGSSClientInit("HTTP@%s" % req.get_host()) if result < 1: log.warning("authGSSClientInit returned result %d" % result) @@ -92,7 +90,7 @@ class AbstractKerberosAuthHandler: response = k.authGSSClientResponse(self.context) log.debug("authGSSClientResponse() succeeded") - + return "Negotiate %s" % response def authenticate_server(self, headers): @@ -101,90 +99,31 @@ class AbstractKerberosAuthHandler: log.critical("mutual auth failed. No negotiate header") return None - result = k.authGSSClientStep(self.context, neg_value) - - if result < 1: - # this is a critical security warning - # should change to a raise --Tim - log.critical( - "mutual auth failed: authGSSClientStep returned result %d" % - result) + if k.authGSSClientStep(self.context, neg_value) < 1: + log.critical("mutual auth failed: authGSSClientStep returned result %d" % result) def clean_context(self): if self.context is not None: - log.debug("cleaning context") k.authGSSClientClean(self.context) - self.context = None - - def http_error_auth_reqed(self, host, req, headers): - neg_value = self.negotiate_value(headers) # Check for auth_header - if neg_value is not None: - if not self.retried > 0: - return self.retry_http_kerberos_auth(req, headers, neg_value) - else: - return None - else: - self.retried = 0 - def retry_http_kerberos_auth(self, req, headers, neg_value): + def http_error_401(self, req, fp, code, msg, headers): + log.debug("inside http_error_401") try: - neg_hdr = self.generate_request_header(req, headers, neg_value) + neg_hdr = self.generate_request_header(req, headers) if neg_hdr is None: log.debug("neg_hdr was None") return None - req.add_unredirected_header(self.authz_header, neg_hdr) + req.add_unredirected_header('Authorization', neg_hdr) resp = self.parent.open(req) - if resp.getcode() != 200: - self.authenticate_server(resp.info()) + self.authenticate_server(resp.info()) return resp - - except k.GSSError, e: + + finally: self.clean_context() - self.retried = 0 - log.critical("GSSAPI Error: %s/%s" % (e[0][0], e[1][0])) - return None - - self.clean_context() - self.retried = 0 - - -class ProxyKerberosAuthHandler(u2.BaseHandler, AbstractKerberosAuthHandler): - """Kerberos Negotiation handler for HTTP proxy auth - """ - - authz_header = 'Proxy-Authorization' - auth_header = 'proxy-authenticate' - - handler_order = 480 # before Digest auth - - def http_error_407(self, req, fp, code, msg, headers): - log.debug("inside http_error_407") - host = req.get_host() - retry = self.http_error_auth_reqed(host, req, headers) - self.retried = 0 - return retry - - -class HTTPKerberosAuthHandler(u2.BaseHandler, AbstractKerberosAuthHandler): - """Kerberos Negotiation handler for HTTP auth - """ - - authz_header = 'Authorization' - auth_header = 'www-authenticate' - - handler_order = 480 # before Digest auth - - def http_error_401(self, req, fp, code, msg, headers): - log.debug("inside http_error_401") - host = req.get_host() - retry = self.http_error_auth_reqed(host, req, headers) - self.retried = 0 - return retry - def test(): log.setLevel(logging.DEBUG) @@ -193,7 +132,7 @@ def test(): opener.add_handler(HTTPKerberosAuthHandler()) resp = opener.open(sys.argv[1]) print dir(resp), resp.info(), resp.code - + if __name__ == '__main__': test() |