1# (c) 2005 Clark C. Evans 2# This module is part of the Python Paste Project and is released under 3# the MIT License: http://www.opensource.org/licenses/mit-license.php 4# This code was written with funding by http://prometheusresearch.com 5""" 6Authentication via Multiple Methods 7 8In some environments, the choice of authentication method to be used 9depends upon the environment and is not "fixed". This middleware allows 10N authentication methods to be registered along with a goodness function 11which determines which method should be used. The following example 12demonstrates how to use both form and digest authentication in a server 13stack; by default it uses form-based authentication unless 14``*authmeth=digest`` is specified as a query argument. 15 16>>> from paste.auth import form, cookie, digest, multi 17>>> from paste.wsgilib import dump_environ 18>>> from paste.httpserver import serve 19>>> 20>>> multi = multi.MultiHandler(dump_environ) 21>>> def authfunc(environ, realm, user): 22... return digest.digest_password(realm, user, user) 23>>> multi.add_method('digest', digest.middleware, "Test Realm", authfunc) 24>>> multi.set_query_argument('digest') 25>>> 26>>> def authfunc(environ, username, password): 27... return username == password 28>>> multi.add_method('form', form.middleware, authfunc) 29>>> multi.set_default('form') 30>>> serve(cookie.middleware(multi)) 31serving on... 32 33""" 34 35class MultiHandler(object): 36 """ 37 Multiple Authentication Handler 38 39 This middleware provides two othogonal facilities: 40 41 - a manner to register any number of authentication middlewares 42 43 - a mechanism to register predicates which cause one of the 44 registered middlewares to be used depending upon the request 45 46 If none of the predicates returns True, then the application is 47 invoked directly without middleware 48 """ 49 def __init__(self, application): 50 self.application = application 51 self.default = application 52 self.binding = {} 53 self.predicate = [] 54 def add_method(self, name, factory, *args, **kwargs): 55 self.binding[name] = factory(self.application, *args, **kwargs) 56 def add_predicate(self, name, checker): 57 self.predicate.append((checker, self.binding[name])) 58 def set_default(self, name): 59 """ set default authentication method """ 60 self.default = self.binding[name] 61 def set_query_argument(self, name, key = '*authmeth', value = None): 62 """ choose authentication method based on a query argument """ 63 lookfor = "%s=%s" % (key, value or name) 64 self.add_predicate(name, 65 lambda environ: lookfor in environ.get('QUERY_STRING','')) 66 def __call__(self, environ, start_response): 67 for (checker, binding) in self.predicate: 68 if checker(environ): 69 return binding(environ, start_response) 70 return self.default(environ, start_response) 71 72middleware = MultiHandler 73 74__all__ = ['MultiHandler'] 75 76if "__main__" == __name__: 77 import doctest 78 doctest.testmod(optionflags=doctest.ELLIPSIS) 79 80