The New Liferay Permission Algorithm (a.k.a. 5, a.k.a RBAC)

Update (Feb 1, 2011): The default permission algorithm from version 6.0+ is now 6. It uses a fast bitmask persistence implementation of RBAC and is functionally equivalent to 5. However, there is only a single table for permissions, and a single table row per resource, per role, and so the data size is significantly smaller (probably at least 1/5 of previous). There is an built-in, automated migration tool to go from 1-5 to 6. There aren't any valid reason to not migrate from 5 to 6.

 

Well, it's been almost 2 months since we introduced a new permission checking algorithm into the portal. The key features of the new algorithm are:

  1. increased speed of evaluation
  2. simpler usage
  3. increased performance
  4. increased speed of evaluation
  5. and lastly increased speed of evaluation and increased performance

So, how did we acheive this and what did we have to sacrific to get it?

With the old default algorithm (a.k.a. 2) we had all kinds of objects to which we could assign permissions; users, groups, roles, orgs, user groups. While this sounds great, it really isn't for several reasons.

1) Having this many objects to which we can assign permissions means that evaluating whether a user has a particular permission on some entity incurs a check on all those objects. Not to mention the fact that some of those objects support inheritence. This lead to some very complex and expensive JOIN queries.

2) The simple fact that EVERY User could have permissions on a given entity meant that we had to define defaults on these entities. This would lead to situations where a user would visit a portal page which contained entities they had never before encountered and suddenly there would be a tone of DB interactions to create these default permissions for these new objects. Imagine a Message Board page with 20 posts happening over night, morning comes and traffic increases to say 100 users (user who had not encountered the 20 posts before) per minute. That is 100 * 20 / minute new objects being created. This lead to hundreds of DB interactions per second on some highly dynamic sites.

3) Managing permissions on so many different objects was difficult at best, and utterly confusing a worst.

The solution

What we did was implement a system based on the Roles Based Access Control (RBAC) paradigm. We had the foundation for such a system in place, we simply had to reduce the number of objects to which we could assign permissions to only one; Role. This allowed us to perform shorter, faster queries at evaluation time with many fewer JOINS. Also, since we eliminated the assignment of Permissions to User objects we no longer had to create defaults for Users encountering new entities. This increased the concurrent load the portal could handle by a huge factor.

For a short while after the initial system was in place we realized that we had overlooked one key issue, "ownership".

Because User is not assigned permissions, how can we define the permissions granted to the original creator? Well, it took a while to discover a flexible enough solution that would not lead us back down a patch which would cause us to lose our recent performance increase. We definitely did not want to go back to one to one association of permissions to Users.

The solution came in the form of an "implied Role". The "implied" meaning that this Role, though it is a Role like any other, can't be assigned to anything, can't be assigned too, rather it is the result of "state", when a new object is created the default permissions normally associated with the User object are associated with the implied "Owner" Role. Then, on objects which are "owned" (meaning they have a userId field, like a Message Board Message, Blog Entry, Bookmarks Entry, Journal Article, etc.) we first check if the current User is the owner of the object. If so, that user inherites the "Owner" Role. Now, since the "Owner" role is actually a real role, an administrator can manage permissions associated with the Owner Role for any object, by the normal means.

Other cases where we want to customize permissions specifically for a give user or set of users, or even with User Groups or Orgs, we can do this through Roles and then assign those. We lose non of the capability we had before, we increased the performance of the portal significantly, and also made permissions management far easer.

Also, since we only have one type of object on which we can assign permissions, it's easier to map onto external autorization systems, because most of those are already RBAC based, like LDAP.

Blogs
Definitely sounds like a great solution Ray. The only issue I see is migration, where someone had a user-specific permission assigned to an object. Is it possible to auto-migrate these? Or is it a necessary tradeoff? I guess a new role could be created for those outlying cases, and the user assigned to that role. But that may get expensive.
I'm planning to write a migration tool to go from old to new. But it'll basically do what you suggested, which is to take those special cases and handle them by defining a new Role, but as much as possible it will do reduction, to try and be smart about the assignment.

This is FAR less expensive that the old way of having permissions per entity, per user.

So, as of right now, it's a tradeoff... until this tool is complete.
Hi Ray!
First of all: I like the work of all of you guys at Liferay.

Do you have any kind of release date in mind for that migration tool?
Thanks and Greets
Tobias
Thanks Tobias,

It's always nice to hear that people appreciate our work.

As for the release of the migration tool, it's been a very busy summer and early fall, so I haven't had a chance to start on it yet. I would have to say POST Liferay 5.2, scheduled for end of November.
That's good to know. Since we have some installations at our customers that need to be upgraded with that migration tool. So I'm waiting for it emoticon
Great job Ray!

Wonder if you had a chance to look at the small bug I found with the AdvancedPermissionChecker: http://support.liferay.com/browse/LPS-49 ? Although i'm using algorithm #2 and not #5 since i'm upgrading.

Thanks!
I did see and have applied your patch locally, but have been so busy that I haven't been able to analyze why this only seemed to have affected you... to me the bug should have had wider ranging impact across our user base. So I want to make sure there isn't a further underlying bug of some sort, in our upgrade logic, or elsewhere.
I really appreciate your response Ray!

Like you, I'm not sure why exactly this seems to only have affected us... Logic kind of points to thinking that not many have upgraded from 4.3.1 and for some reason, either version or configuration, our portal relied only in the particular query that, when correcting the bug, is added to the rest of the queries, while for others, it was another of the 5 or so queries that allowed permissions to pass.

Anyways, I feel more comfortable knowing that someone has seen the ticket.

Thanks again!
Ray... I think i may have found why the bug affected me and not others following the same path. i don't want to polute your blog emoticon please see my last post on http://www.liferay.com/web/guest/community/forums/-/message_boards/message/1434969 .
Ray:

Is there a detailed document about the new permission system , I have read the http://www.liferay.com/web/guest/community/wiki/-/wiki/Main/Using+Liferay%27s+Permission+System+from+a+portlet, but it is for Lifaray 4.4, so am i missing something?

Thanks
There is no API change so you should be ok.
Hi Ray,

Firstly thanks lot and congrats for great job.
would you please tell me how could I put restriction on the default permissions of a user. More clearly if I create a user it will automatically assigned role like user role and there are some pre assigned permission. I want to create a role with some permissions and want to assign this role to user and this user will get only these permission not any other permission even default permission.
Is it possible if then how, please advice.

Thanks
Hmm, I understand what your are asking... I think!

First off, you can change the default Roles assigned to new users from the Control Panel -> Portal -> Users -> Default User Associations -> Roles (one role "name" per line: only regular roles allowed).

Second, users have no permissions by default other than via roles. And by default even if no Roles are assigned via "Default User Associations -> Roles" the user will have _at least_ "User" role (this is mandatory). So what we're talking about are the default permissions that User has.

To be honest I don't think this role has any permissions by default. Rather, users inherit defaults of the "Guest" in most cases. So what you end up wanting to do is reduce the permissions of the "Guest" role.

Next, users might be getting "personal pages" which may be where you are having issues. Here it the user's own community they (depending on configuration) potentially have all rights (and this is because of "ownership" and not due to permissions per se). To prevent users from having personal pages see the following:

http://www.liferay.com/widget/community/wiki/-/wiki/Main/Portal+Properties+6.0.5#section-Portal+Properties+6.0.5-Layouts

Let me know if this helped at all (and I hope I didn't miss the point of your question).
Hi Ray,

Thanks lot for your reply. Yes you have understood my question. When i create a user, he can add blog entry in blog portlet. For example how could i restrict a user from adding new blog entry in blog portlet. One way may be restrict from front end but I will prefer to restrict from permission level by assigning role to that user.

NB. Add blog entry is a default permission of User role.

Please advice.

Thanks.
Which version are you using?

You are correct that the user can created Blog entries in their own community. But ONLY in their own community (are you seeing something different?).

With the currently released versions of Liferay, you can't get fine grained control of permissions for users in their own community. The next EE service packs will have a fix for this though. See http://issues.liferay.com/browse/LPS-15016
I am using liferay-6.0.5, yes you are right but currently I needed to find a way to control of permissions for users in their own community too. But could not. As in earlier version I can do it using resource and algorithm 1-4 but as u suggested in http://www.liferay.com/web/guest/community/forums/-/message_boards/message/2380562

So I don't want to go earlier method in question of efficiency. Currently is there any way or need to wait for the service packs?

Another thing by debugging the code i found finally it returns true from the following code:

value = (Boolean)_portalCache.get(key);
from com.liferay.portal.security.permission.PermissionCacheUtil class

would you please tell me what it does. Again thanks and grateful to for giving your valuable time and helpful comments. waiting for your reply again.

Thanks.
In fact, if you are willing to patch your 6.0.5 CE version with the changes http://issues.liferay.com/browse/LPS-15016 you will have everything you want to control ALL permissions of users in their personal communities.

In fact, there is a planned 6.0.6 CE release soon. And with some luck, maybe this patch will be included.
Thanks. Any help or direction how to use the changes or how to patch in my 6.0.5 version?
You'd have to get the source code from SVN or from Sourceforge, and manually apply the patches. If this proves overly complex, then perhaps waiting to see what happens with the next CE (which should be sometime in the near future) is your best bet. (Or get 6.0EE which has it fixed in the upcoming SP, if that's an option).
The document Library in 6.05 and 6.06 has performace problem due to inlinePermission check in Mysql, is there any solution to this ? Honestly ?

We have a page show in 25 seconds ?

ilke