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:
Public Sub New( _
ByVal identity As IIdentity, _
ByVal roles() As String _
)
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 CanEdit 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 CanEdit 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:
If User.IsInRole("Administrator") then
' Display sensitive material
ElseIf User.IsInRole("ModerateInfo") then
' Display moderately sensitive material
Else
' Display only bland material
End If
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.