Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Windows Logon, Web User Control Implementation - in ASP.NET

0.00/5 (No votes)
24 Nov 2003 1  
A classic example of implementing reusable web user control, with supporting controls and classes to keep the code manageable

Sample Image - ASPdotnet_LoginControl.gif

Overview

This article attempts to work out an example of the impersonation namespace in .NET, to logon a user through a webpage, with his Windows logon credentials. The traditional way of logging in users using their Windows authentication is by enabling the Basic Authentication property of the web application in IIS.

But, using the control, we can eliminate the necessity of controlling logon through IIS, and enable it through our code. This opens up a considerable area of control through code. We can hence have a control on which user login is requested, and on which domain and all that.

We will discuss the creation of the project and the logic I had in mind while developing it. The completed and tested code, that was developed using VS.NET is attached to this article.

Introduction

We create two web user controls.

  • WindowsLoginControl

    This has the implementation and UI for the login pane. It has two UIs, one for new users, one for already logged in users. A session variable maintains the state of the login to determine which UI to show. Code in this control calls the logInUser class' shared method to process the login.

  • ErrorControl

    This has implementation and UI for an error reporting pane. When errors occur, other controls on the page update a session variable, which is checked when this control loads. When there's no error, we display an 'Under construction' message (This may be removed in release versions).

NOTE: We could have implemented the logic of this control also into the WindowsLoginControl, but having this as a separate control allows us to easily move the control on the UI of a target page in VS.NET.

  • A LoginUser class with a shared method for processing the login

    This has implementation of the login process. A shared method takes username, password and domain as parameters and tries a Windows logon with the data, and we impersonate the user.

  • A logoff page which clears user's session and abandons it

    This is to cleanup the sessions, and make the totalActiveUser count on the system more reliable.

The Code

Open an ASP.NET project. Select the project in the Solution Explorer and create a new 'web user control' item. Develop the UI for it... probably two text boxes... for username and password and a 'Login' button.

We make another UI, which shows a viewpane with the details of user login.

We show the login form when the user hasn't logged into the system, and show a login details view after the user logs in. Users login with their Windows authentication (this means that we should have created users on the server and the domain for this to work).

The windowsLoginControl calls shared function LogInThisUser() of the LogInUser class which logs-in the user and impersonates the logged-on user. The code that does this is as below:

Dim loggedOn As Boolean = LogonUser(username, _ 
        domainname, password, 3, 0, token1)
'impersonate user
Dim token2 As IntPtr = New IntPtr(token1)
Dim mWIC As WindowsImpersonationContext = _
    New WindowsIdentity(token2).Impersonate

For this, we declare the loginuser class with the proper namespaces, and in a manner to include unmanaged code. We need unmanaged code to be written, because I believe we don't have a managed code implementation of the LogonUser function of Windows to do the same.

'include permissions namespace for security attributes
'include principal namespace for windowsidentity class
'include interopservices namespace for dllImports.

Imports System.Security.Principal
Imports System.Security.Permissions
Imports System.Runtime.InteropServices

<Assembly: SecurityPermissionAttribute
  (SecurityAction.RequestMinimum, UnmanagedCode:=True)> 
Public Class LogInUser

    <DllImport("C:\\WINDOWS\\System32\\advapi32.dll")> _
    Private Shared Function LogonUser(ByVal _ 
        lpszUsername As String, ByVal lpszDomain _
        As String, ByVal lpszPassword As String, _
        ByVal dwLogonType As Integer, _ 
        ByVal dwLogonProvider As Integer, _
        ByRef phToken As Integer) As Boolean
    End Function

    <DllImport("C:\\WINDOWS\\System32\\Kernel32.dll")> _
    Private Shared Function GetLastError() As Integer
    End Function

We can also find whether the logonuser function generated errors, by calling the GetLastError method.

We use session variables to keep track of the user's login information and last access. We use an application variable to keep track of the total active users in the system.

Below code is part of this implementation (can be found in windowsLoginControl.ascx.vb):

Session.Add("LoggedON", True)
Session.Add("Username", sRetText)

Application.Item("TotalActiveUsers") += 1

lblUserName.Text = Session("Username")
lblLastSession.Text = Session("LastActive")
lblTotalUsers.Text = Application("TotalActiveUsers")

We keep track of the number of active users by simply incrementing the value every time the login method succeeds, and decrementing the value every time session_end event occurs.

Better means to do this can also be used. The idea of this article is only to communicate the logic.

Testing the Project

Before testing the project, we should check the following.

We keep the domainname as constant, rather than taking it from the user as an input. Check whether proper domain name is assigned to the constant.

Private Const domainName = "TestDomain"

Check whether location of the DLLs that are being imported are proper.

<DllImport("C:\\WINDOWS\\System32\\advapi32.dll")>

Check whether the logoff page has the correct page name and path to transfer the user, once cleanup is done.

Server.Transfer("webform1.aspx")

Code-Care

Care has to be taken that code implemented doesn't allow for inappropriate usage through various userLogins.

I preferred to keep the domain name hard-coded into the application through a constant rather than accept it as an user input... so that it's easy to limit or monitor user login sessions.

In case of intranet projects, we can create a separate domain, and user group for the project and use the above logic to allow users to login to the system only on the particular domain. May be, you can call this an 'Idea' :o)

Using the Controls on Another Web Project

To implement the web user controls in a web project, we simply copy the files related to the two controls, the loginuser class, the logoff user page, to our new web project, and also copy the code from our global.asax.vb to the new project's global.asax.vb.

In VS.NET, these copied files can easily be included in the target project by right clicking and selecting 'Include in Project' in Solution Explorer.

Code Extensibility

The code that's been worked out in this article will authenticate users on only one page of the web application. Normally, a web application will have content inside the site to be viewed by authenticated users... in this case, the controls will have to have a mechanism of holding the user's authentication across page requests. This can be done by holding the windowsIdentity object of the authenticated user in a session variable, and allowing users rights on pages by using FileIOPermission and other classes in the System.Security namespace.

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here