Enterprise Library Security Block...
The Enterprise Library Security Block is a means to authorize users to perform certain actions based on a set of rules. The rules approach creates a programmatic way of authorizing users at a function level and reduces the amount of in-line code that does the same work.
One of the application blocks in the Enterprise Library is the security block, which is a very useful utility in securing applications. It has means of both authenticating and authorizing users in applications, which I'll be only looking at the authorization part. This block is similar to the others in that it uses the factory object design to create an instance of the authorization provider. This provider has a single method, Authorize, which returns a Boolean value stating whether the user is authorized under the rule name. This rule name is setup in the configuration file, which I will discuss later. But for now, understand that a rule is associated with a user or role to determine authorization.
The authorization provider requires some information to start with. First, it needs to be given the IPrincipal object that represents the user. Remember that an IPrincipal object contains the IIdentity that represents the user and a string array of roles that the user belongs to. This is the core to the security architecture. With the new provider framework in 2.0, setting up this information using the GenericIdentity and GenericPrincipal objects is a snap. I have an example showing this below.
I created a web project example with this article and use the Enterprise Library Configuration tool to setup the web.config file. Here is how the setup looks visually. To get to this application on your computer (after installing the Enterprise Library), go to Start > Microsoft Patterns & Practices > Enterprise Library - January 2006 > Enterprise Library Configuration. A utility will pop up that looks like this:
Understanding the caching portion isn't important for this example, as I used the default settings. Instead, I want to focus on the one authorization provider I created, called MyRules. As stated before, the authorization provider uses a bunch of rules to validate whether a user has permissions for a specific action. Each rule is associated with a user and role to determine whether the user is authorized for a specific action. The definitions I used for this example is:
<add type="Microsoft.Practices.EnterpriseLibrary.Security.AuthorizationRuleProvider, Microsoft.Practices.EnterpriseLibrary.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" name="MyRules">
<rules>
<add expression="R:Administrators OR R:PowerUsers" name="Insert"/>
<add expression="R:Administrators OR R:PowerUsers" name="Update"/>
<add expression="R:Administrators" name="Delete"/>
<add expression="R:Administrators OR R:BackupUsers" name="Backup"/>
</rules>
</add>
There are four rules: Insert, Update, Delete, and Backup. The first rule allows two roles access to it (denoted by the "R:"), which is the administrators or powerusers role. These are the actual role names as defined in the application. My application that I created to test with does not actually use the role provider, but I use a checkbox to allow you to select the roles you want to belong to, and see if permissions are allowed with those roles. In a real-life scenario, the Roles would be retrieved through Roles.GetRolesForUser().
Let's look at the code to show how we make the determination for authorization. All determinations are made in code; there isn't a framework established to use the enterprise library automatically through the framework and the login controls. Instead, the Authorization provider uses the AuthorizationFactory object to get a reference to IAuthorizationProvider, the provider object for authorizing users. I setup (in the screenshot above) that the default Authorization factory is MyRules, so I don't have to provide a name to the GetAuthorizationProvider method. If no default was specified, I would have to reference it by name. In the comment below, I illustrate the empty and name method overload.
//If no default is specified, I have to do this:
//IAuthorizationProvider auth = AuthorizationFactory.GetAuthorizationProvider("MyRules");
//Default is specified in web.config, and so this is allowed; uses default.
//A name can still be used to reference it or another authorization provider
IAuthorizationProvider auth = AuthorizationFactory.GetAuthorizationProvider ( );
Again, this interface uses one method called Authorize. It takes a reference to the current IPrincipal object and the name of the rule to do the verification. The GenericIdentity is created using the User.Identity.Name property of the current user, and the Generic Principal uses this and a list of the roles from the checkboxlist. The results are written to labels as to whether the user is allowed to perform the associated action. It’s really easy to perform the authorization.
this.lblInsert.Text = auth.Authorize ( principal, "Insert" ).ToString ( );
this.lblUpdate.Text = auth.Authorize ( principal, "Update" ).ToString ( );
this.lblDelete.Text = auth.Authorize ( principal, "Delete" ).ToString ( );
this.lblBackup.Text = auth.Authorize ( principal, "Backup" ).ToString ( );
This functionality is available for both windows and web environments, which makes the enterprise library very versatile. I like this feature because I can break out different actions separately, and change the roles later if I want. For instance, instead of creating one permission for adding, updating, or deleting data in a data object, I can break them out into separate rules, allowing future updates to the application more easily. For example, say only administrators can insert, update, and delete, but later on you want power users to insert and update, but not delete. Using separate rules in the configuration file makes this change a snap; otherwise, an application change may be required. Plus, managing these permissions is easier to do in the web.config file, instead of editing code to edit all of these permission changes. This application block can really enhance the design of your application if used appropriately.