NGWS SDK Documentation  

This is preliminary documentation and subject to change.
To comment on this topic, please send us email at ngwssdk@microsoft.com. Thanks!

Scenario 2 - Cookie Authentication

In this scenario, a protected resource, default.aspx, is requested by the client. In the security section of the configuration file, the authentication mode is set to "Cookie", so ASP+ tries to find a cookie that is attached to the request. If it finds none, it redirects the request to a login page (login.aspx). There, the client user enters the required credentials (e-mail name and password). The page compares the entered credentials to a list of credentials in an XML file. If a match is found, the request is considered authenticated and the client is redirected to the originally requested resource (default.aspx). If no match is found, the request is redirected to the add user page (adduser.aspx). There, the just-entered credentials are encoded and added to the XML file.

There are five files associated with this example — three .aspx files (default.aspx, login.aspx, and adduser.aspx) and two configuration files (both named config.web, but one is located in the application root directory and the other is located in the adduser directory). All five files will be explained in the following discussion.

Application Root Directory Configuration File (config.web)

You should set up this configuration file to have the following entries and place it in the application root directory (the directory in which default.aspx resides).

<configuration>
   <security>
  1. Set the authentication mode to Cookie. Other possible values are Windows, Passport, and None (empty string) - but for this example it must be Cookie.
    <authentication mode="Cookie" /> 
  2. Set the cookie authentication attributes.
    <cookieauthentication
    1. Set the decryptionkey to autogenerate. This causes ASP+ to automatically generate a key for decrypting the cookies.
      decryptionkey = "autogenerate"
    2. Set the loginurl attribute to login.aspx. The is the URL to be used for redirection if ASP+ does not find a cookie with the request.
      loginurl = "login.aspx"
    3. Set the cookie name suffix.
      cookie = ".ASPXCOOKIEAUTH" />
  3. Deny unauthenticated users access to this directory.
        <authorization>
           <deny users="?" /> 
        </authorization>
      </security>
    </configuration>

Adduser Directory Configuration File (config.web)

You should set up this file to have the following entries and place it in the file containing adduser.aspx. These settings allow anyone access to this directory (assuming there are no NTFS ACLs preventing it).

<configuration>
   <security>
      <authentication mode="None" /> 

      <authorization>
          <allow users="*" /> 
      </authorization>

   </security>
</configuration>

Default.aspx File

This is the requested, protected resource. It is a simple file that merely displays the string "Hello" plus the recorded (logged in) e-mail name, and a Signout button.

<%@ Page LANGUAGE="c#" %>
<html>
<head>
<title>Cookie Authentication</title>

<script runat=server>
    private void Page_Load(Object Src, EventArgs E ) 
    {
        Welcome.InnerHtml = "Hello, " + Context.User.Identity.Name;
    }
    private void Signout_Click(Object sender, EventArgs E) 
    {
        CookieAuthentication.SignOut();
        Response.Redirect("login.aspx");
    }
</script>

<body>
<h3><font face="Verdana">Using Cookie Authentication</font></h3>
<span id="Welcome" runat=server/>
<form runat=server>
    <input type="submit" OnServerClick="Signout_Click" Value="Signout" 
                                                       runat="server"/><p>
</form>
</body>
</html>

Login.aspx File

This is the file to which the request gets redirected if ASP+ does not find the cookie with the request. This URL was set up in the configuration file. A form is presented to the client user. It has two text boxes (e-mail name and password) and a submit button. The user enters the e-mail name and password, and clicks the submit button. The code then checks to see if this name and password is contained in an XML file located in this directory. If it is, then the user is connected to default.aspx. If it is not, the adduser.aspx file is called.

To implement this functionality, proceed as follows:

  1. Import the necessary name spaces.
    <%@ Page LANGUAGE="c#" %>
    <%@ Import Namespace="System.Data" %>
    <%@ Import Namespace="System.Data.SQL" %>
    <%@ Import Namespace="System.Web.Security " %>
    <%@ Import Namespace="System.IO" %>
    
    <html>
    <head>
    <title>Cookie Authentication</title>
  2. Create a script section for the code.
    <script runat=server>
  3. Implement a Login_Click function
    private void Login_Click(Object sender, EventArgs E) 
    {
    1. If the page is not valid, tell the user.
      if( !Page.IsValid ) {
          Msg.Text = "Some required fields are missing";
          return;
      }
    2. Set up a string named "cmd" that is initialized to "UserEmail='MyName'", where MyName is the user's e-mail name.
      String cmd = "UserEmail='" + UserEmail.Value + "'";
    3. Instantiate a new DataSet object.
      DataSet ds = new DataSet();
    4. Read in the XML file containing authenticated user name and password combinations. The retrieved data resides in "ds", the DataSet instantiated in the previous step.
    Note   For the sake of simplicity, and the learning experience, the following code does not follow best design practice, in that it does not invoke any file locking or sharing flags. Also, in a real Web site, it would probably be desirable to use a relational database for the list of authenticated users.
    FileStream fs = new FileStream(Server.MapPath("users.xml"), 
                                        FileMode.Open,FileAccess.Read);
    StreamReader reader = new StreamReader(fs);
    ds.ReadXml(reader);
    fs.Close();
    1. Instantiate a new DataTable named "users" that is initialized to "ds".
      DataTable users = ds.Tables[0];
    2. Check for any matches between the Login name and the list of names in "users". For each match found, record the name in a DataRow[] named "matches"
      DataRow[] matches = users.Select(cmd);
    3. Check each of the name matches found in the previous step to see if there is a matching password for any of them.
      if( matches != null && matches.Length > 0 ) 
      {
    4. If at least one name match is found, check for password matches.
          DataRow row = users.Rows[0];
          String pass = (String)row["UserPassword"];
          if( 0 != String.Compare(pass, UserPass.Value, false) ) 
          //**********************************************
          // If no password match is found, tell the user.
          //**********************************************
              Msg.Text = "Invalid Password: Please try again";
          else 
          //*************************************************
          // If a password match is found, redirect the request
          // to the originally requested resource (Default.aspx).
          //*************************************************
              CookieManager.RedirectFromLoginPage(UserEmail.Value, 
                                                  PersistCookie.Checked);
      }
      else {
    5. If no name matches were found, redirect the request to the add users page. First a URL string must be constructed, and then the string is used in a Response.Redirect command.
              StringBuilder url = new StringBuilder();
              url.Append("adduser/adduser.aspx?");
              url.Append(Request.ServerVariables["QUERY_STRING"]);
              url.Append("&UserEmail=");
              url.Append(Server.UrlEncode(UserEmail.Value));
              url.Append("&UserPassword=");
              url.Append(Server.UrlEncode(UserPass.Value));
              Response.Redirect(url.ToString());
          }
      }
      </script>
      <body>
  4. Display a form to collect the login information.
    <form runat=server>
        <h3><font face="Verdana">Login Page</font></h3>
    
        <table>
            <tr>
    1. Create a User E-mail Name text box.
              <td>Email:</td>
              <td><input id="UserEmail" type="text" runat=server/></td>
              <td><ASP:RequiredFieldValidator 
                  ControlToValidate="UserEmail" 
                  Display="Static"
                  ErrorMessage="*"
                  runat=server/>
              </td>
      
          </tr>
          <tr>    
    2. Create a Password text box.
              <td>Password:</td>
              <td><input id="UserPass" type=password runat=server/></td>
              <td><ASP:RequiredFieldValidator 
                  ControlToValidate="UserPass" 
                  Display="Static"
                  ErrorMessage="*"
                  runat=server/>
              </td>
          </tr>
          <tr>
    3. Create a Persistent Cookie check box. If the persist cookie is set (checked), the cookie will be valid across browser sessions. Otherwise, when the browser is closed, the cookie is destroyed.
              <td>Persistent Cookie:</td>
              <td><ASP:CheckBox id=PersistCookie runat="server"
                  autopostback="true" />
              </td>
              <td></td>
          </tr>
      
      </table>
    4. Create a Submit button that causes the Login_Click event to be fired on postback.
      <input type="submit" OnServerClick="Login_Click" Value="Login" 
                                                   runat="server"/><p>
          <asp:Label id="Msg" ForeColor="red" Font-Name="Verdana" 
                                        Font-Size="10" runat=server />
      
      </form>
      </body>
      </html>

Add User.aspx File

When the login page cannot find the e-mail name in the "users" XML file, it redirects the request to this page, and if the user clicks the "Add User" button, the user name and password are added to the file. This page is implemented as follows:

  1. Import the necessary namespaces.
    <%@ Page LANGUAGE="c#" %>
    <%@ Import Namespace="System.Data" %>
    <%@ Import Namespace="System.Data.SQL" %>
    <%@ Import Namespace="System.Web.Security " %>
    <%@ Import Namespace="System.IO" %>
    <html>
    <head>
    <title>Cookie Authentication</title>
  2. Create a script section tag
    <script runat=server>
  3. Implement a Page_Load function
    private void Page_Load(Object Src, EventArgs E ) 
    {
    1. Get the UserEmail and UserPassword strings from the request.
      String email = Request.QueryString["UserEmail"];
      String password = Request.QueryString["UserPassword"];
    2. If they are not null, set up the UserEmail and UserPassword values.
      if( null != email )
          UserEmail.Value = email;
      if( null != password )
          UserPass.Value = password;
      }
  4. Implement the AddUser_Click function.
    private void AddUser_Click(Object sender, EventArgs E) 
    {
    1. If the page is not valid, tell the user.
      if( !Page.IsValid ) {
          Msg.Text = "Some required fields are missing";
          return;    
      }
    2. Instantiate a new DataSet named ds.
      DataSet ds = new DataSet();
    3. Initialize a string named userFile with the path to the Users.xml file.
      String userFile = "../users.xml";
    4. Read in the XML file to a DataSet named "ds" (instantiated in step b).
      FileStream fs = new FileStream(Server.MapPath(userFile), 
                                          FileMode.Open,FileAccess.Read);
      StreamReader reader = new StreamReader(fs);
      ds.ReadXml(reader);
      fs.Close();
    5. Add the new name and password to the DataSet "ds".
      DataRow newUser = ds.Tables[0].NewRow();
      newUser["UserEmail"] = UserEmail.Value;
      newUser["UserPassword"] = UserPass.Value;
      ds.Tables[0].Rows.Add(newUser);
      ds.AcceptChanges();
    6. Write the new DataSet (with the new Name and Password) out to the XML file.
      fs = new FileStream(Server.MapPath(userFile), FileMode.Create, 
                                       FileAccess.Write|FileAccess.Read);
      StreamWriter writer = new StreamWriter(fs);
      ds.WriteXml(writer);
      writer.Close();
      fs.Close();
    7. Redirect the request back to the originally requested resource (Default.aspx).
      CookieManager.RedirectFromLoginPage(UserEmail.Value, 
                                                  PersistCookie.Checked);
      }
      </script>
      <body>
      <form runat=server>
          <div style="background:#ccccff"><h3><font face="Verdana">Add New 
                                                    User</font></h3></div>
  5. With the exception of the button name, the following form is identical to the one described under the Login.aspx File heading.
        <table>
            <tr>
                <td>Name:</td>
                <td><input id="UserEmail" type="text" runat=server/></td>
                <td><ASP:RequiredFieldValidator 
                    ControlToValidate="UserEmail" 
                    Display="Static"
                    ErrorMessage="*"
                    runat=server/>
                </td>
    
            </tr>
            <tr>    
                <td>Password:</td>
                <td><input id="UserPass" type=password runat=server/></td>
                <td><ASP:RequiredFieldValidator 
                    ControlToValidate="UserPass" 
                    Display="Static"
                    ErrorMessage="*"
                    runat=server/>
                </td>
            </tr>
            <tr>
                <td>Persistent Cookie:</td>
                <td><ASP:CheckBox id=PersistCookie runat="server"
                    autopostback="true" />
                </td>
                <td></td>
            </tr>
    
        
        </table>
        <input type="submit" OnServerClick="AddUser_Click" Value="Add User" runat="server"/><p>
            <asp:Label id="Msg" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat=server />
    </form>
    </body>
    </html>

To see an example run that has code very similar to this example, go to the ASP+ Quick Start and run sample "Forms-based/Cookie Authentication".