The publisher handler provides simple ways to control access to modules and functions.
At every traversal step, the Publisher handler checks for presence of __auth__ and __access__ attributes (in this order), as well as __auth_realm__ attribute.
If __auth__ is found and it is callable, it will be called
with three arguments: the Request object, a string containing
the user name and a string containing the password. If the return
value of
__auth__
is false, then HTTP_UNAUTHORIZED is
returned to the client (which will usually cause a password dialog box
to appear).
If __auth__ is a dictionary, then the user name will be matched against the key and the password against the value associated with this key. If the key and password do not match, HTTP_UNAUTHORIZED is returned. Note that this requires storing passwords as clear text in source code, which is not very secure.
__auth__ can also be a constant. In this case, if it is false
(i.e. None, 0
, ""
, etc.), then
HTTP_UNAUTHORIZED is returned.
If there exists an __auth_realm__
string, it will be sent
to the client as Authorization Realm (this is the text that usually
appears at the top of the password dialog box).
If __access__ is found and it is callable, it will be called
with two arguments: the Request object and a string containing
the user name. If the return value of __access__
is false, then
HTTP_FORBIDDEN is returned to the client.
If __access__ is a list, then the user name will be matched against the list elements. If the user name is not in the list, HTTP_FORBIDDEN is returned.
Similarly to __auth__, __access__ can be a constant.
In the example below, only user "eggs" with password "spam" can access
the hello
function:
__auth_realm__ = "Members only" def __auth__(req, user, passwd): if user == "eggs" and passwd == "spam" or \ user == "joe" and passwd == "eoj": return 1 else: return 0 def __access__(req, user): if user == "eggs": return 1 else: return 0 def hello(req): return "hello"
Here is the same functionality, but using an alternative technique:
__auth_realm__ = "Members only" __auth__ = {"eggs":"spam", "joe":"eoj"} __access__ = ["eggs"] def hello(req): return "hello"
Since functions cannot be assigned attributes, to protect a function,
an __auth__
or __access__
function can be defined within
the function, e.g.:
def sensitive(req): def __auth__(req, user, password): if user == 'spam' and password == 'eggs': # let them in return 1 else: # no access return 0 # something involving sensitive information return 'sensitive information`
Note that this technique will also work if __auth__
or
__access__
is a constant, but will not work is they are
a dictionary or a list.
The __auth__
and __access__
mechanisms exist
independently of the standard
PythonAuthenHandler. It
is possible to use, for example, the handler to authenticate, then the
__access__
list to verify that the authenticated user is
allowed to a particular function.
NOTE: In order for mod_python to access __auth__,
the module containing it must first be imported. Therefore, any
module-level code will get executed during the import even if
__auth__ is false. To truly protect a module from
being accessed, use other authentication mechanisms, e.g. the Apache
mod_auth
or with a mod_python PythonAuthenHandler handler.