Przeglądaj źródła

[core] Add urllib2_kerberos library

bc Wong 13 lat temu
rodzic
commit
baba718d41

+ 1 - 0
desktop/core/ext-py/urllib2_kerberos-0.1.6/MANIFEST.in

@@ -0,0 +1 @@
+include hgvers.py

+ 21 - 0
desktop/core/ext-py/urllib2_kerberos-0.1.6/PKG-INFO

@@ -0,0 +1,21 @@
+Metadata-Version: 1.0
+Name: urllib2_kerberos
+Version: 0.1.6
+Summary: Kerberos over HTTP Negotiate/SPNEGO support for urllib2
+Home-page: http://limedav.com/hg/urllib2_kerberos/
+Author: Tim Olsen
+Author-email: tolsen@limespot.com
+License: Apache 2.0
+Description: UNKNOWN
+Keywords: urllib2 kerberos http negotiate spnego
+Platform: UNKNOWN
+Classifier: Development Status :: 3 - Alpha
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Natural Language :: English
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python
+Classifier: Topic :: Internet :: WWW/HTTP
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: System :: Systems Administration :: Authentication/Directory

+ 47 - 0
desktop/core/ext-py/urllib2_kerberos-0.1.6/hgvers.py

@@ -0,0 +1,47 @@
+# Copyright 2008 Lime Nest 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
+
+#     http://www.apache.org/licenses/LICENSE-2.0
+
+# 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.
+
+import re
+
+repo = None
+version = None
+
+try:
+    import hgversion as hgv
+
+except ImportError:
+    # either we couldn't find hgversion or
+    # hgversion couldn't find mercurial libraries
+    pass
+else:
+    repo = hgv.repository # could be None if we're not in an hg repository
+
+if repo is None:
+
+    try:
+        f = open('PKG-INFO')
+    except IOError:
+        pass
+    else:
+        regex = re.compile('^Version:\s+(\S+)')
+        for line in f:
+            mo = regex.match(line)
+            if mo is not None:
+                version = mo.group(1)
+                break
+else:
+    version = hgv.version()
+
+if __name__ == '__main__':
+    print version

+ 5 - 0
desktop/core/ext-py/urllib2_kerberos-0.1.6/setup.cfg

@@ -0,0 +1,5 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+

+ 47 - 0
desktop/core/ext-py/urllib2_kerberos-0.1.6/setup.py

@@ -0,0 +1,47 @@
+# 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
+
+#     http://www.apache.org/licenses/LICENSE-2.0
+
+# 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.
+
+from setuptools import setup
+import hgvers
+
+setup(
+    name = "urllib2_kerberos",
+    version = hgvers.version,
+    py_modules = [ 'urllib2_kerberos' ],
+
+#    install_requires = ['kerberos'],
+
+    author = "Tim Olsen",
+    author_email = "tolsen@limespot.com",
+    description = "Kerberos over HTTP Negotiate/SPNEGO support for urllib2",
+    license = "Apache 2.0",
+    url = "http://limedav.com/hg/urllib2_kerberos/",
+    keywords = "urllib2 kerberos http negotiate spnego",
+    
+    classifiers = [
+        'Development Status :: 3 - Alpha',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: Apache Software License',
+        'Natural Language :: English',
+        'Operating System :: POSIX :: Linux',
+        'Programming Language :: Python',
+        'Topic :: Internet :: WWW/HTTP',
+        'Topic :: Software Development :: Libraries',
+        'Topic :: Software Development :: Libraries :: Python Modules',
+        'Topic :: System :: Systems Administration :: Authentication/Directory'
+        ]
+    
+    )
+

+ 190 - 0
desktop/core/ext-py/urllib2_kerberos-0.1.6/urllib2_kerberos.py

@@ -0,0 +1,190 @@
+#!/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
+
+#     http://www.apache.org/licenses/LICENSE-2.0
+
+# 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.
+
+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 AbstractKerberosAuthHandler:
+    """auth handler for urllib2 that does Kerberos HTTP Negotiate Authentication
+    """
+
+    def negotiate_value(self, headers):
+        """checks for "Negotiate" in proper auth header
+        """
+        authreq = headers.get(self.auth_header, None)
+
+        if authreq:
+            rx = re.compile('(?:.*,)*\s*Negotiate\s*([^,]*),?', re.I)
+            mo = 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)
+
+        return None
+
+    def __init__(self):
+        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)
+
+        host = req.get_host()
+        log.debug("req.get_host() returned %s" % host)
+
+        tail, sep, head = host.rpartition(':')
+        domain = tail if tail else head
+                
+        result, self.context = k.authGSSClientInit("HTTP@%s" % domain)
+
+        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
+
+        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)
+            pass
+
+    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):
+        try:
+            neg_hdr = self.generate_request_header(req, headers, neg_value)
+
+            if neg_hdr is None:
+                log.debug("neg_hdr was None")
+                return None
+
+            req.add_unredirected_header(self.authz_header, neg_hdr)
+            resp = self.parent.open(req)
+
+            self.authenticate_server(resp.info())
+
+            return resp
+
+        except k.GSSError, e:
+            log.critical("GSSAPI Error: %s/%s" % (e[0][0], e[1][0]))
+            return None
+
+        finally:
+            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)
+    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()
+

+ 1 - 0
ext/thirdparty/README.md

@@ -46,6 +46,7 @@ Checked-in third party dependencies
 |Y|threadframe|0.2|Python|http://www.majid.info/mylos/stories/2004/06/10/threadframe.html|
 |Y|threadframe|0.2|Python|http://www.majid.info/mylos/stories/2004/06/10/threadframe.html|
 |Y|Thrift|?|Apache|http://incubator.apache.org/thrift/download/|
 |Y|Thrift|?|Apache|http://incubator.apache.org/thrift/download/|
 |Y|Twisted|8.2.0|MIT|http://twistedmatrix.com/trac/|
 |Y|Twisted|8.2.0|MIT|http://twistedmatrix.com/trac/|
+|Y|urllib2_kerberos|0.1.6|ASL2|http://pypi.python.org/pypi/urllib2_kerberos|
 |Y|Werkzeug|0.5.1|BSD|http://pypi.python.org/packages/source/W/Werkzeug/Werkzeug-0.5.1.zip|
 |Y|Werkzeug|0.5.1|BSD|http://pypi.python.org/packages/source/W/Werkzeug/Werkzeug-0.5.1.zip|
 |Y|zope.interface|3.5.2|ZPL(MIT-like)|http://pypi.python.org/pypi/zope.interface|
 |Y|zope.interface|3.5.2|ZPL(MIT-like)|http://pypi.python.org/pypi/zope.interface|
 |Y|MySQL for Python|1.2.3c1|GPL or the original license based on Python 1.5.2|http://sourceforge.net/projects/mysql-python/|
 |Y|MySQL for Python|1.2.3c1|GPL or the original license based on Python 1.5.2|http://sourceforge.net/projects/mysql-python/|