I am trying to write a module which handles flexible role based inheritable privileges, is fast and yet accurate... Apologies ahead of time as my terminology may be inaccurate and I know little about the theory behind such systems.
Update
I've often looked through CPAN for a module that handles privileges like this, but without success - would this be worth CPANing?
Functionality
-
There are a fixed set of assignable privileges (eg): View, Create, Edit, Delete, Admin and Deny, where Admin grants all other privileges automatically, and Deny overrides all the other privileges including Admin.
- There is a subject and an object, where the subject (eg a user) is granted privileges against an object (eg a photo album). The subject and object could be any object in the system, but usually a subject would be either a user or a group.
- Both subjects and objects could be members of groups which have their own privileges assigned, and these in turn can belong to other groups.
- The reported privileges that a subject has against an object thus depends on the privileges inherited from all the groups that are involved.
It's this last point that provides both the flexbility and the slowdown.
Example
- The group All Users has View privileges granted to all members of the group All Albums
- The group Call Centre has Edit privileges against all Albums
- The group Admins has Admin privileges against All Albums
- The group Joe's Album Group has Admin privileges against Joe's Album
- Joe is a member of Joe's Album Group and thus has Admin privileges against Joe's Album.
- etc...
But this inheritance means a lot of checking for intersections betweens subjects and objects. With a reasonably flat structure, i could easily be checking 60+ combinations of subject and object. So how do I improve the performance?
Design
- Any assigned privileges are stored in a table keyed on subject_id and object_id
- When the privilege level is requested, the module looks for a directly assigned privilege between the subject and object.
- It also find the groups that both the subject and object belong to, and requests the inherited privilege from each combination of the above. These values are ORed together and then reported as the inherited privilege.
- When an inherited privilege is reported, that value is cached to (eg) disk for (eg) 60 seconds.
- It is also cached in memory for the duration of this request (this is running in mod_perl, by the way), so that if the same combination of subject/object is requested again , it should be very quick.
Problems with design
This is all well and good but there are three problems:
- It should be possible to cache the inherited privileges for longer than 60 seconds to make the whole process a lot more responsive.
- When a higher level permission changes, it should immediately be reflected in the inherited privileges - ie the cache beneath that intersection of subject/object should be cleared.
- When running on multiple servers, I don't want inconsistent privileges being reported because there is different information in the local cache of each machine.
Memcached?
- memcached would help with the cache consistency across machines, but is probably slower than having a local file cache
- the problem of clearing out all cached inherited privileges below the intersection of a particular subject/object requires that the cached value is keyed against both subject and object rather than (eg) subjectID_objectID, and entries in memcached have a single key.
Proposed solution
- My idea is to use a MySQL table which has the columns: subject_id, object_id, assigned_privilege, inherited_privilege
- assigned_privilege would represent a fixed assignment between the subject and object (eg granting All Users Viewing rights against All Albums)
- inherited_privilege would be the cached calculated value
- So, the user John may not have any directly assigned privileges against Joe's Album, but because he is a member of the group Call Centre and Joe's Album is a member of All Albums, he has an inherited Edit privilege granted to him
- This would allow me to
- flush any inherited privileges when either the subject or the object changes
- cache all inherited privileges indefinitely and
- have consistency across multiple servers
- However, it would also mean storing many many rows of essentially redundant data. But I could have a cronjob which regularly deletes old rows which have no assigned_privileges
As I said, this was a long one - but I would really appreciate your feedback. Is this a good approach? Am I missing something obvious? How would you change this system?
many thanks
it would allow me
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.