Ayende @ Rahien

It's a girl

Public Service Announcement: Git master repositories for the Rhino Tools projects

There have been some changes, and it seems that it is hard to track them. Here are where you can find the master repositories for the rhino tools projects:

Security Models: On Behalf Of

In a security system, On Behalf Of is a vastly underutilized concept. I created that for the first time in 2007, in a project that spurred the creation of Rhino Security. On Behalf Of allows another user to assume the mantle of another user. From the authorization system, once you activate On Behalf Of, you are that other user. That means that you have all the access rights (and limitations) of that user.

Why is this useful?

  • On Behalf Of gives a help desk operator a very quick way to reproduce a bug that a user run into. Usually those bugs are things like “why can’t I see product Foo”, or “I run into a bug in Order #823838”. Those bugs can only be reproduced when the help desk operator is running within the security context of the user.
  • On Behalf Of represent how the real world work. Imagine a Team Leader that takes a vacation. For the duration of the vacation, there is someone else that assumes that Team Leader role on a temporary basis. On Behalf Of allows that someone to do the required work, in the the context of the Team Leader, which allows her to perform operations that she would otherwise may not be able to do.

Auditing

On Behalf Of has important implications on auditing. In most systems where auditing plays a role, the user who perform the action is just as important as the action that was taken. On Behalf Of integrates with the auditing system, to indicate not only who actually did the operation (the end user), but also what user that operation was On Behalf Of. This is important, because it avoid “impossible” audit entries later on, where either “I was in vacation that time, I couldn’t have done it” or “I never had permissions to do this, there is a bug in the system” might crop up.

It is important to note that most systems where On Behalf Of is used have a sophisticated security rules. At that point, system administrators are more akin to Windows’ Administrators than Unix’s Root. In Unix, if you are root, you can do whatever you like. In Windows, if you are Administrator, you can do almost everything that you like. A typical example is that as an administrator on Windows, you can’t read another’s user files without leaving a mark that you can’t remove (changing ownership), but there are others.

You can think about On Behalf Of as an extension to this, we want to act as another user, but we have to know that we did. That is why you want to be able to pull the operations made by users acting On Behalf Of other users from the Auditing System easily. In fact, when running On Behalf Of, your audit level is much increased, because we need to track what sort of operations you made, even operations that are normally below the audit level of the system (viewing an entity you otherwise had no way of accessing, for example).

Authorization

From authorization perspective, the actual mechanics are pretty simple, instead of passing the actual user to the security system, you pass the user that we execute operations On Behalf Of.

However, the security system does need to be aware of On Behalf Of, because there are some operations that you cannot perform On Behalf Of someone else. For example, while I may be authorized to act On Behalf on another Team Leader, it is not possible for me to fire a team member while operating On Behalf Of Team Leader. Firing someone is a decision that can be made only by that person direct manager, not by someone acting On Behalf Of. This is a business decision, mind you, to define the set of operations that may be performed On Behalf Of (usually most of them) and the few critical ones that you mustn’t.

Authentication

As you can imagine, there is a great deal to abuse with this feature, so for the most part, it is strictly limited. Usually it is active for system administrators only, but very often, there are both temporary and permanent set of conditions where On Behalf Of is enabled.

For example, an exec is always able to act On Behalf OF his captain. And we already discussed covering another Team Leader when they are sick / vacationing / etc.

Summary

On Behalf Of is a powerful feature, but it requires understanding from the users, it has the potential to be looked at as a security hole, even though it is just a reflection of how we work in real life. And the implications if the users expect some level of privacy in the system are huge. A large part of implementing On Behalf OF correctly isn’t in the technical details, it is in the way you build /document / sale it to the users.

Handling complex security conditions with Rhino Security

I got an interesting question about handling complex security conditions that I thought would be perfect to illustrate the underlying design principles for Rhino Security.

The problem is securing surveys. A survey has a start date, an end date, can be marked as applicable to a specific population, may be public or private, etc. The specification says that a survey that the user does not own should only be visible to a user iff:

  • The survey is public
  • The survey is active
  • The survey has started
  • The survey has not ended
  • The survey is for a population that the user is a member of

Can you imagine the amount of work that is required to set up this sort of rule properly? And apply it consistently all over the application? It is exactly for those sort of scenarios that I created Rhino Security.

Let us see how we are going to design the security infrastructure for the application. We are going to specify the following:

  • The owning user for a survey is allowed access at a high level:
    permissionsBuilderService
        .Allow("/Survey") // allow to do everything on a survey
        .For(survery.Owner)
        .On(survey)
        .Level(10)
        .Save();
  • If the survey is for a particular population, that population is created as a user group, and we create a rule that allow that user group access to the survey:
    permissionsBuilderService
        .Allow("/Survey/Vote")
        .For(survery.Population.Name) // the user group name
        .On(survey)
        .Level(1)
        .Save();
  • The other permissions are specified globally, we need to do an and between all of them, and Rhino Security doesn’t give us direct support for that. What we do get, however, is Deny and levels, so we specify those permissions using the following:
    permissionsBuilderService
        .Deny("/Survey/Vote")
        .For("Everyone") // all users
        .On("Inactive Surveys") // an entity group
        .Level(6)
        .Save();
    
    permissionsBuilderService
        .Deny("/Survey/Vote")
        .For("Everyone") // all users
        .On("Private Surveys") // an entity group
        .Level(6)
        .Save();
    
    permissionsBuilderService
        .Deny("/Survey/Vote")
        .For("Everyone") // all users
        .On("Completed Surveys") // an entity group
        .Level(6)
        .Save();
    
    permissionsBuilderService
        .Deny("/Survey/Vote")
        .For("Everyone") // all users
        .On("Unstarted Surveys") // an entity group
        .Level(6)
        .Save();

Now, that we have set it up, what we need to do now is to add and remove the survey to the appropriate entity groups, based on whatever business conditions that we have. Note that those are explicit state transitions. This isn’t just us setting IsActive and IsPublic flag, or verifying date ranges. We have to take explicit action to add and remove the entities from the appropriate groups.

There are two reasons of doing things in this way, the first, it make it significantly easier to handle security, since we don’t have murky rules or implicit state transitions. Second, from a design standpoint, it leads to a situation where we don’t work with just dump objects and queries, but meaningful transitions between states.

Yes, that does implies that you would have to have some sort of a background process to move surveys between groups based on time. That is a good thing, but I talked about this in another post.

On PSake

James Kovacks introduced psake ( a power shell based build system )over a year ago, and at the time, I gave it a glance and decided that it was interesting, but not worth further investigation.

This weekend, as I was restructuring my Rhino Tools project, I realized that I need to touch the build system as well. The Rhino Tools build system has been through several projects, and was originally ported from Hibernate. It is NAnt based, complex, and can do just about everything that you want expect be easily understandable.

It became clear to me very quickly that it ain’t going to be easy to change the way it works, nor would it be easy to modify that to reflect the new structure. There are other issues with complex build systems, they tend to create zones of “there be dragons”, where only the initiated go, and even they go with trepidation. I decided to take advantage of the changes that I am already making to get a simpler build system.

I had a couple of options open to me: Rake and Bake.

Bake seemed natural, until I remember that no one touched it in a year or two. Beside, I can only stretch NIH so far :-). And while I know that people rave about rake, I did not want to introduce a Ruby dependency on my build system. I know that it was an annoyance when I had to build Fluent NHibernate.

One thing that I knew that I am not willing to go back to was editing XML, so I started looking at other build systems, ending up running into PSake.

There are a few interesting things that reading about it brought to mind. First, NAnt doesn’t cut it anymore. It can’t build WPF applications nor handle multi targeting well. Second, I am already managing the compilation part of the build using MSBuild, thanks to Visual Studio.

That leave the build system with executing msbuild, setting up directories, executing tests, running post build tools, etc.

PSake handles those well, since the execution environment is the command line. The syntax is nice, just enough to specify tasks and dependencies, but everything else is just pure command line. The following is Rhino Mocks build script, using PSake:

properties { 
  $base_dir  = resolve-path .
  $lib_dir = "$base_dir\SharedLibs"
  $build_dir = "$base_dir\build" 
  $buildartifacts_dir = "$build_dir\" 
  $sln_file = "$base_dir\Rhino.Mocks-vs2008.sln" 
  $version = "3.6.0.0"
  $tools_dir = "$base_dir\Tools"
  $release_dir = "$base_dir\Release"
} 

task default -depends Release

task Clean { 
  remove-item -force -recurse $buildartifacts_dir -ErrorAction SilentlyContinue 
  remove-item -force -recurse $release_dir -ErrorAction SilentlyContinue 
} 

task Init -depends Clean { 
    . .\psake_ext.ps1
    Generate-Assembly-Info `
        -file "$base_dir\Rhino.Mocks\Properties\AssemblyInfo.cs" `
        -title "Rhino Mocks $version" `
        -description "Mocking Framework for .NET" `
        -company "Hibernating Rhinos" `
        -product "Rhino Mocks $version" `
        -version $version `
        -copyright "Hibernating Rhinos & Ayende Rahien 2004 - 2009"
        
    Generate-Assembly-Info `
        -file "$base_dir\Rhino.Mocks.Tests\Properties\AssemblyInfo.cs" `
        -title "Rhino Mocks Tests $version" `
        -description "Mocking Framework for .NET" `
        -company "Hibernating Rhinos" `
        -product "Rhino Mocks Tests $version" `
        -version $version `
        -clsCompliant "false" `
        -copyright "Hibernating Rhinos & Ayende Rahien 2004 - 2009"
        
    Generate-Assembly-Info `
        -file "$base_dir\Rhino.Mocks.Tests.Model\Properties\AssemblyInfo.cs" `
        -title "Rhino Mocks Tests Model $version" `
        -description "Mocking Framework for .NET" `
        -company "Hibernating Rhinos" `
        -product "Rhino Mocks Tests Model $version" `
        -version $version `
        -clsCompliant "false" `
        -copyright "Hibernating Rhinos & Ayende Rahien 2004 - 2009"
        
    new-item $release_dir -itemType directory 
    new-item $buildartifacts_dir -itemType directory 
    cp $tools_dir\MbUnit\*.* $build_dir
} 

task Compile -depends Init { 
  exec msbuild "/p:OutDir=""$buildartifacts_dir "" $sln_file"
} 

task Test -depends Compile {
  $old = pwd
  cd $build_dir
  exec ".\MbUnit.Cons.exe" "$build_dir\Rhino.Mocks.Tests.dll"
  cd $old        
}

task Merge {
    $old = pwd
    cd $build_dir
    
    Remove-Item Rhino.Mocks.Partial.dll -ErrorAction SilentlyContinue 
    Rename-Item $build_dir\Rhino.Mocks.dll Rhino.Mocks.Partial.dll
    
    & $tools_dir\ILMerge.exe Rhino.Mocks.Partial.dll `
        Castle.DynamicProxy2.dll `
        Castle.Core.dll `
        /out:Rhino.Mocks.dll `
        /t:library `
        "/keyfile:$base_dir\ayende-open-source.snk" `
        "/internalize:$base_dir\ilmerge.exclude"
    if ($lastExitCode -ne 0) {
        throw "Error: Failed to merge assemblies!"
    }
    cd $old
}

task Release -depends Test, Merge {
    & $tools_dir\zip.exe -9 -A -j `
        $release_dir\Rhino.Mocks.zip `
        $build_dir\Rhino.Mocks.dll `
        $build_dir\Rhino.Mocks.xml `
        license.txt `
        acknowledgements.txt
    if ($lastExitCode -ne 0) {
        throw "Error: Failed to execute ZIP command"
    }
}

It is about 50 lines, all told, with a lot of spaces and is quite readable.

This handles the same tasks as the old set of scripts did, and it does this without undue complexity. I like it.

The complexity of unity

This post is about the Rhino Tools project. It has been running for a long time now, over 5 years, and amassed quite a few projects in it.

I really like the codebase in the projects in Rhino Tools, but secondary aspects has been creeping in that made managing the project harder. In particular, putting all the projects in a single repository made it easy, far too easy. Projects had an easy time taking dependencies that they shouldn’t, and the entire build process was… complex, to say the least.

I have been somewhat unhappily tolerant of this so far because while it was annoying, it didn’t actively create problems for me so far. The problems started creeping when I wanted to move Rhino Tools to use NHibernate 2.1. That is when I realized that this is going to be a very painful process, since I have to take on the entire Rhino Tools set of projects in one go, instead of dealing with each of them independently. the fact that so many of the dependencies where in Rhino Commons, to which I have a profound dislike, helped increase my frustration.

There are other things that I find annoying now, Rhino Security is a general purpose library for NHibernate, but it makes a lot of assumptions about how it is going to use, which is wrong. Rhino ETL had a dependency on Rhino Commons because of three classes.

To resolve that, I decided to make a few other changes, taking dependencies is supposed to be a hard process, it is supposed to make you think.

I have been working on splitting the Rhino Tools projects to all its sub projects, so each of them is independent of all the others. That increase the effort of managing all of them as a unit, but decrease the effort of managing them independently.

The current goals are to:

  • Make it simpler to treat each project independently
  • Make it easier to deal with the management of each project (dependencies, build scripts)

There is a side line in which I am also learning to use Git, and there is a high likelihood that the separate Rhino Tools projects will move to github. Suversion’s patching & tracking capabilities annoyed me for the very last time about a week ago.

Opening seams for testing

While testing Rhino Service Bus, I run into several pretty annoying issues. The most consistent one is that the actual work done by the bus is done on another thread, so we have to have some synchronization mechanisms build into the bus just so we would be able to get consistent tests.

In some tests, this is not really needed, because I can utilize the existing synchronization primitives in the platform. Here is a good example of that:

   1: [Fact]
   2: public void when_start_load_balancer_that_has_secondary_will_start_sending_heartbeats_to_secondary()
   3: {
   4:     using (var loadBalancer = container.Resolve<MsmqLoadBalancer>())
   5:     {
   6:         loadBalancer.Start();
   7:  
   8:         Message peek = testQueue2.Peek();
   9:         object[] msgs = container.Resolve<IMessageSerializer>().Deserialize(peek.BodyStream);
  10:  
  11:         Assert.IsType<HeartBeat>(msgs[0]);
  12:         var beat = (HeartBeat)msgs[0];
  13:         Assert.Equal(loadBalancer.Endpoint.Uri, beat.From);
  14:     }
  15: }

Here, the synchronization is happening in line 8, Peek() will wait until a message arrive in the queue, so we don’t need to manage that ourselves.

This is not always possible, however, and this actually breaks down for more complex cases. For example, let us inspect this test:

   1: [Fact]
   2: public void Can_ReRoute_messages()
   3: {
   4:     using (var bus = container.Resolve<IStartableServiceBus>())
   5:     {
   6:         bus.Start();
   7:         var endpointRouter = container.Resolve<IEndpointRouter>();
   8:         var original = new Uri("msmq://foo/original");
   9:  
  10:         var routedEndpoint = endpointRouter.GetRoutedEndpoint(original);
  11:         Assert.Equal(original, routedEndpoint.Uri);
  12:  
  13:         var wait = new ManualResetEvent(false);
  14:         bus.ReroutedEndpoint += x => wait.Set();
  15:  
  16:         var newEndPoint = new Uri("msmq://new/endpoint");
  17:         bus.Send(bus.Endpoint,
  18:                  new Reroute
  19:                  {
  20:                      OriginalEndPoint = original,
  21:                      NewEndPoint = newEndPoint
  22:                  });
  23:  
  24:         wait.WaitOne();
  25:         routedEndpoint = endpointRouter.GetRoutedEndpoint(original);
  26:         Assert.Equal(newEndPoint, routedEndpoint.Uri);
  27:     }
  28: }

Notice that we are making explicit synchronization in the tests, line 14 and line 24. ReroutedEndpoint is an event that we added for the express purpose of allowing us to write this test.

I remember several years ago the big debates on whatever it is okay to change your code to make it more testable. I haven’t heard this issue raised in a while, I guess that the argument was decided.

As a side note, in order to get rerouting to work, we had to change the way that Rhino Service Bus viewed endpoints. That was a very invasive change, and we did it in less than two hours, but simply making the change and fixing the tests where they broke.

The data access challenge: Implement Rhino Security

Rhino Security is an awesome little framework that provide security infrastructure for applications. I created that after having to rebuild a security infrastructure five times, due to changing requirements. It is implemented on top of NHibernate.

I would like to challenge you to implement Rhino Security in your data access strategy of choice. Here is the design, intro and implementation notes. And of course that the code itself is accessible here.

If you think that your data access strategy is awesome, show me the code. Rhino Security is a non trivial example, but it is still quite small, about 1,700 lines of code. So that is quite doable.

Oh, and I would love to see implementations on non RDBMS platforms.

I don't expect anyone to step up and do this, by the way. For the simple reason that I don't think that this is possible. And yes, that is said in the vain hope that someone will actually show me one.

When your extensibility strategy is OOD...

You get to have really simple solutions.

One of the reasons that I like NHibernate so much is that is allow me to use Object Oriented solutions to my problems. Case in point, we have the Rhino Security library, which provide a facility for asking security questions about your domain.

Bart had an issue with Rhino Security, he wanted to extend the library to also contain a type. The original idea was to add a int field called AppSpecific, which will let each app define additional information on top of the existing domain model.

That made me feel so Win32 that I had to go and sleep for a while. I suggested the following OO solution:

public class BartOperation : Operation
{
      OperationType OperationIsStronglyTyped {get;set;}

} 

I mean, if you want to extend Operation, why not... extend operation?

The problem is, I think, that most people have been so brain washed by the impendence mismatch that this wouldn't occur to them. Bart went away and implemented that suggestion, the whole exchange took less than a day.

Chose your tools carefully, and use them well, for they will reward you aplenty.

What hid under the bed...

public class ARValidatingAuthorizationRepository<TIEntityType, TIUsersGroup, TIEntitiesGroup, TIOperation, TIEntityReference, TIPermission>     
  :  RhinoAuthorizationRepository< TIEntityType, TIUsersGroup, TIEntitiesGroup, TIOperation, TIEntityReference, TIPermission> 
      where TIEntityType : class, IEntityType, new()
      where TIUsersGroup : class, IUsersGroup, new()
      where TIEntitiesGroup : class, IEntitiesGroup, new()
      where TIOperation : class, IOperation, new()
      where TIEntityReference : class, IEntityReference, new()
      where TIPermission : class, IPermission, new()

Rhino Security: External API

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:

image

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:

image

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:

image

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.

Interception as an extensibility mechanism

I got a request to allow system-mode for Rhino Security, something like this:

using(Security.ActAsSystem())
{
	// in here the security behaves as if you have permission 
	// to do everything
	// queries are not enhanced, etc.
}

It is not something that I really want to allow, so I started to think how we can implement this, I came up with the following solution:

public class AuthorizationServiceWithActAsSystemSupport : IAuhorizationService
{
	IAuhorizationService inner;

	public AuthorizationServiceWithActAsSystemSupport(IAuhorizationService inner)
	{
		this.inner = innner;
	}

	private bool IsActAsSystem
	{
		get { return true.Equals(Local.Data["act.as.system"]); }
	}

	public bool IsAllowed(IUser user, string operationName)
	{
		if(IsActAsSystem)
			return true;
		return inner.IsAllowed(user, operationName);
	}

	public void AddPermissionsToQuery(IUser user, string operationName, ICriteria query)
	{
		if(IsActAsSystem)
			return;
		inner.AddPermissionsToQuery(user, operationName, query);
	}

	// .. the rest
}

Now, all we need to do is register it first:

component IAuthorizationService, AuthorizationServiceWithActAsSystemSupport

faciliy RhinoSecurityFacility

And that is it. This both answer the requirement and doesn't add the functionality that I don't like to the system.

Again, neat.

Rhino Security: Part II - Discussing the Implementation

I just finished testing an annoying but important feature, NHibernate's second level cache integration with Rhino Security. The security rules are a natural candidate for caching, since they change to change on an infrequent basis but are queried often. As such, it is obvious why I spent time ensuring that the whole thing works successfully.

At any rate, what I wanted to talk about today was structure of the framework. You can see the table layout below.

A few things to note:

  • The tables are all in the "security" schema, I find that it makes more sense this way, but you can set it to work with "security_Operation" if you really like (or the DB doesn't support schemas).
  • User is referenced a few times, but is not shown here. As I mentioned earlier, the user entity is an external concept. We are using the mapping rewriting technique that we discussed earlier.

(more below)

image

Here is the main interface for Rhino Security:

image

The tasks it performs are:

  • Enhance a query with security information.
  • Get an explanation about why permission was given / denied.
  • Perform an explicit permission check on entity or feature.

The last two are fairly easy to understand, but what does the last one means? It means that if I want to perform a "select * from accounts" and I enhance the query, I will give this baby:

SELECT THIS_.ID          AS ID4_0_,

       THIS_.SECURITYKEY AS SECURITY2_4_0_,

       THIS_.NAME        AS NAME4_0_

FROM   ACCOUNTS THIS_

WHERE  @p0 = (SELECT   THIS_0_.ALLOW AS Y0_

              FROM     SECURITY_PERMISSIONS THIS_0_

                       INNER JOIN SECURITY_OPERATIONS OP1_

                         ON THIS_0_.OPERATION = OP1_.ID

                       LEFT OUTER JOIN SECURITY_ENTITIESGROUPS ENTITYGROU2_

                         ON THIS_0_.ENTITIESGROUP = ENTITYGROU2_.ID

                       LEFT OUTER JOIN SECURITY_ENTITYREFERENCESTOENTITIESGROUPS ENTITIES7_

                         ON ENTITYGROU2_.ID = ENTITIES7_.GROUPID

                       LEFT OUTER JOIN SECURITY_ENTITYREFERENCES ENTITYKEY3_

                         ON ENTITIES7_.ENTITYREFERENCEID = ENTITYKEY3_.ID

              WHERE    OP1_.NAME IN (@p1,@p2)

                       AND (THIS_0_."User" = @p3

                             OR THIS_0_.USERSGROUP IN (@p4))

                       AND ((THIS_.SECURITYKEY = THIS_0_.ENTITYSECURITYKEY

                              OR THIS_.SECURITYKEY = ENTITYKEY3_.ENTITYSECURITYKEY)

                             OR (THIS_0_.ENTITYSECURITYKEY IS NULL

                                 AND THIS_0_.ENTITIESGROUP IS NULL))

              ORDER BY THIS_0_.LEVEL DESC,

                       THIS_0_.ALLOW ASC);

Isn't it cute?  This is much better than some home grown security system that I have seen (some of which I have built, actually), since it is stable with regards to the cost of the query that it will use. I mention before that it is possible to de-normalize the information into a single table, but since this requires more invasive approach from the application side, and since I have not seen performance issues with this yet, I'll leave it at this point for the moment.

Advance: Working with non DB backed users

In most applications, the user is a fully fledged entity, even if your authentication is elsewhere. Just keeping things like preferences will necessitate that, but let us assume that we really have that as a non DB entity.

In this case, we would need to make modifications to the tables (which we generally do, anyway, although automatically), and re-map the user references as an IUserType that can get the user from an id instead of a foreign key to entity. I think I'll wait until someone really needs it to make a demo of it.

Anyway, this is the main magic. It was fairly hard to get it right, as a matter of fact. But the query enhancement was one of the things that made security a breeze in my last project. We had a custom security module, but many of the concepts are the same.

The next part we will talk a bit about the IsAllowed and how that works. There is some nice magic there as well.

Convention based security: A MonoRail Sample

I was asked how I would got about building a real world security with the concept of securing operations instead of data.

This is a quick & dirty implementation of the concept by marrying Rhino Security to MonoRail. This is so quick and dirty that I haven't even run it, so take this as a concept, not the real implementation, please.

The idea is that we can map each request to an operation, and use the convention of "id" as a special meaning to perform operation security that pertain to specific data.

Here is the code:

public class RhinoSecurityFilter : IFilter
{
    private readonly IAuthorizationService authorizationService;

    public RhinoSecurityFilter(IAuthorizationService authorizationService)
    {
        this.authorizationService = authorizationService;
    }

    public bool Perform(ExecuteWhen exec, IEngineContext context, IController controller,
                        IControllerContext controllerContext)
    {
        string operation = "/" + controllerContext.Name + "/" + controllerContext.Action;
        string id = context.Request["id"];
        object entity = null;
        if (string.IsNullOrEmpty(id) == false)
        {
            Type entityType = GetEntityType(controller);
            entity = TryGetEntity(entityType, id);
        }

        if(entity==null)
        {
            if (authorizationService.IsAllowed(context.CurrentUser, operation) == false)
            {
                DenyAccessToAction();
            }
        }
        else
        {
            if (authorizationService.IsAllowed(context.CurrentUser, entity, operation) == false)
            {
                DenyAccessToAction();
            }
        }
        return true;
    }
}

It just perform a security check using the /Controller/Action names, and it tries to get the entity from the "id" parameter if it can.

Then, we can write our base controller:

[Filter(ExecuteWhen.BeforeAction,typeof(RhinoSecurityFilter))]
public class AbstractController : SmartDispatcherController
{

}

Now you are left with configuring the security, but you already have a cross cutting security implementation.

As an example, hitting this url: /orders/list.castle?id=15

Will perform a security check that you have permission to list customer's 15 orders.

This is pretty extensive, probably overly so, however. A better alternative would be to define an attribute with the ability to override the default operation name, so you can group several action into the same operation.

You would still need a way to bypass that, however, since there are some thing where you would have to allow access and perform custom permissions, no matter how flexible Rhino Security is, or you may be required to do multiply checks to verify that, and this system doesn't allow for it.

Anyway, this is the overall idea, thoughts?

Designing the Security Model

Right now I want to talk more deeply than merely the security infrastructure, I want to talk about how you use this security infrastructure.

There are several approaches for those. One of them, which I have seen used heavily in CSLA, is to simply make the check in the properties. Something like this:

public class Comment
{
	public virtual IPAddress OriginIP 
	{ 
		get 
		{ 
			CanReadProperty(true); 
			return originIP; 
		} 
		set 
		{ 
			CanWriteProperty(true); 
			originIP = value; 
		} 
	}

	public virtual bool CanDelete() { ... }
}

We can move to a declarative model with attributes, like this:

[SecuredEntity]
public class Comment
{
	[SecuredProperty]
	public virtual IPAddress OriginIP
	{
		get { return originIP; }
		set { originIP = value; }
	}
}

We can take it a step further and decide that we don't want to explicitly state this, and just assume it by convention.

A while ago I decided to make a system work in this exact fashion. Of course, I am a big believer of convention over configuration, so we defined the following rules for the application:

  • Need to secure  Read / Write / Delete
  • Need to support custom operation as well, like "Assign work", "Authorize time sheet", etc
  • Developers will forget to make security calls, we need to develop a system that protects us from this.

We built a really nice implementation that hooked directly into the container and the data access later, you literally could not make a security breach, because you were always running under the context of a user, and the data was filtered for you by the data access in a generic fashion. For that matter, we didn't have to worry about authorization in the business code, we made in memory modification and then persisted that. If we had a security violation, we simply showed an error to the user.

We didn't have to define anything in the code either, it was all convention based and implicit. The only complexity was in configuring the security system itself, but that was the nature of the beast, after all. We though that we found the ultimate security pattern, and were quite pleased with ourselves. Until we started user testing. Then we run into... interesting issues.

We had the idea of a rule in the system, which could be used by the administrators to set policies. It worked just fine in our testing, until we started to get impossible errors from the users. I think that you can understand what it was by now, right? (Yes, the usual, developers always test as admin)

Normal users didn't have permissions to read those rules, but the system really needed them to perform core parts of its tasks. We are always running under the user context and we are always making the security check. The system was designed, up front, to be very explicit about it. Now we found that there really were reasons where the system needed access to the entities without performing those security checks.

Another "interesting issue" that came up was the issue of information aggregation. As it turn out, it was always the wrong idea to report that there is only a single entity in the system, just because the user has access to just that one. I'll let you draw the conclusion about the HR users that found out that they really couldn't see how many hours an employee worked in this month.

It was a big problem, and we had to scramble around and hack-a-lot the ultimate security solution that we so loved.

The security system had two major issues:

  • It was too granular.
  • It didn't have any operating context.

Since then, I have learned a lot about how to design and implement security modules, and my current design has the following requirements:

  • Security decisions are made on a use case level
  • Have a standard, enforced, approach of dealing with security
  • Make security decision easy to code.

How does this translate to code?

Well, first I need to define what a use case is in the code. For a web application, it is almost always at the page / request level, and that makes it very easy to deal with.

In my last project, we had the following base class defined:

public abstract class AbstractController
{
	public abstract AssertUserIsAllowed();
}

Since all the controllers in the application inherited from AbstractController, we had a single place that we put all the security checks. We still had to deal with security in other places, such as when we loaded data from the database, or wanted partial views, but this approach meant that we had remembered what was going on. If we needed to make security decisions elsewhere, we commented that in the assert.

But this was in a Rhino Igloo application, where by necessity we had to have a controller per page. Using MonoRail, we usually have a single controller that handles several actions, in which case I would tend to write something like this:

[AllowEveryone]
public void Login()
{
	...
}

[AllowAuthenticatedUsers]
public void Index()
{
	...
}
[ActionPerformsCustomSecurityCheck]
public void Save(...)
{
	...
}

And then I would mandate that all actions would have to have security attributes on them (Mandate as in, if it doesn't have security attribute, you can't access it).

Well, actually, right now I would probably route it through Rhino Security, which would give me more flexibility than this model, and would keep it out of the code.

Nevertheless, I would put security at the use case level. This is where I have the context to ask the correct questions. Anything else tend to lead to an increasingly complex set of special rules.

Rhino Security Overview: Part I

A few months ago I spoke about how I would build a security infrastructure for an enterprise application, I went over the design goals that I had and the failing of previous attempts.

Since then, I got a few requests to implement that, and since this is really neat piece of work, I decided to go ahead and build it.

The main goals, allow me to remind you, are:

  • Flexible
  • Performant
  • Does not constrain the domain model
  • Easy to work with
  • Understandable
  • No surprises

You can read the post about it to get a feeling about what I had in mind when I thought it up.

When it came the time to actually implement them, however, it turn out that as usual, the implementation is significantly different than the design in all the details. Here is the overall detail of the entities involved.

The main part that we have here is the security model, but notice that the application domain model is off to the side, and have very little to do with the security model. In fact, there is only a single requirement from the application domain model, the User entity needs to implement an interface with a single property, that is all. (more below)

image

 

From the point of view of interactions with the security system, we have two extensions points that we need to supply, a User entity implementing IUser, and a set of services implementing IEntityInformationExtractor<TEntity>:

image

The use of IEntityInformationExtractor<TEntity> is an interesting one. Rhino Security is using all my usual infrastructure, so it can take advantage of Windsor' generic specialization to do some nice tricks. Components of IEntityInformationExtractor<TEntity> are registered in the container, and resolved at runtime when there is a need for them.

This means that you can either implement a generic one for your model, or specialize as needed using generics. I like this approach very much, frankly.

From the point of view of the security model, we have the following:

  • User - the external User entity that is mapped into the security domain. Permissions are defined for users.
  • Users Group - a named grouping of users. Permissions are defined for users groups.
  • Entity - an external entity. Permissions are defined on entities.
  • Entities Groups - a named groups of entities. Permissions are defined on entities groups.
  • Operation - a named operation in the system, using the "/Account/Financial/View" pattern.
  • Permission - Allow or deny an operation for user / users group for an entity / entities group.

Here are a few examples of the kind of rules that we can defined with this method:

  • Allow "/Account/Financial/View" for "Ayende" on "All Accounts", level 1
  • Allow "/Account/Financial/View" for "Accounting Department" on "All Accounts", Level 1
  • Allow "/Case/Assign" for "HelpDesk" on "Standard cases", level 1
  • Allow "/Employee" for "Joe Smith" on "Direct Reports of Joe Smith", level 1

The major shift here is that we treat both entities and users groups as very cheap resources. Instead of having a just a few and structuring around them, we define what we want and then structure the groups around them. The burden them moves from complex code to maintaining the structure. I find this a very reasonable tradeoff for a simple security model and the flexibility that it gives me.

Next time, setting up the security model...