Rhino Tools: Rhino Security Guide

In the post I want to discuss basics of Rhino Security which was developed by Ayende. This is a nice security model implementation that could be easily integrated and adapted in many applications and scenarios. Intention of the post is to give good startup for Rhino Security. I will try to follow KISS (Keep It Simple) in my explanations, yes, I know that “It's All Relative” :) and also keep to minimum required infrastructure for the startup (mainly only required). Rhino Security is a part of Rhino tools, which is a set of already mature reusable classes and tools that cover various scenarios, such as well known:

1.Rhino Mocks - mocking framework

2.Rhino Service bus – enterprise service bus implementation

3.Rhino Common – set of reusable classes (working with threads, IoC, helpful Http Modules, ect..)

4.Rhino ETL (Extract Transform Load) – library that allows moving data in various formats.

5. Rhino Queues - queuing service that queues over the Internet

6. Rhino DHT - Rhino Persistent Hash Table

7.And many other goodies.

Rhino Security in my opinion is less popular then other Rhino stuff, one reason could be that is on web is not so much information. That is why I want to put the basics of Rhino Security and show how easy you can setup working application based on Rhino Security(by “easy” I mean that is much easier to setup rhino security then to try to implement at least a little part of it).

Rhino Security implementation is not very huge in terms of code lines, but is based on many other set of classes. I will describe them shortly later. Rhino Security as a persistence mechanism uses NHibernate that allows you very easy to integrate with many RDBMS types. To more precise Rhino Security could be configured with both: Castle Active Record and NHibernate. Castle Active Record is Active Record pattern implementation which behind the scene uses NHibernate (mmm,… yes,…it is not only Active Record pattern implementation, it has much more other features than are described by classic Active Record pattern). I’ve chosen to use NHibernate because it is more popular then Castle Active Record (Castle AR) and other reason is that Castle AR can’t be used without NHibernate but NHibernate without Castle AR can :).

Let’s do first steps and get all the Rhino bits from SVN repository, here is the SVN link:

https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/

in order to Check out the repository you can use any of SVN clients, there are many free:

1)http://tortoisesvn.net/about - easy to use and is integrated in windows explorer

2)SmartSVN – the SVN client has two versions, free and more limited and professional version, I like the client and I use it in day by day work, and even its free version is powerful enough to handle various scenarios.

I will not dive deep in “How To checkout” details, so the result of checking out from the trunk is on the next image. On the image is the last trunk at the moment, 2077. Rhino Security is in “security” folder, but we will not touch it now. In the root folder are “readme” files for some additional information. Also in the root folder are various NAnt and bat files that will invoke NAnt and build entire projects tree. In order to build a little bit faster run “build_without_tests.cmd” file. After a black screen and a lot of blinking lines will be generated “build” folder that will contain all the generated assemblies for all Rhino projects and dependencies.

If you have made all the steps successfully then let’s start and setup first Rhino Security project, if not then all required assemblies and project sample are in attached zip file.

Rhino Folder Structure

So, create a new folder where we will set our new project. Then in the root of just created folder create a new folder “libs” where we will place all required assembly references and dependencies.

Now, copy following 20 assemblies from Rhino’s generated “build” folder to “libs” folder: 

Rhino Libs

Then open visual studio and create a new console project, name the project “RhinoSecurity”, and place it in the created root folder (on the same level as “libs” folder).

Rhino Sample

In just created project reference following assemblies from our “libs” folder:

Rhino Sample

NHibernate.ByteCode.Castle.dll – assembly is not used directly from our code, but we reference it because it is loaded runtime and should be copied to the output bin folder. The assembly contains implementation for three NHibernate interfaces which are used to generate in memory proxy classes for our POCO mapped classes such as User entity which will be discussed further (that is why we need to set mapped properties as virtual). In this case is used Castle but you can find other implementations.

Now we have a good base to start type our logic. But, before to dive in implementation details, let’s discuss few Rhino Security types that can help us to integrate Rhino Security with our domain model. Most of the systems nowadays have User entity in the domain model, the User entity can have various proprieties that are specific for each different domains. Rhino Security allows attaching the security implementation to any User entity with minimal changes to the existent User entity, but how Rhino Security knows which entity from our model represents the User? For that is responsible Rhino.Security.IUser interface that marks the User entity, the only member of the interface which should be implemented is SecurityInfo member.

Here is typical implementation of the interface which fits in many common user implementations:

public class User : IUser

{

    private long id;

    private string name;

 

    public virtual long Id

    {

        get { return id; }

        set { id = value; }

    }

 

    public virtual string Name

    {

        get { return name; }

        set { name = value; }

    }

 

    /// <summary>

    /// Gets or sets the security info for this user

    /// </summary>

    /// <value>The security info.</value>

    public virtual SecurityInfo SecurityInfo

    {

        get { return new SecurityInfo(name, id); }

    }

}

The Id property is usually identity of the User entity (which not necessary should be a long). SecurityInfo property is used by Rhino Security to attach our user entity to Rhino Security implementation which is used internally by the framework to manage authorization logic for the User. [Mapping file for the User entity and NHibernate configuration are in the provided source code sample] Now I’ll try to describe main Rhino Security model entities from my point of view, which we will explore lately in practice:

-UserGroup – is a user group defined by its name, it’s used to associate users to the group and define common permissions for users that belong to the group. The groups can be structured hierarchically in parent/child relationship. In some cases you can think about users group in terms of Roles which have set of permissions ex: Administrator, Guest, etc…

- Operation – a named operation that also can be structured hierarchically using following convention: “/Content/View”, “/Content/Edit” etc… so if we create a new “/Content/Edit” operation then are created two operations “/Content” as parent and “/Content/Edit” as child. Further you can allow or deny the operation for a User or for a UserGroup. When an operation is allowed or denied for a User, UserGroup, etc… also could be specified a level, levels defines importance of the permission, but very often is used Default Level which is equal to 1. Permission with higher level is more dominant in taking decision of operation allowance. For example: if we deny operation “/Content/View” with default level for a user and after that allow for the same operation but with level 9 then finally the operation will be allowed for the user.

-Permission- is result of allow or deny process for an operation (e.g. “/Content/View”) for a User or UserGroup (or EntityGroups).

-User – represent any entity that implements IUser interface, we already covered it above…

I didn’t cover here EntityGroups, IEntityInformationExtractor, Query Permissions,.. maybe I will cover them in the next posts because I want to concentrate on the basic and most common things, here I only want to mention that they exists and you can use them to associate permissions for any entity that implements IEntityInformationExtractor interface.

For a completeness of the entire image I want to show Rhino Security Data Model and to comment it:

Rhino Security Database Model

All tables which are prefixed with “security_” are related to directly Rhino Security, Users table is used to persist User entity.

Again, tables from red region I won’t touch now because they are related to Entities, shortly, the tables from red region are used to associate permission for entities like Accounts from a given EntitiesGroups or to entities directly (omitting EntitiesGroups) that implements IEntityInformationExtractor which are related by SecurityKey (Accounts.SecurityKey with security_EntityReferences.EntitySecurityKey).

So, from the above diagram we can see that we can allow or deny operations by permission for Users or UserGroups. A User can belong to one or more UserGroups. Operations and UserGroups can be structured hierarchically in parent\child relationship. That’s it... Nothing complicated, is it?

Back to Code:

So, let’s initialize Rhino Security on order to make it work.

First of all we need to initialize Windsor Inversion of Control Container and add at least two Windsor facilities:

1) NHibernateUnitOfWorkFacility

2) RhinoSecurityFacility

we can do it programmatically or using configuration file, here is programmatic version:

//Create container

container = new WindsorContainer();

//Register Unit Of Work Facility instance

container.Kernel.AddFacility("nh", new NHibernateUnitOfWorkFacility());

//Regiser Rhino Security Facility instance:

//1) provide Rhino’s DB table naming convetion:

//  Prefix '_'              ex: security_Permissions or

//  Schema '.'(is default). ex: security.Permissions

//2) provide User Type that implements IUser

container.Kernel.AddFacility("security",

                             new RhinoSecurityFacility(SecurityTableStructure.Prefix, typeof (User)));

All code explanations are in the comments, only what I want to add is that we need to run the code once in application startup.

The configurations could be setup in few ways, and most of them which I saw were using Rhino Bindsor which is Domain Specific Language written in Boo that allows configuring Castle Windsor Inversion of Control container without using any xml tag. Maybe some of you already noted I didn’t go with Boo way, because it can look as more “exotic” way for some folks.

Next, we need to resolve Rhino Security repository\services\facades that will allow us to manage and query Rhino Security model:

//The repository is main "player" that allows to manage security model

authorizationRepository = IoC.Resolve<IAuthorizationRepository>();

//The service provides authorization information                      

authorizationService = IoC.Resolve<IAuthorizationService>();

//Provide a fluent interface that can be used to assign permissions

permissionsBuilderService = IoC.Resolve<IPermissionsBuilderService>();

//Allow to retrieve and remove permissions

//on users, user groups, entities groups and entities.

permissionService = IoC.Resolve<IPermissionsService>(); 

Now, let’s create a transient User entity and save it to DB.

//Create a User

var userArt = new User { Name = ("ArturTrosin") };

UnitOfWork.CurrentSession.Save(userArt);

The user entity we will use to operate with. Then create two groups, child and parent:

//Create "AdminUserGroup" UsersGroup                 

authorizationRepository.CreateUsersGroup("AdminUserGroup");

//Create Child group for "AdminUserGroup"

authorizationRepository.CreateChildUserGroupOf("AdminUserGroup", "GuestUserGroup");

Then create three operations:

//Create two operations: root /Content          operation

//              and its child /Content/Manage   operation

authorizationRepository.CreateOperation("/Content/Manage");

UnitOfWork.Current.TransactionalFlush();

//Create third operation as child of the /Content

authorizationRepository.CreateOperation("/Content/View");

Associate user with created group:

//add user to "AdminUserGroup", so all further permissions for "AdminUserGroup"

//group are aslo applied for the user also              

authorizationRepository.AssociateUserWith(userArt, "AdminUserGroup");

Here is how we can associate two permissions for a user group or a user:

//Create Permission using Builder Pattern

//and its fluent interface:              

permissionsBuilderService

  //Allow "/Content" Operation

  .Allow("/Content")

  //for "AdminUserGroup"

  .For("AdminUserGroup")

  //Could be specified On an entityGroup

  //or an entity that implemented IEntityInformationExtractor 

  .OnEverything()

  //Here could be specified Permission priority Level

  //DefaultLevel is equal with 1

  .DefaultLevel()

  .Save();

 

//Create Deny permission for user with level 5   

permissionsBuilderService

  .Deny("/Content/View")                 

  .For(userArt)                

  .OnEverything()                 

  .Level(5)

  .Save();

 

In the next code lines are demonstrated few Rhino Security methods that allows you to retrieve various info:

//Ask users allowance for an Operation

bool isAllowedContentOp = authorizationService.IsAllowed(userArt, "/Content");

bool isAllowedContentManageOp = authorizationService.IsAllowed(userArt, "/Content/Manage");

 

//Retrieve Rhino Security entities 

UsersGroup adminUsersGroupWithoutUser = authorizationRepository.GetUsersGroupByName("AdminUserGroup");

Operation contentViewOp = authorizationRepository.GetOperationByName("/Content/View");

Permission[] userArtPermission = permissionService.GetPermissionsFor(userArt);

 

//Retrieve athorization info that can help to

//understand reason of allowance (or not) of an operation

//its very helpful for debuging

AuthorizationInformation authInfo = authorizationService

                                                   .GetAuthorizationInformation(userArt, "/Content");

And finally remove created entities:

//Cleanup created entities

authorizationRepository.RemoveOperation("/Content/Manage");

authorizationRepository.RemoveOperation("/Content/View");

authorizationRepository.RemoveOperation("/Content");

//Remove child group first

authorizationRepository.RemoveUsersGroup("GuestUserGroup"); 

authorizationRepository.RemoveUsersGroup("AdminUserGroup");              

 

authorizationRepository.RemoveUser(userArt);               

UnitOfWork.CurrentSession.Delete(userArt); 

Link to full source code and libs is here.

Note that I didn’t show code of UoW Flush method calls, which persists changes to DB. And of course in order to run the code you need a database with Rhino Security DB schema in it similar to provided earlier, so there is a method which will do all the dirty work for you:

new DbSchema().Generate(container);

The only thing that you should care is to create an empty DB (named Security_Test) and verify if connection string from hibernate.cfg.xml file is set properly.

 Conclusion

Even Rhinos tools could be not compatible between SVN versions; However most of the Rhino bits are used already in production environments and are very popular with a great community support.

So, I would recommend taking Rhino Security in account if you already use NHibernate and if you need a similar model or your required model could be expressed with Rhino Security model.

Notice: The code is tested with VS 2008 sp1 and Sql server 2005.

Thank you,

Artur Trosin

 

Published Thursday, April 2, 2009 9:27 AM by Artur Trosin

Comments

# re: Rhino Tools: Rhino Security Guide

Tuesday, April 7, 2009 9:39 AM by Lance

Thanks for this.  I've been wanting to see a walkthrough of this for awhile now.

# re: Rhino Tools: Rhino Security Guide

Monday, April 13, 2009 4:48 PM by Jeff

Thanks for the useful info. I have been looking into rhino security recently.

It would be great if you could cover EntitiesGroups and other areas of Rhino security skipped in this post.

jeff

# re: Rhino Tools: Rhino Security Guide

Thursday, April 23, 2009 8:30 AM by Miha Necak

Great post, i must say. I do however have one question. What version of NHibernate are you using during the build of Rhino.Security (Tools)? There have been many changes in the code base (2.1), which make the current version incompatible with the one in the trunk. Did you modify Rhino.Security to make it compatible? Are u using a second version within you application - both at the same time? Thanks in advance for any explanation.

Regards, Miha

# re: Rhino Tools: Rhino Security Guide

Thursday, April 23, 2009 3:43 PM by Artur Trosin

Hi All,

Thank you for positive feedback, it’s really important for me.

@ Jeff

Possible I will cover also the skipped part but I don’t promise that it would be soon, but believe me that entities part that was skipped by me is not so large topic, if it is really critical for you then I can advice to take a look to Rhino Security Unit tests for the usage, which is good source for learning, or you can ask me directly for some specific questions.

@ Miha

I’ve used NH version from the trunk which is located in the Rhino\SharedLibs\NHibernate folder, I didn’t download any fresh version.  In general, I don’t recommend to use two NH versions and  I’m not sure if it is even possible to have both at the same time.

So, try to get new NH version and to replace all the assemblies from Rhino\SharedLibs\NHibernate and then rebuild the solution, or replace manually the references in from rhino projects then run the tests to see if all of them pass. I didn’t try it by myself so if it works share the info :).

Hope this helps

# re: Rhino Tools: Rhino Security Guide

Wednesday, July 15, 2009 8:58 PM by dotnet.coder

Thanks for the useful info. I have been looking into rhino security recently.

It would be great if you could cover EntitiesGroups and other areas of Rhino security skipped in this post.

# re: Rhino Tools: Rhino Security Guide

Monday, July 20, 2009 9:04 PM by dotnet.coder

Do we need to add tables in the rhino security schema for each and every entity we want to add to entity group ??? or the entities would be picked from application schema only ????

# re: Rhino Tools: Rhino Security Guide

Tuesday, July 21, 2009 2:30 AM by Artur Trosin

Hi @dotnet.coder,

You can store your entities wherever you want (even outside the DB), the only info that is required to “know” by Rhino Security is IEntityInformationExtractor. The interface (should) provides a unique key that in unique mode indentify the entity when the entity is associated with Rhino Security(e.g. add permission for the entity, the entity is added to group,…).

Hope that helps

# re: Rhino Tools: Rhino Security Guide

Tuesday, July 21, 2009 8:36 PM by dotnet.coder

hi

How does the rhino security interact with the entities

> present in application schema(say in sharparch . core )?

> The examples given always show a coding line as

>

> Account account =

> Repository<Account>.FindFirst();    

>        

> User user = Repository<User>.FindFirst();

>  var auth =

> container.Resolve<IAuthorizationService>();

>    Console.WriteLine(auth.IsAllowed(user,

> account, "/Account/Delete"));

> Console.WriteLine(auth.GetAuthorizationInformation(user,

> account, "/Account/Delete"));

>

> Now where is this "Accounts " table ? is it in application

> schema or rhino schema ? n what is the use of

> Repository<Account>.FindFirst(); ???  

>        

> Can u pls send a demo on functionalities like adding

> entities to entity groups ,IEntityInformationextractor

> ?  as the data on these things are not very

> elaborartive on the forums ?

# re: Rhino Tools: Rhino Security Guide

Wednesday, July 22, 2009 1:13 AM by dotnet coder

Can u publish a post for" EntityGroups, IEntityInformationExtractor, Query Permissions,.. ,Permissions class " ??? A demo would be a good start to look into these left out topics of rhino security .

# re: Rhino Tools: Rhino Security Guide

Thursday, August 27, 2009 9:59 AM by Rich

Do you know if it is possible to use Rhino Security with Castles NHibernate Integration facility? It looks like the need to have a Hibernate.cfg.xml configuration file will not allow it.

# re: Rhino Tools: Rhino Security Guide

Thursday, November 19, 2009 1:41 AM by anon

In Program.cs, this line throws a NullReferenceException:

Console.WriteLine("Returned first Permission UsersGroup: {0}", userArtPermission[0].UsersGroup.Name);

The "UsersGroup" is null. I really don't understand why that would be null?

# re: Rhino Tools: Rhino Security Guide

Thursday, November 19, 2009 3:12 AM by Artur Trosin

@Anon

I've updated the sample with explanations.

Thank you.