In part one - IPrincipal, I talked about the right and IPrincipal objects needed to add "right" based security to asp.net applications in addition to role based security.

There are a few things we need to do to get ready to build the IHttpModule.  First we need something to give us a list of rights for a user.  To do this we will create a quick "RightManager" class.  We will create a static method "GetRightsByUserName" to return a list of Right objects for a given user name.  Really this class could also manage creating, editing and deleting rights along with assigning rights to roles, or users but that is outside of the scope of this article.  For a production system this class would likely use a provider model to connect to a data store and return the list of rights specific to the user base on their role membership.  For our purposes we will return the same right list for any user with a name starting with the letter J.

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;

  namespace ObjectHelpDesk.Security
  {
      public static class RightManager
      {
          public static List<Right> GetRightsByUserName(string userName)
          {
              List<Right> result = new List<Right>();
              Right someRight = new Right();
              someRight.Id = new Guid();
              someRight.RightName = "SVN Access";

              if (userName.ToLower().StartsWith("j"))
                  result.Add(someRight);
              return result;
          }
      }
  }

The IHttpModule is where we do most of the heavy lifting. Because the code the gets the rights back from the user name is isolated in the Rights Manager class the amount of code in the module is really rather small.

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Web;  

  namespace ObjectHelpDesk.Security
  {
      public class RightsHttpModule : IHttpModule
      {
          #region IHttpModule Members

          public void Dispose()
          {
          }
  
          public void Init(HttpApplication context)
          {
               context.PostAuthenticateRequest += new EventHandler(context_PostAuthenticateRequest);
          }  

          public void context_PostAuthenticateRequest(object sender, EventArgs e)
          {
              HttpApplication context = (HttpApplication)sender;
              if ((context.User != null) && (context.User.Identity.IsAuthenticated))
              {
                  List<Right> rights=RightManager.GetRightsByUserName(context.User.Identity.Name);
                  RightPrincipal newPrincipal = new RightPrincipal(context.User, rights);
                  HttpContext.Current.User = newPrincipal;
                  System.Threading.Thread.CurrentPrincipal = newPrincipal;
              }
          }  

          #endregion
      }
  }

When the When the module is loaded it will fire the Init method.  This wires the PostAuthenticateRequest event to our custom event handler "context_PostAuthenticateRequest".  The reason we use the PostAuthenticateRequest event is it allows us to alter the security principal after the membership and roles system has already processed and authenticated the user.  Because the user is already authenticated  at this point, the method used to authenticate them does not come into play and we can concentrate on getting the rights loaded.  Yes, this method of adding rights works with both Forms and windows authentication. We create the new RightPrincipal passing in the current principal and the list of rights for the user.  We than add the new principal to the Current HttpContext and the Thread.  The Principal of the thread is important and needs to be set as well.

Next we add the IHttpModule to the web.config.  The order you list the modules in the httpModules section of the web.config is important.  It determines the order of execution for the events in the modules. 

<system.web>
  <httpModules>
    <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    <add name="RightsModule" type="ObjectHelpDesk.Security.RightsHttpModule, ObjectHelpDesk.Security"/>
  </httpModules>
</system.web>

Now you can debug your web site project and login with various user accounts to check their rights.

While this code works, there are things I would take the time to clean up before using it in a production system. 

  1. The RightManager should be fleshed out and working with the ability to create, delete, edit and assign/revoke rights.
  2. The context_PostAuthenticateRequest method in the HttpModule should always create and hook in a RightPrincipal if it is not already one.

 Part 3 : Code security by Right, Attributes

If you are getting lots of SQL traffic for each request (the debugger stops in the module a lot), read this post!