Anyone have any suggestions on frameworks and/or patterns that can be used to manage user roles/groups? The examples using csla are very basic at best and only handle roles. I need something that is configurable and dynamic that can handle groups that can contain roles. I need to either build or find a framework to handle my needs. This needs to be intergrated with asp.net forms authentication.
I'm thinking I need to build a custom role/membership providers and a framework that can assign objects, properties and processes to roles, which can then be assigned groups. There must be some solutions aready built? This seems like something that would be common in large scale systems.
I agree. However, we ended building our own. A CSLA-style framework does support this well. all depends on how complex you want to get. Ours is pretty complex and rivals Windows/ActiveDirectory but integrates tightly with the object-level authorization scheme provided with CSLA (e.g. CanReadProperty, CanWriteProperty, etc.)
If you find something pre-built, post it here. I'd be very interested in seeing what others have done.
Yeah, this is what I was fearing, having to build a framework to handle group/role management. I'm thinking of having roles/groups that are assigned objects and what properties and processes of those objects are allowed/denied/etc.
The issue I found is that there are a number of working examples out there but they are usually simplistic at best (only user/role) or don't come anywhere near what we needed.
In a nutshell, we extended our framework to include an entire security model for our applications that includes User and Group classes. These are both data classes (as are supporting UserCollection, GroupCollection, etc.). We have a configurable switch that indicates how the application is to handle security:
Our SecurityManager class provides a gateway mechanism for most of the settings and functions such as getting the CurrentUser.
We have incorporated Account Lockout and Password Policies similar to Windows as well. Just to further complicate things.
Because we have the ability to enforce password history via the policies, we actaully have a Password object and PasswordCollection that handles all of the behaviors and logic associated with a password.
Both User and Group are derived from Actor which enables us to have both User objects and Group objects as members of a Group.
The Group object maintains a list of Roles associated with that Group. We debated allowing direct assignment of Roles to a User but opted to not implement that - at least not yet. The master list of roles that can be assigned to a Group is found in resource files embedded in the application. Because this is not something you want your users tampering with, this seemed like a good way to go. Plus, it gives us the ability to localize the role descriptions should we be dealing with a multi-lingual app. The SecurityManager class exposes a Roles property which is a RoleCollection. The SecurityManager uses config settings to load all of the "user-defined" resource files - in other words, it knows about the resource file embedded in our framework, so we use config 'hooks' to allow additional resource files containing application specific roles to be added to the list. Oh, the other benefit is that we can refer to the resource name in code when performing authorization checks and not have to worry about how we spelled the role or if a word was capitalized, etc.
Everything is flexible, scalable and inheritable for extensibility. For instance, our policies are designed to allow additional policies to be defined for the application seamlessly with the built-in ones. In fact, we can add additional settings to the built-in ones through the config file.
I know that sounds like a lot and it did take us quite a while to develop, but, we were able to (at least in my opinion) take the best of what's out there and come up with a stable yet robust and flexible model to include in our framework. So far it has worked great.
Outta time on this end, but I'd be more than happy to answer any specific questions that you might have.
Hope that helps.
Let me answer the first question...well, first. The integration with CSLA comes from the fact that our security objects are dervied from the CSLA base classes and make use of the same features and functions provided therein. For instance, the ability to create new users is an authorization feature just like any other.
A word of correction from my previos post. I tend to misuse the terminology and it constantly gets me in trouble. I have been working on getting it straight but still instinctively fall back to the User-Group-Role nomenclature when in reality it is User-Group/Role-Right. This is the correct terminology in our model and may help to understand things better. Too many people interchange the term Group and the term Role that they essentially mean the same thing now - hell, even Microsoft does it...IsInRole(...)! Take a look at the WindowsIdentity and you'll see a Groups property!!! Even they switch 'em up.
Anyway, what we have is a User that hold membership in 'x' number of Groups each of which can also be thought of as a Role and contain a set of assigned Rights. An example of a Group, or Role, would be 'Order Entry Clerk' while a Right would be "Can add new orders". With me?
Now let me try to address the rest all together...
I agree with the need to be flexible and dynamic. Those were the tenets of our design as well and can be seen in the extensibility provided through config files, inheritance, etc. However, there is a compromise to this flexibility based on real-world implementation. That being where the rights are defined.
They have to be defined somewhere. In our case, all rights are defined in a resource file embedded in the project. So, we have a resource file embedded in our framework that contains a list of all rights for objects in our framework, such as creating a new user. When we create an application making use of our framework, we can (obviously this is optional) create a second resource file embedded into the application that will contain the rights for any new objects created for the application. These rights are then used in conjunction with the AuthorizationRules collection held by each business object. The concept we used is basically the same as Rocky's except that we've added the extra layer to the model, so the "role" that is used when establishing an AuthorizationRule is one of these values whereas the roles used in the book translate to Groups in our model.
So, for your example, our application would have a resource file with three string resources added:
You would have two Groups/Roles defined:
The first would have all three rights assigned while the second only the ReadOrderRight.
Then, your Order object would use these rights to authorize the user to perform the requested operation. For instance, in the CanAddOrders static method, you would check to see if the current user has the CreateOrderRight in its list.
FYI - the authorization task in our model is delegated to the SecurityManager object which has a static Authorize() method accepting the right to check against. So, CanAddOrders would look something like this:
public static System.Boolean CanAddOrders()
{
return SecurityManager.Authorize(CreateOrdersRight);
}
So, even though you are coding the rights into the objects, assignment of the rights to users (via Groups/Roles) is dynamic and can be done via a user-interface (which we do have both Web and Windows controls for managing our security objects in our framework).
The only other way I can think of to do this that would remove the hard-coded rights from the object would be to use more of a traditional ACL-type approach where the Order object maintains a dynamic list of Users and/or Groups/Roles that are allowed various access rights. We did look into this and opted for the approach listed above. Our thoughts here were that all objects have a standard set of rights: Read, Create, Modify and Delete. When you add an entry into the ACL for an object you define which of these rights are being granted. Then, your Authorize routine can check the object's ACL for the current user and cross-check to see if the requested right has been granted. This is similar to how file security works in Windows. There are some built-in classes that can help with this in the System.Security.AccessControl namespace.
My hope is that we eventually combine these approaches because I like the idea of being able to set priviledges on an object-by-object basis when applicable as well as the more global approach we've already taken.
Hope that answers your questions.
Copyright (c) Marimer LLC