Skip to content
Browse files

added 243 files; modified README.md

  • Loading branch information...
1 parent 6477aea commit 012c43e6a73062553df2e5a7c4f3116430b92746 Peter Bengtsson committed
Showing with 13,373 additions and 1 deletion.
  1. +4 −0 .gitignore
  2. +9 −1 README.md
  3. +59 −0 analyze-results.py
  4. +23 −0 reverse-geocode-branch/.svn/all-wcprops
  5. +145 −0 reverse-geocode-branch/.svn/entries
  6. +1 −0 reverse-geocode-branch/.svn/format
  7. +19 −0 reverse-geocode-branch/.svn/text-base/LICENSE.svn-base
  8. +3 −0 reverse-geocode-branch/.svn/text-base/setup.cfg.svn-base
  9. +22 −0 reverse-geocode-branch/.svn/text-base/setup.py.svn-base
  10. +19 −0 reverse-geocode-branch/LICENSE
  11. +119 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/PKG-INFO
  12. +232 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/SOURCES.txt
  13. +1 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/dependency_links.txt
  14. +46 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/entry_points.txt
  15. +1 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/namespace_packages.txt
  16. +1 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/not-zip-safe
  17. +15 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/requires.txt
  18. +1 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/top_level.txt
  19. +17 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/__init__.py
  20. +9 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/__init__.py
  21. +352 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/auth_tkt.py
  22. +122 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/basic.py
  23. +99 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/cas.py
  24. +395 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/cookie.py
  25. +213 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/digest.py
  26. +149 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/form.py
  27. +113 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/grantip.py
  28. +79 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/multi.py
  29. +412 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/open_id.py
  30. +133 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/cascade.py
  31. +271 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/cgiapp.py
  32. +116 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/cgitb_catcher.py
  33. +120 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/config.py
  34. +5 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/debug/__init__.py
  35. +79 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/debug/debugapp.py
  36. +435 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/debug/doctest_webapp.py
  37. +409 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/debug/fsdiff.py
  38. +148 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/debug/prints.py
  39. +227 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/debug/profile.py
  40. +93 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/debug/testserver.py
  41. +347 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/debug/watchthreads.py
  42. +117 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/debug/wdg_validate.py
  43. +372 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/errordocument.py
  44. +7 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/evalexception/__init__.py
  45. +68 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/evalexception/evalcontext.py
  46. +161 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/evalexception/media/debug.js
  47. BIN reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/evalexception/media/minus.jpg
  48. BIN reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/evalexception/media/plus.jpg
  49. +611 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/evalexception/middleware.py
  50. +4,802 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/evalexception/mochikit/MochiKit.js
  51. +2 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/evalexception/mochikit/__package__.js
  52. +6 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/exceptions/__init__.py
  53. +526 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/exceptions/collector.py
  54. +460 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/exceptions/errormiddleware.py
  55. +564 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/exceptions/formatter.py
  56. +142 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/exceptions/reporter.py
  57. +123 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/exceptions/serial_number_generator.py
  58. +349 −0 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/fileapp.py
Sorry, we could not display the entire diff because it was too big.
View
4 .gitignore
@@ -0,0 +1,4 @@
+.venv
+*.pickle
+*~
+*.pyc
View
10 README.md
@@ -9,4 +9,12 @@ to access GeoNames to get the place name and country name from a
lat/long coordinate.
[Read my blog entry about this](http://www.peterbe.com/plog/google-reverse-geocoding-vs.-geonames/)
-on [Peterbe.com](http://www.peterbe.com/)
+on [Peterbe.com](http://www.peterbe.com/)
+
+To test it you need to install geopy, the reverse-geocode branch:
+
+ svn checkout \
+ http://geopy.googlecode.com/svn/branches/reverse-geocode \
+ geopy
+
+
View
59 analyze-results.py
@@ -0,0 +1,59 @@
+import sys, os
+import cPickle
+pickle_file = sys.argv[1]
+assert os.path.isfile(pickle_file)
+
+results = cPickle.load(open(pickle_file,'rb'))
+
+from pprint import pprint
+all_apps = set()
+from collections import defaultdict
+coords = defaultdict(list)
+app_totals = defaultdict(float)
+app_totals_count = defaultdict(int)
+app_failures = defaultdict(int)
+for key, result in results.items():
+ app, coord = key.split('__')
+ all_apps.add(app)
+ app_totals[app] += result[1]
+ app_totals_count[app] += 1
+ if result[0] == "FAILED":
+ app_failures[app] += 1
+ else:
+ app_failures[app] += 0
+ this_result = (result[0], result[1], '\n'.join(result[2]))
+ if coord in coords:
+ coords[coord][app] = this_result
+ else:
+ coords[coord] = {app:this_result}
+
+all_apps = list(all_apps)
+all_apps.sort()
+coords = dict(coords)
+print "\t", "App".ljust(15)
+print "_"*70
+
+for coord, results in coords.items():
+ print coord.ljust(39), repr(results[all_apps[0]][2])
+ for app in all_apps:
+ print "\t",app.ljust(15),
+ data = results[app]
+ print str(data[1])[:7].ljust(15),
+ if len(data[0]) > 50:
+ print repr(data[0][:50])+'...'
+ else:
+ print repr(data[0][:50])
+ print
+
+
+
+
+print
+print "FAILURES:"
+for app, count in dict(app_failures).items():
+ print app.ljust(20), count
+
+print
+print "TOTALS:"
+for app, total in dict(app_totals).items():
+ print app.ljust(20), str(total).ljust(20), total/app_totals_count[app], "seconds/request"
View
23 reverse-geocode-branch/.svn/all-wcprops
@@ -0,0 +1,23 @@
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/84/branches/reverse-geocode
+END
+LICENSE
+K 25
+svn:wc:ra_dav:version-url
+V 49
+/svn/!svn/ver/76/branches/reverse-geocode/LICENSE
+END
+setup.py
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svn/!svn/ver/76/branches/reverse-geocode/setup.py
+END
+setup.cfg
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svn/!svn/ver/76/branches/reverse-geocode/setup.cfg
+END
View
145 reverse-geocode-branch/.svn/entries
@@ -0,0 +1,145 @@
+9
+
+dir
+84
+http://geopy.googlecode.com/svn/branches/reverse-geocode
+http://geopy.googlecode.com/svn
+
+
+
+2009-05-22T04:23:31.321467Z
+84
+david.ziegler
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+535ce8a4-231d-0410-ac7f-15f3cd728b52
+
+build
+dir
+
+tests
+dir
+
+LICENSE
+file
+
+
+
+
+2009-08-14T22:47:33.000000Z
+712a488b2729db0f55d992060875f18e
+2009-03-06T20:39:28.083675Z
+76
+david.ziegler
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1065
+
+dist
+dir
+
+geopy
+dir
+
+setup.py
+file
+
+
+
+
+2009-08-14T22:47:33.000000Z
+d4071bed0279fcf0e75f4b90a1068dbd
+2009-03-06T20:39:28.083675Z
+76
+david.ziegler
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+949
+
+geopy.egg-info
+dir
+
+setup.cfg
+file
+
+
+
+
+2009-08-14T22:47:33.000000Z
+ced32e2c28d3b229c8aad7c585425ccf
+2009-03-06T20:39:28.083675Z
+76
+david.ziegler
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+51
+
View
1 reverse-geocode-branch/.svn/format
@@ -0,0 +1 @@
+9
View
19 reverse-geocode-branch/.svn/text-base/LICENSE.svn-base
@@ -0,0 +1,19 @@
+Copyright (c) 2006 Brian Beck
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
View
3 reverse-geocode-branch/.svn/text-base/setup.cfg.svn-base
@@ -0,0 +1,3 @@
+[egg_info]
+tag_build = dev
+tag_svn_revision = true
View
22 reverse-geocode-branch/.svn/text-base/setup.py.svn-base
@@ -0,0 +1,22 @@
+from setuptools import setup, find_packages
+
+setup(name='geopy',
+ version='0.93',
+ description='Python Geocoding Toolbox',
+ author='Brian Beck',
+ author_email='exogen@gmail.com',
+ url='http://exogen.case.edu/projects/geopy/',
+ download_url='http://geopy.googlecode.com/svn/trunk/',
+ packages=find_packages(),
+ license='MIT',
+ keywords='geocode geocoding gis geographical maps earth distance',
+ classifiers=["Development Status :: 3 - Alpha",
+ "Intended Audience :: Developers",
+ "Intended Audience :: Science/Research",
+ "License :: OSI Approved :: MIT License",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python",
+ "Topic :: Scientific/Engineering :: GIS",
+ "Topic :: Software Development :: Libraries :: Python Modules"
+ ],
+ )
View
19 reverse-geocode-branch/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2006 Brian Beck
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
View
119 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/PKG-INFO
@@ -0,0 +1,119 @@
+Metadata-Version: 1.0
+Name: Paste
+Version: 1.7.2
+Summary: Tools for using a Web Server Gateway Interface stack
+Home-page: http://pythonpaste.org
+Author: Ian Bicking
+Author-email: ianb@colorstudy.com
+License: MIT
+Description: These provide several pieces of "middleware" (or filters) that can be nested to build web applications. Each
+ piece of middleware uses the WSGI (`PEP 333`_) interface, and should
+ be compatible with other middleware based on those interfaces.
+
+ .. _PEP 333: http://www.python.org/peps/pep-0333.html
+
+ Includes these features...
+
+ Testing
+ -------
+
+ * A fixture for testing WSGI applications conveniently and in-process,
+ in ``paste.fixture``
+
+ * A fixture for testing command-line applications, also in
+ ``paste.fixture``
+
+ * Check components for WSGI-compliance in ``paste.lint``
+
+ Dispatching
+ -----------
+
+ * Chain and cascade WSGI applications (returning the first non-error
+ response) in ``paste.cascade``
+
+ * Dispatch to several WSGI applications based on URL prefixes, in
+ ``paste.urlmap``
+
+ * Allow applications to make subrequests and forward requests
+ internally, in ``paste.recursive``
+
+ Web Application
+ ---------------
+
+ * Run CGI programs as WSGI applications in ``paste.cgiapp``
+
+ * Traverse files and load WSGI applications from ``.py`` files (or
+ static files), in ``paste.urlparser``
+
+ * Serve static directories of files, also in ``paste.urlparser``; also
+ in that module serving from Egg resources using ``pkg_resources``.
+
+ Tools
+ -----
+
+ * Catch HTTP-related exceptions (e.g., ``HTTPNotFound``) and turn them
+ into proper responses in ``paste.httpexceptions``
+
+ * Several authentication techniques, including HTTP (Basic and
+ Digest), signed cookies, and CAS single-signon, in the
+ ``paste.auth`` package.
+
+ * Create sessions in ``paste.session`` and ``paste.flup_session``
+
+ * Gzip responses in ``paste.gzip``
+
+ * A wide variety of routines for manipulating WSGI requests and
+ producing responses, in ``paste.request``, ``paste.response`` and
+ ``paste.wsgilib``
+
+ Debugging Filters
+ -----------------
+
+ * Catch (optionally email) errors with extended tracebacks (using
+ Zope/ZPT conventions) in ``paste.exceptions``
+
+ * Catch errors presenting a `cgitb
+ <http://python.org/doc/current/lib/module-cgitb.html>`_-based
+ output, in ``paste.cgitb_catcher``.
+
+ * Profile each request and append profiling information to the HTML,
+ in ``paste.debug.profile``
+
+ * Capture ``print`` output and present it in the browser for
+ debugging, in ``paste.debug.prints``
+
+ * Validate all HTML output from applications using the `WDG Validator
+ <http://www.htmlhelp.com/tools/validator/>`_, appending any errors
+ or warnings to the page, in ``paste.debug.wdg_validator``
+
+ Other Tools
+ -----------
+
+ * A file monitor to allow restarting the server when files have been
+ updated (for automatic restarting when editing code) in
+ ``paste.reloader``
+
+ * A class for generating and traversing URLs, and creating associated
+ HTML code, in ``paste.url``
+
+ The latest version is available in a `Subversion repository
+ <http://svn.pythonpaste.org/Paste/trunk#egg=Paste-dev>`_.
+
+ For the latest changes see the `news file
+ <http://pythonpaste.org/news.html>`_.
+
+
+Keywords: web application server wsgi
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python
+Classifier: Topic :: Internet :: WWW/HTTP
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server
+Classifier: Framework :: Paste
View
232 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/SOURCES.txt
@@ -0,0 +1,232 @@
+regen-docs
+setup.cfg
+setup.py
+Paste.egg-info/PKG-INFO
+Paste.egg-info/SOURCES.txt
+Paste.egg-info/dependency_links.txt
+Paste.egg-info/entry_points.txt
+Paste.egg-info/namespace_packages.txt
+Paste.egg-info/not-zip-safe
+Paste.egg-info/requires.txt
+Paste.egg-info/top_level.txt
+docs/DeveloperGuidelines.txt
+docs/StyleGuide.txt
+docs/conf.py
+docs/default.css
+docs/developer-features.txt
+docs/do-it-yourself-framework.txt
+docs/future.txt
+docs/index.txt
+docs/license.txt
+docs/news.txt
+docs/paste-httpserver-threadpool.txt
+docs/test_server.ini
+docs/testing-applications.txt
+docs/url-parsing-with-wsgi.txt
+docs/_static/paste.css
+docs/_templates/layout.html
+docs/community/index.txt
+docs/community/mailing-list.txt
+docs/community/repository.txt
+docs/download/index.txt
+docs/include/contact.txt
+docs/include/reference_header.txt
+docs/modules/auth.auth_tkt.txt
+docs/modules/auth.basic.txt
+docs/modules/auth.cas.txt
+docs/modules/auth.cookie.txt
+docs/modules/auth.digest.txt
+docs/modules/auth.form.txt
+docs/modules/auth.grantip.txt
+docs/modules/auth.multi.txt
+docs/modules/auth.open_id.txt
+docs/modules/cascade.txt
+docs/modules/cgiapp.txt
+docs/modules/cgitb_catcher.txt
+docs/modules/debug.debugapp.txt
+docs/modules/debug.fsdiff.txt
+docs/modules/debug.prints.txt
+docs/modules/debug.profile.txt
+docs/modules/debug.watchthreads.txt
+docs/modules/debug.wdg_validate.txt
+docs/modules/errordocument.txt
+docs/modules/evalexception.txt
+docs/modules/exceptions.txt
+docs/modules/fileapp.txt
+docs/modules/fixture.txt
+docs/modules/gzipper.txt
+docs/modules/httpexceptions.txt
+docs/modules/httpheaders.txt
+docs/modules/httpserver.txt
+docs/modules/lint.txt
+docs/modules/pony.txt
+docs/modules/progress.txt
+docs/modules/proxy.txt
+docs/modules/recursive.txt
+docs/modules/registry.txt
+docs/modules/reloader.txt
+docs/modules/request.txt
+docs/modules/response.txt
+docs/modules/session.txt
+docs/modules/transaction.txt
+docs/modules/translogger.txt
+docs/modules/url.txt
+docs/modules/urlmap.txt
+docs/modules/urlparser.txt
+docs/modules/util.import_string.txt
+docs/modules/util.multidict.txt
+docs/modules/wsgilib.txt
+docs/modules/wsgiwrappers.txt
+docs/web/default-site.css
+docs/web/site.js
+docs/web/style.css
+paste/__init__.py
+paste/cascade.py
+paste/cgiapp.py
+paste/cgitb_catcher.py
+paste/config.py
+paste/errordocument.py
+paste/fileapp.py
+paste/fixture.py
+paste/flup_session.py
+paste/gzipper.py
+paste/httpexceptions.py
+paste/httpheaders.py
+paste/httpserver.py
+paste/lint.py
+paste/modpython.py
+paste/pony.py
+paste/progress.py
+paste/proxy.py
+paste/recursive.py
+paste/registry.py
+paste/reloader.py
+paste/request.py
+paste/response.py
+paste/session.py
+paste/transaction.py
+paste/translogger.py
+paste/url.py
+paste/urlmap.py
+paste/urlparser.py
+paste/wsgilib.py
+paste/wsgiwrappers.py
+paste/auth/__init__.py
+paste/auth/auth_tkt.py
+paste/auth/basic.py
+paste/auth/cas.py
+paste/auth/cookie.py
+paste/auth/digest.py
+paste/auth/form.py
+paste/auth/grantip.py
+paste/auth/multi.py
+paste/auth/open_id.py
+paste/debug/__init__.py
+paste/debug/debugapp.py
+paste/debug/doctest_webapp.py
+paste/debug/fsdiff.py
+paste/debug/prints.py
+paste/debug/profile.py
+paste/debug/testserver.py
+paste/debug/watchthreads.py
+paste/debug/wdg_validate.py
+paste/evalexception/__init__.py
+paste/evalexception/evalcontext.py
+paste/evalexception/middleware.py
+paste/evalexception/media/debug.js
+paste/evalexception/media/minus.jpg
+paste/evalexception/media/plus.jpg
+paste/evalexception/mochikit/MochiKit.js
+paste/evalexception/mochikit/__package__.js
+paste/exceptions/__init__.py
+paste/exceptions/collector.py
+paste/exceptions/errormiddleware.py
+paste/exceptions/formatter.py
+paste/exceptions/reporter.py
+paste/exceptions/serial_number_generator.py
+paste/util/PySourceColor.py
+paste/util/UserDict24.py
+paste/util/__init__.py
+paste/util/classinit.py
+paste/util/classinstance.py
+paste/util/converters.py
+paste/util/dateinterval.py
+paste/util/datetimeutil.py
+paste/util/doctest24.py
+paste/util/filemixin.py
+paste/util/finddata.py
+paste/util/findpackage.py
+paste/util/import_string.py
+paste/util/intset.py
+paste/util/ip4.py
+paste/util/killthread.py
+paste/util/looper.py
+paste/util/mimeparse.py
+paste/util/multidict.py
+paste/util/quoting.py
+paste/util/scgiserver.py
+paste/util/string24.py
+paste/util/subprocess24.py
+paste/util/template.py
+paste/util/threadedprint.py
+paste/util/threadinglocal.py
+tests/conftest.py
+tests/test_cgiapp.py
+tests/test_cgitb_catcher.py
+tests/test_config.py
+tests/test_doctests.py
+tests/test_errordocument.py
+tests/test_fileapp.py
+tests/test_fixture.py
+tests/test_grantip.py
+tests/test_gzipper.py
+tests/test_httpheaders.py
+tests/test_import_string.py
+tests/test_multidict.py
+tests/test_profilemiddleware.py
+tests/test_proxy.py
+tests/test_recursive.py
+tests/test_registry.py
+tests/test_request.py
+tests/test_request_form.py
+tests/test_response.py
+tests/test_session.py
+tests/test_template.txt
+tests/test_urlmap.py
+tests/test_urlparser.py
+tests/test_wsgiwrappers.py
+tests/cgiapp_data/error.cgi
+tests/cgiapp_data/form.cgi
+tests/cgiapp_data/ok.cgi
+tests/cgiapp_data/stderr.cgi
+tests/test_auth/test_auth_cookie.py
+tests/test_auth/test_auth_digest.py
+tests/test_exceptions/__init__.py
+tests/test_exceptions/test_error_middleware.py
+tests/test_exceptions/test_formatter.py
+tests/test_exceptions/test_httpexceptions.py
+tests/test_exceptions/test_reporter.py
+tests/test_util/test_datetimeutil.py
+tests/urlparser_data/__init__.py
+tests/urlparser_data/secured.txt
+tests/urlparser_data/deep/index.html
+tests/urlparser_data/deep/sub/Main.txt
+tests/urlparser_data/find_file/index.txt
+tests/urlparser_data/find_file/test 3.html
+tests/urlparser_data/find_file/test2.html
+tests/urlparser_data/find_file/dir with spaces/test 4.html
+tests/urlparser_data/hook/__init__.py
+tests/urlparser_data/hook/app.py
+tests/urlparser_data/hook/index.py
+tests/urlparser_data/not_found/__init__.py
+tests/urlparser_data/not_found/recur/__init__.py
+tests/urlparser_data/not_found/recur/isfound.txt
+tests/urlparser_data/not_found/simple/__init__.py
+tests/urlparser_data/not_found/simple/found.txt
+tests/urlparser_data/not_found/user/__init__.py
+tests/urlparser_data/not_found/user/list.py
+tests/urlparser_data/python/__init__.py
+tests/urlparser_data/python/simpleapp.py
+tests/urlparser_data/python/stream.py
+tests/urlparser_data/python/sub/__init__.py
+tests/urlparser_data/python/sub/simpleapp.py
View
1 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/dependency_links.txt
@@ -0,0 +1 @@
+
View
46 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/entry_points.txt
@@ -0,0 +1,46 @@
+
+ [paste.app_factory]
+ cgi = paste.cgiapp:make_cgi_application [subprocess]
+ static = paste.urlparser:make_static
+ pkg_resources = paste.urlparser:make_pkg_resources
+ urlparser = paste.urlparser:make_url_parser
+ proxy = paste.proxy:make_proxy
+ test = paste.debug.debugapp:make_test_app
+ test_slow = paste.debug.debugapp:make_slow_app
+ transparent_proxy = paste.proxy:make_transparent_proxy
+ watch_threads = paste.debug.watchthreads:make_watch_threads
+
+ [paste.composite_factory]
+ urlmap = paste.urlmap:urlmap_factory
+ cascade = paste.cascade:make_cascade
+
+ [paste.filter_app_factory]
+ error_catcher = paste.exceptions.errormiddleware:make_error_middleware
+ cgitb = paste.cgitb_catcher:make_cgitb_middleware
+ flup_session = paste.flup_session:make_session_middleware [Flup]
+ gzip = paste.gzipper:make_gzip_middleware
+ httpexceptions = paste.httpexceptions:make_middleware
+ lint = paste.lint:make_middleware
+ printdebug = paste.debug.prints:PrintDebugMiddleware
+ profile = paste.debug.profile:make_profile_middleware [hotshot]
+ recursive = paste.recursive:make_recursive_middleware
+ # This isn't good enough to deserve the name egg:Paste#session:
+ paste_session = paste.session:make_session_middleware
+ wdg_validate = paste.debug.wdg_validate:make_wdg_validate_middleware [subprocess]
+ evalerror = paste.evalexception.middleware:make_eval_exception
+ auth_tkt = paste.auth.auth_tkt:make_auth_tkt_middleware
+ auth_basic = paste.auth.basic:make_basic
+ auth_digest = paste.auth.digest:make_digest
+ auth_form = paste.auth.form:make_form
+ grantip = paste.auth.grantip:make_grantip
+ openid = paste.auth.open_id:make_open_id_middleware [openid]
+ pony = paste.pony:make_pony
+ errordocument = paste.errordocument:make_errordocument
+ auth_cookie = paste.auth.cookie:make_auth_cookie
+ translogger = paste.translogger:make_filter
+ config = paste.config:make_config_filter
+ registry = paste.registry:make_registry_manager
+
+ [paste.server_runner]
+ http = paste.httpserver:server_runner
+
View
1 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/namespace_packages.txt
@@ -0,0 +1 @@
+paste
View
1 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/not-zip-safe
@@ -0,0 +1 @@
+
View
15 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/requires.txt
@@ -0,0 +1,15 @@
+
+
+[Flup]
+flup
+
+[openid]
+python-openid
+
+[Paste]
+
+
+[hotshot]
+
+
+[subprocess]
View
1 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/EGG-INFO/top_level.txt
@@ -0,0 +1 @@
+paste
View
17 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/__init__.py
@@ -0,0 +1,17 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ # don't prevent use of paste if pkg_resources isn't installed
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
+
+try:
+ import modulefinder
+except ImportError:
+ pass
+else:
+ for p in __path__:
+ modulefinder.AddPackagePath(__name__, p)
View
9 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/__init__.py
@@ -0,0 +1,9 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Package for authentication/identification of requests.
+
+The objective of this package is to provide single-focused middleware
+components that implement a particular specification. Integration of
+the components into a usable system is up to a higher-level framework.
+"""
View
352 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/auth_tkt.py
@@ -0,0 +1,352 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+##########################################################################
+#
+# Copyright (c) 2005 Imaginary Landscape LLC and Contributors.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+##########################################################################
+"""
+Implementation of cookie signing as done in `mod_auth_tkt
+<http://www.openfusion.com.au/labs/mod_auth_tkt/>`_.
+
+mod_auth_tkt is an Apache module that looks for these signed cookies
+and sets ``REMOTE_USER``, ``REMOTE_USER_TOKENS`` (a comma-separated
+list of groups) and ``REMOTE_USER_DATA`` (arbitrary string data).
+
+This module is an alternative to the ``paste.auth.cookie`` module;
+it's primary benefit is compatibility with mod_auth_tkt, which in turn
+makes it possible to use the same authentication process with
+non-Python code run under Apache.
+"""
+
+import time as time_mod
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+import Cookie
+from paste import request
+
+class AuthTicket(object):
+
+ """
+ This class represents an authentication token. You must pass in
+ the shared secret, the userid, and the IP address. Optionally you
+ can include tokens (a list of strings, representing role names),
+ 'user_data', which is arbitrary data available for your own use in
+ later scripts. Lastly, you can override the cookie name and
+ timestamp.
+
+ Once you provide all the arguments, use .cookie_value() to
+ generate the appropriate authentication ticket. .cookie()
+ generates a Cookie object, the str() of which is the complete
+ cookie header to be sent.
+
+ CGI usage::
+
+ token = auth_tkt.AuthTick('sharedsecret', 'username',
+ os.environ['REMOTE_ADDR'], tokens=['admin'])
+ print 'Status: 200 OK'
+ print 'Content-type: text/html'
+ print token.cookie()
+ print
+ ... redirect HTML ...
+
+ Webware usage::
+
+ token = auth_tkt.AuthTick('sharedsecret', 'username',
+ self.request().environ()['REMOTE_ADDR'], tokens=['admin'])
+ self.response().setCookie('auth_tkt', token.cookie_value())
+
+ Be careful not to do an HTTP redirect after login; use meta
+ refresh or Javascript -- some browsers have bugs where cookies
+ aren't saved when set on a redirect.
+ """
+
+ def __init__(self, secret, userid, ip, tokens=(), user_data='',
+ time=None, cookie_name='auth_tkt',
+ secure=False):
+ self.secret = secret
+ self.userid = userid
+ self.ip = ip
+ self.tokens = ','.join(tokens)
+ self.user_data = user_data
+ if time is None:
+ self.time = time_mod.time()
+ else:
+ self.time = time
+ self.cookie_name = cookie_name
+ self.secure = secure
+
+ def digest(self):
+ return calculate_digest(
+ self.ip, self.time, self.secret, self.userid, self.tokens,
+ self.user_data)
+
+ def cookie_value(self):
+ v = '%s%08x%s!' % (self.digest(), int(self.time), self.userid)
+ if self.tokens:
+ v += self.tokens + '!'
+ v += self.user_data
+ return v
+
+ def cookie(self):
+ c = Cookie.SimpleCookie()
+ c[self.cookie_name] = self.cookie_value().encode('base64').strip().replace('\n', '')
+ c[self.cookie_name]['path'] = '/'
+ if self.secure:
+ c[self.cookie_name]['secure'] = 'true'
+ return c
+
+class BadTicket(Exception):
+ """
+ Exception raised when a ticket can't be parsed. If we get
+ far enough to determine what the expected digest should have
+ been, expected is set. This should not be shown by default,
+ but can be useful for debugging.
+ """
+ def __init__(self, msg, expected=None):
+ self.expected = expected
+ Exception.__init__(self, msg)
+
+def parse_ticket(secret, ticket, ip):
+ """
+ Parse the ticket, returning (timestamp, userid, tokens, user_data).
+
+ If the ticket cannot be parsed, ``BadTicket`` will be raised with
+ an explanation.
+ """
+ ticket = ticket.strip('"')
+ digest = ticket[:32]
+ try:
+ timestamp = int(ticket[32:40], 16)
+ except ValueError, e:
+ raise BadTicket('Timestamp is not a hex integer: %s' % e)
+ try:
+ userid, data = ticket[40:].split('!', 1)
+ except ValueError:
+ raise BadTicket('userid is not followed by !')
+ if '!' in data:
+ tokens, user_data = data.split('!', 1)
+ else:
+ # @@: Is this the right order?
+ tokens = ''
+ user_data = data
+
+ expected = calculate_digest(ip, timestamp, secret,
+ userid, tokens, user_data)
+
+ if expected != digest:
+ raise BadTicket('Digest signature is not correct',
+ expected=(expected, digest))
+
+ tokens = tokens.split(',')
+
+ return (timestamp, userid, tokens, user_data)
+
+def calculate_digest(ip, timestamp, secret, userid, tokens, user_data):
+ secret = maybe_encode(secret)
+ userid = maybe_encode(userid)
+ tokens = maybe_encode(tokens)
+ user_data = maybe_encode(user_data)
+ digest0 = md5(
+ encode_ip_timestamp(ip, timestamp) + secret + userid + '\0'
+ + tokens + '\0' + user_data).hexdigest()
+ digest = md5(digest0 + secret).hexdigest()
+ return digest
+
+def encode_ip_timestamp(ip, timestamp):
+ ip_chars = ''.join(map(chr, map(int, ip.split('.'))))
+ t = int(timestamp)
+ ts = ((t & 0xff000000) >> 24,
+ (t & 0xff0000) >> 16,
+ (t & 0xff00) >> 8,
+ t & 0xff)
+ ts_chars = ''.join(map(chr, ts))
+ return ip_chars + ts_chars
+
+def maybe_encode(s, encoding='utf8'):
+ if isinstance(s, unicode):
+ s = s.encode(encoding)
+ return s
+
+class AuthTKTMiddleware(object):
+
+ """
+ Middleware that checks for signed cookies that match what
+ `mod_auth_tkt <http://www.openfusion.com.au/labs/mod_auth_tkt/>`_
+ looks for (if you have mod_auth_tkt installed, you don't need this
+ middleware, since Apache will set the environmental variables for
+ you).
+
+ Arguments:
+
+ ``secret``:
+ A secret that should be shared by any instances of this application.
+ If this app is served from more than one machine, they should all
+ have the same secret.
+
+ ``cookie_name``:
+ The name of the cookie to read and write from. Default ``auth_tkt``.
+
+ ``secure``:
+ If the cookie should be set as 'secure' (only sent over SSL) and if
+ the login must be over SSL.
+
+ ``include_ip``:
+ If the cookie should include the user's IP address. If so, then
+ if they change IPs their cookie will be invalid.
+
+ ``logout_path``:
+ The path under this middleware that should signify a logout. The
+ page will be shown as usual, but the user will also be logged out
+ when they visit this page.
+
+ If used with mod_auth_tkt, then these settings (except logout_path) should
+ match the analogous Apache configuration settings.
+
+ This also adds two functions to the request:
+
+ ``environ['paste.auth_tkt.set_user'](userid, tokens='', user_data='')``
+
+ This sets a cookie that logs the user in. ``tokens`` is a
+ string (comma-separated groups) or a list of strings.
+ ``user_data`` is a string for your own use.
+
+ ``environ['paste.auth_tkt.logout_user']()``
+
+ Logs out the user.
+ """
+
+ def __init__(self, app, secret, cookie_name='auth_tkt', secure=False,
+ include_ip=True, logout_path=None):
+ self.app = app
+ self.secret = secret
+ self.cookie_name = cookie_name
+ self.secure = secure
+ self.include_ip = include_ip
+ self.logout_path = logout_path
+
+ def __call__(self, environ, start_response):
+ cookies = request.get_cookies(environ)
+ if cookies.has_key(self.cookie_name):
+ cookie_value = cookies[self.cookie_name].value
+ else:
+ cookie_value = ''
+ if cookie_value:
+ if self.include_ip:
+ remote_addr = environ['REMOTE_ADDR']
+ else:
+ # mod_auth_tkt uses this dummy value when IP is not
+ # checked:
+ remote_addr = '0.0.0.0'
+ # @@: This should handle bad signatures better:
+ # Also, timeouts should cause cookie refresh
+ timestamp, userid, tokens, user_data = parse_ticket(
+ self.secret, cookie_value, remote_addr)
+ tokens = ','.join(tokens)
+ environ['REMOTE_USER'] = userid
+ if environ.get('REMOTE_USER_TOKENS'):
+ # We want to add tokens/roles to what's there:
+ tokens = environ['REMOTE_USER_TOKENS'] + ',' + tokens
+ environ['REMOTE_USER_TOKENS'] = tokens
+ environ['REMOTE_USER_DATA'] = user_data
+ environ['AUTH_TYPE'] = 'cookie'
+ set_cookies = []
+ def set_user(userid, tokens='', user_data=''):
+ set_cookies.extend(self.set_user_cookie(
+ environ, userid, tokens, user_data))
+ def logout_user():
+ set_cookies.extend(self.logout_user_cookie(environ))
+ environ['paste.auth_tkt.set_user'] = set_user
+ environ['paste.auth_tkt.logout_user'] = logout_user
+ if self.logout_path and environ.get('PATH_INFO') == self.logout_path:
+ logout_user()
+ def cookie_setting_start_response(status, headers, exc_info=None):
+ headers.extend(set_cookies)
+ return start_response(status, headers, exc_info)
+ return self.app(environ, cookie_setting_start_response)
+
+ def set_user_cookie(self, environ, userid, tokens, user_data):
+ if not isinstance(tokens, basestring):
+ tokens = ','.join(tokens)
+ if self.include_ip:
+ remote_addr = environ['REMOTE_ADDR']
+ else:
+ remote_addr = '0.0.0.0'
+ ticket = AuthTicket(
+ self.secret,
+ userid,
+ remote_addr,
+ tokens=tokens,
+ user_data=user_data,
+ cookie_name=self.cookie_name,
+ secure=self.secure)
+ # @@: Should we set REMOTE_USER etc in the current
+ # environment right now as well?
+ cur_domain = environ.get('HTTP_HOST', environ.get('SERVER_NAME'))
+ wild_domain = '.' + cur_domain
+ cookies = [
+ ('Set-Cookie', '%s=%s; Path=/' % (
+ self.cookie_name, ticket.cookie_value())),
+ ('Set-Cookie', '%s=%s; Path=/; Domain=%s' % (
+ self.cookie_name, ticket.cookie_value(), cur_domain)),
+ ('Set-Cookie', '%s=%s; Path=/; Domain=%s' % (
+ self.cookie_name, ticket.cookie_value(), wild_domain))
+ ]
+ return cookies
+
+ def logout_user_cookie(self, environ):
+ cur_domain = environ.get('HTTP_HOST', environ.get('SERVER_NAME'))
+ wild_domain = '.' + cur_domain
+ cookies = [
+ ('Set-Cookie', '%s=""; Path=/' % self.cookie_name),
+ ('Set-Cookie', '%s=""; Path=/; Domain=%s' %
+ (self.cookie_name, cur_domain)),
+ ('Set-Cookie', '%s=""; Path=/; Domain=%s' %
+ (self.cookie_name, wild_domain)),
+ ]
+ return cookies
+
+def make_auth_tkt_middleware(
+ app,
+ global_conf,
+ secret=None,
+ cookie_name='auth_tkt',
+ secure=False,
+ include_ip=True,
+ logout_path=None):
+ """
+ Creates the `AuthTKTMiddleware
+ <class-paste.auth.auth_tkt.AuthTKTMiddleware.html>`_.
+
+ ``secret`` is requird, but can be set globally or locally.
+ """
+ from paste.deploy.converters import asbool
+ secure = asbool(secure)
+ include_ip = asbool(include_ip)
+ if secret is None:
+ secret = global_conf.get('secret')
+ if not secret:
+ raise ValueError(
+ "You must provide a 'secret' (in global or local configuration)")
+ return AuthTKTMiddleware(
+ app, secret, cookie_name, secure, include_ip, logout_path or None)
View
122 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/basic.py
@@ -0,0 +1,122 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Basic HTTP/1.0 Authentication
+
+This module implements ``Basic`` authentication as described in
+HTTP/1.0 specification [1]_ . Do not use this module unless you
+are using SSL or need to work with very out-dated clients, instead
+use ``digest`` authentication.
+
+>>> from paste.wsgilib import dump_environ
+>>> from paste.httpserver import serve
+>>> # from paste.auth.basic import AuthBasicHandler
+>>> realm = 'Test Realm'
+>>> def authfunc(environ, username, password):
+... return username == password
+>>> serve(AuthBasicHandler(dump_environ, realm, authfunc))
+serving on...
+
+.. [1] http://www.w3.org/Protocols/HTTP/1.0/draft-ietf-http-spec.html#BasicAA
+"""
+from paste.httpexceptions import HTTPUnauthorized
+from paste.httpheaders import *
+
+class AuthBasicAuthenticator(object):
+ """
+ implements ``Basic`` authentication details
+ """
+ type = 'basic'
+ def __init__(self, realm, authfunc):
+ self.realm = realm
+ self.authfunc = authfunc
+
+ def build_authentication(self):
+ head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
+ return HTTPUnauthorized(headers=head)
+
+ def authenticate(self, environ):
+ authorization = AUTHORIZATION(environ)
+ if not authorization:
+ return self.build_authentication()
+ (authmeth, auth) = authorization.split(' ', 1)
+ if 'basic' != authmeth.lower():
+ return self.build_authentication()
+ auth = auth.strip().decode('base64')
+ username, password = auth.split(':', 1)
+ if self.authfunc(environ, username, password):
+ return username
+ return self.build_authentication()
+
+ __call__ = authenticate
+
+class AuthBasicHandler(object):
+ """
+ HTTP/1.0 ``Basic`` authentication middleware
+
+ Parameters:
+
+ ``application``
+
+ The application object is called only upon successful
+ authentication, and can assume ``environ['REMOTE_USER']``
+ is set. If the ``REMOTE_USER`` is already set, this
+ middleware is simply pass-through.
+
+ ``realm``
+
+ This is a identifier for the authority that is requesting
+ authorization. It is shown to the user and should be unique
+ within the domain it is being used.
+
+ ``authfunc``
+
+ This is a mandatory user-defined function which takes a
+ ``environ``, ``username`` and ``password`` for its first
+ three arguments. It should return ``True`` if the user is
+ authenticated.
+
+ """
+ def __init__(self, application, realm, authfunc):
+ self.application = application
+ self.authenticate = AuthBasicAuthenticator(realm, authfunc)
+
+ def __call__(self, environ, start_response):
+ username = REMOTE_USER(environ)
+ if not username:
+ result = self.authenticate(environ)
+ if isinstance(result, str):
+ AUTH_TYPE.update(environ, 'basic')
+ REMOTE_USER.update(environ, result)
+ else:
+ return result.wsgi_application(environ, start_response)
+ return self.application(environ, start_response)
+
+middleware = AuthBasicHandler
+
+__all__ = ['AuthBasicHandler']
+
+def make_basic(app, global_conf, realm, authfunc, **kw):
+ """
+ Grant access via basic authentication
+
+ Config looks like this::
+
+ [filter:grant]
+ use = egg:Paste#auth_basic
+ realm=myrealm
+ authfunc=somepackage.somemodule:somefunction
+
+ """
+ from paste.util.import_string import eval_import
+ import types
+ authfunc = eval_import(authfunc)
+ assert isinstance(authfunc, types.FunctionType), "authfunc must resolve to a function"
+ return AuthBasicHandler(app, realm, authfunc)
+
+
+if "__main__" == __name__:
+ import doctest
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
View
99 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/cas.py
@@ -0,0 +1,99 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+CAS 1.0 Authentication
+
+The Central Authentication System is a straight-forward single sign-on
+mechanism developed by Yale University's ITS department. It has since
+enjoyed widespread success and is deployed at many major universities
+and some corporations.
+
+ https://clearinghouse.ja-sig.org/wiki/display/CAS/Home
+ http://www.yale.edu/tp/auth/usingcasatyale.html
+
+This implementation has the goal of maintaining current path arguments
+passed to the system so that it can be used as middleware at any stage
+of processing. It has the secondary goal of allowing for other
+authentication methods to be used concurrently.
+"""
+import urllib
+from paste.request import construct_url
+from paste.httpexceptions import HTTPSeeOther, HTTPForbidden
+
+class CASLoginFailure(HTTPForbidden):
+ """ The exception raised if the authority returns 'no' """
+
+class CASAuthenticate(HTTPSeeOther):
+ """ The exception raised to authenticate the user """
+
+def AuthCASHandler(application, authority):
+ """
+ middleware to implement CAS 1.0 authentication
+
+ There are several possible outcomes:
+
+ 0. If the REMOTE_USER environment variable is already populated;
+ then this middleware is a no-op, and the request is passed along
+ to the application.
+
+ 1. If a query argument 'ticket' is found, then an attempt to
+ validate said ticket /w the authentication service done. If the
+ ticket is not validated; an 403 'Forbidden' exception is raised.
+ Otherwise, the REMOTE_USER variable is set with the NetID that
+ was validated and AUTH_TYPE is set to "cas".
+
+ 2. Otherwise, a 303 'See Other' is returned to the client directing
+ them to login using the CAS service. After logon, the service
+ will send them back to this same URL, only with a 'ticket' query
+ argument.
+
+ Parameters:
+
+ ``authority``
+
+ This is a fully-qualified URL to a CAS 1.0 service. The URL
+ should end with a '/' and have the 'login' and 'validate'
+ sub-paths as described in the CAS 1.0 documentation.
+
+ """
+ assert authority.endswith("/") and authority.startswith("http")
+ def cas_application(environ, start_response):
+ username = environ.get('REMOTE_USER','')
+ if username:
+ return application(environ, start_response)
+ qs = environ.get('QUERY_STRING','').split("&")
+ if qs and qs[-1].startswith("ticket="):
+ # assume a response from the authority
+ ticket = qs.pop().split("=", 1)[1]
+ environ['QUERY_STRING'] = "&".join(qs)
+ service = construct_url(environ)
+ args = urllib.urlencode(
+ {'service': service,'ticket': ticket})
+ requrl = authority + "validate?" + args
+ result = urllib.urlopen(requrl).read().split("\n")
+ if 'yes' == result[0]:
+ environ['REMOTE_USER'] = result[1]
+ environ['AUTH_TYPE'] = 'cas'
+ return application(environ, start_response)
+ exce = CASLoginFailure()
+ else:
+ service = construct_url(environ)
+ args = urllib.urlencode({'service': service})
+ location = authority + "login?" + args
+ exce = CASAuthenticate(location)
+ return exce.wsgi_application(environ, start_response)
+ return cas_application
+
+middleware = AuthCASHandler
+
+__all__ = ['CASLoginFailure', 'CASAuthenticate', 'AuthCASHandler' ]
+
+if '__main__' == __name__:
+ authority = "https://secure.its.yale.edu/cas/servlet/"
+ from paste.wsgilib import dump_environ
+ from paste.httpserver import serve
+ from paste.httpexceptions import *
+ serve(HTTPExceptionHandler(
+ AuthCASHandler(dump_environ, authority)))
View
395 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/cookie.py
@@ -0,0 +1,395 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Cookie "Saved" Authentication
+
+This authentication middleware saves the current REMOTE_USER,
+REMOTE_SESSION, and any other environment variables specified in a
+cookie so that it can be retrieved during the next request without
+requiring re-authentication. This uses a session cookie on the client
+side (so it goes away when the user closes their window) and does
+server-side expiration.
+
+Following is a very simple example where a form is presented asking for
+a user name (no actual checking), and dummy session identifier (perhaps
+corresponding to a database session id) is stored in the cookie.
+
+::
+
+ >>> from paste.httpserver import serve
+ >>> from paste.fileapp import DataApp
+ >>> from paste.httpexceptions import *
+ >>> from paste.auth.cookie import AuthCookieHandler
+ >>> from paste.wsgilib import parse_querystring
+ >>> def testapp(environ, start_response):
+ ... user = dict(parse_querystring(environ)).get('user','')
+ ... if user:
+ ... environ['REMOTE_USER'] = user
+ ... environ['REMOTE_SESSION'] = 'a-session-id'
+ ... if environ.get('REMOTE_USER'):
+ ... page = '<html><body>Welcome %s (%s)</body></html>'
+ ... page %= (environ['REMOTE_USER'], environ['REMOTE_SESSION'])
+ ... else:
+ ... page = ('<html><body><form><input name="user" />'
+ ... '<input type="submit" /></form></body></html>')
+ ... return DataApp(page, content_type="text/html")(
+ ... environ, start_response)
+ >>> serve(AuthCookieHandler(testapp))
+ serving on...
+
+"""
+
+import hmac, base64, random, time, warnings
+try:
+ from hashlib import sha1
+except ImportError:
+ # NOTE: We have to use the callable with hashlib (hashlib.sha1),
+ # otherwise hmac only accepts the sha module object itself
+ import sha as sha1
+from paste.request import get_cookies
+
+def make_time(value):
+ return time.strftime("%Y%m%d%H%M", time.gmtime(value))
+_signature_size = len(hmac.new('x', 'x', sha1).digest())
+_header_size = _signature_size + len(make_time(time.time()))
+
+# @@: Should this be using urllib.quote?
+# build encode/decode functions to safely pack away values
+_encode = [('\\', '\\x5c'), ('"', '\\x22'),
+ ('=', '\\x3d'), (';', '\\x3b')]
+_decode = [(v, k) for (k, v) in _encode]
+_decode.reverse()
+def encode(s, sublist = _encode):
+ return reduce((lambda a, (b, c): a.replace(b, c)), sublist, str(s))
+decode = lambda s: encode(s, _decode)
+
+class CookieTooLarge(RuntimeError):
+ def __init__(self, content, cookie):
+ RuntimeError.__init__("Signed cookie exceeds maximum size of 4096")
+ self.content = content
+ self.cookie = cookie
+
+_all_chars = ''.join([chr(x) for x in range(0, 255)])
+def new_secret():
+ """ returns a 64 byte secret """
+ return ''.join(random.sample(_all_chars, 64))
+
+class AuthCookieSigner(object):
+ """
+ save/restore ``environ`` entries via digially signed cookie
+
+ This class converts content into a timed and digitally signed
+ cookie, as well as having the facility to reverse this procedure.
+ If the cookie, after the content is encoded and signed exceeds the
+ maximum length (4096), then CookieTooLarge exception is raised.
+
+ The timeout of the cookie is handled on the server side for a few
+ reasons. First, if a 'Expires' directive is added to a cookie, then
+ the cookie becomes persistent (lasting even after the browser window
+ has closed). Second, the user's clock may be wrong (perhaps
+ intentionally). The timeout is specified in minutes; and expiration
+ date returned is rounded to one second.
+
+ Constructor Arguments:
+
+ ``secret``
+
+ This is a secret key if you want to syncronize your keys so
+ that the cookie will be good across a cluster of computers.
+ It is recommended via the HMAC specification (RFC 2104) that
+ the secret key be 64 bytes since this is the block size of
+ the hashing. If you do not provide a secret key, a random
+ one is generated each time you create the handler; this
+ should be sufficient for most cases.
+
+ ``timeout``
+
+ This is the time (in minutes) from which the cookie is set
+ to expire. Note that on each request a new (replacement)
+ cookie is sent, hence this is effectively a session timeout
+ parameter for your entire cluster. If you do not provide a
+ timeout, it is set at 30 minutes.
+
+ ``maxlen``
+
+ This is the maximum size of the *signed* cookie; hence the
+ actual content signed will be somewhat less. If the cookie
+ goes over this size, a ``CookieTooLarge`` exception is
+ raised so that unexpected handling of cookies on the client
+ side are avoided. By default this is set at 4k (4096 bytes),
+ which is the standard cookie size limit.
+
+ """
+ def __init__(self, secret = None, timeout = None, maxlen = None):
+ self.timeout = timeout or 30
+ if isinstance(timeout, basestring):
+ raise ValueError(
+ "Timeout must be a number (minutes), not a string (%r)"
+ % timeout)
+ self.maxlen = maxlen or 4096
+ self.secret = secret or new_secret()
+
+ def sign(self, content):
+ """
+ Sign the content returning a valid cookie (that does not
+ need to be escaped and quoted). The expiration of this
+ cookie is handled server-side in the auth() function.
+ """
+ cookie = base64.encodestring(
+ hmac.new(self.secret, content, sha1).digest() +
+ make_time(time.time() + 60*self.timeout) +
+ content)[:-1]
+ cookie = cookie.replace("/", "_").replace("=", "~")
+ if len(cookie) > self.maxlen:
+ raise CookieTooLarge(content, cookie)
+ return cookie
+
+ def auth(self, cookie):
+ """
+ Authenticate the cooke using the signature, verify that it
+ has not expired; and return the cookie's content
+ """
+ decode = base64.decodestring(
+ cookie.replace("_", "/").replace("~", "="))
+ signature = decode[:_signature_size]
+ expires = decode[_signature_size:_header_size]
+ content = decode[_header_size:]
+ if signature == hmac.new(self.secret, content, sha1).digest():
+ if int(expires) > int(make_time(time.time())):
+ return content
+ else:
+ # This is the normal case of an expired cookie; just
+ # don't bother doing anything here.
+ pass
+ else:
+ # This case can happen if the server is restarted with a
+ # different secret; or if the user's IP address changed
+ # due to a proxy. However, it could also be a break-in
+ # attempt -- so should it be reported?
+ pass
+
+class AuthCookieEnviron(list):
+ """
+ a list of environment keys to be saved via cookie
+
+ An instance of this object, found at ``environ['paste.auth.cookie']``
+ lists the `environ` keys that were restored from or will be added
+ to the digially signed cookie. This object can be accessed from an
+ `environ` variable by using this module's name.
+ """
+ def __init__(self, handler, scanlist):
+ list.__init__(self, scanlist)
+ self.handler = handler
+ def append(self, value):
+ if value in self:
+ return
+ list.append(self, str(value))
+
+class AuthCookieHandler(object):
+ """
+ the actual handler that should be put in your middleware stack
+
+ This middleware uses cookies to stash-away a previously authenticated
+ user (and perhaps other variables) so that re-authentication is not
+ needed. This does not implement sessions; and therefore N servers
+ can be syncronized to accept the same saved authentication if they
+ all use the same cookie_name and secret.
+
+ By default, this handler scans the `environ` for the REMOTE_USER
+ and REMOTE_SESSION key; if found, it is stored. It can be
+ configured to scan other `environ` keys as well -- but be careful
+ not to exceed 2-3k (so that the encoded and signed cookie does not
+ exceed 4k). You can ask it to handle other environment variables
+ by doing:
+
+ ``environ['paste.auth.cookie'].append('your.environ.variable')``
+
+
+ Constructor Arguments:
+
+ ``application``
+
+ This is the wrapped application which will have access to
+ the ``environ['REMOTE_USER']`` restored by this middleware.
+
+ ``cookie_name``
+
+ The name of the cookie used to store this content, by default
+ it is ``PASTE_AUTH_COOKIE``.
+
+ ``scanlist``
+
+ This is the initial set of ``environ`` keys to
+ save/restore to the signed cookie. By default is consists
+ only of ``REMOTE_USER`` and ``REMOTE_SESSION``; any tuple
+ or list of environment keys will work. However, be
+ careful, as the total saved size is limited to around 3k.
+
+ ``signer``
+
+ This is the signer object used to create the actual cookie
+ values, by default, it is ``AuthCookieSigner`` and is passed
+ the remaining arguments to this function: ``secret``,
+ ``timeout``, and ``maxlen``.
+
+ At this time, each cookie is individually signed. To store more
+ than the 4k of data; it is possible to sub-class this object to
+ provide different ``environ_name`` and ``cookie_name``
+ """
+ environ_name = 'paste.auth.cookie'
+ cookie_name = 'PASTE_AUTH_COOKIE'
+ signer_class = AuthCookieSigner
+ environ_class = AuthCookieEnviron
+
+ def __init__(self, application, cookie_name=None, scanlist=None,
+ signer=None, secret=None, timeout=None, maxlen=None):
+ if not signer:
+ signer = self.signer_class(secret, timeout, maxlen)
+ self.signer = signer
+ self.scanlist = scanlist or ('REMOTE_USER','REMOTE_SESSION')
+ self.application = application
+ self.cookie_name = cookie_name or self.cookie_name
+
+ def __call__(self, environ, start_response):
+ if self.environ_name in environ:
+ raise AssertionError("AuthCookie already installed!")
+ scanlist = self.environ_class(self, self.scanlist)
+ jar = get_cookies(environ)
+ if jar.has_key(self.cookie_name):
+ content = self.signer.auth(jar[self.cookie_name].value)
+ if content:
+ for pair in content.split(";"):
+ (k, v) = pair.split("=")
+ k = decode(k)
+ if k not in scanlist:
+ scanlist.append(k)
+ if k in environ:
+ continue
+ environ[k] = decode(v)
+ if 'REMOTE_USER' == k:
+ environ['AUTH_TYPE'] = 'cookie'
+ environ[self.environ_name] = scanlist
+ if "paste.httpexceptions" in environ:
+ warnings.warn("Since paste.httpexceptions is hooked in your "
+ "processing chain before paste.auth.cookie, if an "
+ "HTTPRedirection is raised, the cookies this module sets "
+ "will not be included in your response.\n")
+
+ def response_hook(status, response_headers, exc_info=None):
+ """
+ Scan the environment for keys specified in the scanlist,
+ pack up their values, signs the content and issues a cookie.
+ """
+ scanlist = environ.get(self.environ_name)
+ assert scanlist and isinstance(scanlist, self.environ_class)
+ content = []
+ for k in scanlist:
+ v = environ.get(k)
+ if v is not None:
+ if type(v) is not str:
+ raise ValueError(
+ "The value of the environmental variable %r "
+ "is not a str (only str is allowed; got %r)"
+ % (k, v))
+ content.append("%s=%s" % (encode(k), encode(v)))
+ if content:
+ content = ";".join(content)
+ content = self.signer.sign(content)
+ cookie = '%s=%s; Path=/;' % (self.cookie_name, content)
+ if 'https' == environ['wsgi.url_scheme']:
+ cookie += ' secure;'
+ response_headers.append(('Set-Cookie', cookie))
+ return start_response(status, response_headers, exc_info)
+ return self.application(environ, response_hook)
+
+middleware = AuthCookieHandler
+
+# Paste Deploy entry point:
+def make_auth_cookie(
+ app, global_conf,
+ # Should this get picked up from global_conf somehow?:
+ cookie_name='PASTE_AUTH_COOKIE',
+ scanlist=('REMOTE_USER', 'REMOTE_SESSION'),
+ # signer cannot be set
+ secret=None,
+ timeout=30,
+ maxlen=4096):
+ """
+ This middleware uses cookies to stash-away a previously
+ authenticated user (and perhaps other variables) so that
+ re-authentication is not needed. This does not implement
+ sessions; and therefore N servers can be syncronized to accept the
+ same saved authentication if they all use the same cookie_name and
+ secret.
+
+ By default, this handler scans the `environ` for the REMOTE_USER
+ and REMOTE_SESSION key; if found, it is stored. It can be
+ configured to scan other `environ` keys as well -- but be careful
+ not to exceed 2-3k (so that the encoded and signed cookie does not
+ exceed 4k). You can ask it to handle other environment variables
+ by doing:
+
+ ``environ['paste.auth.cookie'].append('your.environ.variable')``
+
+ Configuration:
+
+ ``cookie_name``
+
+ The name of the cookie used to store this content, by
+ default it is ``PASTE_AUTH_COOKIE``.
+
+ ``scanlist``
+
+ This is the initial set of ``environ`` keys to
+ save/restore to the signed cookie. By default is consists
+ only of ``REMOTE_USER`` and ``REMOTE_SESSION``; any
+ space-separated list of environment keys will work.
+ However, be careful, as the total saved size is limited to
+ around 3k.
+
+ ``secret``
+
+ The secret that will be used to sign the cookies. If you
+ don't provide one (and none is set globally) then a random
+ secret will be created. Each time the server is restarted
+ a new secret will then be created and all cookies will
+ become invalid! This can be any string value.
+
+ ``timeout``
+
+ The time to keep the cookie, expressed in minutes. This
+ is handled server-side, so a new cookie with a new timeout
+ is added to every response.
+
+ ``maxlen``
+
+ The maximum length of the cookie that is sent (default 4k,
+ which is a typical browser maximum)
+
+ """
+ if isinstance(scanlist, basestring):
+ scanlist = scanlist.split()
+ if secret is None and global_conf.get('secret'):
+ secret = global_conf['secret']
+ try:
+ timeout = int(timeout)
+ except ValueError:
+ raise ValueError('Bad value for timeout (must be int): %r'
+ % timeout)
+ try:
+ maxlen = int(maxlen)
+ except ValueError:
+ raise ValueError('Bad value for maxlen (must be int): %r'
+ % maxlen)
+ return AuthCookieHandler(
+ app, cookie_name=cookie_name, scanlist=scanlist,
+ secret=secret, timeout=timeout, maxlen=maxlen)
+
+__all__ = ['AuthCookieHandler', 'AuthCookieSigner', 'AuthCookieEnviron']
+
+if "__main__" == __name__:
+ import doctest
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
+
View
213 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/digest.py
@@ -0,0 +1,213 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Digest HTTP/1.1 Authentication
+
+This module implements ``Digest`` authentication as described by
+RFC 2617 [1]_ .
+
+Basically, you just put this module before your application, and it
+takes care of requesting and handling authentication requests. This
+module has been tested with several common browsers "out-in-the-wild".
+
+>>> from paste.wsgilib import dump_environ
+>>> from paste.httpserver import serve
+>>> # from paste.auth.digest import digest_password, AuthDigestHandler
+>>> realm = 'Test Realm'
+>>> def authfunc(environ, realm, username):
+... return digest_password(realm, username, username)
+>>> serve(AuthDigestHandler(dump_environ, realm, authfunc))
+serving on...
+
+This code has not been audited by a security expert, please use with
+caution (or better yet, report security holes). At this time, this
+implementation does not provide for further challenges, nor does it
+support Authentication-Info header. It also uses md5, and an option
+to use sha would be a good thing.
+
+.. [1] http://www.faqs.org/rfcs/rfc2617.html
+"""
+from paste.httpexceptions import HTTPUnauthorized
+from paste.httpheaders import *
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+import time, random
+
+def digest_password(realm, username, password):
+ """ construct the appropriate hashcode needed for HTTP digest """
+ return md5("%s:%s:%s" % (username, realm, password)).hexdigest()
+
+class AuthDigestAuthenticator(object):
+ """ implementation of RFC 2617 - HTTP Digest Authentication """
+ def __init__(self, realm, authfunc):
+ self.nonce = {} # list to prevent replay attacks
+ self.authfunc = authfunc
+ self.realm = realm
+
+ def build_authentication(self, stale = ''):
+ """ builds the authentication error """
+ nonce = md5(
+ "%s:%s" % (time.time(), random.random())).hexdigest()
+ opaque = md5(
+ "%s:%s" % (time.time(), random.random())).hexdigest()
+ self.nonce[nonce] = None
+ parts = {'realm': self.realm, 'qop': 'auth',
+ 'nonce': nonce, 'opaque': opaque }
+ if stale:
+ parts['stale'] = 'true'
+ head = ", ".join(['%s="%s"' % (k, v) for (k, v) in parts.items()])
+ head = [("WWW-Authenticate", 'Digest %s' % head)]
+ return HTTPUnauthorized(headers=head)
+
+ def compute(self, ha1, username, response, method,
+ path, nonce, nc, cnonce, qop):
+ """ computes the authentication, raises error if unsuccessful """
+ if not ha1:
+ return self.build_authentication()
+ ha2 = md5('%s:%s' % (method, path)).hexdigest()
+ if qop:
+ chk = "%s:%s:%s:%s:%s:%s" % (ha1, nonce, nc, cnonce, qop, ha2)
+ else:
+ chk = "%s:%s:%s" % (ha1, nonce, ha2)
+ if response != md5(chk).hexdigest():
+ if nonce in self.nonce:
+ del self.nonce[nonce]
+ return self.build_authentication()
+ pnc = self.nonce.get(nonce,'00000000')
+ if nc <= pnc:
+ if nonce in self.nonce:
+ del self.nonce[nonce]
+ return self.build_authentication(stale = True)
+ self.nonce[nonce] = nc
+ return username
+
+ def authenticate(self, environ):
+ """ This function takes a WSGI environment and authenticates
+ the request returning authenticated user or error.
+ """
+ method = REQUEST_METHOD(environ)
+ fullpath = SCRIPT_NAME(environ) + PATH_INFO(environ)
+ authorization = AUTHORIZATION(environ)
+ if not authorization:
+ return self.build_authentication()
+ (authmeth, auth) = authorization.split(" ", 1)
+ if 'digest' != authmeth.lower():
+ return self.build_authentication()
+ amap = {}
+ for itm in auth.split(", "):
+ (k,v) = [s.strip() for s in itm.split("=", 1)]
+ amap[k] = v.replace('"', '')
+ try:
+ username = amap['username']
+ authpath = amap['uri']
+ nonce = amap['nonce']
+ realm = amap['realm']
+ response = amap['response']
+ assert authpath.split("?", 1)[0] in fullpath
+ assert realm == self.realm
+ qop = amap.get('qop', '')
+ cnonce = amap.get('cnonce', '')
+ nc = amap.get('nc', '00000000')
+ if qop:
+ assert 'auth' == qop
+ assert nonce and nc
+ except:
+ return self.build_authentication()
+ ha1 = self.authfunc(environ, realm, username)
+ return self.compute(ha1, username, response, method, authpath,
+ nonce, nc, cnonce, qop)
+
+ __call__ = authenticate
+
+class AuthDigestHandler(object):
+ """
+ middleware for HTTP Digest authentication (RFC 2617)
+
+ This component follows the procedure below:
+
+ 0. If the REMOTE_USER environment variable is already populated;
+ then this middleware is a no-op, and the request is passed
+ along to the application.
+
+ 1. If the HTTP_AUTHORIZATION header was not provided or specifies
+ an algorithem other than ``digest``, then a HTTPUnauthorized
+ response is generated with the challenge.
+
+ 2. If the response is malformed or or if the user's credientials
+ do not pass muster, another HTTPUnauthorized is raised.
+
+ 3. If all goes well, and the user's credintials pass; then
+ REMOTE_USER environment variable is filled in and the
+ AUTH_TYPE is listed as 'digest'.
+
+ Parameters:
+
+ ``application``
+
+ The application object is called only upon successful
+ authentication, and can assume ``environ['REMOTE_USER']``
+ is set. If the ``REMOTE_USER`` is already set, this
+ middleware is simply pass-through.
+
+ ``realm``
+
+ This is a identifier for the authority that is requesting
+ authorization. It is shown to the user and should be unique
+ within the domain it is being used.
+
+ ``authfunc``
+
+ This is a callback function which performs the actual
+ authentication; the signature of this callback is:
+
+ authfunc(environ, realm, username) -> hashcode
+
+ This module provides a 'digest_password' helper function
+ which can help construct the hashcode; it is recommended
+ that the hashcode is stored in a database, not the user's
+ actual password (since you only need the hashcode).
+ """
+ def __init__(self, application, realm, authfunc):
+ self.authenticate = AuthDigestAuthenticator(realm, authfunc)
+ self.application = application
+
+ def __call__(self, environ, start_response):
+ username = REMOTE_USER(environ)
+ if not username:
+ result = self.authenticate(environ)
+ if isinstance(result, str):
+ AUTH_TYPE.update(environ,'digest')
+ REMOTE_USER.update(environ, result)
+ else:
+ return result.wsgi_application(environ, start_response)
+ return self.application(environ, start_response)
+
+middleware = AuthDigestHandler
+
+__all__ = ['digest_password', 'AuthDigestHandler' ]
+
+def make_digest(app, global_conf, realm, authfunc, **kw):
+ """
+ Grant access via digest authentication
+
+ Config looks like this::
+
+ [filter:grant]
+ use = egg:Paste#auth_digest
+ realm=myrealm
+ authfunc=somepackage.somemodule:somefunction
+
+ """
+ from paste.util.import_string import eval_import
+ import types
+ authfunc = eval_import(authfunc)
+ assert isinstance(authfunc, types.FunctionType), "authfunc must resolve to a function"
+ return AuthDigestHandler(app, realm, authfunc)
+
+if "__main__" == __name__:
+ import doctest
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
View
149 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/form.py
@@ -0,0 +1,149 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Authentication via HTML Form
+
+This is a very simple HTML form login screen that asks for the username
+and password. This middleware component requires that an authorization
+function taking the name and passsword and that it be placed in your
+application stack. This class does not include any session management
+code or way to save the user's authorization; however, it is easy enough
+to put ``paste.auth.cookie`` in your application stack.
+
+>>> from paste.wsgilib import dump_environ
+>>> from paste.httpserver import serve
+>>> from paste.auth.cookie import AuthCookieHandler
+>>> from paste.auth.form import AuthFormHandler
+>>> def authfunc(environ, username, password):
+... return username == password
+>>> serve(AuthCookieHandler(
+... AuthFormHandler(dump_environ, authfunc)))
+serving on...
+
+"""
+from paste.request import construct_url, parse_formvars
+
+TEMPLATE = """\
+<html>
+ <head><title>Please Login!</title></head>
+ <body>
+ <h1>Please Login</h1>
+ <form action="%s" method="post">
+ <dl>
+ <dt>Username:</dt>
+ <dd><input type="text" name="username"></dd>
+ <dt>Password:</dt>
+ <dd><input type="password" name="password"></dd>
+ </dl>
+ <input type="submit" name="authform" />
+ <hr />
+ </form>
+ </body>
+</html>
+"""
+
+class AuthFormHandler(object):
+ """
+ HTML-based login middleware
+
+ This causes a HTML form to be returned if ``REMOTE_USER`` is
+ not found in the ``environ``. If the form is returned, the
+ ``username`` and ``password`` combination are given to a
+ user-supplied authentication function, ``authfunc``. If this
+ is successful, then application processing continues.
+
+ Parameters:
+
+ ``application``
+
+ The application object is called only upon successful
+ authentication, and can assume ``environ['REMOTE_USER']``
+ is set. If the ``REMOTE_USER`` is already set, this
+ middleware is simply pass-through.
+
+ ``authfunc``
+
+ This is a mandatory user-defined function which takes a
+ ``environ``, ``username`` and ``password`` for its first
+ three arguments. It should return ``True`` if the user is
+ authenticated.
+
+ ``template``
+
+ This is an optional (a default is provided) HTML
+ fragment that takes exactly one ``%s`` substution
+ argument; which *must* be used for the form's ``action``
+ to ensure that this middleware component does not alter
+ the current path. The HTML form must use ``POST`` and
+ have two input names: ``username`` and ``password``.
+
+ Since the authentication form is submitted (via ``POST``)
+ neither the ``PATH_INFO`` nor the ``QUERY_STRING`` are accessed,
+ and hence the current path remains _unaltered_ through the
+ entire authentication process. If authentication succeeds, the
+ ``REQUEST_METHOD`` is converted from a ``POST`` to a ``GET``,
+ so that a redirect is unnecessary (unlike most form auth
+ implementations)
+ """
+
+ def __init__(self, application, authfunc, template=None):
+ self.application = application
+ self.authfunc = authfunc
+ self.template = template or TEMPLATE
+
+ def __call__(self, environ, start_response):
+ username = environ.get('REMOTE_USER','')
+ if username:
+ return self.application(environ, start_response)
+
+ if 'POST' == environ['REQUEST_METHOD']:
+ formvars = parse_formvars(environ, include_get_vars=False)
+ username = formvars.get('username')
+ password = formvars.get('password')
+ if username and password:
+ if self.authfunc(environ, username, password):
+ environ['AUTH_TYPE'] = 'form'
+ environ['REMOTE_USER'] = username
+ environ['REQUEST_METHOD'] = 'GET'
+ environ['CONTENT_LENGTH'] = ''
+ environ['CONTENT_TYPE'] = ''
+ del environ['paste.parsed_formvars']
+ return self.application(environ, start_response)
+
+ content = self.template % construct_url(environ)
+ start_response("200 OK", [('Content-Type', 'text/html'),
+ ('Content-Length', str(len(content)))])
+ return [content]
+
+middleware = AuthFormHandler
+
+__all__ = ['AuthFormHandler']
+
+def make_form(app, global_conf, realm, authfunc, **kw):
+ """
+ Grant access via form authentication
+
+ Config looks like this::
+
+ [filter:grant]
+ use = egg:Paste#auth_form
+ realm=myrealm
+ authfunc=somepackage.somemodule:somefunction
+
+ """
+ from paste.util.import_string import eval_import
+ import types
+ authfunc = eval_import(authfunc)
+ assert isinstance(authfunc, types.FunctionType), "authfunc must resolve to a function"
+ template = kw.get('template')
+ if template is not None:
+ template = eval_import(template)
+ assert isinstance(template, str), "template must resolve to a string"
+
+ return AuthFormHandler(app, authfunc, template)
+
+if "__main__" == __name__:
+ import doctest
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
View
113 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/grantip.py
@@ -0,0 +1,113 @@
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+"""
+Grant roles and logins based on IP address.
+"""
+from paste.util import ip4
+
+class GrantIPMiddleware(object):
+
+ """
+ On each request, ``ip_map`` is checked against ``REMOTE_ADDR``
+ and logins and roles are assigned based on that.
+
+ ``ip_map`` is a map of {ip_mask: (username, roles)}. Either
+ ``username`` or ``roles`` may be None. Roles may also be prefixed
+ with ``-``, like ``'-system'`` meaning that role should be
+ revoked. ``'__remove__'`` for a username will remove the username.
+
+ If ``clobber_username`` is true (default) then any user
+ specification will override the current value of ``REMOTE_USER``.
+ ``'__remove__'`` will always clobber the username.
+
+ ``ip_mask`` is something that `paste.util.ip4:IP4Range
+ <class-paste.util.ip4.IP4Range.html>`_ can parse. Simple IP
+ addresses, IP/mask, ip<->ip ranges, and hostnames are allowed.
+ """
+
+ def __init__(self, app, ip_map, clobber_username=True):
+ self.app = app
+ self.ip_map = []
+ for key, value in ip_map.items():
+ self.ip_map.append((ip4.IP4Range(key),
+ self._convert_user_role(value[0], value[1])))
+ self.clobber_username = clobber_username
+
+ def _convert_user_role(self, username, roles):
+ if roles and isinstance(roles, basestring):
+ roles = roles.split(',')
+ return (username, roles)
+
+ def __call__(self, environ, start_response):
+ addr = ip4.ip2int(environ['REMOTE_ADDR'], False)
+ remove_user = False
+ add_roles = []
+ for range, (username, roles) in self.ip_map:
+ if addr in range:
+ if roles:
+ add_roles.extend(roles)
+ if username == '__remove__':
+ remove_user = True
+ elif username:
+ if (not environ.get('REMOTE_USER')
+ or self.clobber_username):
+ environ['REMOTE_USER'] = username
+ if (remove_user and 'REMOTE_USER' in environ):
+ del environ['REMOTE_USER']
+ if roles:
+ self._set_roles(environ, add_roles)
+ return self.app(environ, start_response)
+
+ def _set_roles(self, environ, roles):
+ cur_roles = environ.get('REMOTE_USER_TOKENS', '').split(',')
+ # Get rid of empty roles:
+ cur_roles = filter(None, cur_roles)
+ remove_roles = []
+ for role in roles:
+ if role.startswith('-'):
+ remove_roles.append(role[1:])
+ else:
+ if role not in cur_roles:
+ cur_roles.append(role)
+ for role in remove_roles:
+ if role in cur_roles:
+ cur_roles.remove(role)
+ environ['REMOTE_USER_TOKENS'] = ','.join(cur_roles)
+
+
+def make_grantip(app, global_conf, clobber_username=False, **kw):
+ """
+ Grant roles or usernames based on IP addresses.
+
+ Config looks like this::
+
+ [filter:grant]
+ use = egg:Paste#grantip
+ clobber_username = true
+ # Give localhost system role (no username):
+ 127.0.0.1 = -:system
+ # Give everyone in 192.168.0.* editor role:
+ 192.168.0.0/24 = -:editor
+ # Give one IP the username joe:
+ 192.168.0.7 = joe
+ # And one IP is should not be logged in:
+ 192.168.0.10 = __remove__:-editor
+
+ """
+ from paste.deploy.converters import asbool
+ clobber_username = asbool(clobber_username)
+ ip_map = {}
+ for key, value in kw.items():
+ if ':' in value:
+ username, role = value.split(':', 1)
+ else:
+ username = value
+ role = ''
+ if username == '-':
+ username = ''
+ if role == '-':
+ role = ''
+ ip_map[key] = value
+ return GrantIPMiddleware(app, ip_map, clobber_username)
+
+
View
79 reverse-geocode-branch/Paste-1.7.2-py2.5.egg/paste/auth/multi.py
@@ -0,0 +1,79 @@
+# (c) 2005 Clark C. Evans
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+# This code was written with funding by http://prometheusresearch.com
+"""
+Authentication via Multiple Methods
+
+In some environments, the choice of authentication method to be used
+depends upon the environment and is not "fixed". This middleware allows
+N authentication methods to be registered along with a goodness function
+which determines which method should be used. The following example
+demonstrates how to use both form and digest authentication in a server
+stack; by default it uses form-based authentication unless
+``*authmeth=digest`` is specified as a query argument.
+
+>>> from paste.auth import form, cookie, digest, multi
+>>> from paste.wsgilib import dump_environ
+>>> from paste.httpserver import serve
+>>>
+>>> multi = multi.MultiHandler(dump_environ)
+>>> def authfunc(environ, realm, user):
+... return digest.digest_password(realm, user, user)
+>>> multi.add_method('digest', digest.middleware, "Test Realm", authfunc)
+>>> multi.set_query_argument('digest')
+>>>
+>>> def authfunc(environ, username, password):
+... return username == password
+>>> multi.add_method('form', form.middleware, authfunc)
+>>> multi.set_default('form')
+>>> serve(cookie.middleware(multi))
+serving on...
+
+"""
+
+class MultiHandler(object):
+ """
+ Multiple Authentication Handler
+
+ This middleware provides two othogonal facilities:
+
+ - a manner to register any number of authentication middlewares
+
+ - a mechanism to register predicates which cause one of the
+ registered middlewares to be used depending upon the request
+
+ If none of the predicates returns True, then the application is
+ invoked directly without middleware
+ """
+ def __init__(self, application):
+ self.application = application
+ self.default = application
+ self.binding = {}
+ self.predicate = []
+ def add_method(self, name, factory, *args, **kwargs):
+ self.binding[name] = factory(self.application, *args, **kwargs)
+ def add_predicate(self, name, checker):
+ self.predicate.append((checker, self.binding[name]))