[TransWarp] Authentication services, specialists, and rules-checking

Roché Compaan roche at upfrontsystems.co.za
Fri Aug 8 02:32:09 EDT 2003


* Phillip J. Eby <pje at telecommunity.com> [2003-08-07 23:50]:
> I've been working the last day or two on authentication services for 
> peak.web, and have run into some interesting hitches.  The most basic 
> functions of an authentication service are easily met, you just need 
> something that pulls data out of a request and looks up a user, no real 
> problem.
> 
> However, although identifying the current user is a straightforward 
> computation-only task, there is a wide assortment of related services that 
> are also needed.  For example, a login form, and a logout method.  There 
> may also be needs to manage users, register a new member and so on.
> 
> In principle, these needs are part of the application, and should be 
> defined as part of the application's presentation components.  But, it may 
> be that the authentication service needs to access them.  For example, 
> maybe the right behavior is for the authentication service to present the 
> login screen when there's invalid authentication data found.
> 
> As I think this over, I'm realizing that this isn't quite right.  The 
> authentication service can just raise an error, which can then be adapted 
> to whatever behavior is desired by the application.  And, different 
> services might have different errors that they raise.  For example, an auth 
> service with policies like those of Yahoo, might raise a "your login has 
> timed out" error, which would then be adapted to a "please re-enter your 
> password" screen.  (Technically, it probably wouldn't work this way, and 
> thinking about how to do it correctly actually leads to some other 
> interesting thoughts I'll explore later in this message.)
> 
> For other operations, like logging a user out, signalling credential 
> changes and such, it's more than adequate to use the convenient, centrally 
> located authentication service.  However, for services that a user needs to 
> access via the web, the authentication service can't be used.  So, we end 
> up needing a "user specialist" component that has a known URL within the 
> site, in order to have e.g. a '/logout' method.
> 
> This isn't such a big deal, but it does make me wonder then, how other 
> components in the site will find it.  For most of our current applications, 
> we just use '/acl_users' or some such, per Zope, and it's a hardcoded 
> path.  But I've been saying for some time now that hardcoded paths make for 
> poor modularity.  It seems to me that there should be some way to access 
> specialists, in the same way that we can DMs.  Thus, presentation 
> components would be more reusable between sites.  To do this, a Decorator 
> would just bind to a Specialist, and the Specialist would have to be 
> available from some parent Decorator.  In a template, one can refer to the 
> specialist relative to the current decorator, and use a "url" DOMlet to 
> point it to its "true" URL, so long as the Specialist is a "Resource" in 
> our current terminology.  Thus, we need service-oriented Decorator classes 
> that know how to ensure their absolute URL-ness, even if accessed via 
> another object.

Sounds great!

> Backing up a little bit to the error handling thing, I'm thinking that 
> probably authentication services should be configurable as to what errors 
> they use, and/or that the NotAllowed error may need to be more 
> fine-grained.  Right now, NotAllowed just means that you didn't have the 
> access needed to do what you wanted to do.  But, there is no way to 
> parameterize that, to say that you're not allowed because for example, your 
> session expired, versus, you're just not allowed, period.
> 
> At issue here is the fact that interaction.allows() communicates only via a 
> true-or-false return value, so there's no way to get the details, even if 
> the business rules that interpret the permissions know exactly what's going 
> on.  Further, the current traversal machinery just uses NOT_FOUND and 
> NOT_ALLOWED as sentinel values, so there's no data there, either.
> 
> So I wonder: should rules raise errors, instead of just a yes/no 
> response?  Certainly, this would allow them to communicate in very 
> application-specific terms about the nature of the issue.  If part of the 
> required interface for such errors was to provide a method that would 
> provide alternate data for templates trying to access the protected data, 
> then we could perhaps allow DOMlets to catch these errors and render the 
> alternate content, similar to certain modules in My Yahoo displaying "you 
> must log in to access this feature" when you haven't entered your password 
> in a while, and meanwhile the news modules and such would still display 
> their (public) contents.

This made me wonder how conditions in general translate to DOMlets. In
TAL you can specify tal:condition="some condition". Probably as simple
as having a "condition" DOMLet which replace itself and its contents
with nothing if the condition returns false:

    <li define="condition:foo">show foo</li>
    <li define="condition:bar">show bar</li>

> Granted, I do have some qualms about throwing exceptions for this.  For 
> example, if more than one permission guards an object, how do you determine 
> which exception should be used/displayed?  I suppose another useful 
> approach would be to have interaction.allows() return the failed "attempt" 
> object, which would have a false value, but contain a log of information 
> about why the attempt failed.  OTOH, this seems like maybe *too much* 
> information, especially if you're paranoid about security.  (Of course, I 
> suppose if you're paranoid, you won't put that kind of information 
> disclosure into your security rules.)
> 
> Hm.  As I think about how we might try to deal with such "logs of failing 
> things", I begin to think two things: 1) maybe exceptions would be better, 
> and 2) we could simply require that permissions always be 
> singular.  Instead of saying permissions=[Worker,Manager], we might want to 
> say permission=WorkerOrManager, and encapsulate the "or" within the 
> permission rule.  Then, it could say, e.g. "You must be a worker or manager 
> within this facility", instead of issuing two errors for, "You must be a 
> worker" and "You must be a manager", which makes little sense to the 
> user.  Meanwhile, permissions that "and" two other permissions can simply 
> return the result from the permission that failed first.

Very cool. How will one introspect permissions? It's easy to say:

    if "Worker" in permissions: ...

but how would you do that with WorkerOrManager?

> I still don't really want interaction.allows() to throw an error, though, 
> all things considered.  It would probably make more sense for 
> 'contextFor()' or 'traverseTo()' to throw the error.  The idea here is that 
> we do want an error, so that code using a traversal knows that the 
> traversal it's on is broken.  It doesn't really make sense to return a 
> valid new traversal context that simply points to a special "not found" or 
> "not allowed" place, because then you might have a template that keeps on 
> going and just coincidentally appears to work.
> 
> Incidentally, this actually is better for error handling in templates, 
> because it can be made explicit.  Right now, DOMlets just (explicitly) 
> ignore missing or unauthorized data.  It would be better to let them 
> implicitly ignore it, but also be able to explicitly handle it, e.g. by 
> letting you specify the granularity at which a set of items is 
> required.  For example, if you lack access to one field of the record, 
> should you be denied access to just the field, or the entire record?  Maybe 
> the whole list of records?  Being able to handle the error at the level of 
> some useful block structure is better for things like the Yahoo "you need 
> to login to use this module", as it makes no sense for the module to write 
> this once for every record it would have shown!
> 
> In order to do this, of course, there would need to be an explicit 
> "catcher" DOMlet specified at some level.  The catcher would supply a new 
> state to its children, that wrote their output to a temporary buffer.  In 
> case of an error, the catcher would attempt to adapt the error to something 
> that could be displayed in place of the original contents, and write that 
> instead.  If there was no error, it would write the buffered output to its 
> parent stream.
> 
> So, for something like My Yahoo, each module's content block would be 
> wrapped with a catcher that would revert to giving an error message as soon 
> as a contained, non-error-handling DOMlet tried to access the protected 
> content.  But, if all the content was accessible, it would be written out 
> and processing would proceed.
> 
> So, to go back and try to summarize...
> 
> * We need "absolute location" decorator classes for services like 
> Specialists
> 
> * There needs to be some kind of security.Denial("message") object that has 
> a false value but can also be converted to a string/unicode value, and 
> maybe can be raised as an exception.
> 
> * permissionsNeeded should become permissionNeeded, throughout all of 
> PEAK.  Permissions like "ThisOrThat", can be implemented by rules that 
> simply return 'attempt.allows(This) or attempt.allows(That) or 
> security.Denial("You need this or that").
> 
> * IWebTraversable.traverseTo() should accept a context rather than an 
> interaction, and throw NotAllowed(context, denial) instead of returning 
> NOT_ALLOWED, when an access attempt is denied.  Similarly, it should throw 
> NotFound(context) when something isn't found.  Special handling for 
> NOT_FOUND and NOT_ALLOWED should just go away altogether.  This 
> unfortunately means that certain traversables such as Decorator and 
> MultiTraverser will now need some extra exception handling to accomplish 
> their tasks, as will interaction.getDefaultTraversal.  But, I think this 
> will save a lot of duplicated effort in DOMlet classes, and I think there 
> will be a lot more custom DOMlet classes than there will be custom 
> traversables that need special treatment for these not allowed/not found 
> conditions.
> 
> * There needs to be some kind of "catch" DOMlet, although I don't know what 
> it should be called.  Maybe "try"?

"try" is good.

> There's also something of a question as to what its default handling
> for errors should be.  I suppose we could have a
> 'templateErrorProtocol' on the interaction, to which the error
> instance is adapted, but then I wonder whether an individual DOMlet
> might want specific configuration for this.  Perhaps we should just
> make the target protocol a binding on the DOMlet, and let people with
> custom needs subclass it.  That might be simplest.  Indeed, perhaps we
> could just make IWebException include a method for being rendered
> *within* a template, as opposed to *instead of* a template.  That
> would let you specify both behaviors for an error in one place.

How is it determined which is rendered when an error occurs?




-- 
Roché Compaan
Upfront Systems                 http://www.upfrontsystems.co.za



More information about the PEAK mailing list