I had some fun today setting up trac with apache and mod-auth-pam, and I wondered if the same would be possible using paste.
I wrote this module to try and get PAM authentication working in paste. It depends on the PAM module, and also the pwd and grp modules, so it's pretty much unix specific. I have it located in paste.auth.pam. I haven't gotten around to testing it with trac, but the example at the bottom of the module works well for me. You have to run it as root if you're using shadow passwords so the PAM subsystem can read the shadow file. Thoughts, comments, criticisms or suggestions are welcome! Cheers, Chris
# (c) 2006 Chris AtLee <[EMAIL PROTECTED]> # This module is part of the Python Paste Project and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php """ PAM Authentication This module provides a PamAuth class which can be used by any of the paste auth modules to perform user authentication using PAM. Requires the PAM python module. Example usage: >>> from paste.wsgilib import dump_environ >>> from paste.httpserver import serve >>> from paste.auth.basic import AuthBasicHandler >>> realm = 'Test Realm' >>> auth = PamAuth("passwd") >>> serve(AuthBasicHandler(dump_environ, "Test realm", auth)) """ import PAM import grp, pwd, sets __all__ = ['PamAuth'] def _groups(user): """ Returns a set of all groups the given user is a member of Raises KeyError if the user is not found in the group database """ retval = [] gid = pwd.getpwnam(user).pw_gid for g in grp.getgrall(): if user in g.gr_mem or gid == g.gr_gid: retval.append(g.gr_name) return sets.ImmutableSet(retval) class _PamConv: """ Helper class to respond to password prompt from PAM """ def __init__(self, password): self.password = password def __call__(self, auth, queryList, userData): resp = [] for query, typ in queryList: if typ == PAM.PAM_PROMPT_ECHO_OFF: resp.append((self.password, 0)) return resp class PamAuth: """ PAM Authentication class Parameters: ``service`` Which PAM service to authenticate against. Examples could be ``passwd``, ``login``, ``httpd`` ``groups`` A list of groups the user must be in one of to be authenticated. Set to None (the default) if a user can be in any group. """ def __init__(self, service="passwd", groups=None): self.groups = groups self.auth = PAM.pam() self.auth.start(service) def __call__(self, environ, username, password): self.auth.set_item(PAM.PAM_USER, username) self.auth.set_item(PAM.PAM_CONV, _PamConv(password)) try: self.auth.authenticate() self.auth.acct_mgmt() except PAM.error, resp: # Try and forget the password (the previous _PamConv had # a reference to the password string; by replacing it with # a new instance, the old one should be garbage collected) self.auth.set_item(PAM.PAM_CONV, _PamConv("")) return False else: # Try and forget the password self.auth.set_item(PAM.PAM_CONV, _PamConv("")) # Check group membership if self.groups is not None: if _groups(username).intersection(self.groups): return True else: return False return True if "__main__" == __name__: from paste.wsgilib import dump_environ from paste.httpserver import serve from paste.auth.basic import AuthBasicHandler realm = 'Test Realm' auth = PamAuth("passwd", ["users",]) serve(AuthBasicHandler(dump_environ, "Test realm", auth))
_______________________________________________ Paste-users mailing list [email protected] http://webwareforpython.org/cgi-bin/mailman/listinfo/paste-users
