When I thought about Rhino Security, I imagine it with a single public interface that had exactly three methods:
- IsAllowed
- AddPermissionsToQuery
- Why
When I sat down and actually wrote it, it turned out to be quite different. Turn out that you usually want to handle editing permissions, not just check permissions. The main interface that you'll deal with is usually IAuthorizationService:
It has the three methods that I thought about (plus overloads), and with the exception of renaming Why() to GetAuthorizationInformation(), it is pretty much how I conceived it. That change was motivated by the desire to get standard API concepts. Why() isn't a really good method name, after all.
For building the security model, we have IAuthorizationRepository:
This is a much bigger interface, and it composes almost everything that you need to do in order to create the security model that you want. I am at the point where this is getting just a tad too big, another few methods and I'll need to break it in two, I think. I am not quite sure how to do this and keep it cohesive.
Wait, why do we need things like CreateOperation() in the first place? Can't we just create the operation and call Repository<Operation>.Save() ?
No, you can't, this interface is about more than just simple persistence. It is also handling logic related to keeping the security model. What do I mean by that? For example, CreateOperation("/Account/Edit") will actually generate two operations, "/Account" and "/Account/Edit", where the first is the parent of the second.
This interface also ensures that we are playing nicely with the second level cache, which is also important.
I did say that this interface is almost everything, what did I leave out?
The actual building of the permissions, of course:
This is utilizing a fluent interface in order to define the permission. A typical definition would be:
permissionsBuilderService .Allow("/Account/Edit") .For(CurrentUser) .OnEverything() .DefaultLevel() .Save(); permissionsBuilderService .Deny("/Account/Edit") .For("Administrators") .OnEverything() .DefaultLevel() .Save();
This allow the current user to edit all accounts, and deny all members of the administrators group account editing permission.
And that sums all the interfaces that you have to deal with in order to work with Rhino Security.
Next, the required extension points.