durusmail: quixote-users: Authentication/permissions
Authentication/permissions
2004-11-08
2004-11-09
2004-11-10
2004-11-10
Authentication/permissions
Evan LaForge
2004-11-10
> My application has to authenticate a user, determine which group
> (singular) they belong to, then enforce group permissions.  (I'm
> vaguely thinking of Zope's roles.)  The permissions range from including
> certain fields in the display to accessing update screens.  However, the
> anonymous user can also do searches and get limited displays without
> logging in.  Management wants people to be able to log in at any point
> and continue their search-in-progress with upgraded permissions.  This
> implies a login link on every page, which goes to a login form, then
> back to the previous page, now displaying more fields or records.

This is sort of what my webmail app does.  _q_access does 3 things: if your
query string has magic __passwd and __login fields, it makes a new session for
you and lets you go; if you're logged in, it lets you go; otherwise, it throws
Not_logged_in.  _q_exception_handler snags Not_logged_in and returns the login
page.  The login page packs up the query string in hidden fields and adds
__passwd and __login fields, setting the action target to wherever you really
wanted to go before the login machinery snagged you.

BTW, my webmail app also uses multiple threads, if you want to see how it
could be done.  But unless you want a lot of shared state between processes
(like a shared cache), then you're probably better off with the multiple
process SCGI model.  FastCGI also does multiple processes automatically, but
it's more complicated than SCGI.

> Alternatives seem to be a custom Publisher subclass, calling an
> authenticate() function at the beginning of every "servlet" function
> (undesirable), or making all "servlets" be a subclass of an
> AuthenticatedPage class (also undesirable because I'd lose Quixote's

I don't see how this is much different from writing _q_access for a root-like
object.

> My user scheme is like this.
>
>     # User logs in, and  determines which group they're in.
>     === user.py
>         class User:
>             def __init__(self, username, group):
>                 self.username = username
>                 self.group = group
>                 self.canViewSensitiveData = 
>                 self.canUpdate = 
>                 self.can...

Maybe a Group object whose instances are like tokens?  More powerful groups are
subclasses, so each page (or each pages _q_access) can have a
require_group(request.session, Some_group) that does
any(lambda g: isinstance(g, Some_group), session.user.groups)

reply