Role-Based Authorization With Forms Authentication, Part 2
By Darren Neimke and Scott Mitchell
In Part 1 we examined a data model to provide
role-based authorization. We also saw how in order to assign roles to an authenticated user,
we needed to create an event handler for the Application's AuthenticateRequest
event. In this part we'll continue our examination of this event handler.
The HttpContext Class
The
HttpContext class encapsulates HTTP-specific information about
an HTTP request. This includes response/request headers, server variables,
session variables, user information, and so on. Of particular interest is a property
called Current, which returns an instance of the HttpContext
class that represents the current HTTP request.
Another important property in the HttpContext class is User,
which contains security information about the user who made the Web request. The
User property returns a type the implements the IPrincipal
interface, which is our topic of discussion in the following section...
Principals, Roles, and Identities, Oh My!
If you've done any administering of Windows you will be familiar with the concept of Users and Groups. Basically, to access a secured network you must have a user account and that account would be assigned to one or many groups. In .NET these are referred to as Identities and Roles respectively, and they are contained within a
Principal object. To understand how role based authorization works you
need to have an understanding of how these three elements are tied together, and how
you can programmatically access their values. Let's look at each element separately.
Identities
Identities represent users, and as such, have properties that allow you to obtain information (such as the username) about that user. The classes for working with Identities reside in the
System.Security.Principal
namespace. This namespace contains two classes: GenericIdentity
and WindowsIdentity through which you can determine the properties of
a user; and one interface: IIdentity that you
can use to create custom Identities that can extend the base Identity type to suit
needs that are specific to your application.
The IIdentity interface contains three properties, the two more interesting
ones for this article being Name and IsAuthenticated. This
means you can access the name of the authenticated user using User.Identity.Name.
(Note that with Forms authentication, the value of User.Identity.Name is the
same value as specified in the name parameter of the FormsAuthentication.RedirectFromLoginPage()
method.)
Roles
Roles are simply a comma-delimited String of role names that are added to the Principal to associate the current user with one or more roles.
Principals
A Principal contains information about the identity and role(s) that the current user is associated with. It is through the Principal that you are able to check the role membership of the current user. In many ways a Principal is the glue that binds identities, roles, and the various other pieces of information that fully describe that Principal to the application.
A Principal is encapsulated by classes found in the System.Security.Principal
namespace. This namespace contains two Classes:
GenericPrincipal and WindowsPrincipal through which you can
determine the properties of a principal; and one interface IPrincipal
that you can use to define your own custom Principals.
The .NET runtime uses the Principal that is attached to the current thread to gain
information about the identity and roles of a user when handling requests that
require authorization. To programmatically assign your own principal settings you
simply create an instance of the Principal
class passing in an identity object and a comma delimited string of roles for that
identity. The constructor for the Principal object looks like this:
|
Putting It All Together
Now that we've had our discussion on Principals, Roles,
HttpContext, and
Identities, hopefully the last line of code in the AuthenticateRequest
event handler looks a little more sensible - HttpContext.Current.User =
New GenericPrincipal(User.Identity, roleListArray). Here, we are assigning to the
current HTTP request's User principal a new GenericPrincipal
build up from the user's existing principal plus the set of roles obtained from the
database.
Role-Based Authorization
There are a number of ways to perform role-based authorization, once you have specified the user's roles. One of the more common approaches is to use the
<authorization>
element in the Web.config file. With this element, you can restrict or grant
access to the Web application based on roles. For example, imagine that you wanted to
allow only those playing the Administrator or Moderators roles to a particular Web application
or directory in a Web application. To do so, you would simply need to add the following
line in your directory's Web.config file:
|
This allows those who are in the Administrator or Moderators roles, while denying all other users. Membership in roles can also be checked programmatically.
Membership into roles can also be done programmatically using the IsInRole()
method of the User object. For example, you might have an ASP.NET Web page
that you wanted to allow everyone to access, but the amount of details displayed depended
upon the user's role. Here is some pseudocode that implements such functionality:
|
Conclusion
As we saw in this article, implementing role-base authorization in a Forms authenticated environment requires that we determine the roles a user belongs to in the Application's
AuthenticationRequest event's event handler. Once we have assigned the
roles to a user's principal, we can grant or deny access to various resources either through
the <authorization> element in the Web.config file, or
by programmatic means via the IsInRole() method.
If this topic interests you and you plan on implementing it on your Web site, I would
first encourage you to read with a keen eye an excellent publication from Microsoft:
Building
Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication.
This "best practices" paper discusses in great detail the IIS and ASP.NET security models,
and various techniques for authentication and authorization. Also worth checking out
is How To:
Create GenericPrincipal Objects with Forms Authentication. This article looks at
using role-based authorization with Forms authentication, but instead of hitting the
database at each AuthenticationRequest event firing, this other approach
stores the authentication information in an encrypted cookie.
Happy Programming!



