[Zope-PTK] Stability rule-of-thumb (fwd)

Phillip J. Eby pje@telecommunity.com
Fri, 04 Feb 2000 02:20:52 -0500


At 02:29 PM 2/4/00 +1100, Stuart 'Zen' Bishop wrote:
>    The original design and scope of GUF was to allow seperation of the 
>    following:
>	authentication (username & password)
>	authentication (valid domains)
>	authorization (role membership)

Authentication is handled by Validators and Users.  The Validator parses
the data from the REQUEST, and asks the appropriate User object whether the
credentials are valid (unless it's a token auth scheme like GUF's, in which
case it simply looks up the user associated with the token).


>	listing valid users

In the UUF/PTK model, listing valid users is not a required interface,
since it is inappropriate to use it for large databases.  The PTK really
wants a list of registered Members, which is not the same thing as a list
of everyone who can log in.  It's the responsibility of the UserSource to
provide a UserFolder-style management interface, if one is desired.


>    In particular, I needed to pull a list of users and role membership from
>    my Oracle server, and dynamically authenticate via one of two Radius
>    servers (choice of Radius server being dependant on role membership -
thus
>    GUF had to support arbitrary code).

This would be done by having a UserSource which returned User objects from
the Oracle db, but the User objects' authenticate() method would talk to
the Radius server.  As long as the User objects know their roles, they can
find their server.


>    So in an ideal world, we would need four pluggable components:
>	userList + userExists
>	userRoles
>	userAuthenticate
>	userDomains

Not exactly.  These things are covered, but in a more OO way.  The
authentication and domain checks are methods on the User object.


>> 	* has validate() method which strictly looks at the request for
>> authentication tokens (e.g. cookies) or login fields
>
>It would be nice if the UUF would also try breaking down the cookies/login
>fields for you. Most of the validators would prefer just being able to
>say yes/no to a username & password combination rather all of them
>needing the intelligence to decode the cookie,basic auth and form data.
>It can be done securely once rather than cut & paste, and validators
>would instantly support new authentication-passing mechanisms.

Um, all validators *do* is get data out of the REQUEST object.  It's up to
the user objects to do everything else.  The design is based on the
assumption that the UserSource's job is to retrieve user objects.  This is
a very different model than GUF and the standard Zope UserFolder, which
both usurp various tasks which properly belong to the User object itself,
while commingling the functions of a Validator and a UserSource.


>It would also be nice if you stole my token authentication code and made
>it an option so we can turn off storing username & password in the cookies.
>One advantage besides security of this method is that Zope can determine if
>a username/password combination is valid rather than having to talk to
>a possibly slow validator. Spamming my Radius or NDS servers with a request 
>for every hit is really not an option. Username/password caching cannot

>be done for systems using any sort of one-time password scheme.

Again, we must distinguish between a Validator and a UserSource.  Radius
and NDS would be either UserSources, or something a User object would talk
to in order to implement authenticate().  Either way, they are not
Validators.  I currently envision only three kinds of Validators:

* Basic auth
* Zope.org style cookies
* GUF-style tokens

Repeat...  all a Validator does is parse data out of the REQUEST object,
set cookies, etc.  It does not look up any data, as that is the job of the
UserSource.  It does not actually authenticate the user, as that is the job
of the UserSource.

I think this is going to be a lot easier to see than to explain, especially
if you're used to the GUF model, whose plugins are grouped along functional
lines rather than object-oriented lines.

Let me show it as a folder/object hierarchy:

acl_users/ (a UUF)

   UserSource/ (a folder in the UUF)

      getUser
       (method that returns one User object using SQL, LDAP,
        or whatever)

   BasicAuthValidator (object in the UUF)
    (object that gets id/pwd, calls user=UserSource.getUser(id),
     and does user.authenticate() and user.checkDomains())

   BasicCookieValidator (object in the UUF)
    (like BAV, only it checks cookies, and sets a cookie on
     login)

   TokenCookieValidator (object in the UUF)
    (similar to BCV, but instead of calling user.auth/check()
     on each hit, it just looks up the user ID from its token
     cache and returns getUser(id))

Notice that the user simply drops in as many Validators as are applicable,
though usually it will be just BAV + ?CV.  If you're wondering where roles
and domains come into play, that's the duty of the User objects returned by
UserSource.getUser().  getUser should return an instance of a class that
knows how to get its roles, domains, authenticate itself, etc.  In the case
of the PTK, it also has to know how to get its propertysheet objects.  

Fortunately, in the next Zope, SQL Methods can return ZClass instances from
an SQL query, which makes these things quite easy.  Also, the UserSource
can implement helper methods which User objects can take advantage of, if
for example they need to retrieve roles from a different SQL table than the
base user record.  (Or do things like update PTK login stats in a berkeley
DB, etc., etc.)