ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


ASP.NET Forms Authentication, Part 2

by Abel Banda
01/20/2003

Introduction

When you need to have an OS security level wrapped around your Web application in a legacy environment, you would switch your Web app's IIS setting for "Allow Anonymous User" off, thus enabling your Web application to execute without allowing anonymous users to access your Web application's resources. Doing this would prompt the user to enter their credentials. If your Web app had an application security layer, the user would be required to re-enter their credentials. Often, clients can find this redundant, but necessary for the security level that the business scope requires.

ASP.NET brought us Forms Authentication, which encompasses and extends the application security layer seen in most Web applications. We can extend Forms Authentication's functionality to authenticate against the Active Directory, hence adding an OS security level without the user having to provide their credentials multiple times. In this article, we'll discuss how to log in with Forms Authentication using an active account in Active Directory.

Forms Authentication

Forms Authentication is a system in which unauthenticated requests are redirected to a Web form where users are required to provide their credentials. Upon submitting the form, and being properly verified by your application, an authorization ticket is issued by your Web application, in the form of a cookie. This authorization cookie contains the user's credentials or a key for reacquiring the user's identity (therefore making the user's identity persistent). In essence, Forms Authentication is a means for wrapping your Web application with a thin security layer, allowing you to have your own custom login interface and verification functionality.

Related Reading

.NET Windows Forms in a Nutshell
By Ian Griffiths, Matthew Adams

Active Directory

Active Directory is an essential and inseparable element of the Windows 2000 network architecture that lets organizations efficiently share and manage information about network resources and users. It's essentially a single point of management for Windows-based user accounts, clients, and applications. It also helps organizations integrate non-Windows application with Windows-based applications and devices, thus consolidating directories and easing management of the entire network operating system. Organizations also use Active Directory to extend systems securely to the Internet by forcing their Web application users to authenticate themselves against their single-point Active Directory.

Setting Up Forms Authentication with Active Directory

Let's take a look at the applicable settings to execute Forms Authentication with Active Directory. If you would like more details on Forms Authentication on general, please refer to Part 1 of this series, where all the settings, properties, attributes, and general code for a standard Forms Authentication setup are discussed in greater detail.

In general, setting up Forms Authentication involves just a few more simple steps than the average setup for a standard Forms Authentication Web site. The additional steps, of course, revolve around the the code logic to authenticate the user's credentials against Active Directory. Let's start by setting up a standard Forms Authentication!

  1. Enable anonymous access in IIS. By default, anonymous users should be allowed to access your Web application.
  2. Configure your Web application's web.config file to use Forms Authentication. Start by setting the authentication mode attribute to Forms, and denying access to anonymous users. The following example shows how this can be done in the web.config file for your Web application:
    
    <configuration>
      <system.web>
        <authentication mode="Forms">
          <forms name=".COOKIEDEMO"
                 loginUrl="login.aspx"
                 protection="All"
                 timeout="30"
                 path="/"/>
        </authentication>
        <authorization>
          <deny users="?" />
        </authorization>
      </system.web>
    </configuration>
    
  3. Create your login page (as referenced in the loginURL attribute discussed above). In this case, we should save our login page as login.aspx. This is the page to where clients without valid authentication cookie will be redirected. The client will complete the HTML form and submit the values to the server. You can use the example below as a prototype.

    
    <%@ Import Namespace="System.Web.Security " %>
    <html>
      <script language="C#" runat=server>
      void Login_Click(Object sender, EventArgs E)
      {
        // we will append our authentication logic here next!
      }
      </script>
      <body>
        <form runat="server" ID="Form1">
          <h3>Login Page</h3>
          <hr>
          UserName:<input id="UserName"
                          type="text"
                          runat="server"/>
          <asp:RequiredFieldValidator ControlToValidate="UserName"
                                      Display="Static"
                                      ErrorMessage="*"
                                      runat="server"/>
          <p>Password:<input id="UserPass"
                             type="password"
                             runat="server"/>
          <asp:RequiredFieldValidator ControlToValidate="UserPass"
                                      Display="Static"
                                      ErrorMessage="*"
                                      runat="server"/>
    		<p>Domain:<input id="UserDomain"
    		                 type="text"
    		                 runat="server"/>
          <asp:RequiredFieldValidator ControlToValidate="UserDomain"
                                      Display="Static"
                                      ErrorMessage="*"
                                      runat="server"/>
          <p>Persistent Cookie:<ASP:CheckBox id="PersistCookie"
                                             runat="server" />
          <p><asp:button id="cmdLogin"
                         text="Login"
                         OnClick="Login_Click"
                         runat="server"/>
          <p><asp:Label id="lblResults"
                        ForeColor="red"
                        Font-Size="10"
                        runat="server" />
        </form>
      </body>
    </html>
    

    It's important to note that the above page authenticates the client on the click event of the cmdLogin button. This will trigger the Login_Click function to execute. You can adjust the logic in this function to fit your needs. It is common practice to substitute database logic to verify the credentials against a data table with a stored procedure. It is here at the Login_Click function that we will insert the logic to authenticate against Active Directory. Before we work on the authentication logic, we must first import some new namespaces to have accessibility to advapi32.dll, which we will interact with through interop. The following namespaces must be accessed as follows:

    <%@ Import Namespace="System.Web.Security" %>
      <%@ Import Namespace="System.Runtime.InteropServices" %>

    Now the fun part! Let's alter the <script> for our authentication run, as follows :

    
    <script language="C#" runat=server>
      [DllImport("advapi32.dll", CharSet=CharSet.Auto)]
      public static extern int LogonUser(String lpszUserName,
                                         String lpszDomain,
                                         String lpszPassword,
                                         int dwLogonType,
                                         int dwLogonProvider,
                                         ref IntPtr phToken);
    
      public const int LOGON32_LOGON_INTERACTIVE = 2;
      public const int LOGON32_PROVIDER_DEFAULT = 0;
    
      void Login_Click(Object sender, EventArgs E)
      {
        IntPtr token = IntPtr.Zero;
    
        if(LogonUser(UserName.Value,
                     UserDomain.Value,
                     UserPass.Value,
                     LOGON32_LOGON_INTERACTIVE,
                     LOGON32_PROVIDER_DEFAULT,
                     ref token) != 0)
        {
            FormsAuthentication.RedirectFromLoginPage(UserName.Value,
                                              PersistCookie.Checked);
        }
        else
        {
          lblResults.Text = "Invalid Credentials: Please try again";
        }
      }
    </script>
    

    The <script> block above uses COM Interop provided by the System.Runtime.InteropServices namespace. This is necessary to interact with the advapi32.dll. This DLL is accessed from the [DllImport] call made at the top of the script block. We specify which method to access and the required parameters to send (this is also referred to as the method fingerprint).

    We declare a couple of constants by their variable names. LOGON32_LOGON_INTERACTIVE is an integer representing the logon type we wish to execute and LOGON32_PROVIDER_DEFAULT specifies the provider we wish to use. Now, let's look at the Login_Click function more closely.

    The first thing we do, right off the bat, is create a pointer, token. We set it to "0" by default. It will be used to receive the results of the call to LogonUser. If it returns anything other than a "0" integer, then we we're successfully issued a valid user token, meaning that credentials were successfully authenticated.

    If the user's credentials were successfully authenticated, the user is redirected to the resource he/she tried to access, via the FormsAuthentication.RedirectFromLoginPage call. If not, an error message is displayed on the page via the setting of the text property for the lblResults object.

Summary

Now that wasn't hard, was it? For so little code, it has huge implications and opens the gateway for possibilities in your next application. There are several reasons why companies utilize Active Directory. The primary reason, though, is to have a consolidated single point of user account control. Enabling your Web application to take advantage of interaction with Active Directory will allow you to prevent duplicate user account control systems and snap into an already established architecture already in effect. Good luck and see you next time!

Abel Banda


Return to ONDotnet.com

Copyright © 2009 O'Reilly Media, Inc.