Introduction to Application-Based Security...
In writing applications, there are several ways to validate the user at the application level. The authentication method depends on the type of application.
In writing applications, there are several ways to validate the user at the application level. The authentication method depends on the type of application. For intranet applications, windows-based authentication is an option; however, in the internet realm, the only options for validation are forms and passport options.
Windows-based authentication allows the credentials of the user to be accessed via the application. When you log into the computer, your credentials that you sign on with are available via integrated security. For example, when I sign onto my computer, my credentials are ZION\Brian. This user ID is then available to applications running on the computer or Intranet-based web applications. For Windows-based authentication to work correctly, Anonymous Access cannot be allowed for the site. The WindowsIdentity object is defined in the System.Security.Principal namespace.
For applications implementing Windows-based authentication, the WindowsIdentity object represents the user context that is running the application. For web-based applications, this object contains information about the ASPNET user account, instead of the actual user logging into the web site (unless impersonation is used). If impersonation is specified, this user can also be represented through the WindowsIdentity object.
Dim objIdentity As WindowsIdentity = WindowsIdentity.GetCurrent()
In addition to the WindowsIdentity object, the user context can be retrieved from the HttpContext object. The current context has a User property that contains the current principal and identity settings representing the user. The code attached shows an illustration of this.
Dim objIIdentity As WindowsIdentity = HttpContext.Current.User.Identity
Forms-based authentication is where the user is forced to sign into the application through a web form. Any authentication information is either specified in the configuration file, or can also be at the database level. When the user signs in, the information can be passed into a database procedure, which queries a table and validates the results. For best results, hashing the password should be done with either validation option.
The FormsIdentity object represents the user that logs into the forms-based authentication site. For the forms redirection to take place, Anonymous Access must be turned on and the web.config option of <deny users=”?”> must exist. This means that any anonymous users (which will be every user) is denied and must validate their credentials. The user then is redirected to the login page, and upon successful validation, the user is redirected back to the original page and continues surfing the web site. An example of this is in the attached project. This object is defined in the System.Web.Security namespace.
Web.Config:
<authentication mode="Forms">
<forms name=".FormsAuthCookieName" path="/" loginUrl="login.aspx" protection="All" timeout="30">
<credentials passwordFormat="Clear">
<user name="bmains" password="bmains"/>
<user name="guest" password="guest"/>
</credentials>
</forms>
</authentication>
Web Form:
Dim objIdentity As FormsIdentity = HttpContext.Current.User.Identity
Passport-based authentication authenticates users through the Microsoft Passport system. Users register for a Microsoft Passport. When a user logs into a system with a passport, the information is communicated to the system and validated. The applications using this validation must pay for this service. This level of security will not be illustrated in this article.
The GenericIdentity object can be used in applications as another solution. Creating your own objects that are inherited from this object can also add additional security features or identity parameters, which the attached code shows an example of. These parameters could be populated from a database, a file, Active Directory service, etc. This class resides in the System.Security.Principal namespace.
When a new Generic identity is created, the user credentials are passed to it in the constructor. In web applications, this can be retrieved through the Request.ServerVariables collection. The LOGON_USER value contains the user ID of the individual logged onto the computer when Anonymous Access to the web site is turned off. In addition, the current context’s user property contains another property, Identity, which is the current identity of the user. Both approaches are shown below
Dim objIdentity As New GenericIdentity(Request.ServerVariables.Get("LOGON_USER"))
Dim objIdentity As New GenericIdentity(HttpContext.Current.User.Identity.Name)
Response.Write(objIdentity.Name)
The user property for the current context is actually an object of type IPrincipal. Principal objects contain the user context, as well as role-based information about the user. This information is provided at the constructor level. Any roles that need to be verified can be done so later through the IsInRole method. The following code is the establishment of a GenericPrincipal object.
Dim objPrincipal As New GenericPrincipal(objIdentity, strRolesArray)
If (Not objPrincipal.IsInRole(“Administrators”)) Then
Throw New System.Security.SecurityException
End If
Below is an example of the identity of the user, when logging into a windows-based application. The WindowsIdentity object contains information about the ASPNET account running the application, whereas the GenericIdentity object, created from the LOGON_USER server variable, contains the identity of the actual user logging into the request.
Figure 1: The WindowsIdentity account, and the Generic Identity account (using Request.ServerVariables.Get("LOGON_USER")) for Intranet-based web applications
The next example retrieves user information from a SQL Server stored procedure. This approach would be for a forms-based application, where the user needs to be validated at the database level. When the user logs in, the User ID is passed to the stored procedure. If the user doesn't exist, no results are returned from the stored procedure and an exception is thrown. The password values are checked to ensure a correct password value has been provided. In this scenario, the password is stored in the database and is a clear-text value; in a practical use, this password should be hashed using the SHA1 or MD5 hashing algorithms.
If the user credentials check out, the GenericIdentity and GenericPrincipal objects are created. To preserve the validation objects among requests, the current user context is assigned the GenericPrincipal object. The form is then redirected to the original page requested for the application.
Dim objConnection As New SqlConnection(strConnectionString)
Dim objAdapter As New SqlDataAdapter("SelectUser", objConnection)
objAdapter.SelectCommand.CommandType = CommandType.StoredProcedure
objAdapter.SelectCommand.Parameters.Add("@UserID", SqlDbType.VarChar, 25).Value = txtUserID.Text
Dim objTable As New DataTable("Users")
objAdapter.Fill(objTable)
If (objTable.Rows.Count > 0) Then
If (txtPassword.Text = objTable.Rows(0).Item("Password")) Then
Dim objIdentity As New GenericIdentity(txtUserID.Text)
Dim objPrincipal As New GenericPrincipal(objIdentity, New String() {"Users"})
HttpContext.Current.User = objPrincipal
FormsAuthentication.RedirectFromLoginPage(txtUserID, False)
Else
Throw New System.Exception("User could not be authenticated in the system.")
End If
Else
Throw New System.Exception("User doesn't exist in the system.")
End If
To determine whether a user has privileges, the GenericPrincipal object has an IsInRole method that verifies the permissions of the users. In addition, the GenericPrincipal object maintains a reference to the identity of the user, which can be used to reference the user’s identity.
ObjPrincipal = CType(HttpContext.Current.User, GenericPrincipal)
If (Not objPrincipal.IsInRole("Administrators")) Then
Throw New System.Exception(objPrincipal.Identity.Name & " does not have the appropriate permissions for this page.")
End If
About the Code
The code attached is an ASP.NET project. Please copy the folder to your wwwroot directory in order to use this example. Additionally, you may have to set this project up as an application for the virtual directory. In IIS, right-click the Caching virtual directory, select Properties. Where it says "Application Name", the button next to it should say "Remove". If it doesn't, hit the create button to create the application.
The attached projects illustrate the windows and forms authentication methods, as well as retrieving user credentials in .NET applications. Various projects are attached, which are:
Because the Passport security option requires a subscription, this option will not be illustrated. There is a Passport SDK if desired, which is available from Microsoft.
The WindowsAuth project contains User.cls, which is the customized version of the GenericIdentity and GenericPrincipal. The form is a very simple one, and contains some enhancements. However, additional enhancements can be added to customize towards a solution, such as storing user preferences. These preferences could be stored in a database, a file, isolated storage, Active Directory structure, serialized object, etc. The possibilities are endless.
You may download the code here.