Authentication and Authorization Without IIS

for RuBoard

When using ASP.NET, remoting, or any technology that relies on authentication, it seems common that somewhere there will be a relational database (SQL Server 2000) that contains user information for purposes of authenticating users to a site. While this practice is somewhat understandable for those who don't want to issue a network account to every user who visits their site, probably because the site and the rest of the network are on the same subnet, it raises some security issues of its own. In fact, "issues" may not quite describe it ”burning red flags of despair probably comes closer. Regardless, because ASP.NET has introduced new methods of authentication, discussed in Chapter 14, they rely on the use of Internet Information Services (IIS). This section will address what is possible to do when you cannot use one of these new methods that easily encrypt everything for you or when porting an existing system to the .NET platform where you cannot replace the entire existing infrastructure.

Using a SQL Server Database for Authentication

This practice is as old as the Internet itself ”using a database to validate user login information, setting some session or hidden variables , and personalizing or allowing access based on the results. What is disturbing is that while some sites do not support SSL for handling this information, the information is stored in plain text within the database. While the code samples in the section are not intended to be the "be all and end all" of how .NET can help, at least the minimal implementation involved will increase security exponentially compared to using nothing at all. For this section, we will go on the assumption that you do not want to create an NTLM account for each and every user that could access the Web site. This is often the case for large portals and e-commerce sites. To start with, let's create the Users table. Note that the sample is for demonstration purposes and is in no way intended to represent a live production site.

Listing 28.5 shows the Users table created to hold the basic user information; the database in this sample is named NetSecurityDemo , but this could be in any database.

Listing 28.5 Users Table Script
 if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Users]') and graphics/ccc.gif OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[Users] GO CREATE TABLE [dbo].[Users] (     [UserID] [uniqueidentifier] DEFAULT NEWID() ,     [UserLogonName] [varchar] (20) NULL ,     [UserPassword] [varchar] (128) NULL ,     [UserFirstName] [varchar] (32) NULL ,     [UserLastName] [varchar] (50) NULL ,     [CreateDate] [datetime] DEFAULT GETDATE() ) ON [PRIMARY] GO 

You may also want to add a user to see this work; Listing 28.6 is an INSERT statement for Joe User. This user has a UserLogonName of juser and a password of password . For the purposes of this example, the password has already been encrypted with the code in Listing 28.4. The resulting value is B081DBE85E1EC3FFC3D4E7D0227400CD . Listings 28.4 (as CryptText.asmx.cs ), 28.5, and 28.6 are all available for download from the book's Web site.

Listing 28.6 Insert User Statement
 insert into users (userlogonname, userpassword, userfirstname, userlastname)  values ('juser', 'B081DBE85E1EC3FFC3D4E7D0227400CD', 'Joe', 'User') 

NOTE

Notice in Listing 28.5 that the UserPassword field is given space for a potential 128 characters. This is based on the fact that once padded and encrypted, the password may be considerably longer than originally typed. As a general rule, this table was designed calculating a factor of four (4) for storing padded and encrypted strings; a factor of two (2) is usually sufficient if the data is merely encrypted. This may not be apparent at first because byte array sizes may not equal the length of a string in characters .


From the ASP.NET side, I have created one page ” default.aspx . This page handles the basic login functionality and returns a simple result. Listing 28.7 shows the basic HTML page that the user will see. Listing 28.8 shows the functionality within this page.

Listing 28.7 default.aspx
 <%@ Page language="c#" Codebehind="default.aspx.cs" AutoEventWireup="false" graphics/ccc.gif Inherits="Chapter28.WebForm1" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional/ graphics/ccc.gif /EN" > <HTML>  <HEAD>  <title>WebForm1</title>  <meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">  <meta name="CODE_LANGUAGE" Content="C#">  <meta name="vs_defaultClientScript" content="JavaScript">  <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">  </HEAD>  <body MS_POSITIONING="GridLayout">   <form id="Form1" method="post" runat="server">   <asp:Label id="lblLoginName" style="Z-INDEX: 101; LEFT: 40px; POSITION: absolute; TOP: graphics/ccc.gif 44px" runat="server" Width="91px" Height="16px" Font-Names="Tahoma" Font-Size="Small"> graphics/ccc.gif Login Name:</asp:Label>   <asp:TextBox id="txtLoginName" style="Z-INDEX: 102; LEFT: 150px; POSITION: absolute; graphics/ccc.gif TOP: 47px" runat="server" Width="141px" Height="20px" Font-Names="Tahoma" graphics/ccc.gif Font-Size="Smaller"></asp:TextBox>   <asp:Label id="lblPassword" style="Z-INDEX: 103; LEFT: 42px; POSITION: absolute; TOP: graphics/ccc.gif 84px" runat="server" Width="74px" Height="13px" Font-Names="Tahoma" graphics/ccc.gif Font-Size="Small">Password: </asp:Label>   <INPUT style="Z-INDEX: 104; LEFT: 130px; WIDTH: 170px; POSITION: absolute; TOP: 86px; graphics/ccc.gif HEIGHT: 18px" type="password" size="23" name="txtPassword" id="Password1" runat="server">   <asp:Button id="btnSubmit" style="Z-INDEX: 105; LEFT: 40px; POSITION: absolute; TOP: graphics/ccc.gif 123px" runat="server" Width="85px" Height="21px" Text="Submit"></asp:Button>   <asp:Label id="lblResults" style="Z-INDEX: 106; LEFT: 46px; POSITION: absolute; TOP: graphics/ccc.gif 162px" runat="server" Font-Names="Tahoma" Height="38px" Width="268px"></asp:Label>   </form>  </body> </HTML> 
Listing 28.8 default.aspx.cs
 using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Data.SqlClient; using System.Drawing; using System.Web; using System.Web.SessionState; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; namespace Chapter28 {  /// <summary>  /// Summary description for WebForm1.  /// </summary>  public class WebForm1 : System.Web.UI.Page  {   protected System.Web.UI.WebControls.Label lblLoginName;   protected System.Web.UI.WebControls.TextBox txtLoginName;   protected System.Web.UI.WebControls.Button btnSubmit;   protected System.Web.UI.HtmlControls.HtmlInputText Password1;   protected System.Web.UI.WebControls.Label lblPassword;   protected System.Web.UI.WebControls.Label lblResults;   //Create a private variable to use   //as a security check. This variable   //can only be modified from with this code   private static bool doSubmit;   private void Page_Load(object sender, System.EventArgs e)   {    // No initialization code needed for this page   }   #region Web Form Designer generated code   override protected void OnInit(EventArgs e)   {    //    // CODEGEN: This call is required by the ASP.NET Web Form Designer.    //    InitializeComponent();    base.OnInit(e);   }   /// <summary>   /// Required method for Designer support - do not modify   /// the contents of this method with the code editor.   /// </summary>   private void InitializeComponent()   {    this.btnSubmit.Click += new System.EventHandler(this.btnSubmit_Click);    this.Load += new System.EventHandler(this.Page_Load);   }   #endregion   //Trap the button click event   private void btnSubmit_Click(object sender, System.EventArgs e)   {    //Check to make sure we have something to work with    if(txtLoginName.Text.Length == 0  Password1.Value.Length == 0)    {     lblResults.Text = "Invalid Login Attempt";     doSubmit = false;    }     //If so, attempt to authenticate the users credentials    else    {     lblResults.Text = "";     doSubmit = true;     isAuthenticated();    }   }   private String makePassword()   {    //Make the hash that will be compared    //as the password. If you wanted to    //limit this to a specific domain name, or machine    //you could append that information to the    //string value passed to the Encrypted String method    Chapter28.CryptText ct = new Chapter28.CryptText();    return ct.EncryptedString(Password1.Value.Trim());   }   private bool isAuthenticated()   {    //Internal security check    if(doSubmit)    {     //Connect to the database and compare     //information submitted     try     {      SqlConnection conn = new SqlConnection();      conn.ConnectionString = "server=(local);database=NetSecurityDemo;TRUSTED_CON graphics/ccc.gif NECTION=Yes";      SqlCommand cmd = new SqlCommand("SELECT UserLogonName, UserPassword FROM USERS WHERE graphics/ccc.gif UserLogonName = '" + txtLoginName.Text.Trim() + "'", conn);      SqlDataReader dr = null;      conn.Open();      dr = cmd.ExecuteReader();      //Check to see if there are any results      //before proceeding      if(!dr.Read())      {       lblResults.Text = "Name not found in database";       conn.Close();       return false;      }      String hPassword = makePassword();      if(dr.GetString(1).Trim() == hPassword)      {       lblResults.Text = "Login OK";       conn.Close();       return true;      }      else      {       lblResults.Text = "Login Failed";       conn.Close();       return false;      }     }     catch(Exception err)     {      lblResults.ForeColor = System.Drawing.Color.Red;      lblResults.Text = err.ToString();      return(false);     }    }    else    {     lblResults.Text = "Method Failed Security Check";     return false;    }   }  } } 

Though database-based authentication may be subject to replay attack, this can be augmented with session information that times out quickly, within 20 minutes, to help prevent attacks. Also, in Listings 28.4, 28.7 and 28.8, as well as all of the listings in this chapter, SSL can be implemented.

Using JSP to Call a Web Service

As an example of the true versatility of Web Services, Listings 28.9, 28.10 and 28.11 show the use of JavaServer Pages to invoke the Web Service using the result to determine whether or not to allow the user. Listing 28.9 is a modification to the CryptText service from Listing 28.4. By adding a reference to System.Data.SqlClient and the doLogin method, we can call this from any HTTP client and get the same results.

NOTE

To execute this sample in its entirety, you must have a Web server with some sort of processor for JavaServer Pages, such as Apache's Tomcat Server or JServ from Allaire. This sample was written using Windows XP Professional, Sun's Java Development Kit (JDK) 1.3, Apache's Tomcat Server Version 4, Microsoft VisualStudio.NET, and Microsoft SQL Server 2000, Developer's Edition.


Listing 28.9 doLogin Method for CryptText Web Service
 [WebMethod]   public bool doLogin(String sUserName, String sPassword)   {    try    {     SqlConnection conn = new SqlConnection();     conn.ConnectionString = "server=(local);database=NetSecurityDemo; TRUSTED_CON graphics/ccc.gif NECTION=Yes"; SqlCommand cmd = new SqlCommand("SELECT UserLogonName, UserPassword FROM USERS WHERE graphics/ccc.gif UserLogonName = '" + sUserName.Trim() + "'", conn);     SqlDataReader dr = null;     conn.Open();     dr = cmd.ExecuteReader();     //Check to see if there are any results     //before proceeding     if(!dr.Read())     {      conn.Close();      return false;     }     String hPassword = EncryptedString(sUserName.Trim() + sPassword.Trim());     if(dr.GetString(1).Trim() == hPassword)     {      conn.Close();      return true;     }     else     {      conn.Close();      return false;     }    }    catch(Exception err)    {     return(false);    }   } 

As you may notice, this is very much like the code from Listing 28.9. This was done intentionally to show the two different means of implementation. Next, Listings 28.10 and 28.11 show the default login page for our JSP login and the processing page used to call the Web Service.

Listing 28.10 index.jsp
 <html> <head> <title>Login Page</title> <body bgcolor="white"> <form method="POST" action="login.jsp">   <table border="0" cellspacing="5">     <tr>       <th align="right">Username:</th>       <td align="left"><input type="text" name="j_username"></td>     </tr>     <tr>       <th align="right">Password:</th>       <td align="left"><input type="password" name="j_password"></td>     </tr>     <tr>       <td align="right"><input type="submit" value="Log In"></td>       <td align="left"><input type="reset"></td>     </tr>   </table> </form> </body> </html> 
Listing 28.11 login.jsp
 <%@ page contentType="text/html;charset=WINDOWS-1252"%> //Note:* is used for compression of space in code sample //as always, import only what you must have to make the //code execute <%@ page import="java.NET.*"%> <%@ page import="java.io.*"%> <% try { //First get the variables passed from login.jsp String user = request.getParameter("j_username"); String pass = request.getParameter("j_password"); //Create a URL object to use for the request URL url = new URL("http://localhost/Chapter28/CryptText.asmx/doLogin? sUserName=" + user graphics/ccc.gif + "&sPassword=" + pass); //Read the response stream to look for a result BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); String str; while ((str=in.readLine()) != null)   { //since the method we are calling returns a boolean //check for true   if(str.indexOf("true") != -1)  out.println("Login Succeeded");   else    out.println(str);   } //Cleanup   in.close(); } catch (Exception e) {} %> <HTML> <HEAD> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=WINDOWS-1252"> <TITLE> Calling .NET from JSP </TITLE> </HEAD> <BODY> </BODY> </HTML> 

As Listings 28.10 and 28.11 have indicated, the programmatic ways of gathering basic user information for the purposes of authorization and authentication do extend beyond just ASP.NET and IIS. This is the reason for using eXtensible Markup Language (XML) to store information. From here, authorization may be extended by mapping a database-based account to a generic network account that has permissions for delegation.

for RuBoard


. NET Framework Security
.NET Framework Security
ISBN: 067232184X
EAN: 2147483647
Year: 2000
Pages: 235

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net