Programmer to ProgrammerTM  
Wrox Press Ltd  
   
  Search ASPToday Living Book ASPToday Living Book
Index Full Text
 
ASPToday Home
 
 
Home HOME
Site Map SITE MAP
Index INDEX
Full-text search SEARCH
Forum FORUM
Feedback FEEDBACK
Advertise with us ADVERTISE
Subscribe SUBSCRIBE
Bullet LOG OFF
                         
      The ASPToday Article
March 1, 2002
      Previous article -
February 28, 2002
   
 
   
   
   
Blending Integrated Windows Security and Custom User Profiling in ASP.NET   Akil Franklin  
by Akil Franklin
 
CATEGORIES:  .NET Framework, Security/Admin  
ARTICLE TYPE: Tutorial Reader Comments
   
    ABSTRACT  
 
Article Rating
 
   Useful
  
   Innovative
  
   Informative
  
1 response

With a constant stream of usernames, account IDs, and passwords to remember it is not surprising that users do not like to log on. If you can automatically log your users into your application while simultaneously determining their preferences and security settings, you’ve gone a long way towards satisfying your users’ definition of a “killer-app”. In this article, Akil Franklin will show you how to secure your ASP.NET applications using integrated Windows security.

He will then show you how to blend Windows credentials and personalized user information to form a comprehensive view of your users that is available to every page within your application.




   
                   
    Article Discussion   Rate this article   Related Links   Index Entries  
   
 
    ARTICLE

This article is part of the ASPToday Security Week, 25th February - 1st March 2002.

Introduction

"Single login" is the rallying cry of all user-interface experts (not to mention frustrated end users). The idea is that once your users are authenticated to a trusted system, you should not have to interrogate them for credentials every time they attempt to access a secured resource - any resource - including your application.

So how do you achieve single login within your ASP.NET application? Well the quick answer is by using integrated Windows security. By using the Windows authentication provider, you ensure that your user's Windows logon credentials are always available to your application. But knowing that your user is a valid Windows user is seldom enough. Most likely you will want to secure parts of your application according to roles (or Groups as they are known in Active Directory). This is simple enough to do, either by customizing your application's Web.config files or with methods available to you via the WindowsPrincipal object (more on the WindowsPrincipal object later).

But what if you would like to go further? What if once you know who your users are you also would like to obtain their preferences (such as language or view settings)? Or, what if your application requires roles that can't or shouldn't exist within your organization's Active Directory structure? Of course you could always grab this customized user-specific information within the logic of your ASP.NET pages themselves. You could even go so far as to encapsulate this logic in a class or function accessible globally within your project, but a much more elegant solution exists. ASP.NET provides a mechanism by which you can blend your own customized personalization and membership solution with Integrated Windows security (or any authentication provider) and make that information available to every ASP.NET page within your application "automagically."

In this article I will illustrate a technique for:

System Requirements

In order for the code samples in this article to work you will need to have IIS 5.0 and the .NET framework properly installed on your machine. It is assumed that the reader has a working knowledge of basic security concepts, the .NET framework, C# and ASP.NET.

The Case for Using Windows Authentication

Authentication is the process of finding out who your user is. Once you know who they are you can make decisions about what they are allowed to do (this decision-making process is referred to as authorization) as well as associate user-specific information to their requests. Users prove their identity to a system by providing identification credentials. Usually these identification credentials consist of a username and password but they could be anything - even biometric data like a fingerprint or a retinal scan. The idea of single logon mandates that once users are authenticated to a trusted authority you should use those credentials to identify users in your own system as well.

The decision of which authentication provider to trust depends on many factors, but Microsoft Windows is a great choice in many situations. In most corporate environments users must log on to a Windows domain in order to gain access to any network resources, so you are guaranteed to have their credentials available when they attempt to access your application. This makes the Windows authentication provider a good choice for the vast majority of corporate intranet projects.

It should be noted however that Windows authentication is not ideal in all situations. First of all, if you must support Netscape, integrated Windows authentication is not an option. Integrated Windows authentication only works with Internet Explorer. You will also find that if you have a large number of users (hundreds of thousands or millions for example), you will exhaust the limit of Active Directory's performance capabilities. If your authentication needs are this intense, you will be forced to authenticate your users via some other method (most likely against a customized database scheme). Also, if your users aren't on your corporate network, Windows authentication will not provide the single logon functionality that you are looking for because your users will have to log on to your network (or face the NT challenge provided by IE) in order to use your application. Finally, if all of your users do not have a valid Windows account, then integrated Windows authentication obviously won't fulfill your needs.

Despite the limitations of Windows authentication, it should be noted that the techniques used in this article are applicable to any authentication provider.

Windows Authentication under ASP.NET

ASP.NET makes integrating Windows authentication a snap. You select your authentication provider using the Web.config file. The settings for windows authentication are as follows:

<authentication mode="Windows"/> 

The above entry is all that you need to ensure that your users' Windows identity is available to all of your ASP.NET pages. Of course, IIS does the least amount of work possible when authenticating your users. This means that if you allow anonymous access within IIS and NTFS access control lists don't prevent anonymous access to your application's resources; the web server will skip the hard work of figuring out exactly who your users are and will report that everyone accessing your site is an anonymous user! In the vast majority of cases, this is not what you will want, so the next step in securing your ASP.NET application is to turn off anonymous access to your site. To disallow anonymous access to your application, follow these steps:

Image 1

Note: This screenshot is taken from Windows 2000. The XP version looks slightly different.

User Security in .NET

User authentication and authorization in .NET are handled primarily via Identities and Principals. You will find the basic Identity and Principal classes in the System.Security.Principal namespace. An Identity object tells you who the user is. Identity objects implement to the IIdentity interface and as a result contain the following properties:

AuthenticationType Gets the type of authentication used
IsAuthenticated Gets a value that indicates whether the user has been authenticated
Name Gets the name of the user

A Principal object is a combination of an Identity object and its associated roles. This additional information is usually used to determine what a user has permission to do (a process known as authorization). Principal objects conform to the IPrincipal interface. As a result, all Principal objects must contain (at the very least) a property exposing their associated Identity, as well as a method called IsInRole. The IsInRole method can be called to determine whether or not a user has a particular role (or in Active Directory parlance, whether or not they are the member of a particular group).

The User Property

All ASP.NET pages (objects of type System.Web.UI.Page) contain a User property. This property returns a Principal object that represents the user making the current request. This object can be of any type as long as it implements the IPrincipal interface. This is an important point to remember as we'll be making use of it later to create our own customized user object and attach it to our application context.

WindowsPrincipal and WindowsIdentity

By default, when you use windows authentication the User property of your ASP.NET pages is populated with a WindowsPrincipal object. As you might remember, all Principal objects contain an Identity property. In the case of the WindowsPrincipal object, this property returns a WindowsIdentity object. The WindowsIdentity object contains quite a few useful properties and methods, a few of which are listed below:

Properties

IsAnonymous Gets a value indicating whether the user account is identified as an anonymous account by the system.
IsAuthenticated Gets a value indicating whether the user has been authenticated by Windows.
IsGuest Gets a value indicating whether the user account is identified as a Guest account by the system.
IsSystem Gets a value indicating whether the user account is identified as a System account by the system.
Name Gets the user's Windows logon name.
Token Gets the Windows account token for the user.

Methods

GetAnonymous Returns a WindowsIdentity object that represents an anonymous Windows user.
GetCurrent Returns a WindowsIdentity object that represents the current Windows user.
Impersonate Overloaded. Allows code to impersonate a different Windows user.

Using the WindowsPrincipal object you can determine if a user is in a particular Windows Group. For example, the following code tests to see if the user is a member of the local machine Administrators group and sends the result to the browser (of course you must be using Windows authentication in order for this to work). If the user is in the group, it will print "true"; otherwise it will print false:

Response.Write(User.IsInRole(@"BUILTIN\Administrators").ToString());

Implementing IPrincipal

In order to implement IPrincipal you must provide the implementation for the IsInRole method. The following is a Customized User object that effectively wraps any Principal and Identity information passed to it during construction and also exposes preference information read from an XML resource file called Preferences. In our example we will pass Windows Principal/Identity information into the object during construction, but it could just as easily be Principal/Identity information from Passport, a database or some other authentication provider.

using System;
using System.Resources;
using System.Security.Principal;

namespace BlendedSecurity
{
       public class CustomUser : IPrincipal
       {
              protected string mstrPreferences;
              protected ResourceManager mobjManager;
              protected IPrincipal mobjPrincipal;

              public string Preferences
              {
                     get
                     {
                           //Get the preferences stored in the resource file
                           //for the user with the name given
                         mstrPreferences = 
                         mobjManager.GetString(mobjPrincipal.Identity.Name);
                            return mstrPreferences;
                     }
              }

              //Identity Property. Returns the 
              public IIdentity Identity
              {
                     get{return mobjPrincipal.Identity;}
              }

              // Constructor
              public CustomUser(IPrincipal robjPrincipal)
              {
                     //Get resource manager for the resource file 
                     mobjManager = new 
                              ResourceManager("BlendedSecurity.Preferences", 
                            typeof(CustomUser).Assembly);

                     mobjPrincipal = robjPrincipal;
              }

              public bool IsInRole(string vstrRoleName)
              {
                     //Use the IsInRole method of the Principal
                     //object stored internally
                     return mobjPrincipal.IsInRole(vstrRoleName);
              }
       }
}

Attaching your Custom User Object to the ASP.NET Application Context

The key to blending your own custom personalization and membership solution with integrated Windows authentication is replacing the IPrincipal object returned by the page's User property with one of your own creation. You can do this quite easily within your application's global.asax file. You can catch the authentication event fired when a Windows user is authenticated to your application by handling the WindowsAuthentication_OnAuthenticate event handler. This is where you will want to replace the Application Context's User object with your own. I'll be using the custom user object just described above:

public void WindowsAuthentication_OnAuthenticate(Object sender, 
WindowsAuthenticationEventArgs e)
{
       //Create a WindowsPrincipal object from the WindowsIdentity object
       //contained in the Windows Authentication Event Arguments
       WindowsPrincipal objPrincipal = new WindowsPrincipal(e.Identity);

       //Create your customized user object from the WindowsPrincipal
       CustomUser objUser = new CustomUser(objPrincipal);

       //Attach the custom user object to the application context
       Context.User = objUser;
}

Accessing Your Customized User Object

Once you've attached your custom User object to your application context in global.asax , it is available to every ASP.NET page within your application. In order to access the custom properties and methods available on your object you will have to cast the object returned by the User property of the ASP.NET page to your custom object type. This step is necessary because the User property returns the IPrincipal interface to your object. The following code snippet shows a page that accesses our custom user object in the Page_Load method:

private void Page_Load(object sender, System.EventArgs e)
{
       //The global.asax has taken care of creating your customized
       //user object and attaching it to the application context.
//Now you must cast the User object to the CustomUser type so
       //that you can access its enhanced abilities!
CustomUser objUser = User as CustomUser;
       string strPreferences = objUser.Preferences;
       if (strPreferences == null) 
strPreferences = "Unable to retrieve Preferences for " + objUser.Identity.Name;
                     
       strPreferences = "<h2>Preferences for " + 
objUser.Identity.Name + "</h2>" + Server.HtmlEncode(strPreferences);

       Response.Write(strPreferences);
}

Disposing of your Customized User Object

In our simple example, the CustomUser object doesn't hold any expensive shared resources (such as database connections) that must be released once you are done with them. But in a real-world application your user object may very well need access to such resources in order to populate themselves with user-specific data. In this case, you will need to implement the IDisposable interface on your object. But when do you call it? A good time to dispose of resources tied up by your user object is in the Application_EndRequest event handler of global.asax. For example:

protected void Application_EndRequest(Object sender, EventArgs e)
{
CustomUser objUser = this.User as CustomUser;
objUser.Dispose();
}

The above code ensures that the Dispose() method for your User object is called whenever a request is finished.

The BlendedSecurity Sample Application

The code snippets you've seen in this article are taken from the BlendedSecurity Sample Application. This sample application uses integrated Windows authentication to determine a user's identity and then combines that information with preferences data obtained from a resource file. The customized user object containing the user's blended data is then attached to the request's application context using the techniques described in this article. The Preference data is then displayed on screen:

Image 2

BlendedSecurity Application Setup

The code provided with this article is packaged in a zip file. Unzipping the file will place the necessary files in a directory called BlendedSecurity. Next you will have to:

Conclusion

Of course in the real world your user preferences would never be persisted in an XML resource file, but hopefully this example will give you the tools you need to apply these techniques to your data store of choice. Whatever the data store you choose, however, keep in mind that you will need to implement some mechanism for keeping it synchronized with the users that exist in your authentication provider. This will usually take the form of the typical add/update/delete user admin screens that you would normally provide in an application, but in this case they will be pulling data from your authentication store as a part of performing their respective services.

Attaching customized user objects to your application context is a great way to solve the single logon dilemma. The capabilities of your customized user object are limited only by your imagination. It's a great place to store user preferences, permissions and other user-specific information. Once more, these powerful customized User objects are instantly and seamlessly available to every page in your ASP.NET application. This is a tremendous win-win for both end users and developers!

Related Links

How ASP.NET Security Works

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconhowaspnetsecurityworks.asp&WROXEMPTOKEN=77785ZrPepuudtuWA3eiCODNXJ

The Windows Authentication Module Provider

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconthewindowsauthenticationprovider.asp&WROXEMPTOKEN=77785ZrPepuudtuWA3eiCODNXJ

Principal and Identity Objects

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconprincipalidentityobjects.asp&WROXEMPTOKEN=77785ZrPepuudtuWA3eiCODNXJ

Article Information
Author Akil Franklin
Technical Editors John R. Chapman, Vickie Pring
Project Manager Helen Cuthill
Reviewers Sean M. Schade, John Boyd Nolan

If you have any questions or comments about this article, please contact the technical editor.

 
 
   
  RATE THIS ARTICLE
  Please rate this article (1-5). Was this article...
 
 
Useful? No Yes, Very
 
Innovative? No Yes, Very
 
Informative? No Yes, Very
 
Brief Reader Comments?
Your Name:
(Optional)
 
  USEFUL LINKS
  Related Tasks:
 
 
   
  Related ASPToday Articles
   
  • Securing Web Services with ASP.NET Authentication (February 28, 2002)
  • Enhanced Security Options of Win2k/COM+ (February 27, 2002)
  • Unifying Windows and Web security infrastructure: Threads, Principals, Permissions, Caching, and HttpModules (February 26, 2002)
  • Guarding your Web Site against SQL Injection Attacks (February 25, 2002)
  •  
           
     
     
      Related Sources
     
  • How ASP.NET Security Works: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconhowaspnetsecurityworks.asp
  • Principal and Identity Objects: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconprincipalide
  • The Windows Authentication Module Provider: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconthewindowsau
  • Code Access Security : http://www.csharptoday.com/content/articles/20011112.asp
  • Role Based Security : http://www.csharptoday.com/content/articles/20011113.asp
  • Custom Permissions : http://www.csharptoday.com/content/articles/20011114.asp
  • Custom Security Implementation : http://www.csharptoday.com/content/articles/20011115.asp
  • COM+ and .NET Security Interoperation : http://www.csharptoday.com/content/articles/20011116.asp
  •  
     
           
      Search the ASPToday Living Book   ASPToday Living Book
     
      Index Full Text Advanced 
     
     
           
      Index Entries in this Article
     
  • anonymous access
  •  
  • AuthenticationType property
  •  
  • credentials
  •  
  • Custom Principal objects
  •  
  • Dispose method
  •  
  • GetAnonymous method
  •  
  • GetCurrent method
  •  
  • Identities
  •  
  • Identity property
  •  
  • IDisposable interface
  •  
  • IIdentity interface
  •  
  • IIS
  •  
  • Impersonate method
  •  
  • Internet Explorer
  •  
  • IPrincipal interface
  •  
  • IsAnonymous property
  •  
  • IsAuthenticated property
  •  
  • IsGuest property
  •  
  • IsInRole method
  •  
  • IsSystem property
  •  
  • limitations
  •  
  • login management
  •  
  • Name property
  •  
  • Netscape Navigator
  •  
  • Page Objects
  •  
  • preventing anonymous access
  •  
  • principals
  •  
  • problems with
  •  
  • reasons for using
  •  
  • security
  •  
  • single login
  •  
  • System.Security.Principal namespace
  •  
  • Token property
  •  
  • User property
  •  
  • users
  •  
  • web applications
  •  
  • web.config file
  •  
  • Windows Authentication
  •  
  • WindowsIdentity class
  •  
  • WindowsPrincipal class
  •  
     
     
    HOME | SITE MAP | INDEX | SEARCH | REFERENCE | FEEDBACK | ADVERTISE | SUBSCRIBE
    .NET Framework Components Data Access DNA 2000 E-commerce Performance
    Security Admin Site Design Scripting XML/Data Transfer Other Technologies

     
    ASPToday is brought to you by Wrox Press (http://www.asptoday.com/OffSiteRedirect.asp?Advertiser=www.wrox.com/&WROXEMPTOKEN=77785ZrPepuudtuWA3eiCODNXJ). Please see our terms and conditions and privacy policy.
    ASPToday is optimised for Microsoft Internet Explorer 5 browsers.
    Please report any website problems to webmaster@asptoday.com. Copyright © 2002 Wrox Press. All Rights Reserved.