[Zope-Coders] please review LocalRolesRevamp

Martijn Faassen faassen@vet.uu.nl
Thu, 11 Oct 2001 00:15:21 +0200


Shane Hathaway wrote:
> Martijn Faassen wrote:
[snip]
> It's a lot more user-friendly.  One of the things people always disliked 
> about search engines is the tendency to return outdated results.  (Until 
> Google's cache, anyway ;-) )  Returning results the user is not allowed 
> to see is probably even worse.

Agreed that it should be avoided in most cases. :)

> >[overriding User] 
> >
> >>You could override getRolesInContext(), I think.
> >
> >An optimization was introduced in Zope 2.3 (I think) that makes this 
> >impossible.
> >getRolesInContext() is I think not used by the core anymore.
> 
> Well, maybe we can undo that fix. :-)

While retaining the optimization? Better fix the whole local roles
story right away then, only a bit more work. :)

> >But you'd need to in order to accomplish some use cases. What I'd like to
> >compute is user attributes to local roles. This computation is place
> >dependent; in place A in the tree I'd like user attribute 'employee' to
> >have, say, 'Manager' rights, but in place B I'd like the same user
> >attribute to only have 'Authenticated' rights. It seems hard to avoid
> >actually going to the place and asking what their mapping is in this
> >scenario.
> 
> Well, before I even joined with Zope Corp. I wrote a product called 
> ACLManager. It was designed to deal with exactly this problem.

Cool, I'll check it out then.

> I was 
> working at a major educational institution, putting courses on the web.

My client is a major education institution. :)
  
>  I was trying to move all their Internet offerrings to Zope.  There 
> were over 100 courses already on the web, each class had 30 or so 
> students, and students added or dropped courses every day.
> 
> I didn't feel that Zope's local role management was up to the task.

Same feeling here. I think local roles would be very powerful and used
a lot more if:

a) they could be computed in some way 

b) the management screens exposed them better. I'm thinking along the
   lines of an acl_roles object, much like acl_users but for
   managing (local) roles. Eventually all roles could be local roles
   anyway, so that user roles are not special anymore in the code base.
   They're just local roles that are defined in the same place the
   user is defined. :)

> So 
> what ACLManager is supposed to do is let you define named workgroups and 
> essentially associate access rules for the named workgroups.  A 
> workgroup name could be, for example, "CIS1100", and does not usually 
> correspond with the name of a folder.  Then in the /courses/cis1100 
> folder you create a "satellite" user folder and tell it to draw users 
> from the "CIS1100" workgroup.

Is this satellite user folder associated with the ACLManager in some
way?
 
> Having the workgroup name gives you a lot of advantages IMHO.  If you 
> move or rename /courses/cis1100, the user roles continue to work.

I'm not sure I understand this part.

> You 
> get central management *and* distributed management.  For web courses 
> there is another great advantage: while you're running a class you can 
> be creating a new version of the class for next semester.  Just before 
> the next semester you set the workgroup of your new course.
> 
> ACLManager is still available for download, though unfortunately I 
> didn't know the internals of Zope as well as I do now, so it doesn't 
> work as well as it could.  For example, I would be more bold now ;-) and 
> I wouldn't use satellite user folders, instead opting to change the way 
> local roles are computed.

As you may recall I was thinking along those lines myself. :) Right now
they aren't really computed so it's not easy to accomplish this, 
except by overriding some (important) methods in the User object, which
gives some other problems (I'd prefer it to work with the basic user object if
at all possible, too).

> >Per user you'd still have to go off asking dozens if not hundreds of
> >objects for this information, though, in large sites where this is
> >used a lot. You could employ some caching here though, and it'd still
> >be less expensive than filtering cataloged objects each time (which can
> >easily run into multiple hundreds).  
> 
> That depends on the complexity of your security policy.  If you keep 
> your policy simple (as you should ;-) ), the expressions and the number 
> of them you have to use to compute a given user's roles should also be 
> simple.

How? I have employees working in dozens of places in the organization,
not to mention students in many different departments. All this information
is already in the LDAP database. Now I want the ability to locally say
'employees in department X get role Foo here' in some particular place,
using somekind of special mapping object. We easily have a couple of dozen
places in the site where this happens, I expect, so quite a few of
such mapping objects.

In order to calculate the local roles completely before doing a catalog
query for a user, I'd need to ask all those dozens of objects if this user
doesn't happen to gain roles in those locations. I think this can be kept
within bounds more or less, if this particular check only happens for
catalog queries using this special new role index. If a complete list of
local roles for a user will have to be determined each and every time this
user generates a request, we have a bigger problem; it'd be more efficient
to resolve that locally.

> >>Our difference of opinion is, AFAICT, rooted in different perceptions of
> >>the need to filter catalog results based on access.  Obviously you don't
> >>have that goal. :-)
> >
> >Sure, but that's why we're talking, right? I have my goal, you have your
> >goal, and we're trying to figure out some approach that would make us
> >both moderately happy. What do you think about the approach I listed above?
> 
> I'm not quite sure what you suggested.  Maybe my head is clouded by 
> reminiscing over my early Zope days. :-)

I'll try to sketch it out. Hm..

Users have meta-data. Let's say in a simple case users can have a set of
properties A, B, and C. So, a particular user can be A, or just B, or
A and B, or B and C, say.

Based on this meta data, certain folders need to grant access.
Folder X for instance grants the Foo role to a user only if the user
has meta data A and B. Folder Y grants the Foo role to a user only 
if the user has meta data C, for instance. 

For this, we introduce a kind of mapping object, that knows how to
map meta data to the local role. I.e. it computes local roles in
some way based on user meta-data (in my example from the A, B, and C, but
it could be anything). This role mapping object is placed in the folders
where the mapping should occur (and all subfolders will automatically
gain this mapping as well).

Now, we run into your problem with the catalog. In order to fix the
catalog problem, you proposed all local roles are defined per
user (or can at least be looked up for a particular user in some
special object storing them). So, when you ask for the local roles of
a user, you get a list of (object, local roles) tuples, or possibly
(path, local roles) tuples. This way, you only need to store object
roles in the catalog index. We do need a special new catalog index for this
that knows about the way local roles are acquired by subobjects (would this
be path based?) and so on.

Now we'd like to have computable local roles again in this new scenario.
Of course, we could easily return a different list of object/local role
pairs for a user based on some computation.

The problem is however that the mapping objects are somewhere out there
in folders and only they know what local roles a user would gain in
these folders, based on the user meta data. You want them to be in
those places for management reasons.

So, I proposed keeping a collection of those as well in some special 
catalog (or catalog-gy) kind of object in our centralized local role
manager object. So, while the mapping objects are created and managed locally,
they actually report to the central repository. Whenever there's a catalog
query for a user and you want to use the role index, all the mapping objects
need to be asked what kind of local roles (if any) this user gets for
their folder. This is a relatively expensive operation, though I think
you could optimize it pretty well and for a catalog query it wouldn't
be that bad (and you could cache the results to a certain extent as well).

In fact the same mapping object could also just store userid/local role
combinations as well, so that the central repository in fact doesn't
need to keep a list of local roles, but simply asks all these mapping
objects for them, even for non-computed local roles.
   
I do think it would be too expensive if this local role computation happened
*all the time* for security checks. I think for normal security checks it's
better to have something similar to the current approach, where you
only have to ask the nearest __ac_local_roles__ (and not all the other
ones in your Zope!).

I hope I haven't totally lost everyone here. :)

Regards,

Martijn