AuthKit-0.4.3/0000755000175000017500000000000011121727574012056 5ustar jamesjamesAuthKit-0.4.3/LICENSE.txt0000644000175000017500000000213711121727466013704 0ustar jamesjamesLicense ======= Copyright (c) Copyright 2005-2007 James Gardner 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. AuthKit-0.4.3/examples/0000755000175000017500000000000011121727574013674 5ustar jamesjamesAuthKit-0.4.3/examples/docs/0000755000175000017500000000000011121727574014624 5ustar jamesjamesAuthKit-0.4.3/examples/docs/form2.py0000755000175000017500000000124611121727466016231 0ustar jamesjames# -*- coding: utf-8 -*- """ Simple form example which uses a custom validation function to authenticate users. The username is ``test`` the password is ``password``. """ from authkit.authenticate import middleware, sample_app def valid(environ, username, password): return username == 'test' and password == 'password' app = middleware( sample_app, setup_method='form,cookie', cookie_secret='secret encryption string', form_authenticate_function = valid, form_charset='UTF-8', cookie_signoutpath = '/signout', form_method='get', ) if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/docs/open_id.py0000644000175000017500000000110511121727466016610 0ustar jamesjamesfrom authkit.authenticate import middleware, sample_app from beaker.middleware import SessionMiddleware app = middleware( sample_app, setup_method='openid, cookie', openid_path_signedin='/private', openid_store_type='file', openid_store_config='', openid_charset='UTF-8', cookie_secret='secret encryption string', cookie_signoutpath = '/signout', ) app = SessionMiddleware( app, key='authkit.open_id', secret='some secret', ) if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/docs/form.py0000644000175000017500000000135011121727466016140 0ustar jamesjames# -*- coding: utf-8 -*- from authkit.authenticate import middleware, sample_app app = middleware( sample_app, setup_method='form,cookie', cookie_secret='secret encryption string', form_authenticate_user_data = """ الإعلاني:9406649867375c79247713a7fb81edf0 username2:4e64aba9f0305efa50396584cfbee89c """, form_authenticate_user_encrypt = 'authkit.users:md5', form_authenticate_user_encrypt_secret = 'some secret string', form_charset='UTF-8', # For overriding proxied defaults: # form_action = 'http://localhost/forms/private', cookie_signoutpath = '/signout', ) if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/docs/form_no_user_in_cookie.py0000755000175000017500000000200411121727466021711 0ustar jamesjames# -*- coding: utf-8 -*- """\ This example uses an in-memory session for storing the username but still stores other information in the cookie. The username and password are username2, password2 and الإعلاني, password1 respectively. """ from authkit.authenticate import middleware, sample_app from beaker.middleware import SessionMiddleware app = middleware( sample_app, setup_method='form,cookie', cookie_secret='secret encryption string', form_authenticate_user_data = """ الإعلاني:9406649867375c79247713a7fb81edf0 username2:4e64aba9f0305efa50396584cfbee89c """, form_authenticate_user_encrypt = 'authkit.users:md5', form_authenticate_user_encrypt_secret = 'some secret string', form_charset='UTF-8', cookie_signoutpath = '/signout', cookie_nouserincookie = True, ) app = SessionMiddleware(app, key='authkit.session', secret="some secret") if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/docs/basic.py0000644000175000017500000000056611121727466016266 0ustar jamesjamesfrom authkit.authenticate import middleware, sample_app def valid(environ, username, password): return username == password app = middleware( sample_app, setup_method='basic', basic_realm='Test Realm', basic_authenticate_function=valid ) if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/docs/digest.py0000644000175000017500000000073311121727466016460 0ustar jamesjamesfrom authkit.authenticate import middleware, sample_app from authkit.authenticate.digest import digest_password def digest(environ, realm, username): password = username return digest_password(realm, username, password) app = middleware( sample_app, setup_method='digest', digest_realm='Test Realm', digest_authenticate_function=digest ) if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/docs/forward.py0000644000175000017500000000537011121727466016647 0ustar jamesjamesfrom authkit.authenticate import middleware def sample_app(environ, start_response): """ A sample WSGI application that returns a 401 status code when the path ``/private`` is entered, triggering the authenticate middleware to forward to ``/signin`` where the user is prompted to sign in. If the sign in is successful a cookie is set and the user can visit the ``/private`` path. The path ``/signout`` will display a signed out message if and sign the user out if cookie_signout = '/signout' is specified in the middelware config. The path ``/`` always displays the environment. """ if environ['PATH_INFO']=='/private' and not environ.has_key('REMOTE_USER'): start_response('401 Not signed in', []) elif environ['PATH_INFO'] == '/signout': start_response('200 OK', [('Content-type', 'text/plain')]) if environ.has_key('REMOTE_USER'): return ["Signed Out"] else: return ["Not signed in"] elif environ['PATH_INFO'] == '/signin': page = """ %s
Username: Password:
""" if not environ.get('QUERY_STRING'): start_response( '200 Sign in required', [('Content-type', 'text/html')] ) return [page%'

Please Sign In

'] else: # Quick and dirty sign in check, do it properly in your code params = {} for part in environ['QUERY_STRING'].split('&'): params[part.split("=")[0]] = part.split('=')[1] if params['username'] and params['username'] == params['password']: start_response('200 OK', [('Content-type', 'text/html')]) environ['paste.auth_tkt.set_user'](params['username']) return ["Signed in."] else: start_response('200 OK', [('Content-type', 'text/html')]) return [page%'

Invalid details

'] start_response('200 OK', [('Content-type', 'text/plain')]) result = ['You Have Access To This Page.\n\nHere is the environment...\n\n'] for k,v in environ.items(): result.append('%s: %s\n'%(k,v)) return result app = middleware( sample_app, setup_method='forward,cookie', forward_signinpath = '/signin', cookie_signoutpath = '/signout', cookie_secret = 'somesecret', ) if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/docs/multi2.py0000644000175000017500000000235311121727466016415 0ustar jamesjames"This example checks AuthKit's streaming ability" from authkit.authenticate import middleware, sample_app import time class AppClass(object): def __init__(self, environ, start_response): self.environ = environ self.start_response = start_response self.pos = 0 self.data = [1,2,3,4,5] def __iter__(self): self.start_response('200 OK', [('Content-type','text/html')]) return self def next(self): time.sleep(1) if self.pos < len(self.data): res = str(self.data[self.pos]) self.pos += 1 return res else: raise StopIteration def generator(environ, start_response): start_response('200 OK', [('Content-type','text/html')]) pos = 0 data = [1,2,3,4,5] while pos < len(data): time.sleep(1) yield str(data[pos]) pos += 1 app = AppClass #app = generator #app = sample_app def valid(environ, username, password): return username == password app = middleware( app, setup_method='basic', basic_realm='Test Realm', basic_authenticate_function=valid ) if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/docs/multi.py0000644000175000017500000002042411121727466016332 0ustar jamesjames# -*- coding: utf-8 -*- """\ This is an example of multiple middleware components being setup at once in such away that the authentication method used is dynamically selected at runtime. What happens is that each authentication method is based an ``AuthSwitcher`` object which when a status response matching a code specified in ``authkit.setup.intercept`` is intercepted, will perform a ``switch()`` check. If the check returns ``True`` then that particular ``AuthHandler`` will be triggered. In this example the ``AuthSwitcher`` decides whether to trigger a particular ``AuthHandler`` based on the value of the ``authkit.authhandler`` key in ``environ`` and this is set when visiting the various paths such as ``/private_openid``, ``private_basic`` etc. Notice though that the form method is setup with a ``Default`` ``AuthSwitcher`` whose ``switch()`` method always returns ``True``. This means of the other ``AuthHandlers`` don't handle the response, the from method's handler will. This is the case if you visit ``/private``. Once the user is authenticated the ``UserSetter``s middleware sets the ``REMOTE_USER`` environ variable so that the user remains signed in. This means that a user can authenticate with say digest authentication and when they visit ``/private_openid`` they will still be signed in, even if that wasn't the method they used to authenticate. Also, note that you are free to implement and use any ``AuthSwitcher`` you like as long as it derives from ``AuthSwitcher`` so you could for example choose which authentication method to show to the user based on their IP address. The authentication details for each method in this example are: Form: username2:password2 Digest: test:test (or any username which is identical to the password) Basic: test:test (or any username which is identical to the password) OpenID: any valid openid (get one at myopenid.com for example) Of course, everything is totally configurable. """ # Needed for the middleware from authkit.authenticate import middleware, strip_base from authkit.authenticate.open_id import OpenIDAuthHandler, \ OpenIDUserSetter, load_openid_config from authkit.authenticate.form import FormAuthHandler, load_form_config from authkit.authenticate.cookie import CookieUserSetter, load_cookie_config from authkit.authenticate.basic import BasicAuthHandler, BasicUserSetter, \ load_basic_config from authkit.authenticate.digest import DigestAuthHandler, \ DigestUserSetter, load_digest_config, digest_password from authkit.authenticate.multi import MultiHandler, AuthSwitcher, \ status_checker # Needed for the sample app from authkit.authorize import authorize_request from authkit.permissions import RemoteUser, no_authkit_users_in_environ, \ AuthKitConfigError # Setup a switcher which will switch if environ['authkit.authhandler'] equals # the method name specified and if the response matches one of the values of # authkit.setup.intercept class EnvironKeyAuthSwitcher(AuthSwitcher): def __init__(self, method, key='authkit.authhandler'): self.method = method self.key = key def switch(self, environ, status, headers): if environ.has_key(self.key) and environ[self.key] == self.method: return True return False class Default(AuthSwitcher): def switch(self, environ, status, headers): return True def make_multi_middleware(app, auth_conf, app_conf=None, global_conf=None, prefix='authkit.'): # Load the configurations and any associated middleware app, oid_auth_params, oid_user_params = load_openid_config( app, strip_base(auth_conf, 'openid.')) app, form_auth_params, form_user_params = load_form_config( app, strip_base(auth_conf, 'form.')) app, cookie_auth_params, cookie_user_params = load_cookie_config( app, strip_base(auth_conf, 'cookie.')) app, basic_auth_params, basic_user_params = load_basic_config( app, strip_base(auth_conf, 'basic.')) app, digest_auth_params, digest_user_params = load_digest_config( app, strip_base(auth_conf, 'digest.')) # The cookie plugin doesn't provide an AuthHandler so no config assert cookie_auth_params == None # The form plugin doesn't provide a UserSetter (it uses cookie) assert form_user_params == None # Setup the MultiHandler to switch between authentication methods # based on the value of environ['authkit.authhandler'] if a 401 is # raised app = MultiHandler(app) app.add_method('openid', OpenIDAuthHandler, **oid_auth_params) app.add_checker('openid', EnvironKeyAuthSwitcher('openid')) app.add_method('basic', BasicAuthHandler, **basic_auth_params) app.add_checker('basic', EnvironKeyAuthSwitcher('basic')) app.add_method('digest', DigestAuthHandler, **digest_auth_params) app.add_checker('digest', EnvironKeyAuthSwitcher('digest')) app.add_method('form', FormAuthHandler, **form_auth_params) app.add_checker('form', Default()) # Add the user setters to set REMOTE_USER on each request once the # user is signed on. app = DigestUserSetter(app, **digest_user_params) app = BasicUserSetter(app, **basic_user_params) # OpenID relies on cookie so needs to be set up first app = OpenIDUserSetter(app, **oid_user_params) app = CookieUserSetter(app, **cookie_user_params) return app def sample_app(environ, start_response): """ A sample WSGI application that returns a 401 status code when the path ``/private`` is entered, triggering the authenticate middleware to prompt the user to sign in. If used with the authenticate middleware's form method, the path ``/signout`` will display a signed out message if ``authkit.cookie.signout = /signout`` is specified in the config file. If used with the authenticate middleware's forward method, the path ``/signin`` should be used to display the sign in form. The path ``/`` always displays the environment. """ if environ['PATH_INFO']=='/private': authorize_request(environ, RemoteUser()) if environ['PATH_INFO']=='/private_openid': environ['authkit.authhandler'] = 'openid' authorize_request(environ, RemoteUser()) if environ['PATH_INFO']=='/private_digest': environ['authkit.authhandler'] = 'digest' authorize_request(environ, RemoteUser()) if environ['PATH_INFO']=='/private_basic': environ['authkit.authhandler'] = 'basic' authorize_request(environ, RemoteUser()) if environ['PATH_INFO'] == '/signout': start_response( '200 OK', [('Content-type', 'text/plain; charset=UTF-8')] ) if environ.has_key('REMOTE_USER'): return ["Signed Out"] else: return ["Not signed in"] elif environ['PATH_INFO'] == '/signin': start_response( '200 OK', [('Content-type', 'text/plain; charset=UTF-8')] ) return ["Your application would display a \nsign in form here."] else: start_response( '200 OK', [('Content-type', 'text/plain; charset=UTF-8')] ) result = [ 'You Have Access To This Page.\n\nHere is the environment...\n\n' ] for k,v in environ.items(): result.append('%s: %s\n'%(k,v)) return result def digest_authenticate(environ, realm, username): password = username return digest_password(realm, username, password) def basic_authenticate(environ, username, password): return username == password app = middleware( sample_app, middleware = make_multi_middleware, openid_path_signedin='/private', openid_store_type='file', openid_store_config='', openid_charset='UTF-8', cookie_secret='secret encryption string', cookie_signoutpath = '/signout', openid_sreg_required = 'fullname,nickname,city,country', openid_sreg_optional = 'timezone,email', openid_sreg_policyurl = 'http://localhost:5000', form_authenticate_user_data = """ username2:password2 """, form_charset='UTF-8', digest_realm='Test Realm', digest_authenticate_function=digest_authenticate, basic_realm='Test Realm', basic_authenticate_function=basic_authenticate, ) # XXX No Session variables in the config now. if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/docs/redirect.py0000644000175000017500000000045511121727466017003 0ustar jamesjamesfrom authkit.authenticate import middleware, sample_app app = middleware( sample_app, setup_method='redirect,cookie', redirect_url='http://3aims.com', cookie_secret='asdasd' ) if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/docs/open_id_sreg.py0000644000175000017500000000134411121727466017635 0ustar jamesjamesfrom authkit.authenticate import middleware, sample_app from beaker.middleware import SessionMiddleware app = middleware( sample_app, setup_method='openid, cookie', openid_path_signedin='/private', openid_store_type='file', openid_store_config='', openid_charset='UTF-8', cookie_secret='secret encryption string', cookie_signoutpath = '/signout', openid_sreg_required = 'fullname,nickname,dob,country', openid_sreg_optional = 'timezone,email', openid_sreg_policyurl = 'http://localhost:8080', ) app = SessionMiddleware( app, key='authkit.open_id', secret='some secret', ) if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/authorize2.py0000644000175000017500000000206111121727466016341 0ustar jamesjames""" This is the same as the authorize.py example but it tests that the ``authkit.setup.enable = false`` option also disables authorisation checks. """ from authorize import * if __name__ == '__main__': from paste.httpserver import serve from authkit.authenticate import middleware def valid(environ, username, password): """ Sample, very insecure validation function """ return username == password app = httpexceptions.make_middleware(AuthorizeExampleApp()) app = middleware( app, setup_enable=False, setup_method='basic', basic_realm='Test Realm', basic_authenticate_function=valid ) print """ Clear the HTTP authentication first by closing your browser if you have been testing other basic authentication examples on the same port. You will be able to sign in as any user as long as the password is the same as the username, but all users apart from `james' will be denied access to the resources. """ serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/config/0000755000175000017500000000000011121727574015141 5ustar jamesjamesAuthKit-0.4.3/examples/config/digest.py0000644000175000017500000000110511121727465016766 0ustar jamesjamesfrom authkit.authenticate import middleware, sample_app from authkit.authenticate.digest import digest_password def digest(environ, realm, username): password = username return digest_password(realm, username, password) config = { 'authkit.setup.method':'digest', 'authkit.digest.realm':'Test Realm', 'authkit.digest.authenticate.function':digest, 'authkit.setup.enable':'True', } app = middleware( sample_app, app_conf = config ) if __name__ == '__main__': from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/authorize.py0000644000175000017500000001041011121727466016254 0ustar jamesjames#!/usr/bin/env python """ This code demonstrates some of the features of authkit.authorize. Start the server with:: python authorize.py Then visit http://localhost:8080/ and you should see the output from the ``index()`` method which invites you to try some of the links. Each method linked to is implemented using a different means of checking the permission. In the ``__call__`` method, the code which implements the permission attribute checking also demonstrates the use of authorize ``middleware``. If you sign in with a user other than ``james``, you will be signed in but denied access to the resources. Close your browser to clear the HTTP authentication cache and try the example again. """ from authkit.permissions import UserIn from authkit.authorize import authorized, authorize, PermissionError from authkit.authorize import middleware as authorize_middleware from paste import httpexceptions class NoSuchActionError(httpexceptions.HTTPNotFound): pass class AuthorizeExampleApp: def __call__(self, environ, start_response): if environ['PATH_INFO'] == '/': method = 'index' else: method = environ['PATH_INFO'].split('/')[1] if not hasattr(self, method): raise NoSuchActionError('No such method') app = getattr(self,method) # This facilitates an alternative way you might want to check permisisons # rather than using an authorize() decorator if hasattr(app, 'permission'): app = authorize_middleware(app, app.permission) return app(environ, start_response) def index(self, environ, start_response): start_response('200 OK', [('Content-type','text/html')]) return [''' AuthKit Authorize Example

Authorize Example

Try the following links. You should only be able to sign in as user james with the password the same as the username.

Once you have signed in you will need to close your browser to clear the authentication cache.

'''] def mid_method_test(self, environ, start_response): """Authorize using a mid-method permissions check""" if authorized(environ, UserIn(users=['james'])): start_response('200 OK', [('Content-type','text/html')]) return ['Access granted to /mid_method_test'] else: start_response('200 OK', [('Content-type','text/html')]) return ['User is not authorized'] @authorize(UserIn(users=['james'])) def decorator_test(self, environ, start_response): """Authorize using a decorator""" start_response('200 OK', [('Content-type','text/html')]) return ['Access granted to /decorator_test'] def attribute_test(self, environ, start_response): """Authorize using a permission attribute""" start_response('200 OK', [('Content-type','text/html')]) return ['Access granted to /attribute_test'] attribute_test.permission = UserIn(users=['james']) if __name__ == '__main__': from paste.httpserver import serve from authkit.authenticate import middleware def valid(environ, username, password): """ Sample, very insecure validation function """ return username == password app = httpexceptions.make_middleware(AuthorizeExampleApp()) app = middleware( app, setup_method='basic', basic_realm='Test Realm', basic_authenticate_function=valid ) print """ Clear the HTTP authentication first by closing your browser if you have been testing other basic authentication examples on the same port. You will be able to sign in as any user as long as the password is the same as the username, but all users apart from `james' will be denied access to the resources. """ serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/user/0000755000175000017500000000000011121727574014652 5ustar jamesjamesAuthKit-0.4.3/examples/user/database/0000755000175000017500000000000011121727574016416 5ustar jamesjamesAuthKit-0.4.3/examples/user/database/README.txt0000644000175000017500000000074211121727466020117 0ustar jamesjamesTo use this example do the following: 1. Edit ``app.py`` to choose the database you wish to use. The default should be fine but you will need ``pysqlite`` installed. 2. Start the example server (this will create the database and setup the user information):: python app.py 3. Visit the server at http://localhost:8080/private 4. Delete the test.db file if you want to test the example again. The usernames and passwords are set up in the app.py file. AuthKit-0.4.3/examples/user/database/app.py0000644000175000017500000001172711121727466017560 0ustar jamesjames""" See the README.txt file for how to setup and use this example. Note that the AuthKit middleware is by default only setup to intercept 401 responses due to NotAuthenticated errors. This means if you try to access a resource when you aren't signed in and you don't have access to it you will be prompted to sign in. If you are signed in you will be shown the server's default 403 error page. If you want to be prompted to sign in under these circumstances too, uncomment this line to the middleware setup at the end of this example:: # setup_intercept = "401, 403", """ from paste.httpexceptions import HTTPExceptionHandler from authkit.authenticate import middleware from authkit.authorize import authorize from authkit.permissions import ValidAuthKitUser, HasAuthKitRole, HasAuthKitGroup class SampleApp: # Application setup def __call__(self, environ, start_response): path = environ.get('PATH_INFO') if path == '/user': return self.user(environ, start_response) elif path == '/admin': return self.admin(environ, start_response) elif path == '/group': return self.group(environ, start_response) elif path == '/': return self.index(environ, start_response) elif path == '/signout': return self.signout(environ, start_response) else: start_response("404 Not Found", [("Content-type","text/plain")]) return ["Not Found"] def _access_granted(self, start_response, message): start_response("200 OK", [("Content-type","text/html")]) return [ "AuthKit Database Example", "

AuthKit Database Example

", message, "" ] # Induvidual pages def signout(self, environ, start_response): start_response('200 OK', [('Content-type','text/html')]) return ['Signed out'] def index(self, environ, start_response): return self._access_granted( start_response, """

This page is public, try visiting the following pages:

The code is set up like this:

    users.group_create("pylons")
    users.role_create("admin")
    users.user_create("james", password="password1", group="pylons")
    users.user_create("ben", password="password2")
    users.user_add_role("ben", role="admin")
""" ) @authorize(ValidAuthKitUser()) # Note we don't use RemoteUser() here because we only want users in the AuthKit database def user(self, environ, start_response): return self._access_granted(start_response, "Any user in the database can access this") @authorize(HasAuthKitRole(["admin"])) def admin(self, environ, start_response): return self._access_granted(start_response, "You have the admin role.") @authorize(HasAuthKitGroup(["pylons"])) def group(self, environ, start_response): return self._access_granted(start_response, "You are in the pylons group.") from sqlalchemymanager import SQLAlchemyManager import authkit.users.sqlalchemy_04_driver import os # os.remove('test.db') app = SampleApp() app = middleware( app, setup_method='form,cookie', cookie_secret='secret encryption string', form_authenticate_user_type = "authkit.users.sqlalchemy_04_driver:UsersFromDatabase", cookie_signoutpath = '/signout', setup_intercept = "401, 403", ) app = SQLAlchemyManager(app, {'sqlalchemy.url':'sqlite:///test.db'}, [authkit.users.sqlalchemy_04_driver.setup_model]) app.create_all() connection = app.engine.connect() session = app.session_maker(bind=connection) try: environ = {} environ['sqlalchemy.session'] = session environ['sqlalchemy.model'] = app.model users = authkit.users.sqlalchemy_04_driver.UsersFromDatabase(environ) users.group_create("pylons") users.role_create("admin") users.user_create("james", password="password1", group="pylons") users.user_create("ben", password="password2") users.user_add_role("ben", role="admin") session.flush() session.commit() finally: session.close() connection.close() app = HTTPExceptionHandler(app) if __name__ == '__main__': import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='test.log', filemode='w') from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/user/database-model/0000755000175000017500000000000011121727574017514 5ustar jamesjamesAuthKit-0.4.3/examples/user/database-model/create.py0000644000175000017500000000121211121727466021325 0ustar jamesjamesimport model from authkit.users.sqlalchemy_driver import UsersFromDatabase # Setup SQLAlchemy database engine from sqlalchemy import engine_from_config engine = engine_from_config({'sqlalchemy.url':'sqlite:///test.db'}, 'sqlalchemy.') model.init_model(engine) model.engine = engine users = UsersFromDatabase(model) model.meta.metadata.create_all(model.engine) users.group_create("pylons") users.role_create("admin") users.user_create("james", password="password1", group="pylons") users.user_create("ben", password="password2") users.user_add_role("ben", role="admin") # Commit the changes model.meta.Session.commit() model.meta.Session.remove() AuthKit-0.4.3/examples/user/database-model/README.txt0000644000175000017500000000060611121727466021214 0ustar jamesjamesTo use this example do the following: 1. Edit ``model.py`` to choose the database you wish to use. The default should be fine but you will need ``pysqlite`` installed. 2. Run the ``create.py`` file to create the necessary database tables:: python create.py 3. Start the example server:: python app.py 4. Visit the server at http://localhost:8080/private AuthKit-0.4.3/examples/user/database-model/meta.py0000644000175000017500000000074711121727466021024 0ustar jamesjames"""SQLAlchemy Metadata and Session object""" from sqlalchemy import MetaData from sqlalchemy.orm import scoped_session, sessionmaker import pylons __all__ = ['Session', 'metadata'] # SQLAlchemy database engine. Updated by model.init_model(). engine = None # SQLAlchemy session manager. Updated by model.init_model(). Session = None # Global metadata. If you have multiple databases with overlapping table # names, you'll need a metadata for each database. metadata = MetaData() AuthKit-0.4.3/examples/user/database-model/app.py0000644000175000017500000000740611121727466020655 0ustar jamesjames""" See the README.txt file for how to setup and use this example. Note that the AuthKit middleware is by default only setup to intercept 401 responses due to NotAuthenticated errors. This means if you try to access a resource when you aren't signed in and you don't have access to it you will be prompted to sign in. If you are signed in you will be shown the server's default 403 error page. If you want to be prompted to sign in under these circumstances too, uncomment this line to the middleware setup at the end of this example:: # setup_intercept = "401, 403", """ from paste.httpexceptions import HTTPExceptionHandler from authkit.authenticate import middleware from authkit.authorize import authorize from authkit.users.sqlalchemy_driver import UsersFromDatabase from authkit.permissions import ValidAuthKitUser, HasAuthKitRole, HasAuthKitGroup class SampleApp: # Application setup def __call__(self, environ, start_response): path = environ.get('PATH_INFO') if path == '/user': return self.user(environ, start_response) elif path == '/admin': return self.admin(environ, start_response) elif path == '/group': return self.group(environ, start_response) elif path == '/': return self.index(environ, start_response) else: start_response("404 Not Found", [("Content-type","text/plain")]) return ["Not Found"] def _access_granted(self, start_response, message): start_response("200 OK", [("Content-type","text/html")]) return [ "AuthKit Database Example", "

AuthKit Database Example

", message, "" ] # Induvidual pages def index(self, environ, start_response): return self._access_granted( start_response, """

This page is public, try visiting the following pages:

""" ) @authorize(ValidAuthKitUser()) # Note we don't use RemoteUser() here because we only want users in the AuthKit database def user(self, environ, start_response): return self._access_granted(start_response, "Any user in the database can access this") @authorize(HasAuthKitRole(["admin"])) def admin(self, environ, start_response): return self._access_granted(start_response, "You have the admin role.") @authorize(HasAuthKitGroup(["pylons"])) def group(self, environ, start_response): return self._access_granted(start_response, "You are in the pylons group.") app = SampleApp() # Not needed, included by the authenticate middleware #app = HTTPExceptionHandler(app) app = middleware( app, setup_method='form,cookie', cookie_secret='secret encryption string', form_authenticate_user_type = "authkit.users.sqlalchemy_driver:UsersFromDatabase", form_authenticate_user_data = "model", cookie_signoutpath = '/signout', # setup_intercept = "401, 403", ) app = HTTPExceptionHandler(app) if __name__ == '__main__': import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='test.log', filemode='w') from paste.httpserver import serve serve(app, host='0.0.0.0', port=8080) AuthKit-0.4.3/examples/user/database-model/model.py0000644000175000017500000000057311121727466021173 0ustar jamesjamesimport sqlalchemy as sa import datetime from sqlalchemy import orm from sqlalchemy import schema, types import sqlalchemy import meta def init_model(engine): """Call me before using any of the tables or classes in the model.""" sm = orm.sessionmaker(autoflush=True, transactional=True, bind=engine) meta.engine = engine meta.Session = orm.scoped_session(sm) AuthKit-0.4.3/AuthKit.egg-info/0000755000175000017500000000000011121727574015121 5ustar jamesjamesAuthKit-0.4.3/AuthKit.egg-info/PKG-INFO0000644000175000017500000002615711121727574016231 0ustar jamesjamesMetadata-Version: 1.0 Name: AuthKit Version: 0.4.3 Summary: An authentication and authorization toolkit for WSGI applications and frameworks Home-page: http://authkit.org/ Author: James Gardner Author-email: james@pythonweb.org License: MIT Description: AuthKit +++++++ .. contents :: Summary ======= * Built for WSGI applications and middleware * Sophisticated and extensible permissions system * Built in support for HTTP basic, HTTP digest, form, cookie and OpenID authentication methods plus others * Easily define users, passwords and roles * Designed to be totally extensible so you can use the components to integrate with a database, LDAP connection or your own custom system * Plays nicely with the `Pylons `_ web framework There is also a `development version `_. Get Started =========== * `Download and Installation `_ * `Pylons Book `_ (the two chapters on *Authentication and Authorization* and *Advanced AuthKit* form the AuthKit 0.4 documentation) * `Module Reference `_ * `AuthKit Cookbook `_ * `Trac `_ - Tickets, Wiki, Subversion * `Examples `_ Author ====== `James Gardner `_ james at pythonweb dot org Development sponsored by `3aims `_ and `Prometheus Research `_. Changes ======= 0.4.3 * Updated authkit.authenticate.form to handle the suggest change in #61 * Added powerpack adaptors * Changed the multi middleware to return the WSGI response rather than iterating over it and yielding results. * Fixed #50 OpenID problem and tested on blogger.com * Added the ability to pass the environ dictionary to render() functions * Added bad cookie customisation options to fix #65 but also to allow bad cookie template customisation. See the docstring of the authkit.authenticate.cookie module. * Added a new algorithm based on ideas from #61 to guess the correct action for the form produced by the form middleware but also added support for an authkit.form.action option which allows you to manually override AuthKit's guess. (The OpenID middleware calls this baseurl) * Added user_set_password() methods to users API. Fixes #64. * Removed arabic letters from the form handler. Fixes #40. * Added headers to the form handling for IE. Fixes #54. * Adding SQLAlchemy 0.5 support, uses session.add() instead of session.save() * The multi handler now handles WSGI applications implemented as iterators, it already supported generators. The multi2.py example demonstrates this. * Set the pylons.status_code_redirect environment variable on all redirected AuthKit responses * Set the pylons.error_call environment variable on all redirected AuthKit responses * Trigger an error when trying to use server-side password encryption with digest authentication 0.4.2 * Applied most of #59 and tested the two OpenID examples * Added support for WebOb HTTPExceptions to remove a deprecation warning in Pylons 0.9.7 * Fixed a missing md5 import in the cookie module * Applied patch in ticket #52 0.4.1 * Added ``setup.fakeuser`` option which automatically sets the REMOTE_USER so that it appears someone has signed in. Useful with setup.enable = False ******************************************************************************** * The ``setup.enable = false`` option now also disables authorisation * * checks (reported by Rick Flosi) * ******************************************************************************** * Applied patch from Pawel Niewiadomski to fix #53 * Changed the import of the openid.sreg module to openid.extensions.sreg * Fixed the encoding of the form.py file * Updated the examples to use the latest syntax * Updated the tests for the new SQLAlchemy drivers * Added Daniel Pronych's SQLAlchemy drivers but with significant changes * Fixed a bug due to a change in the latest version of Python OpenID so that AuthKit OpenID works with Yahoo sign-ins. Phil Kershaw #50 * Updated the user/database example, it now works #43 * Updated user tokens code to fix #17 * Updated authkit.authenticate.multi so that it should fix #41 and pass the WSGI writable from start_response() correctly. * Added a form.method option so you can choose GET authentication for cases when another piece of middleware has already parsed the form variables (eg with repoze?). * Fixed bug in form action generation for non-standard ports * Fixed bug reported by Sam Gentle where remote addr is obtained from X_FORWARDED_FOR after multiple proxies. * AuthKit form authentication now picks up HTTP_X_FORWARDED_HOST and HTTP_X_FORWARDED_PORT when generating an action. This allows you to run an AuthKit app on port 80, proxied from 443 as long as you set up these two (slightly unstandard) variables. * Fixed #38, cookie sign out path should match the path specified in the config file. * Fixed #37, missing import of sys in digest authentication * Updated SQLAlchemy code to use SQLAlchemyManager. Needs installing manually with ``easy_install SQLAlchemyManager``. * Added a user management api_version attribute and changed the API so that the users object is set up on each request and recieves an environ argument. * OpenID middleware now no longer sets up beaker middleware itself. This should now be done manually in the middleware stack. See the example in examples/docs/open_id.py * OpenID support now upgraded to use 2.0 (from Dalius Dobravolskas) * Fixed encrypt typo with postgres users driver * The cookie middleware now has a nouserincookie option which forces the middleware to store the username in a Beaker session rather than in plain text in the cookie. See examples/docs/form_no_user_in_cookie.py for an example of its use. * Form authentication method now defaults to 200 OK rather than 401 when the sign in form is displayed so that it works with Safari 3 Beta. * The cookie middleware Bad Ticket page now also uses 200 OK, also to support Safari 3 Beta. * The cookie middleware bad ticket now logs to debug rather than error to avoid the ``No handlers could be found for logger "authkit.authenticate.cookie"`` message you get with a bad cookie if no error logging is specifically set up. * Added a user management api_version attribute and changed the API so that the users object is set up on each request and recieves an environ argument. * Fixed encrypt typo with postgres users driver * Renamed the config_paste option to app_conf in authenticate middleware. If you get an "No authkit.setup.method was specified" error when you are sure it is specified, this might be why. 0.4.0 * Added support for encrypted passwords * Fixed the IE7 bug in digest middleware * Adding SSO sub-directory, redirecting API, and CAS auth handler. * Fixed binding check to return none, instead of throwing an Exception (for performance reasons). * Moved start_response check outside of app_iter consumption since it must be called by this point to comply with WSGI. * Fixed consumption app iter in multi, loading entire response into ram. * Adding changelog * Added IP and Time based permission objects * Started unit tests * Extended the user management API and added SQLAlchemy driver and example * Restructured the authenticate middleware into induvidual pluggable components * Simplified the configuration file system * Added OpenID dependencies * Removed the larger SQLAlchemy based demos * The cookie module uses ``authkit`` as a default cookie name, not ``auth_tkt``. Any code which does anything manually with this cookie needs the name changing if it wasn't explicitly set to ``auth_tkt`` in the config file. 0.3.0pre5 * Changed the arguments to the authkit.authenticate.middleware() factory. You will need to update your middleware setup to use app_conf instead of config_paste for the app_conf dictionary. 0.3 * Re-written from scratch to be a modular toolkit for building your own auth framework rather than an all-in-one solution. 0.2 * Re-written from scratch so to use SQLAlchemy only, old driver system considered unnecessary and limiting. Also doesn't fit in with current Pylons best-practice. 0.1 * Based on the web.auth 0.6 module from www.pythonweb.org, support for SQLObject driver included License ======= Copyright (c) Copyright 2005-2007 James Gardner 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. Download ======== Platform: UNKNOWN AuthKit-0.4.3/AuthKit.egg-info/SOURCES.txt0000644000175000017500000000614511121727574017013 0ustar jamesjamesCHANGELOG.txt LICENSE.txt README.txt setup.cfg setup.py AuthKit.egg-info/PKG-INFO AuthKit.egg-info/SOURCES.txt AuthKit.egg-info/dependency_links.txt AuthKit.egg-info/entry_points.txt AuthKit.egg-info/not-zip-safe AuthKit.egg-info/requires.txt AuthKit.egg-info/top_level.txt authkit/__init__.py authkit/permissions.py authkit/pylons_adaptors.py authkit/authenticate/__init__.py authkit/authenticate/basic.py authkit/authenticate/cookie.py authkit/authenticate/digest.py authkit/authenticate/form.py authkit/authenticate/forward.py authkit/authenticate/multi.py authkit/authenticate/open_id.py authkit/authenticate/redirect.py authkit/authenticate/sso/__init__.py authkit/authenticate/sso/api.py authkit/authenticate/sso/cas.py authkit/authorize/__init__.py authkit/authorize/powerpack_adaptors.py authkit/authorize/pylons_adaptors.py authkit/authorize/wsgi_adaptors.py authkit/template/__init__.py authkit/template/authenticate/setup.cfg authkit/template/authenticate/setup.py_tmpl authkit/template/authenticate/+package+/__init__.py_tmpl authkit/template/authenticate/docs/license.txt_tmpl authkit/template/authenticate/ez_setup/README.txt authkit/template/authenticate/ez_setup/__init__.py authkit/users/__init__.py authkit/users/postgresql_driver.py authkit/users/sqlalchemy_04_driver.py authkit/users/sqlalchemy_driver/__init__.py authkit/users/sqlalchemy_driver/sqlalchemy_03.py authkit/users/sqlalchemy_driver/sqlalchemy_04.py authkit/users/sqlalchemy_driver/sqlalchemy_044.py authkit/users/sqlalchemy_driver/sqlalchemy_05.py docs/community.txt docs/download.txt docs/index.txt docs/manual.txt docs/pylons.txt docs/pudge_template/class.html docs/pudge_template/common.html docs/pudge_template/document.html docs/pudge_template/layout.css docs/pudge_template/layout.html docs/pudge_template/master-index.html docs/pudge_template/member.html docs/pudge_template/module-index.html docs/pudge_template/module.html docs/pudge_template/package-index.html docs/pudge_template/pudge.css docs/pudge_template/rst.css docs/pudge_template/silvercity.css docs/pudge_template/transitions.html docs/scripts/shBrushCSharp.js docs/scripts/shBrushCss.js docs/scripts/shBrushDelphi.js docs/scripts/shBrushJScript.js docs/scripts/shBrushJava.js docs/scripts/shBrushPasteIni.js docs/scripts/shBrushPhp.js docs/scripts/shBrushPython.js docs/scripts/shBrushRuby.js docs/scripts/shBrushSql.js docs/scripts/shBrushVb.js docs/scripts/shBrushXml.js docs/scripts/shCore.js docs/scripts/shCore.uncompressed.js examples/authorize.py examples/authorize2.py examples/config/digest.py examples/docs/basic.py examples/docs/digest.py examples/docs/form.py examples/docs/form2.py examples/docs/form_no_user_in_cookie.py examples/docs/forward.py examples/docs/multi.py examples/docs/multi2.py examples/docs/open_id.py examples/docs/open_id_sreg.py examples/docs/redirect.py examples/user/database/README.txt examples/user/database/app.py examples/user/database-model/README.txt examples/user/database-model/app.py examples/user/database-model/create.py examples/user/database-model/meta.py examples/user/database-model/model.py ez_setup/README.txt ez_setup/__init__.py test/test.py test/user_file_data.txtAuthKit-0.4.3/AuthKit.egg-info/not-zip-safe0000644000175000017500000000000111121727465017346 0ustar jamesjames AuthKit-0.4.3/AuthKit.egg-info/requires.txt0000644000175000017500000000054411121727574017524 0ustar jamesjamesPaste>=1.4 nose>=0.9.2 PasteDeploy>=1.1 PasteScript>=1.1 python-openid>=2.1.1 elementtree>=1.2,<=1.3 Beaker>=0.7.3 decorator>=2.1.0 WebOb>=0.9.3 [pudge] pudge==0.1.3 buildutils==dev pygments>=0.7 TurboKid==0.9.5 [full] Pylons>=0.9.5,<=1.0 SQLAlchemy>=0.4.0,<=0.4.99 pudge==0.1.3 buildutils==dev pygments>=0.7 TurboKid==0.9.5 [pylons] Pylons>=0.9.5,<=1.0AuthKit-0.4.3/AuthKit.egg-info/dependency_links.txt0000644000175000017500000000000111121727574021167 0ustar jamesjames AuthKit-0.4.3/AuthKit.egg-info/entry_points.txt0000644000175000017500000000120611121727574020416 0ustar jamesjames [authkit.method] basic=authkit.authenticate.basic:make_basic_handler digest=authkit.authenticate.digest:make_digest_handler form=authkit.authenticate.form:make_form_handler forward=authkit.authenticate.forward:make_forward_handler openid=authkit.authenticate.open_id:make_passurl_handler redirect=authkit.authenticate.redirect:make_redirect_handler cookie=authkit.authenticate.cookie:make_cookie_handler cas = authkit.authenticate.sso.cas:make_cas_handler [paste.paster_create_template] authenticate_plugin=authkit.template:AuthenticatePlugin AuthKit-0.4.3/AuthKit.egg-info/top_level.txt0000644000175000017500000000001011121727574017642 0ustar jamesjamesauthkit AuthKit-0.4.3/ez_setup/0000755000175000017500000000000011121727574013714 5ustar jamesjamesAuthKit-0.4.3/ez_setup/README.txt0000755000175000017500000000114611121727466015417 0ustar jamesjamesThis directory exists so that Subversion-based projects can share a single copy of the ``ez_setup`` bootstrap module for ``setuptools``, and have it automatically updated in their projects when ``setuptools`` is updated. For your convenience, you may use the following svn:externals definition:: ez_setup svn://svn.eby-sarna.com/svnroot/ez_setup You can set this by executing this command in your project directory:: svn propedit svn:externals . And then adding the line shown above to the file that comes up for editing. Then, whenever you update your project, ``ez_setup`` will be updated as well. AuthKit-0.4.3/ez_setup/__init__.py0000755000175000017500000002054211121727466016033 0ustar jamesjames#!python """Bootstrap setuptools installation If you want to use setuptools in your package's setup.py, just include this file in the same directory with it, and add this to the top of your setup.py:: from ez_setup import use_setuptools use_setuptools() If you want to require a specific version of setuptools, set a download mirror, or use an alternate download directory, you can do so by supplying the appropriate options to ``use_setuptools()``. This file can also be run as a script to install or upgrade setuptools. """ import sys DEFAULT_VERSION = "0.6c5" DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3] md5_data = { 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', } import sys, os def _validate_md5(egg_name, data): if egg_name in md5_data: from md5 import md5 digest = md5(data).hexdigest() if digest != md5_data[egg_name]: print >>sys.stderr, ( "md5 validation of %s failed! (Possible download problem?)" % egg_name ) sys.exit(2) return data def use_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, download_delay=15 ): """Automatically find/download setuptools and make it available on sys.path `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where setuptools will be downloaded, if it is not already available. If `download_delay` is specified, it should be the number of seconds that will be paused before initiating a download, should one be required. If an older version of setuptools is installed, this routine will print a message to ``sys.stderr`` and raise SystemExit in an attempt to abort the calling script. """ try: import setuptools if setuptools.__version__ == '0.0.1': print >>sys.stderr, ( "You have an obsolete version of setuptools installed. Please\n" "remove it from your system entirely before rerunning this script." ) sys.exit(2) except ImportError: egg = download_setuptools(version, download_base, to_dir, download_delay) sys.path.insert(0, egg) import setuptools; setuptools.bootstrap_install_from = egg import pkg_resources try: pkg_resources.require("setuptools>="+version) except pkg_resources.VersionConflict, e: # XXX could we install in a subprocess here? print >>sys.stderr, ( "The required version of setuptools (>=%s) is not available, and\n" "can't be installed while this script is running. Please install\n" " a more recent version first.\n\n(Currently using %r)" ) % (version, e.args[0]) sys.exit(2) def download_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, delay = 15 ): """Download setuptools from a specified location and return its filename `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ import urllib2, shutil egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) url = download_base + egg_name saveto = os.path.join(to_dir, egg_name) src = dst = None if not os.path.exists(saveto): # Avoid repeated downloads try: from distutils import log if delay: log.warn(""" --------------------------------------------------------------------------- This script requires setuptools version %s to run (even to display help). I will attempt to download it for you (from %s), but you may need to enable firewall access for this script first. I will start the download in %d seconds. (Note: if this machine does not have network access, please obtain the file %s and place it in this directory before rerunning this script.) ---------------------------------------------------------------------------""", version, download_base, delay, url ); from time import sleep; sleep(delay) log.warn("Downloading %s", url) src = urllib2.urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = _validate_md5(egg_name, src.read()) dst = open(saveto,"wb"); dst.write(data) finally: if src: src.close() if dst: dst.close() return os.path.realpath(saveto) def main(argv, version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" try: import setuptools except ImportError: egg = None try: egg = download_setuptools(version, delay=0) sys.path.insert(0,egg) from setuptools.command.easy_install import main return main(list(argv)+[egg]) # we're done here finally: if egg and os.path.exists(egg): os.unlink(egg) else: if setuptools.__version__ == '0.0.1': # tell the user to uninstall obsolete version use_setuptools(version) req = "setuptools>="+version import pkg_resources try: pkg_resources.require(req) except pkg_resources.VersionConflict: try: from setuptools.command.easy_install import main except ImportError: from easy_install import main main(list(argv)+[download_setuptools(delay=0)]) sys.exit(0) # try to force an exit else: if argv: from setuptools.command.easy_install import main main(argv) else: print "Setuptools version",version,"or greater has been installed." print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' def update_md5(filenames): """Update our built-in md5 registry""" import re from md5 import md5 for name in filenames: base = os.path.basename(name) f = open(name,'rb') md5_data[base] = md5(f.read()).hexdigest() f.close() data = [" %r: %r,\n" % it for it in md5_data.items()] data.sort() repl = "".join(data) import inspect srcfile = inspect.getsourcefile(sys.modules[__name__]) f = open(srcfile, 'rb'); src = f.read(); f.close() match = re.search("\nmd5_data = {\n([^}]+)}", src) if not match: print >>sys.stderr, "Internal error!" sys.exit(2) src = src[:match.start(1)] + repl + src[match.end(1):] f = open(srcfile,'w') f.write(src) f.close() if __name__=='__main__': if len(sys.argv)>2 and sys.argv[1]=='--md5update': update_md5(sys.argv[2:]) else: main(sys.argv[1:]) AuthKit-0.4.3/PKG-INFO0000644000175000017500000002615711121727574013166 0ustar jamesjamesMetadata-Version: 1.0 Name: AuthKit Version: 0.4.3 Summary: An authentication and authorization toolkit for WSGI applications and frameworks Home-page: http://authkit.org/ Author: James Gardner Author-email: james@pythonweb.org License: MIT Description: AuthKit +++++++ .. contents :: Summary ======= * Built for WSGI applications and middleware * Sophisticated and extensible permissions system * Built in support for HTTP basic, HTTP digest, form, cookie and OpenID authentication methods plus others * Easily define users, passwords and roles * Designed to be totally extensible so you can use the components to integrate with a database, LDAP connection or your own custom system * Plays nicely with the `Pylons `_ web framework There is also a `development version `_. Get Started =========== * `Download and Installation `_ * `Pylons Book `_ (the two chapters on *Authentication and Authorization* and *Advanced AuthKit* form the AuthKit 0.4 documentation) * `Module Reference `_ * `AuthKit Cookbook `_ * `Trac `_ - Tickets, Wiki, Subversion * `Examples `_ Author ====== `James Gardner `_ james at pythonweb dot org Development sponsored by `3aims `_ and `Prometheus Research `_. Changes ======= 0.4.3 * Updated authkit.authenticate.form to handle the suggest change in #61 * Added powerpack adaptors * Changed the multi middleware to return the WSGI response rather than iterating over it and yielding results. * Fixed #50 OpenID problem and tested on blogger.com * Added the ability to pass the environ dictionary to render() functions * Added bad cookie customisation options to fix #65 but also to allow bad cookie template customisation. See the docstring of the authkit.authenticate.cookie module. * Added a new algorithm based on ideas from #61 to guess the correct action for the form produced by the form middleware but also added support for an authkit.form.action option which allows you to manually override AuthKit's guess. (The OpenID middleware calls this baseurl) * Added user_set_password() methods to users API. Fixes #64. * Removed arabic letters from the form handler. Fixes #40. * Added headers to the form handling for IE. Fixes #54. * Adding SQLAlchemy 0.5 support, uses session.add() instead of session.save() * The multi handler now handles WSGI applications implemented as iterators, it already supported generators. The multi2.py example demonstrates this. * Set the pylons.status_code_redirect environment variable on all redirected AuthKit responses * Set the pylons.error_call environment variable on all redirected AuthKit responses * Trigger an error when trying to use server-side password encryption with digest authentication 0.4.2 * Applied most of #59 and tested the two OpenID examples * Added support for WebOb HTTPExceptions to remove a deprecation warning in Pylons 0.9.7 * Fixed a missing md5 import in the cookie module * Applied patch in ticket #52 0.4.1 * Added ``setup.fakeuser`` option which automatically sets the REMOTE_USER so that it appears someone has signed in. Useful with setup.enable = False ******************************************************************************** * The ``setup.enable = false`` option now also disables authorisation * * checks (reported by Rick Flosi) * ******************************************************************************** * Applied patch from Pawel Niewiadomski to fix #53 * Changed the import of the openid.sreg module to openid.extensions.sreg * Fixed the encoding of the form.py file * Updated the examples to use the latest syntax * Updated the tests for the new SQLAlchemy drivers * Added Daniel Pronych's SQLAlchemy drivers but with significant changes * Fixed a bug due to a change in the latest version of Python OpenID so that AuthKit OpenID works with Yahoo sign-ins. Phil Kershaw #50 * Updated the user/database example, it now works #43 * Updated user tokens code to fix #17 * Updated authkit.authenticate.multi so that it should fix #41 and pass the WSGI writable from start_response() correctly. * Added a form.method option so you can choose GET authentication for cases when another piece of middleware has already parsed the form variables (eg with repoze?). * Fixed bug in form action generation for non-standard ports * Fixed bug reported by Sam Gentle where remote addr is obtained from X_FORWARDED_FOR after multiple proxies. * AuthKit form authentication now picks up HTTP_X_FORWARDED_HOST and HTTP_X_FORWARDED_PORT when generating an action. This allows you to run an AuthKit app on port 80, proxied from 443 as long as you set up these two (slightly unstandard) variables. * Fixed #38, cookie sign out path should match the path specified in the config file. * Fixed #37, missing import of sys in digest authentication * Updated SQLAlchemy code to use SQLAlchemyManager. Needs installing manually with ``easy_install SQLAlchemyManager``. * Added a user management api_version attribute and changed the API so that the users object is set up on each request and recieves an environ argument. * OpenID middleware now no longer sets up beaker middleware itself. This should now be done manually in the middleware stack. See the example in examples/docs/open_id.py * OpenID support now upgraded to use 2.0 (from Dalius Dobravolskas) * Fixed encrypt typo with postgres users driver * The cookie middleware now has a nouserincookie option which forces the middleware to store the username in a Beaker session rather than in plain text in the cookie. See examples/docs/form_no_user_in_cookie.py for an example of its use. * Form authentication method now defaults to 200 OK rather than 401 when the sign in form is displayed so that it works with Safari 3 Beta. * The cookie middleware Bad Ticket page now also uses 200 OK, also to support Safari 3 Beta. * The cookie middleware bad ticket now logs to debug rather than error to avoid the ``No handlers could be found for logger "authkit.authenticate.cookie"`` message you get with a bad cookie if no error logging is specifically set up. * Added a user management api_version attribute and changed the API so that the users object is set up on each request and recieves an environ argument. * Fixed encrypt typo with postgres users driver * Renamed the config_paste option to app_conf in authenticate middleware. If you get an "No authkit.setup.method was specified" error when you are sure it is specified, this might be why. 0.4.0 * Added support for encrypted passwords * Fixed the IE7 bug in digest middleware * Adding SSO sub-directory, redirecting API, and CAS auth handler. * Fixed binding check to return none, instead of throwing an Exception (for performance reasons). * Moved start_response check outside of app_iter consumption since it must be called by this point to comply with WSGI. * Fixed consumption app iter in multi, loading entire response into ram. * Adding changelog * Added IP and Time based permission objects * Started unit tests * Extended the user management API and added SQLAlchemy driver and example * Restructured the authenticate middleware into induvidual pluggable components * Simplified the configuration file system * Added OpenID dependencies * Removed the larger SQLAlchemy based demos * The cookie module uses ``authkit`` as a default cookie name, not ``auth_tkt``. Any code which does anything manually with this cookie needs the name changing if it wasn't explicitly set to ``auth_tkt`` in the config file. 0.3.0pre5 * Changed the arguments to the authkit.authenticate.middleware() factory. You will need to update your middleware setup to use app_conf instead of config_paste for the app_conf dictionary. 0.3 * Re-written from scratch to be a modular toolkit for building your own auth framework rather than an all-in-one solution. 0.2 * Re-written from scratch so to use SQLAlchemy only, old driver system considered unnecessary and limiting. Also doesn't fit in with current Pylons best-practice. 0.1 * Based on the web.auth 0.6 module from www.pythonweb.org, support for SQLObject driver included License ======= Copyright (c) Copyright 2005-2007 James Gardner 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. Download ======== Platform: UNKNOWN AuthKit-0.4.3/docs/0000755000175000017500000000000011121727574013006 5ustar jamesjamesAuthKit-0.4.3/docs/manual.txt0000644000175000017500000000027311121727465015025 0ustar jamesjamesAuthKit Manual ++++++++++++++ The AuthKit Manual has been replaced by two chapters of the `Pylons Book `_: * Authentication and Authorization * Advanced AuthKit AuthKit-0.4.3/docs/index.txt0000644000175000017500000000252311121727465014657 0ustar jamesjamesAuthKit +++++++ .. contents :: Summary ======= * Built for WSGI applications and middleware * Sophisticated and extensible permissions system * Built in support for HTTP basic, HTTP digest, form, cookie and OpenID authentication methods plus others * Easily define users, passwords and roles * Designed to be totally extensible so you can use the components to integrate with a database, LDAP connection or your own custom system * Plays nicely with the `Pylons `_ web framework There is also a `development version `_. Get Started =========== * `Download and Installation `_ * `Pylons Book `_ (the two chapters on *Authentication and Authorization* and *Advanced AuthKit* form the AuthKit 0.4 documentation) * `Module Reference `_ * `AuthKit Cookbook `_ * `Trac `_ - Tickets, Wiki, Subversion * `Examples `_ Author ====== `James Gardner `_ james at pythonweb dot org Development sponsored by `3aims `_ and `Prometheus Research `_. AuthKit-0.4.3/docs/community.txt0000644000175000017500000000031211121727465015566 0ustar jamesjamesCommunity ========= Mailing List ------------ Currently any questions, suggestions, and patches can be directed at the `Pylons-discuss mailing list `_. AuthKit-0.4.3/docs/pudge_template/0000755000175000017500000000000011121727574016005 5ustar jamesjamesAuthKit-0.4.3/docs/pudge_template/layout.css0000644000175000017500000000014611121727465020034 0ustar jamesjames@import url("pudge.css"); @import url("silvercity.css"); /* SilverCity default.css, code coloring */ AuthKit-0.4.3/docs/pudge_template/master-index.html0000644000175000017500000000104411121727465021271 0ustar jamesjames

${index_document['title']}

${index_document['subtitle']}

${XML(index_document['fragment'])}
AuthKit-0.4.3/docs/pudge_template/layout.html0000644000175000017500000000031411121727465020205 0ustar jamesjames
${content()}
AuthKit-0.4.3/docs/pudge_template/module.html0000644000175000017500000000073011121727465020157 0ustar jamesjames
AuthKit-0.4.3/docs/pudge_template/package-index.html0000644000175000017500000000073011121727465021372 0ustar jamesjames
${module_index_table(browser.modules(recursive=0), qualified_names=1, split_packages=True)}
AuthKit-0.4.3/docs/pudge_template/class.html0000644000175000017500000000062711121727465020004 0ustar jamesjames
AuthKit-0.4.3/docs/pudge_template/document.html0000644000175000017500000000040011121727465020502 0ustar jamesjames

${XML(parts['title'])}

${XML(parts['docinfo'])} ${XML(parts['body'])}
AuthKit-0.4.3/docs/pudge_template/common.html0000644000175000017500000001021611121727465020162 0ustar jamesjames - ${XML(item.blurb(html=1))}

${XML(member.blurb(html=1))}

${member_sigil(member.type_name)} ${member.name}${member.formatargs()} ...

${member_doc(member)}

${member_sigil(member.type_name)} ${member.name}${member.formatargs()} ...

${member_doc(member)}

This class contains ${member_count} member${member_count > 1 and 's' or ''}.


${myname}
${XML(module.blurb(html=1))}

${sigil_for_type(type)} AuthKit-0.4.3/docs/pudge_template/transitions.html0000644000175000017500000000147611121727465021257 0ustar jamesjames ${name} AuthKit-0.4.3/docs/pudge_template/module-index.html0000644000175000017500000000275311121727465021273 0ustar jamesjames

Index of the ${subject.name} ${subject.type_name}

  • ${member_sigil(member.type_name)} ${full and member.qualified_name() or member.name} ... ${blurb(member)}
  • AuthKit-0.4.3/docs/pudge_template/pudge.css0000644000175000017500000000211211121727465017616 0ustar jamesjames/* Layout ----------------------------------- */ @import url("rst.css"); /* Pudge Elements ----------------------------------- */ .note { font-size: 90% } h4.pudge-member-name { font-size: 110%; margin-bottom: 0; } h4.pudge-member-name a.obj-link { font-weight: bold; text-decoration: none; } h4.pudge-member-name .prefix { font-style: oblique; padding-right: 6px; font-weight: bold; color: #c9c; } h1.pudge-member-page-heading { font-size: 250%; } h4.pudge-member-page-subheading { font-size: 150%; font-style: italic; } h4.pudge-member-page-subheading p { display: inline; } div.pudge-member { margin-top: 1.5em; margin-bottom: 1.5em; } ul.pudge-module-index { margin-left: 0; padding-left: 0; } ul.pudge-module-index ul { padding-left: 1.5em; margin-left: 0; } ul.pudge-module-index li { list-style-type: none; } ul.pudge-module-index .prefix { font-style: oblique; padding-right: 6px; font-size: 90%; font-weight: bold; color: purple; } ul.pudge-module-index a { text-decoration: none; } div.pudge-section { margin-left: 2em; }AuthKit-0.4.3/docs/pudge_template/member.html0000644000175000017500000000722411121727465020146 0ustar jamesjames

    ${heading}

    ${XML(blurb)}

    ${XML(doc)}

    AuthKit-0.4.3/docs/pudge_template/rst.css0000644000175000017500000000502111121727465017324 0ustar jamesjames/* Headings ------------------------------- */ .rst h1 { font-size: 110% } .rst h2 { font-size: 100% } /*.rst-doc h1 { font-size: 200% } .rst-doc h2 { font-size: 140% } .rst-doc h3 { font-size: 110% }*/ .rst-doc h1.title { font-size: 220% } .rst-doc h1 a, .rst-doc h2 a, .rst-doc h3 a { color: inherit ; font-weight: inherit; text-decoration: inherit; } /* Blockquotes ------------------------------- */ .rst blockquote, .rst-doc blockquote { font-style: italic; font-family: Georgia, serif; max-width: 30em; } /* Document Info ------------------------------- */ .rst-doc table.docinfo { margin: 2em 0 width: 100%; } .rst-doc table.docinfo th { text-align: left ; padding-right: 2em; color: #555; } .rst-doc table.docinfo td { text-align: left } /* Field Lists ------------------------------- */ .rst table.field-list, .rst-doc table.field-list { border: 0; margin-left: 0; } .rst table.field-list ul, .rst-doc table.field-list ul { margin-left: 0; } .rst-doc table.field-list ul { border: 0; margin-left: 2em; background: #fff; color: #119; } /* Tables ------------------------------- */ .rst table.docutils, .rst-doc table.docutils { border: 0; } .rst table.docutils th, .rst-doc table.docutils th { border: 0; background: #777; color: #fff; padding: 3px; } .rst table.docutils td, .rst-doc table.docutils td { border: 0; border-bottom: 1px solid #ccc; padding-bottom: 2px; } /* Contents and Back References ------------------------------- */ .rst-doc div.contents { margin: 2em inherit; } .rst-doc div.contents ul { margin-left: 0; padding-left: 2em; line-height: 150%; } .rst-doc div.contents ul li { font-weight: bold; list-style-type: none; } .rst-doc div.contents p.topic-title { font-size: 160%; font-weight: normal; color: #555; margin-top: .5em; } .rst-doc .contents .reference, .rst-doc .toc-backref { text-decoration: none; } /* Admonitions ------------------------------- */ .rst-doc div.admonition, .rst-doc div.warning, .rst-doc div.note { margin: 2.5em 6em; padding: .6em 2.5em; background: #ddf; border: 2px solid #ccc; font-family: Georgia, serif; color: #333; } .rst-doc div.warning { background: #ff8; border-color: #fe2; } .rst-doc div .admonition-title { font-weight: bold; font-style: italic; color: #223; font-size: 110%; font-family: sans-serif; } /* Misc ------------------------------- */ tt.literal { color: #333; } .footnote-reference { vertical-align: super; font-size: 20%; }AuthKit-0.4.3/docs/pudge_template/silvercity.css0000644000175000017500000000774411121727465020727 0ustar jamesjames .code_default { FONT-FAMILY: "Courier New", Courier, monospace; FONT-SIZE: 10pt; } .css_class { color: #900000; } .css_comment { color: green; font-style: italic; } .css_default { } .css_directive { color: #009000; font-weight: bold; } .css_doublestring { color: navy; } .css_id { color: #900000; } .css_identifier { color: black; } .css_important { color: blue; } .css_operator { color: #000090; font-weight: bold; } .css_pseudoclass { color: #900000; } .css_singlestring { color: navy; } .css_tag { color: #900000; font-weight: bold; } .css_unknown_identifier { color: red; } .css_unknown_pseudoclass { color: #ff0000; } .css_value { color: navy; } .c_character { color: olive; } .c_comment { color: green; font-style: italic; } .c_commentdoc { color: green; font-style: italic; } .c_commentdockeyword { color: navy; font-weight: bold; } .c_commentdockeyworderror { color: red; font-weight: bold; } .c_commentline { color: green; font-style: italic; } .c_commentlinedoc { color: green; font-style: italic; } .c_default { } .c_identifier { color: black; } .c_number { color: #009999; } .c_operator { color: black; } .c_preprocessor { color: navy; font-weight: bold; } .c_regex { color: olive; } .c_string { color: olive; } .c_stringeol { color: olive; } .c_uuid { color: olive; } .c_verbatim { color: olive; } .c_word { color: navy; font-weight: bold; } .c_word2 { color: navy; font-weight: bold; } .h_asp { color: #ffff00; } .h_aspat { color: #ffdf00; } .h_attribute { color: #008080; } .h_attributeunknown { color: #ff0000; } .h_cdata { color: #ffdf00; } .h_comment { color: #808000; } .h_default { } .h_doublestring { color: olive; } .h_entity { color: #800080; } .h_number { color: #009999; } .h_other { color: #800080; } .h_script { color: #000080; } .h_singlestring { color: olive; } .h_tag { color: #000080; } .h_tagend { color: #000080; } .h_tagunknown { color: #ff0000; } .h_xmlend { color: #0000ff; } .h_xmlstart { color: #0000ff; } .pl_array { color: black; } .pl_backticks { color: olive; } .pl_character { color: olive; } .pl_commentline { color: green; font-style: italic; } .pl_datasection { color: olive; } .pl_default { } .pl_error { color: red; font-style: bold; } .pl_hash { color: black; } .pl_here_delim { color: olive; } .pl_here_q { color: olive; } .pl_here_qq { color: olive; } .pl_here_qx { color: olive; } .pl_identifier { color: black; } .pl_longquote { color: olive; } .pl_number { color: #009999; } .pl_operator { color: black; } .pl_pod { color: black; font-style: italic; } .pl_preprocessor { color: navy; font-weight: bold; } .pl_punctuation { color: black; } .pl_regex { color: olive; } .pl_regsubst { color: olive; } .pl_scalar { color: black; } .pl_string { color: olive; } .pl_string_q { color: olive; } .pl_string_qq { color: olive; } .pl_string_qr { color: olive; } .pl_string_qw { color: olive; } .pl_string_qx { color: olive; } .pl_symboltable { color: black; } .pl_word { color: navy; font-weight: bold; } .p_character { color: olive; } .p_classname { color: blue; font-weight: bold; } .p_commentblock { color: gray; font-style: italic; } .p_commentline { color: green; font-style: italic; } .p_default { } .p_defname { color: #009999; font-weight: bold; } .p_identifier { color: black; } .p_number { color: #009999; } .p_operator { color: black; } .p_string { color: olive; } .p_stringeol { color: olive; } .p_triple { color: olive; } .p_tripledouble { color: olive; } .p_word { color: navy; font-weight: bold; } .yaml_comment { color: #008800; font-style: italic; } .yaml_default { } .yaml_document { color: #808080; font-style: italic; } .yaml_identifier { color: navy; font-weight: bold; } .yaml_keyword { color: #880088; } .yaml_number { color: #880000; } .yaml_reference { color: #008888; } AuthKit-0.4.3/docs/download.txt0000644000175000017500000000210111121727465015347 0ustar jamesjamesDownload ======== Latest Release -------------- The latest release and installation instructions are available from http://python.org/pypi/AuthKit Development Version ------------------- You can checkout the latest AuthKit code from the svn repository with:: svn co http://authkit.org/svn/AuthKit/trunk AuthKit or browse the source online at http://authkit.org/trac/browser/AuthKit/trunk Creating a Release ------------------ .. Note :: This is intended for developers only. #. Make sure the ``setup.cfg`` file is set not use the dev version. #. Ensure the version number is correct in ``setup.py`` and that any dependencies have the correct version numbers. #. Check in the final release. #. Export a copy of trunk. #. Check in the exported trunk (together with the ``ez_setup`` directory in its current state) as a tag. #. Using the exported files create all the required distributions, register the package and upload the files. #. Change the ``setup.cfg`` file back to use ``dev`` in the main trunk. #. Increment the version number. #. Check in the changes. AuthKit-0.4.3/docs/scripts/0000755000175000017500000000000011121727574014475 5ustar jamesjamesAuthKit-0.4.3/docs/scripts/shCore.uncompressed.js0000644000175000017500000004056411121727465020774 0ustar jamesjames/** * Code Syntax Highlighter. * Version 1.3.0 * Copyright (C) 2004 Alex Gorbatchev. * http://www.dreamprojections.com/syntaxhighlighter/ * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // // create namespaces // var dp = { sh : { Toolbar : {}, Utils : {}, RegexLib: {}, Brushes : {}, Strings : {}, Version : '1.4.0' } }; dp.sh.Strings = { AboutDialog : 'About...

    dp.SyntaxHighlighter

    Version: {V}

    http://www.dreamprojections.com/SyntaxHighlighter

    ©2004-2005 Alex Gorbatchev. All right reserved.
    ' }; dp.SyntaxHighlighter = dp.sh; // // Toolbar functions // dp.sh.Toolbar.Commands = { ExpandSource: { label: '+ expand source', check: function(highlighter) { return highlighter.collapse; }, func: function(sender, highlighter) { sender.parentNode.removeChild(sender); highlighter.div.className = highlighter.div.className.replace('collapsed', ''); } }, // opens a new windows and puts the original unformatted source code inside. ViewSource: { label: 'view plain', func: function(sender, highlighter) { var code = highlighter.originalCode.replace(/' + code + ''); wnd.document.close(); } }, // copies the original source code in to the clipboard (IE only) CopyToClipboard: { label: 'copy to clipboard', check: function() { return window.clipboardData != null; }, func: function(sender, highlighter) { window.clipboardData.setData('text', highlighter.originalCode); alert('The code is in your clipboard now'); } }, // creates an invisible iframe, puts the original source code inside and prints it PrintSource: { label: 'print', func: function(sender, highlighter) { var iframe = document.createElement('IFRAME'); var doc = null; // this hides the iframe iframe.style.cssText = 'position:absolute;width:0px;height:0px;left:-500px;top:-500px;'; document.body.appendChild(iframe); doc = iframe.contentWindow.document; dp.sh.Utils.CopyStyles(doc, window.document); doc.write('
    ' + highlighter.div.innerHTML + '
    '); doc.close(); iframe.contentWindow.focus(); iframe.contentWindow.print(); alert('Printing...'); document.body.removeChild(iframe); } }, About: { label: '?', func: function(highlighter) { var wnd = window.open('', '_blank', 'dialog,width=300,height=150,scrollbars=0'); var doc = wnd.document; dp.sh.Utils.CopyStyles(doc, window.document); doc.write(dp.sh.Strings.AboutDialog.replace('{V}', dp.sh.Version)); doc.close(); wnd.focus(); } } }; // creates a
    with all toolbar links dp.sh.Toolbar.Create = function(highlighter) { var div = document.createElement('DIV'); div.className = 'tools'; for(var name in dp.sh.Toolbar.Commands) { var cmd = dp.sh.Toolbar.Commands[name]; if(cmd.check != null && !cmd.check(highlighter)) continue; div.innerHTML += '' + cmd.label + ''; } return div; } // executes toolbar command by name dp.sh.Toolbar.Command = function(name, sender) { var n = sender; while(n != null && n.className.indexOf('dp-highlighter') == -1) n = n.parentNode; if(n != null) dp.sh.Toolbar.Commands[name].func(sender, n.highlighter); } // copies all from 'target' window to 'dest' dp.sh.Utils.CopyStyles = function(destDoc, sourceDoc) { var links = sourceDoc.getElementsByTagName('link'); for(var i = 0; i < links.length; i++) if(links[i].rel.toLowerCase() == 'stylesheet') destDoc.write(''); } // // Common reusable regular expressions // dp.sh.RegexLib = { MultiLineCComments : new RegExp('/\\*[\\s\\S]*?\\*/', 'gm'), SingleLineCComments : new RegExp('//.*$', 'gm'), SingleLinePerlComments : new RegExp('#.*$', 'gm'), DoubleQuotedString : new RegExp('"(?:\\.|(\\\\\\")|[^\\""])*"','g'), SingleQuotedString : new RegExp("'(?:\\.|(\\\\\\')|[^\\''])*'", 'g') }; // // Match object // dp.sh.Match = function(value, index, css) { this.value = value; this.index = index; this.length = value.length; this.css = css; } // // Highlighter object // dp.sh.Highlighter = function() { this.addGutter = true; this.addControls = true; this.collapse = false; this.tabsToSpaces = true; this.wrapColumn = 80; this.showColumns = true; } // static callback for the match sorting dp.sh.Highlighter.SortCallback = function(m1, m2) { // sort matches by index first if(m1.index < m2.index) return -1; else if(m1.index > m2.index) return 1; else { // if index is the same, sort by length if(m1.length < m2.length) return -1; else if(m1.length > m2.length) return 1; } return 0; } dp.sh.Highlighter.prototype.CreateElement = function(name) { var result = document.createElement(name); result.highlighter = this; return result; } // gets a list of all matches for a given regular expression dp.sh.Highlighter.prototype.GetMatches = function(regex, css) { var index = 0; var match = null; while((match = regex.exec(this.code)) != null) this.matches[this.matches.length] = new dp.sh.Match(match[0], match.index, css); } dp.sh.Highlighter.prototype.AddBit = function(str, css) { if(str == null || str.length == 0) return; var span = this.CreateElement('SPAN'); str = str.replace(/&/g, '&'); str = str.replace(/ /g, ' '); str = str.replace(/'); // when adding a piece of code, check to see if it has line breaks in it // and if it does, wrap individual line breaks with span tags if(css != null) { var regex = new RegExp('
    ', 'gi'); if(regex.test(str)) { var lines = str.split(' 
    '); str = ''; for(var i = 0; i < lines.length; i++) { span = this.CreateElement('SPAN'); span.className = css; span.innerHTML = lines[i]; this.div.appendChild(span); // don't add a
    for the last line if(i + 1 < lines.length) this.div.appendChild(this.CreateElement('BR')); } } else { span.className = css; span.innerHTML = str; this.div.appendChild(span); } } else { span.innerHTML = str; this.div.appendChild(span); } } // checks if one match is inside any other match dp.sh.Highlighter.prototype.IsInside = function(match) { if(match == null || match.length == 0) return false; for(var i = 0; i < this.matches.length; i++) { var c = this.matches[i]; if(c == null) continue; if((match.index > c.index) && (match.index < c.index + c.length)) return true; } return false; } dp.sh.Highlighter.prototype.ProcessRegexList = function() { for(var i = 0; i < this.regexList.length; i++) this.GetMatches(this.regexList[i].regex, this.regexList[i].css); } dp.sh.Highlighter.prototype.ProcessSmartTabs = function(code) { var lines = code.split('\n'); var result = ''; var tabSize = 4; var tab = '\t'; // This function inserts specified amount of spaces in the string // where a tab is while removing that given tab. function InsertSpaces(line, pos, count) { var left = line.substr(0, pos); var right = line.substr(pos + 1, line.length); // pos + 1 will get rid of the tab var spaces = ''; for(var i = 0; i < count; i++) spaces += ' '; return left + spaces + right; } // This function process one line for 'smart tabs' function ProcessLine(line, tabSize) { if(line.indexOf(tab) == -1) return line; var pos = 0; while((pos = line.indexOf(tab)) != -1) { // This is pretty much all there is to the 'smart tabs' logic. // Based on the position within the line and size of a tab, // calculate the amount of spaces we need to insert. var spaces = tabSize - pos % tabSize; line = InsertSpaces(line, pos, spaces); } return line; } // Go through all the lines and do the 'smart tabs' magic. for(var i = 0; i < lines.length; i++) result += ProcessLine(lines[i], tabSize) + '\n'; return result; } dp.sh.Highlighter.prototype.SwitchToList = function() { // thanks to Lachlan Donald from SitePoint.com for this
    tag fix. var html = this.div.innerHTML.replace(/<(br)\/?>/gi, '\n'); var lines = html.split('\n'); if(this.addControls == true) this.bar.appendChild(dp.sh.Toolbar.Create(this)); // add columns ruler if(this.showColumns) { var div = this.CreateElement('div'); var columns = this.CreateElement('div'); var showEvery = 10; var i = 1; while(i <= 150) { if(i % showEvery == 0) { div.innerHTML += i; i += (i + '').length; } else { div.innerHTML += '·'; i++; } } columns.className = 'columns'; columns.appendChild(div); this.bar.appendChild(columns); } for(var i = 0, lineIndex = this.firstLine; i < lines.length - 1; i++, lineIndex++) { var li = this.CreateElement('LI'); var span = this.CreateElement('SPAN'); // uses .line1 and .line2 css styles for alternating lines li.className = (i % 2 == 0) ? 'alt' : ''; span.innerHTML = lines[i] + ' '; li.appendChild(span); this.ol.appendChild(li); } this.div.innerHTML = ''; } dp.sh.Highlighter.prototype.Highlight = function(code) { function Trim(str) { return str.replace(/^\s*(.*?)[\s\n]*$/g, '$1'); } function Chop(str) { return str.replace(/\n*$/, '').replace(/^\n*/, ''); } function Unindent(str) { var lines = str.split('\n'); var indents = new Array(); var regex = new RegExp('^\\s*', 'g'); var min = 1000; // go through every line and check for common number of indents for(var i = 0; i < lines.length && min > 0; i++) { if(Trim(lines[i]).length == 0) continue; var matches = regex.exec(lines[i]); if(matches != null && matches.length > 0) min = Math.min(matches[0].length, min); } // trim minimum common number of white space from the begining of every line if(min > 0) for(var i = 0; i < lines.length; i++) lines[i] = lines[i].substr(min); return lines.join('\n'); } // This function returns a portions of the string from pos1 to pos2 inclusive function Copy(string, pos1, pos2) { return string.substr(pos1, pos2 - pos1); } var pos = 0; this.originalCode = code; this.code = Chop(Unindent(code)); this.div = this.CreateElement('DIV'); this.bar = this.CreateElement('DIV'); this.ol = this.CreateElement('OL'); this.matches = new Array(); this.div.className = 'dp-highlighter'; this.div.highlighter = this; this.bar.className = 'bar'; // set the first line this.ol.start = this.firstLine; if(this.CssClass != null) this.ol.className = this.CssClass; if(this.collapse) this.div.className += ' collapsed'; // replace tabs with spaces if(this.tabsToSpaces == true) this.code = this.ProcessSmartTabs(this.code); this.ProcessRegexList(); // if no matches found, add entire code as plain text if(this.matches.length == 0) { this.AddBit(this.code, null); this.SwitchToList(); this.div.appendChild(this.ol); return; } // sort the matches this.matches = this.matches.sort(dp.sh.Highlighter.SortCallback); // The following loop checks to see if any of the matches are inside // of other matches. This process would get rid of highligted strings // inside comments, keywords inside strings and so on. for(var i = 0; i < this.matches.length; i++) if(this.IsInside(this.matches[i])) this.matches[i] = null; // Finally, go through the final list of matches and pull the all // together adding everything in between that isn't a match. for(var i = 0; i < this.matches.length; i++) { var match = this.matches[i]; if(match == null || match.length == 0) continue; this.AddBit(Copy(this.code, pos, match.index), null); this.AddBit(match.value, match.css); pos = match.index + match.length; } this.AddBit(this.code.substr(pos), null); this.SwitchToList(); this.div.appendChild(this.bar); this.div.appendChild(this.ol); } dp.sh.Highlighter.prototype.GetKeywords = function(str) { return '\\b' + str.replace(/ /g, '\\b|\\b') + '\\b'; } // highlightes all elements identified by name and gets source code from specified property dp.sh.HighlightAll = function(name, showGutter /* optional */, showControls /* optional */, collapseAll /* optional */, firstLine /* optional */, showColumns /* optional */) { function FindValue() { var a = arguments; for(var i = 0; i < a.length; i++) { if(a[i] == null) continue; if(typeof(a[i]) == 'string' && a[i] != '') return a[i] + ''; if(typeof(a[i]) == 'object' && a[i].value != '') return a[i].value + ''; } return null; } function IsOptionSet(value, list) { for(var i = 0; i < list.length; i++) if(list[i] == value) return true; return false; } function GetOptionValue(name, list, defaultValue) { var regex = new RegExp('^' + name + '\\[(\\w+)\\]$', 'gi'); var matches = null; for(var i = 0; i < list.length; i++) if((matches = regex.exec(list[i])) != null) return matches[1]; return defaultValue; } var elements = document.getElementsByName(name); var highlighter = null; var registered = new Object(); var propertyName = 'value'; // if no code blocks found, leave if(elements == null) return; // register all brushes for(var brush in dp.sh.Brushes) { var aliases = dp.sh.Brushes[brush].Aliases; if(aliases == null) continue; for(var i = 0; i < aliases.length; i++) registered[aliases[i]] = brush; } for(var i = 0; i < elements.length; i++) { var element = elements[i]; var options = FindValue( element.attributes['class'], element.className, element.attributes['language'], element.language ); var language = ''; if(options == null) continue; options = options.split(':'); language = options[0].toLowerCase(); if(registered[language] == null) continue; // instantiate a brush highlighter = new dp.sh.Brushes[registered[language]](); // hide the original element element.style.display = 'none'; highlighter.addGutter = (showGutter == null) ? !IsOptionSet('nogutter', options) : showGutter; highlighter.addControls = (showControls == null) ? !IsOptionSet('nocontrols', options) : showControls; highlighter.collapse = (collapseAll == null) ? IsOptionSet('collapse', options) : collapseAll; highlighter.showColumns = (showColumns == null) ? IsOptionSet('showcolumns', options) : showColumns; // first line idea comes from Andrew Collington, thanks! highlighter.firstLine = (firstLine == null) ? parseInt(GetOptionValue('firstline', options, 1)) : firstLine; highlighter.Highlight(element[propertyName]); element.parentNode.insertBefore(highlighter.div, element); } } AuthKit-0.4.3/docs/scripts/shBrushRuby.js0000644000175000017500000000267011121727465017317 0ustar jamesjames/* Ruby 1.8.4 syntax contributed by Erik Peterson */ dp.sh.Brushes.Ruby = function() { var keywords = 'alias and BEGIN begin break case class def define_method defined do each else elsif ' + 'END end ensure false for if in module new next nil not or raise redo rescue retry return ' + 'self super then throw true undef unless until when while yield'; var builtins = 'Array Bignum Binding Class Continuation Dir Exception FalseClass File::Stat File Fixnum Fload ' + 'Hash Integer IO MatchData Method Module NilClass Numeric Object Proc Range Regexp String Struct::TMS Symbol ' + 'ThreadGroup Thread Time TrueClass' this.regexList = [ { regex: dp.sh.RegexLib.SingleLinePerlComments, css: 'comment' }, // one line comments { regex: dp.sh.RegexLib.DoubleQuotedString, css: 'string' }, // double quoted strings { regex: dp.sh.RegexLib.SingleQuotedString, css: 'string' }, // single quoted strings { regex: new RegExp(':[a-z][A-Za-z0-9_]*', 'g'), css: 'symbol' }, // symbols { regex: new RegExp('[\\$|@|@@]\\w+', 'g'), css: 'variable' }, // $global, @instance, and @@class variables { regex: new RegExp(this.GetKeywords(keywords), 'gm'), css: 'keyword' }, // keywords { regex: new RegExp(this.GetKeywords(builtins), 'gm'), css: 'builtin' } // builtins ]; this.CssClass = 'dp-rb'; } dp.sh.Brushes.Ruby.prototype = new dp.sh.Highlighter(); dp.sh.Brushes.Ruby.Aliases = ['ruby', 'rails']; AuthKit-0.4.3/docs/scripts/shBrushPasteIni.js0000644000175000017500000000104411121727465020104 0ustar jamesjamesdp.sh.Brushes.PasteIni = function() { this.regexList = [ { regex: new RegExp('^#.*', 'gm'), css: 'comment' }, { regex: new RegExp('^\\[.*\\]$', 'gm'), css: 'header' }, { regex: new RegExp('^use\ =\ (\\w|:)*', 'gm'), css: 'use' }, { regex: new RegExp('\%\\(\\w+\\)s', 'gm'), css: 'interp-variable' }, { regex: new RegExp('\\${\\w+}', 'gm'), css: 'variable' } ]; this.CssClass = 'dp-paste-ini'; } dp.sh.Brushes.PasteIni.prototype = new dp.sh.Highlighter(); dp.sh.Brushes.PasteIni.Aliases = ['pasteini']; AuthKit-0.4.3/docs/scripts/shBrushXml.js0000644000175000017500000000355311121727465017137 0ustar jamesjamesdp.sh.Brushes.Xml = function() { this.CssClass = 'dp-xml'; } dp.sh.Brushes.Xml.prototype = new dp.sh.Highlighter(); dp.sh.Brushes.Xml.Aliases = ['xml', 'xhtml', 'xslt', 'html', 'xhtml']; dp.sh.Brushes.Xml.prototype.ProcessRegexList = function() { function push(array, value) { array[array.length] = value; } /* If only there was a way to get index of a group within a match, the whole XML could be matched with the expression looking something like that: () | () | (<)*(\w+)*\s*(\w+)\s*=\s*(".*?"|'.*?'|\w+)(/*>)* | () */ var index = 0; var match = null; var regex = null; // Match CDATA in the following format // <\!\[[\w\s]*?\[(.|\s)*?\]\]> this.GetMatches(new RegExp('<\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\]>', 'gm'), 'cdata'); // Match comments // this.GetMatches(new RegExp('', 'gm'), 'comments'); // Match attributes and their values // (\w+)\s*=\s*(".*?"|\'.*?\'|\w+)* regex = new RegExp('([\\w-\.]+)\\s*=\\s*(".*?"|\'.*?\'|\\w+)*', 'gm'); while((match = regex.exec(this.code)) != null) { push(this.matches, new dp.sh.Match(match[1], match.index, 'attribute')); // if xml is invalid and attribute has no property value, ignore it if(match[2] != undefined) { push(this.matches, new dp.sh.Match(match[2], match.index + match[0].indexOf(match[2]), 'attribute-value')); } } // Match opening and closing tag brackets // this.GetMatches(new RegExp('', 'gm'), 'tag'); // Match tag names // About...

    dp.SyntaxHighlighter

    Version: {V}

    http://www.dreamprojections.com/SyntaxHighlighter

    ©2004-2005 Alex Gorbatchev. All right reserved.
    "};dp.SyntaxHighlighter=dp.sh;dp.sh.Toolbar.Commands={ExpandSource:{label:"+ expand source",check:function(_1){return _1.collapse;},func:function(_2,_3){_2.parentNode.removeChild(_2);_3.div.className=_3.div.className.replace("collapsed","");}},ViewSource:{label:"view plain",func:function(_4,_5){var _6=_5.originalCode.replace(/"+_6+"");_7.document.close();}},CopyToClipboard:{label:"copy to clipboard",check:function(){return window.clipboardData!=null;},func:function(_8,_9){window.clipboardData.setData("text",_9.originalCode);alert("The code is in your clipboard now");}},PrintSource:{label:"print",func:function(_a,_b){var _c=document.createElement("IFRAME");var _d=null;_c.style.cssText="position:absolute;width:0px;height:0px;left:-500px;top:-500px;";document.body.appendChild(_c);_d=_c.contentWindow.document;dp.sh.Utils.CopyStyles(_d,window.document);_d.write("
    "+_b.div.innerHTML+"
    ");_d.close();_c.contentWindow.focus();_c.contentWindow.print();alert("Printing...");document.body.removeChild(_c);}},About:{label:"?",func:function(_e){var _f=window.open("","_blank","dialog,width=300,height=150,scrollbars=0");var doc=_f.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write(dp.sh.Strings.AboutDialog.replace("{V}",dp.sh.Version));doc.close();_f.focus();}}};dp.sh.Toolbar.Create=function(_11){var div=document.createElement("DIV");div.className="tools";for(var _13 in dp.sh.Toolbar.Commands){var cmd=dp.sh.Toolbar.Commands[_13];if(cmd.check!=null&&!cmd.check(_11)){continue;}div.innerHTML+=""+cmd.label+"";}return div;};dp.sh.Toolbar.Command=function(_15,_16){var n=_16;while(n!=null&&n.className.indexOf("dp-highlighter")==-1){n=n.parentNode;}if(n!=null){dp.sh.Toolbar.Commands[_15].func(_16,n.highlighter);}};dp.sh.Utils.CopyStyles=function(_18,_19){var _1a=_19.getElementsByTagName("link");for(var i=0;i<_1a.length;i++){if(_1a[i].rel.toLowerCase()=="stylesheet"){_18.write("");}}};dp.sh.RegexLib={MultiLineCComments:new RegExp("/\\*[\\s\\S]*?\\*/","gm"),SingleLineCComments:new RegExp("//.*$","gm"),SingleLinePerlComments:new RegExp("#.*$","gm"),DoubleQuotedString:new RegExp("\"(?:\\.|(\\\\\\\")|[^\\\"\"])*\"","g"),SingleQuotedString:new RegExp("'(?:\\.|(\\\\\\')|[^\\''])*'","g")};dp.sh.Match=function(_1c,_1d,css){this.value=_1c;this.index=_1d;this.length=_1c.length;this.css=css;};dp.sh.Highlighter=function(){this.addGutter=true;this.addControls=true;this.collapse=false;this.tabsToSpaces=true;this.wrapColumn=80;this.showColumns=true;};dp.sh.Highlighter.SortCallback=function(m1,m2){if(m1.indexm2.index){return 1;}else{if(m1.lengthm2.length){return 1;}}}}return 0;};dp.sh.Highlighter.prototype.CreateElement=function(_21){var _22=document.createElement(_21);_22.highlighter=this;return _22;};dp.sh.Highlighter.prototype.GetMatches=function(_23,css){var _25=0;var _26=null;while((_26=_23.exec(this.code))!=null){this.matches[this.matches.length]=new dp.sh.Match(_26[0],_26.index,css);}};dp.sh.Highlighter.prototype.AddBit=function(str,css){if(str==null||str.length==0){return;}var _29=this.CreateElement("SPAN");str=str.replace(/&/g,"&");str=str.replace(/ /g," ");str=str.replace(/");if(css!=null){var _2a=new RegExp("
    ","gi");if(_2a.test(str)){var _2b=str.split(" 
    ");str="";for(var i=0;i<_2b.length;i++){_29=this.CreateElement("SPAN");_29.className=css;_29.innerHTML=_2b[i];this.div.appendChild(_29);if(i+1<_2b.length){this.div.appendChild(this.CreateElement("BR"));}}}else{_29.className=css;_29.innerHTML=str;this.div.appendChild(_29);}}else{_29.innerHTML=str;this.div.appendChild(_29);}};dp.sh.Highlighter.prototype.IsInside=function(_2d){if(_2d==null||_2d.length==0){return false;}for(var i=0;ic.index)&&(_2d.index/gi,"\n");var _43=_42.split("\n");if(this.addControls==true){this.bar.appendChild(dp.sh.Toolbar.Create(this));}if(this.showColumns){var div=this.CreateElement("div");var _45=this.CreateElement("div");var _46=10;var i=1;while(i<=150){if(i%_46==0){div.innerHTML+=i;i+=(i+"").length;}else{div.innerHTML+="·";i++;}}_45.className="columns";_45.appendChild(div);this.bar.appendChild(_45);}for(var i=0,lineIndex=this.firstLine;i<_43.length-1;i++,lineIndex++){var li=this.CreateElement("LI");var _4a=this.CreateElement("SPAN");li.className=(i%2==0)?"alt":"";_4a.innerHTML=_43[i]+" ";li.appendChild(_4a);this.ol.appendChild(li);}this.div.innerHTML="";};dp.sh.Highlighter.prototype.Highlight=function(_4b){function Trim(str){return str.replace(/^\s*(.*?)[\s\n]*$/g,"$1");}function Chop(str){return str.replace(/\n*$/,"").replace(/^\n*/,"");}function Unindent(str){var _4f=str.split("\n");var _50=new Array();var _51=new RegExp("^\\s*","g");var min=1000;for(var i=0;i<_4f.length&&min>0;i++){if(Trim(_4f[i]).length==0){continue;}var _54=_51.exec(_4f[i]);if(_54!=null&&_54.length>0){min=Math.min(_54[0].length,min);}}if(min>0){for(var i=0;i<_4f.length;i++){_4f[i]=_4f[i].substr(min);}}return _4f.join("\n");}function Copy(_56,_57,_58){return _56.substr(_57,_58-_57);}var pos=0;this.originalCode=_4b;this.code=Chop(Unindent(_4b));this.div=this.CreateElement("DIV");this.bar=this.CreateElement("DIV");this.ol=this.CreateElement("OL");this.matches=new Array();this.div.className="dp-highlighter";this.div.highlighter=this;this.bar.className="bar";this.ol.start=this.firstLine;if(this.CssClass!=null){this.ol.className=this.CssClass;}if(this.collapse){this.div.className+=" collapsed";}if(this.tabsToSpaces==true){this.code=this.ProcessSmartTabs(this.code);}this.ProcessRegexList();if(this.matches.length==0){this.AddBit(this.code,null);this.SwitchToList();this.div.appendChild(this.ol);return;}this.matches=this.matches.sort(dp.sh.Highlighter.SortCallback);for(var i=0;i