This is the part 3 of a series of posts on Rhino Security, which is an enterprise security framework built on top of NHibernate, by Ayende Rahien. In part 2 I looked at how Rhino Security works. Here I’ll look at getting it up and running. Again I’ll be referencing back to points I made in previous parts so I’m assuming you’ve read and understood them.
First up lets get some binaries. You can download the latest build here.
If you interested compiling from source you can grab it here. For the Mono chaps, I’m afraid the the Rhino Security build scripts are psake, which is an automation tool for Powershell, a Windows command line shell . There is a cross platform implementation of Powershell out in the wild but with limited functionality, so moving forwards its either writing a nant build script or investigating the aforementioned PASH.
We also need to grab the Common Service Locator as Rhino Security depends on this. Previous versions of Rhino Security used to depend on Castle Windsor but it can now be used with any IOC container, as it now depends on the CSL which is essentially an interface for IOC containers, more on this in a moment.
Essentially we need to do 7 things before we can start using Rhino Security on our project:
- Register several Rhino Security services on our container so that our application can use them.
- Configure our IOC container so when Rhino Security requests something which implements an ISession, the session is returned to it.
- Configure the CSL to point to Windsor.
- Augment our NHibernate configuration data with some Rhino Security table information.
- Add some security keys on our entities.
- Implement IUser on our user entity.
- Add an entity information extractor so that Rhino Security understands our domain sufficiently.
Now to my specific setup, I’m using Castle Windsor as my IOC container, binsor to configure it, and the Castle NHibernate Facility. Rhino Security used to come with a facility you could simply reference in your config but now that it no longer depends on Windsor we need to write a custom facility (or extension point depending on your choice of container/preferred language) to achieve our first 2 objectives. Using Windsor, my facillity looks like this
public class RhinoSecurityFacility : AbstractFacility
{
protected override void Init ()
{
Kernel.Register (Component.For<IAuthorizationService> ()
.ImplementedBy<AuthorizationService> ()
.LifeStyle.PerWebRequest,
Component.For<IAuthorizationRepository> ()
.ImplementedBy<AuthorizationRepository> ()
.LifeStyle.PerWebRequest,
Component.For<IPermissionsBuilderService> ()
.ImplementedBy<PermissionsBuilderService> ()
.LifeStyle.PerWebRequest,
Component.For<IPermissionsService> ()
.ImplementedBy<PermissionsService> ()
.LifeStyle.PerWebRequest);
Kernel.Resolver.AddSubResolver (new SessionResolver ());
}
}
I start by registering Rhino Security services on the container. These services are transient to ensure that any call to that service grabs the current session. I then add a Session Resolver. There are several ways of configuring the session, you can use a factory method or make use of an ISubDependencyResolver, which is the method I have chose. The main reason for this is that the factory method implements IDisposable and can lead to memory leaks, though there are workarounds for this. Also this method would allow you to use multiple dbs, which you couldn’t achieve with the factory method.
Here is my Session Resolver
using Castle.Core;
using Castle.Facilities.NHibernateIntegration;
using Castle.MicroKernel;
using NHibernate;
public class SessionResolver : ISubDependencyResolver
{
IKernel Kernel { get; set; }
public object Resolve (CreationContext context,
ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency)
{
return Kernel.Resolve<ISessionManager> ().OpenSession ();
}
public bool CanResolve (CreationContext context,
ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency)
{
return typeof(ISession).IsAssignableFrom (dependency.TargetType);
}
}
You notice that I am resolving the ISessionManager, this is something the NH facility provides me which manages the session. Essentially in here you need whatever manages your Unit of Work to return the current session.
Ok, first 2 down. Now step 3. I need to add a Windsor adaptor for the CSL, again written by Ayende Rahien
using System;
using System.Collections.Generic;
using Castle.Windsor;
using Microsoft.Practices.ServiceLocation;
public class WindsorServiceLocator : ServiceLocatorImplBase
{
private readonly IWindsorContainer container;
public WindsorServiceLocator (IWindsorContainer container)
{
this.container = container;
}
protected override object DoGetInstance (Type serviceType, string key)
{
if (key != null)
return container.Resolve (key, serviceType);
return container.Resolve (serviceType);
}
protected override IEnumerable<object> DoGetAllInstances (Type serviceType)
{
return (object[])container.ResolveAll (serviceType);
}
}
And now to tell the Service Locator to use Windsor, I add this line where I have access to my container, as I’m dealing with a web app I add it in my Application_OnStart()
ServiceLocator.SetLocatorProvider (() => new WindsorServiceLocator (_container));
Step 4 can be achieved by a static method Rhino Security makes available to us.
Security.Configure<Person> (configuration, SecurityTableStructure.Prefix);
The Castle NHibernate facility allows you to modify the NHibernate configuration as its being constructed. Within my binsor NHibernate facility configuration I make a call to my specific configuration builder class, this implements IConfigurationBuilder, an interface provided by the Castle NHibernate facility. The method GetConfiguration accepts my facility configuration which I can then augment using the method above and then return. You can read more about how the facility works here. If your not using the Castle NHibernate Facility, at the point your Unit of Work code registers the ISessionFactory on the container you’ll want to augment your NHibernate config using the above code.
Step 5 and 6 are more time consuming than anything else, simply implement the IUser interface on your user entity and add a GUID security key on EVERY entity :)
Step 7, requires the addition of an entity information extractor, this is a class Rhino uses to understand the parts of our domain it needs to. Firstly Rhino Security needs to understand which property of your entity holds the SecurityKey. Secondly it needs to understand how to look up entities based on the key and return some meaningful information about it.
You can either write one for each entity or write a generic one, heres my generic one
public class EntityInformationExtractor<TEntity> : IEntityInformationExtractor<TEntity>
where TEntity : Entity
{
private ISessionManager sessionManager;
public EntityInformationExtractor (ISessionManager SessionManager)
{
sessionManager = SessionManager;
}
public Guid GetSecurityKeyFor (TEntity entity)
{
return entity.SecurityKey;
}
public string SecurityKeyPropertyName {
get { return "SecurityKey"; }
}
public string GetDescription (Guid SecurityKey)
{
TEntity entity;
var criteria = DetachedCriteria.For<TEntity> ().Add (Expression.Eq (SecurityKeyPropertyName(), SecurityKey));
using (ISession session = sessionManager.OpenSession ()) {
entity = criteria.GetExecutableCriteria (session).UniqueResult<TEntity> ();
}
return string.Format ("Event: {0}", entity.Name);
}
}
Method 1 and 2 deal with accessing the property which contains the Security Key, firstly when Rhino Security has the entity and secondly when it doesn’t. Method 3 reports on the entity in question. I just choose to return the entities name. I can do this generically as I have made my entire domain inherit from a class called entity which has the properties Id, Name and SecurityKey, hence why TEntity : Entity in this class.
Thats it. Configure your facility/extension on your container, add some Rhino Security tables in your database and you should be ready to start writing code!
I realise this may not all immediately make sense but it is worth having a good grounding on the principles of Rhino Security, before writing code.
Next post
Part 4: Using Rhino Security
I’m new to rhino security. I’m really want to use it at work but still struggling to get it working. Can you please share a complete solution or something from where to start?. I mean, I don’t even pass the configuration stage, everything feels so overwhelming in .NET land, I think that I need more time with it.
Any code that you are willing to share with me, comments or anything regarding rhino security and friends (lots of dependencies) will be highly appreciated. Really need to get up and running with rhino security at work.
good posts, looking forward for the next installments.
Link | February 23rd, 2011 at 7:32 pm
@Julio
The problem with providing a sample application/complete solution is that there are many different environments in which you can choose to us Rhino Security. That is why in part 3 I first outline the principles behind what is required so you can understand how they are being applied when I start showing code and, thus, have to use an explicit example.
What, specifically, are you struggling with?
Link | February 23rd, 2011 at 9:06 pm
Dan, thanks for the quick reply.
I’m working in a windows form application at work, I’m the guy in charge of the security. So, my environment is the simplest there is, I think. I’m trying to write a security model that don’t mess a lot with the domain model, and is that very reason why rhino security catches my eye in the first place, the wiring with the rest of the application would be by filters, attributes, convention, whatever, but the security model really has to be separeted and evolved without touching the domain model. The problem, of course, is that I’m really new to all the .NET ecosystem.
I don’t think that the rhino api will present much of a problem, what I’m really struggling with is the configuration/initialization part, I think I understand everything you said but I’m still having problems wiring everything together.
Also, for a desktop application windows form, what do you think would be the best approach for using rhino security? can you point me in the right direction and/or examples?
Link | February 24th, 2011 at 1:40 pm
@Julio,
The best place to look for code examples are first and foremost the tests of the project itself. And then 2 sample apps:
https://github.com/nexida/Rhino-Security-Administration.git
http://code.google.com/p/winecellarmanager/
Both are web applications but they should provide an insight.
My intention in these posts is to explain the principles behind what is required to configure Rhino Security so that you may apply it to your environment, rather than simply copying code verbatim. If you understand what I have laid out, where is your implementation falling down? If the issue is beyond the scope of a single question perhaps you need to hire a consultant.
Link | February 25th, 2011 at 12:44 am
Hi Dan…
Are you expecting to post the fourth article (Using Rhino Security) in the rhino series anytime soon?
cheers and good work…
Link | March 15th, 2011 at 7:56 pm
@Arletis
I have various material gathered, I just need to find some time to put it together! Hopefully before the month is up. Is there any particular aspect your interested in?
Link | March 15th, 2011 at 9:31 pm
Well Dan, how do I register the session?
When I run following your configuration an exception is raised saying that my services are waiting for dependencies, in this case an ISession.
Doesn’t the NHibernate facility is in charge of that?
very eagear waiting for your next post…
cheers…
Link | March 16th, 2011 at 4:46 pm
@Arletis
I won’t be covering anymore configuration in part 4. I’ll be looking at using the functionality Rhino Security provides…
Point 2 of my list covers registering the session on the container.
Link | March 16th, 2011 at 7:07 pm
Love your post.
Any implementation of Rhino Security in Entity Framework?
Link | May 4th, 2011 at 2:07 am
Hi Dan,
Quick question, I working on custom web application and already configured Nhibernate.Burrow framework with Fluent. At this moment I am looking for Security and seems like Rhino is answer specially for nhibernate but I am in nutshell. My main concern is about IOC and windsor, as I have never used any activerecord.
Does configuring Windsor require full configure and knowledge of ActiveRecord…
Can you please and other who used this post can shed some thought with code…
Link | February 10th, 2012 at 7:03 pm
@George
Not at all, Castle.ActiveRecord is just an implementation of a . It sits on top of NHibernate and attempts to simplify data access, it is no way required. You can just use NHibernate directly.
@Jopo
I’m afraid RS is just for NHibernate, in theory it should be fairly easy to make it work with any relational DB. Feel free to submit a patch :-)
Link | February 17th, 2012 at 2:00 pm