How To? Highly Complex Query Generating Based On Security Needs

I have the following object model:

 image

An Office belongs to one Office Group. An Office also belongs to one Office Region. There is no relationship between Office Group and Office Region. They are two separate groupings for various reasons. A Counselor belongs to one Office. A Veteran is assigned to one Office.

I need to implement the following security rules for a Counselor looking at Veterans, starting with “deny access to all Veteran records, unless any of the following are true”:

  1. If a Counselor is an Administrator (a role of the Counselor), that Counselor can see all Veteran records
  2. A Counselor can see any Veteran that has no current Office assignment
  3. A Counselor can see Veterans that are assigned to an Office within the Counselor’s Office Group
  4. If a Counselor belongs to a “Regional Office”, that Counselor can see Veterans that are assigned to that Region
  5. … a few others in similar fashion …

I also need to implement the following around the above rules:

  1. When a Counselor searches for Veterans, they are only allowed to see search results that meet the above criteria
  2. When a Counselor views the detail of a Veteran, they are only allowed to see the the Veteran if the above criteria is met. This includes, if a Counselor tries to manually load a Veteran (manually type in url “id=1234”)
    1. … and the Counselor is not allowed to see the Veteran, show a “Not Authorized” message
    2. … and the Vet does not exist, show a “Vet Does Not Exist” message

so…

how do you create a search process around a security need like this? How do you go about creating a very complex rule system to determine which Veterans the Counselor can see? In my ideal world, I’d have some way of checking this security need against the search results and against an individual veteran record, without duplicating the code or logic for that check anywhere… is this a realistic expectation? What “standard” security implementations are out there, that would help me resolve my needs?

This is being done in C# in an ASP.NET Webforms app, using NHibernate for our ORM. I don’t expect NHibernate to be able to solve this problem for us, but if it can, that’s even better. And, I do expect to be able to write some sort of Unit or Integration tests around whatever the process is.

Any advice or help is appreciated.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in .NET, C#, Data Access, Security, Unit Testing. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://tunatoksoz.com Tuna Toksoz

    In case you haven’t seen Rhino.Security
    http://ayende.com/Blog/archive/2008/01/22/Rhino-Security-Overview-Part-I.aspx

    I am not sure if can do exactly what you want, but it is worth looking.

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @Tuna,

    Thanks. I spent the last 30 minutes trying to read up on it. It seems fairly complex, off-hand, but it certainly looks like it is worth diving into, to see if it can help.

  • Gilligan

    We have similar complexity in parts of our system, like only retail members can see these items but everyone can see these other items.

    I used Rhino security and put it in a separate bounded context. Rhino security can attach security criteria to any query. It also has the ability to relate permissions to a specific entity. So I created a set of security listeners that represent my security rules. The listeners listen to appropriate events and apply the needed security rules. Example for Rule #4. I would create listeners for the following events: Veteran added to region, veteran removed from region, Counselor added to Regional Office, and Counselor removed from regional office. When any of these events occurs the listener will add/remove the appropriate permissions for the Counselor/Veteran pair. Rhino Security handles everything else.

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @Gilligan,

    so what you’re saying is that the permission would be stored in a table, to say “this couselor (id x) can see this veteran (id y)” and then at the time the check needs to be made, it would look at that cached permission list? is that close to what you’re saying Rhino.Security does?

    that’s certainly a different concept than what I was trying to do, but is sparking some interesting thoughts in the back of my head… definately makes me want to look at Rhino Security further.

  • Gilligan

    Exactly. Rhino Security Permissions have three “dimensions” : User/User Groups, Operations (which are hierarchal), and optionally Entities/Entity Groups.

    This allows us to break any security rule down into a simple “this user/group either can or cannot perform these operations on this entity/entity group”. Rhino Security handles the aggregation of permissions (eg a user is a member of a group but also has its own permissions for an operation) automatically.
    Trust me once you implement Rhino Security you will never look back and you will wonder how you ever managed with only Asp.Net’s role system before.

  • http://abombss.com Adam Tybor

    +1 to Rhino Security. The really cool part is how it transparently attaches to your domain then applies the necessary nhibernate detached criteria so filtering can happen in the query at the db level. No more client side filtering and applying rules on huge result sets!

  • http://devlicio.us/blogs/mike_nichols MIke

    I wonder if you can take advantage of NHibernate Filters here and attach a security to the session at runtime to get let NH do the heavy lifting for you.
    Might be simpler if this is the only place in your app you have encountered this

  • http://www.thegrubbsian.com JC Grubbs

    What about just building a set of composable methods that expose IQueryable and then building up a query based on the current context’s security concerns. As you chain these methods together the query gets more and more limiting. It’s not a very “slick” way of doing it but the composability of IQueryable is extremely powerful.

  • Doug Ferguson

    You might consider using a collection of specification patterns (Evans).

    Given the fact that you need to see the difference between “not-authorized” and “does not exist”, you may want to pull the releveant records for a vet even if the Conselor can’t have access to the record.

    Then, you can run the results through a Specification rule, or a series of them, to determine if the conselor has access to the particular record.

    If not data is returned from the query, you know the record does not exist. If a record IS returned, but the combination of the conselor and the vet fail the specification rule, you can return “not-authorized.”

    Here’s a link to a specification implementation using generics. I found it helpful and modified it to accept two objects. You could pass in your conselor and the vet dto’s.

    http://devlicio.us/blogs/jeff_perrin/archive/2006/12/13/the-specification-pattern.aspx

    This may or may not work from a performance standpoint depending upon how many records are being returned/evaluated.

  • dot net coder

    For Rhino Security
    1.Where and how in the app life cycle(at which layer ) , do we “set” the
    security keys for the entities ?
    n does setting the security keys for entities inserts a record in the
    EntityReferences (security) table ??

    2.How do u bind entities from application domain (or application
    tables ) with the rhino security using IInformation Extractor ? and
    how and in which table of the rhino schema, these links shown.Permissions are to be added for entities as
    enity group using permissions builder service using two overloads
    .On(EntityGroup) and .On(Entity)

    3.Please provide more documenation on the usage n implementation of
    security tables :
    a) Entity References (security)
    b) EntityReferencesToEntityGroups
    c) Use of “Oneverything”