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 | """ |
---|
6 | Authentication via Multiple Methods |
---|
7 | |
---|
8 | In some environments, the choice of authentication method to be used |
---|
9 | depends upon the environment and is not "fixed". This middleware allows |
---|
10 | N authentication methods to be registered along with a goodness function |
---|
11 | which determines which method should be used. The following example |
---|
12 | demonstrates how to use both form and digest authentication in a server |
---|
13 | stack; 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)) |
---|
31 | serving on... |
---|
32 | |
---|
33 | """ |
---|
34 | |
---|
35 | class 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 | |
---|
72 | middleware = MultiHandler |
---|
73 | |
---|
74 | __all__ = ['MultiHandler'] |
---|
75 | |
---|
76 | if "__main__" == __name__: |
---|
77 | import doctest |
---|
78 | doctest.testmod(optionflags=doctest.ELLIPSIS) |
---|
79 | |
---|