On Thu, Sep 09, 2004 at 09:30:51AM -0500, Edward Hartfield wrote:
Johan Carlsson wrote: Why do you need different authentication logic?
My client wants to do form-based authentication and have user data stored in a database so they can manage users without having to know anything about Zope.
Lots of people do this. The usual way is to use a UserFolder that interacts with your data source. If you want to do something custom, SimpleUserFolder is a nice place to start, it provides examples of getting users from SQL.
My idea is to create a folder object that can be given a method (AuthenticateMethod) to call when someone tries to traverse the folder's contents. AuthenticateMethod returns true or false. The folder itself knows nothing of the authentication scheme. That's AuthenticateMethod's concern.
And this method would presumably make requests to your database? Hmm. Here's an alternative that was suggested to me when I had some similar requirements, and worked out pretty well: let the User object do it instead, by supplementing its local roles. First, decide what role you will use for protecting your Zope data. You only need one role. Let's call it 'myrole'. Give that role "View" (or whatever) permissions on the data you're restricting. Don't grant the role to any users - your User object will be dynamically granting itself this role depending on the context object and your own authorization rules. Here's a way to do that: Subclass a UserFolder implementation (such as SimpleUserFolder) and have its getUser() method return a custom User class. Define a method of this user class named something like _getExtraRolesInContext(self, object), which, given a context object, does your database lookups or whatever, and returns either ['myrole'] if you want to authorize or [] if you don't. Next, write a trivial getRolesInContext() method that adds the output of the parent class' getRolesInContext() to _getExtraRolesInContext(). Finally, wrap the base class' allowed() method, something like: def allowed(self, object, object_roles=None): """Return true if the user has one of the given roles in the context of object. sadly, getRolesInContext is not called by this in the base class, or we wouldn't have to define this method. """ if object_roles is None: return 0 extra_roles = self._getExtraRolesInContext(object) for role in object_roles: if role in extra_roles: if self._check_context(object): return 1 # fall back to the old behavior return TheBaseClass.allowed(self, object, object_roles)
My partner and I agree that it doesn't make sense to throw away Zope's built-in security.
Good :-) I don't even know how you could possibly do so.
But we don't like the hack required to logout a user with basic authentication.
Have you tried CookieCrumbler?
Also, we need to implement a record-level authorization scheme.
I assume by "record" you mean an individual persistent object in Zope?
The easiest, most cost-effective way to do this seems to be using a database to define user permissions just the way we want.
You can do this in the scenario I described above. It's really not much work, and it allows you to keep data in any Folder-like containers you wish. The authentication/ authorization magic is entirely encapsulated by the UserFolder and User. For one thing this just feels cleaner to me; for another thing, you won't have people wondering why security is broken because they accidentally added a vanilla Folder or Plone Folder or whatever. -- Paul Winkler http://www.slinkp.com