Some weeks ago I was integrating SiteMinder authentication within an ASP.NET application. Fortunately, this was not a big deal because the whole SiteMinder stuff is absolutely transparent to the ASP.NET application. The only thing what must be done (beside the installation and configuration of the Web Agent, Policy Server, etc, of course) is to extract the SiteMinder HTTP headers from the web request and construct a GenericPrincipal object which holds the identity of the authenticated user.

Process Description

  1. User types the URL for an ASP.NET application into the web browser.
  2. The SiteMinder Web Agent intercepts the request and checks its resource cache. If there is no information in cache about this resource (URL), the Web Agent then sends the request to the Policy Server, asking if the resource is protected.
  3. The Policy Server responds indicating that the resource is protected.
  4. The Web Agent forwards the request to a login page for challenging the user for their credential.
  5. The Web Agent forwards the credentials back to the Policy Server for authentication and authorization.
  6. The Policy Server authenticates the user against a directory. After verifying the user’s identity, the Policy Server checks rules in the Policy Store, where user entitlements are stored and grant the user access to the resource.
  7. The Policy Server notifies the Web Agent that the user is authenticated and authorized for this resource.
  8. The Web Agent constructs several SiteMinder HTTP headers with information about the authenticated user (userid), generates an encrypted session cookie and redirects the request to the original target URL.
  9. The request reaches the ASP.NET application where the userid can be extracted from the SiteMinder headers for further processing.

 

Source Code of HTTPModule to Extract SiteMinder Headers

 

   1:  /// <summary>
   2:  /// This HttpModule is responsible for retrieving the SiteMinder headers from the web
   3:  /// request.
   4:  /// </summary>
   5:  public class SiteMinderModule : IHttpModule, IRequiresSessionState
   6:  {
   7:      /// <summary>
   8:      /// Required default constructor
   9:      /// </summary>
  10:      public SiteMinderModule()
  11:      { }
  12:   
  13:      /// <summary>
  14:      // Required Dispose Method
  15:      /// </summary>
  16:      public void Dispose()
  17:      { }
  18:   
  19:   
  20:      /// <summary>
  21:      /// Register for events that are handled within this module
  22:      /// </summary>
  23:      /// <param name="app">Application object</param>
  24:      public void Init(HttpApplication app)
  25:      {
  26:          app.PreRequestHandlerExecute += new EventHandler(Application_PreRequestHandler);
  27:      }
  28:   
  29:   
  30:      /// <summary>
  31:      /// This event occurs just before ASP.NET begins executing a handler such a aspx page.
  32:      /// We use this event to extract the SiteMinder headers from the request and construct
  33:      /// our principal object
  34:      /// </summary>
  35:      /// <param name="sender"></param>
  36:      /// <param name="e"></param>
  37:      private void Application_PreRequestHandler(Object sender, EventArgs e)
  38:      {
  39:          if (HttpContext.Current.Request.Headers["SM_USER"] != null)
  40:          {
  41:              // Get a collection of all available HTTP headers from the request
  42:              NameValueCollection coll = HttpContext.Current.Request.Headers;
  43:   
  44:              // Retrieve the userid from the SiteMinder header SM_USER
  45:              string smUser = coll["SM_USER"];
  46:   
  47:              // Create GenericPrincipal with authentication type "SiteMinder".
  48:              GenericIdentity webIdentity = new GenericIdentity(smUser, "SiteMinder");
  49:              GenericPrincipal principal = new GenericPrincipal(webIdentity);
  50:   
  51:              // TODO: Attach additional attributes to the principal object (e.g. from session
  52:              // object, DB, directory, etc.)
  53:   
  54:              HttpContext.Current.User = principal;
  55:              Thread.CurrentPrincipal = principal;
  56:          }
  57:          else
  58:          {
  59:              // Throw an exception, because SiteMinder headers are not available.
  60:          }
  61:      }
  62:  }

 

A future article will cover how to integrate .NET SmartClient applications with SiteMinder.