asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search








Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

ASP.NET Mixed Mode Authentication
By Paul Glavich
Rating: 3.9 out of 5
Rate this article


  • email this article to a colleague
  • suggest an article

    In an increasing number of the web applications I have had to design and work on, the client has requested the best of both worlds when it comes to authentication. Ideally, they would like their intranet users to be able to seamlessly logon on to the system (windows integrated authentication) and make authorization decisions based on their domain roles, as well as be able to have external parties log onto the system using standard forms authentication. In this article, I will show you one way of achieving this goal.

    Note: This method assumes that cookies are allowed and enabled on the client browsers.

    Assumed Knowledge

    This article assumes the reader is familiar with the setup of forms authentication in ASP.Net, windows principal objects, role based authorisation, reflection, and is also familiar with the setup of Windows integrated authentication using the Internet Information Services (IIS) snap-in management console.

    A Common Model

    In order for this mixed model authentication scenario to work, and also to make it easy on developers, a common and familiar security model is required for authentication, and subsequently authorisation. If we were trying to emulate windows integrated authentication from a forms authentication based site, it would be extremely difficult, if not impossible to accurately mimic, and obtain a users roles from the domain in a seamless manner. It would be much easier to let windows/IIS provide a users roles for us in an appropriate principal object, and to extract those roles, and mimic a forms authentication process.

    This method means that to the application, all users have authenticated via the forms authentication method, but that intranet users will have a larger and more specific set of roles attached with their principal object. The diagram below illustrates this.

    Basic Setup

    In ASP.Net, you cannot have a single application with different modes of authentication. For this to work we will need to have 2 applications, or in IIS terms, 2 virtual directories. These act as 2 different entry points to the same application. One is a very simple application that uses windows integrated authentication, the other is the complete/main application using forms authentication. The windows authorisation site exists only for the purposes of extracting an intranet users roles and passing them to the forms authentication site. To examine this in more detail, we will begin by giving a detailed explanation of the Windows Integrated authorisation site/entry point.

    Windows Integrated Authentication Site

    As mentioned above, this site exists only to extract role information from an intranet user, and pass it along to the forms authentication site. Forms authentication (for our purposes) uses cookies as the method of indicating an authenticated user. It can be configured to use cookieless mode, but we will only be using cookies in this scenario. So we will need to peform 3 main functions :

    1. Authenticate the user (Performed automatically for us by IIS and in combination with the web.config)
    2. Extract a users roles to pass to main application.
    3. Supply a valid forms authentication ticket to the forms authentication entry point so that the site believes we are a valid authenticated user.

    Step 1 - Authenticate the User

    Accomplishing step 1 is easy. When creating the virtual directory using the IIS MMC snap-in, ensure that 'Anonoynous Access' is disabled (not checked) and that 'Integrated Windows Authentication' is checked/enabled as shown in the diagram below:

    Modifying the Web.Config

    We also need to ensure that the Web.Config file of our windows authentication entry point application is set up correctly. Below is a sample of a Web.Config file. The important part is the 'authentication' element. It must have its 'mode' set to 'Windows'.

    <system.web>
       .....
       <authentication mode="windows">
       .....
    </system.web>
    

    You might be thinking, in order to get access to a windows principal with roles, we will need to use impersonation. Well actually, no we dont. I too at first thought this, and it still obviously will work fine if we do enable impersonation, but the principal is still passed to our application at an early stage for us to work with. Within the 'Application_AuthenticateRequest' event in the Global.asax file of our application is where we will be extracting the role information. If we needed to work with the principal, and have it attached to our currently running thread, then impersonation would be required.

    Important Note: This application needs to exist in a virtual directory, that is a sub-directory or sub-application of the main forms authentication application. The reason for this is that both applications will need to have the same HOST name. Cookies are generated and named according to the host name they apply to. Specifying the same cookie name in code, but using different host names will cause 2 different cookies to be generated because of the different host names. The diagram below shows an example of how the virtual directories should be setup in the IIS manager. 

    Step 2 - Extracting the users role information

    Extracting the users role information involves a bit of reflection magic. Bascially, we use reflection to look inside the principal object that is provided to us by Windows/IIS when the user is authenticated. Please note that this involves reflecting over specific properties of the principal object and is not guranteed to work in future versions of .Net. It does work, and has been tested in production environments using .Net Version 1.1 (V1.1.4322).

    The most logical place to extract the role information from the principal is the 'Application_AuthenticateRequest' event. Briefly, we look at a particular string array within the principal to extract any role information from the principal. There are some tricks to watch out for, which we will cover shortly. Listed below is some code that will extract the role from a principal object.

    private static string[] GetRoles(IPrincipal princ)
    {
       Type type = princ.GetType();

       // Note: This code sets the 'MAGIC_NUMBER' field of the principal object.
       FieldInfo field2 = type.GetField("MAGIC_NUMBER", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
       field2.SetValue(princ,40); // This value can be any number but defaults to 23.

       princ.IsInRole("DummyRole"); // This call is required so that the subsystem goes and retrieves a list of roles.
       // Without this call, the principal object does not contain any roles in its internal
       // variables, and thus the code below that uses reflection to get the value of this variable
       // will fail and return NULL.

       FieldInfo field = type.GetField("m_roles", BindingFlags.Instance | BindingFlags.NonPublic);
       String[] roles = (String[]) field.GetValue(princ);

       return roles;
    }

    And we obviously need to call this routine from the 'Application_AuthenticateRequest' event as in the code shown below:

    protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
       WindowsIdentity ident = WindowsIdentity.GetCurrent();
       WindowsPrincipal wind_princ = new WindowsPrincipal(ident);

       string[] roles = GetRoles(wind_princ);
       ...
       ...
    }

    You will notice in the 'GetRoles' method above, we set a 'MAGIC_NUMBER'. This number determines how many roles the user can have before the roles are stored in a hashtable in the principal object, instead of a string array. This is done for performance reasons but the important part is, that if your intranet users are on a domain and happen to have more than this 'MAGIC_NUMBER' number of roles, then the string array you are getting the users roles from will be empty. By default, this 'MAGIC_NUMBER' is set to 23. The code in the method above provides the ability to change this 'MAGIC_NUMBER' to any value you like. For our purposes, we will change it to something higher to make sure we get all the roles in our string array.

    Step 3 - Simulating a valid forms authentication ticket and supplying the users role information

    Now we need to put all this together. We need to take the role information we have extracted from the principal, and pass it over to our forms authentication entry point application, and tell that entry point we have a valid autenticated user.

    The Windows authentication entry point site has extracted the role information. Now it only needs to create a forms authentication ticket, store the roles in the user data, and issue the ticket. The ticket must have the same path and name across both the forms authentication site and the windows authentication site. The code below shows the code that should be placed in the 'Global.asax - Application_AuthenticateRequest' event for the storage of the roles and the redirection.

    protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
       //NOTE: Because we are encrypting some information and passing it to another site, the MACHINE.CONFIG file needs
       // to have the <machinekey> element set to a static value. By default, this value is autogenerated for each web
       // application on the machine and will therefore fail if you try and pass encrypted tickets/data between
       // web apps.
       WindowsIdentity ident = WindowsIdentity.GetCurrent();
       WindowsPrincipal wind_princ = new WindowsPrincipal(ident);
       string[] roles = GetRoles(wind_princ); // See method above for implementation of this method

       string roleData = String.Join(";",roles);
       FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,"your_ticket_name",DateTime.Now,DateTime.Now.AddMinutes(30),false,roleData,"/");
       string encTicket = FormsAuthentication.Encrypt(ticket);

       // NOTE: The name of the HttpCookie must match what the FormsAuth site expects.
       Response.Cookies.Add(new HttpCookie("YourCookieName",encTicket));
       // Ticket and cookie issued, now go to the FormsAuth site and all should be well.
       Response.Redirect("http://localhost/TestFormsAuthSite/IntoSite.aspx");
    }

    As you can see, we encrypt this ticket using the forms authentication standard routines. For this to work across applications, modifications must be made to the machine.config file to ensure encryption keys are not auto-generated for each application. The modification required is shown below:

    <!-- Your old machine.config entry will resemble the line below -->
    <!-- <machineKey validationKey="AutoGenerate,IsolateApps" decryptionKey="AutoGenerate,IsolateApps" validation="SHA1" /> -->

    <!-- You NEED to change that entry to resemble something like the line below. Note: The validationKey/decriptionKey should be your own -->
       <machineKey validationKey="357356792679345184568256876535689056434617489465" decryptionKey="357356792679345184568256876535689056434617489465" validation="SHA1"/>

    Lastly, the 'Global.asax' file in the forms authentication entry point site must be modified, so that the 'Application_AuthenticateRequest' event knows how to decipher a valid ticket issued by the windows authentication entry point site, and assign these roles to the current principal. The web.config of this site must also be setup to have matching attributes (ie. name) as what the Windows Authorisation site is issueing. The code below demonstrates this :

    Web.Config

    <authentication mode="Forms">
       <forms name="YourCookieName" <!-- This cookie name matches what the Windows Auth site creates -->
          loginUrl="forms_login.aspx"
          protection="All"
          timeout="30"
          path="/" <!-- This same path as what the Windows auth site uses when creating the cookie/auth ticket -->
          requireSSL="false"
          slidingExpiration="true">
       </forms>
    </authentication>

    <authorization>
       <deny users="?" /> <!-- Only allow authenticated users. Add your application and domain specific access roles here -->
    </authorization>

    Application_Authenticate Event (Forms Auth site)

    protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
       bool cookieFound = false;

       HttpCookie authCookie = null;
       HttpCookie cookie;

       for(int i=0; i < Request.Cookies.Count; i++)
       {
          cookie = Request.Cookies[i];

          if (cookie.Name == FormsAuthentication.FormsCookieName)
          {
             cookieFound = true;
             authCookie = cookie;
             break;
          }
       }

       // If the cookie has been found, it means it has been issued from either
       // the windows authorisation site, is this forms auth site.
       if (cookieFound)
       {
          // Extract the roles from the cookie, and assign to our current principal, which is attached to the
          // HttpContext.
          FormsAuthenticationTicket winAuthTicket = FormsAuthentication.Decrypt(authCookie.Value);
          string[] roles = winAuthTicket.UserData.Split(';');
          FormsIdentity formsId = new FormsIdentity(winAuthTicket);
          GenericPrincipal princ = new GenericPrincipal(formsId,roles);
          HttpContext.Current.User = princ;
       }
       else
       {
          // No cookie found, we can redirect to the Windows auth site if we want, or let it pass through so
          // that the forms auth system redirects to the logon page for us.
       }
    }

    Final Considerations

    The Forms authentication site must also contain code for users who are logging in via the standard logon page. Typically, you would assign a single role of low privilege to identify the user as a non-intranet user (eg. external to the organisation) and assign that role to a principal and attach it to the HttpContext in similar fashion to the code above.

    At this point, your application can make role checks against the principal attached to the HttpContext in a standard manner. The application does not have to worry about where the user came from, standard role checks are all that is needed, and can therefore tailor the user experience based on the different roles.

    Conclusion

    The technique I have described here is not trivial, and requires reasonable knowledge of the forms authentication system that .Net uses. The advantage is great though. You can now let both intranet users and external parties access the same application in a consistent manner with the standard role based access checks being applied to determine a users functionality and origin. The code to do this is not great and the setup can be tricky, but this technique does work and is currently being used in a number of ways within our organisation to great effect.

    If you are having difficulty with the concept or its implementation, I can be contacted at glav@aspalliance.com.

    Happy coding...

  • Rate This Article
    Not HelpfulMost Helpful
    1 2 3 4 5
    Supporting Products/Tools
    AspEncrypt
    Built around the Microsoft CryptoAPI, AspEncrypt helps you harness all major encryption and hashing algorithms such as DES, Triple-DES, RC2, RC4, RSA, MD5 and SHA1 in just a few lines of code. The component can be used in tandem with AspEmail to send encrypted and signed mail in the industry-standard S/MIME format, or with AspUpload to encrypt files as they are being uploaded. AspEncrypt can also be used to issue and manage X.509 digital certificates.
    [Top]
    AspPDF
    AspPDF is an ASP/ASP.NET component which enables generation and management of documents in PDF format. Features include advanced text formatting, font embedding, form fill-in, images, tables, content and page extraction, document stitching, encryption, digital signatures, and more.
    [Top]
    Other Articles
    Dec 8, 2004 - Designing Role-Based Security Models for .NET
    In this article, Michele Leroux Bustamante discusses authentication, authorization and role-based security in .NET. Along the way, he provides some best practices for implementing role-based security in some typical .NET application scenarios including rich clients, Web applications, and Web services.
    [Read This Article]  [Top]
    May 11, 2004 - SharePoint Security and .NET Impersonation
    When implementing custom components that require access to restricted resources, implicit impersonation must be used. Jay Nathan shows how to create a class that makes using .NET Impersonation a snap.
    [Read This Article]  [Top]
    Mar 10, 2004 - Intellectual Property Protection and Code Obfuscation
    Learn about the execution process of CLR-based programs and how to protect your applications from being easily disassembled back into source code.
    [Read This Article]  [Top]
    Feb 24, 2004 - How to Send Secure Mail in ASP-Based E-Commerce Applications - Part II
    Businesses that utilize encrypted e-mail may find Secure Multipurpose Internet Mail Extensions (S/MIME) to be somewhat restrictive. This article shows how to use security features in PDF as an alternative to S/MIME.
    [Read This Article]  [Top]
    Feb 2, 2004 - Fighting Spambots with .NET and AI
    Bill Gates, in a recent interview, predicted the end of spam by 2006. One of the methods he mentioned involved a challenge only a real live person could handle. Adnan Masood shows how to use AI and .NET to create a user verification scheme that incorporates similar concepts Gates alluded to.
    [Read This Article]  [Top]
    Jan 21, 2004 - Configuring .NET Code Access Security
    Code Access Security (CAS) is the .NET Framework security model that grants code permission to resources based on "evidence" pertaining to the encapsulating assembly. In this article, David Myers examines CAS and explains different configuration methods.
    [Read This Article]  [Top]
    Mar 10, 2003 - Platform Neutral and Transparent Encryption of Sensitive Customer Information
    Zhenlei Cai combines an open source C++ encryption library with SQL Server extended stored procedures to create a platform neutral, transparent encryption solution that resides at the database layer.
    [Read This Article]  [Top]
    Jan 15, 2003 - Exploring Machine.Config - User Security and More
    Christopher Spann offers a .NET configuration tip that should help ease system administrators' fears of security compromise and thus assuage growing developer demand for a .NET environment.
    [Read This Article]  [Top]
    Dec 10, 2002 - Encrypting Cookie Data with ASP.NET
    You don't have to be a cryptography expert or spend lots of money on third-party components to secure sensitive data in .NET. In this article, Wayne Plourde shows just how easy it is to encrypt cookie data using encryption classes in the .NET System.Security.Cryptography namespace.
    [Read This Article]  [Top]
    Aug 21, 2002 - Web Application Error Handling and Logging For ASP
    One of the most important aspects of an application is how well it responds to the user, and this includes response to errors. In this article, Adam Tuliper shares techniques for catching ASP errors and shows how to create a notification system that is sure to keep customers at bay.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry



    JupiterOnlineMedia

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info


    Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

    Solutions
    Whitepapers and eBooks
    Microsoft Article: HyperV-The Killer Feature in WinServer ‘08
    Avaya Article: How to Feed Data into the Avaya Event Processor
    Microsoft Article: Install What You Need with Win Server ‘08
    HP eBook: Putting the Green into IT
    Whitepaper: HP Integrated Citrix XenServer for HP ProLiant Servers
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 1
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 2--The Future of Concurrency
    Avaya Article: Setting Up a SIP A/S Development Environment
    IBM Article: How Cool Is Your Data Center?
    Microsoft Article: Managing Virtual Machines with Microsoft System Center
    HP eBook: Storage Networking , Part 1
    Microsoft Article: Solving Data Center Complexity with Microsoft System Center Configuration Manager 2007
    MORE WHITEPAPERS, EBOOKS, AND ARTICLES
    Webcasts
    Intel Video: Are Multi-core Processors Here to Stay?
    On-Demand Webcast: Five Virtualization Trends to Watch
    HP Video: Page Cost Calculator
    Intel Video: APIs for Parallel Programming
    HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
    Microsoft Silverlight Video: Creating Fading Controls with Expression Design and Expression Blend 2
    MORE WEBCASTS, PODCASTS, AND VIDEOS
    Downloads and eKits
    Sun Download: Solaris 8 Migration Assistant
    Sybase Download: SQL Anywhere Developer Edition
    Red Gate Download: SQL Backup Pro and free DBA Best Practices eBook
    Red Gate Download: SQL Compare Pro 6
    Iron Speed Designer Application Generator
    MORE DOWNLOADS, EKITS, AND FREE TRIALS
    Tutorials and Demos
    How-to-Article: Preparing for Hyper-Threading Technology and Dual Core Technology
    eTouch PDF: Conquering the Tyranny of E-Mail and Word Processors
    IBM Article: Collaborating in the High-Performance Workplace
    HP Demo: StorageWorks EVA4400
    Intel Featured Algorhythm: Intel Threading Building Blocks--The Pipeline Class
    Microsoft How-to Article: Get Going with Silverlight and Windows Live
    MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES