permissioning
If you ever decide to write an application that deals with Information Architecture (IA) [wikipedia], you'll eventually probably run into the permissions problem.
In theory, permissions are this awesome concept of controlling the flow of information. I predict the next big take-off for web applications will be privacy granularity, once API standards (like Atom) standardize and concepts like OpenID allow you to centralize your login.
Gated communities (LiveJournal, Tabulas, Facebook), thrive on the the privacy model. The earliest manifestation (that I remember) was the LiveJournal "friends-only" posting. You defined a set of LJ friends, then you can pick posts that only appear to them (I stole that idea for Tabulas). Facebook's whole popularity (and the 'elite' feelings from its members) derive from the fact that people feel like they're a part of a very inclusive crowd.
Anyways, I ramble. The point of this post is talk about some of the internal discussions that went into the permissions model for DekiWiki.
I wrote the initial page permissions spec for DekiWiki a while back, but we've since revamped to a different model which is a lot more logical for the end user.
DekiWiki Permissions Overview
In DekiWiki, you can allow a page to only be viewable or editable to a certain group of people. This is to protect sensitive information. Besides some of the terminology (which still seems a bit too techie), this screen should make some sense. You've got a list of users on the left; you add users on the right, and you've got the permission type in the top center.
The problem
Handling restrictions for each individual page is easy - when a user loads up the dialog, they can see who is in the list; add and remove, and save. In computer lingo, the user interface stores the state of permissions, which you (the contributor) take in and then figure out how to modify. Very easy. We then send the list of users to the smart computers, and they store that information.
The problem occurs when you try to handle recursive page permissions in a hierarchical system. How do you cascade a permission down to its children?
You might say, "Easy! Just give the children the same permissions as the page you're operating on!"
Hooooooooooooold it, partnuh.
Let's say there's a fictional playa named Royboy, who creates a wiki detailing all of his girlfriends. He sucks at remembering things like birthdates and anniversary dates, so he uses the wiki to document this type of information. He decides to create a hierarchy that looks like this:
Now, he doesn't want the whole world to know about his biz-nass, so he makes the whole hierarchy private.
But, his personal assistant needs information about his current long-term girlfriend (Royboy is a hot in-demand movie star, so he has a personal assistant), so Royboy grants the ability for his personal assistant to view his current current:
Now, let's say Royboy's momma calls up, grillin' him for some info about his girlfriends (she has a keen interest in seeing who Royboy's potential baby momma's are). So he decides to give her permission to the "Long Term Girlfriends" hierarchy (he doesn't want her knowing about his one-night stands).
In a system where changes simple propagate down, you end up with this:
Notice how the personal assistant got removed from the page?
Simply put, for the children pages, users who had better information about who had access to the page get their changes overwritten by users higher up in the hierarchy.
Possible solutions
Here's a chart of the possible ways of handling recursive page permissions:
Cascade all Permissioning
What we were describing above is "cascade all" effect. Basically if you have access to modify the permissions, it will overwrite whatever permissions are already on the page with your set. This can lead to behavior where somebody explicitly set permissions on a page to allow somebody, but got those permissions revoked when somebody higher up in the hierarchy updated permissions.
Delta
The other effect we see is delta. What delta does is calculate the change in permissions for the page, then applies those changes recursively to each page. For example, in the example I gave above ... adding Momma to the to hierarchy would result in a delta of +Momma. That means when it hit the "Cashier who works at that restaurant" page, the operation wouldn't replace the permission ... but would append Momma to that list.
The cons of delta is that it quickly leads to disorganized permission sets in a hierarchy. It also makes it very hard to "reset" all permissions down to nothing. For example, for every operation that was done, the exact same operation in reverse (Removing Momma from the "Royboy's Girls" page) would have to be done. If you have an organization with hundreds of people dealing with permissions, you can quickly see how that would get out of hand.
Where equal?
The "Where equal" case is supposed to resolve some of these issues - the changes are only applied to pages with the exact same permission set. So basically even if you have the ability to apply permissions, it wouldn't necessary take effect.
In our example, the delta where equal case for adding Momma was: "Add Momma to pages with permission private with nobody else". When it gets to the "cashier who works at that restaurant" page, the operation would return "page permission private with personal assistant" and therefore Momma wouldn't be added.
This can lead to very unpredictable operations where you *think* you're adding somebody to the permissions set for a set of pages, but you're really not.
Delta where any, I guess
In order to preserve the permission specificity of children pages, we have to apply a delta where any operation. This means that anytime you add/remove a person from a permissioned page, they will be added (or removed) from all children pages. The end result for the user is that this person can view all children pages (if added to permissions list) or will not be able to view it at all (if removed).
So how do we solve the problem of "resetting" the permissions? I suggested the equivalent of a "tactical nuke" operation which would wipe everything down to public. This seems to be the only way to handle this ... and imagine clicking a little bomb icon! How cool would that be?
Walking...
Another issue that comes up is whether to block operations on grandchildren pages. Look at this picture:
Even if Page C is blocked to the person (Bob) who is attempting to operate on Page A, it will operate on Page D.
At first, this made no sense to me... if a operation gets blocked with a page, it should stop!
But then, it made better sense when I rephrased the operation: "Bob is attempting to view every page in this hierarchy and setting the pages to private." So even if he gets blocked at Page C, it makes no difference! He could navigate to Page D and operate from the UI ... so we should maintain that operation!
Conclusions
I know this is a hasty post, but I'm a bit tired, and I only really wanted to capture this for reference in the future. Here are the conclusions:
- Being blocked by a child node shouldn't affect grandchild node operations, since you could get to them via the UI and operate on them normally. The system should emulate exactly what the user is doing on the front-end in a recursive manner.
- When a user operates by adding or removing people from a list of permissions on a page, the deltas should be used in operating on all the child nodes to maintain the specificity set by previous users. This means that if you remove a user from a node higher in the hierarchy, he will not be able to view *any* pages on the children pages. Likewise, a user who is added will not destroy anybody else's permissions, and will be added to all the child pages.
Tomorrow, a long post about standardizing UIs... wooooo
Comment with Facebook
Want to comment with Tabulas?. Please login.
hapy
Phatcorndog
I about fell out of my chair laughing when reading those flow charts and explanations. Good work.
roy