Programmatically Impersonate a user in ASP.NET

When you run an ASP.NET application, it accesses files and resources on the web server using a specified user account. At times, you may want ASP.NET to access resources as though it were someone, or something, else. Impersonation is when ASP.NET executes with the security credentials of a different user account. This may be necessary, for instance, to access a file in a protected directory.

The account ASP.NET uses to access resources varies depending on the version of Windows and IIS running. You can poke around the web for specifics but, in general, the following discussion is what happens. In a web application you have several layers of security. IIS, Windows and the .NET framework all play roles.

Windows forces all access to resources such as web files to be accessed through an existing user account. For HTML and ASP pages and components of ASP V3.0 and earlier, the IUSR_machinename and IWAM_machine name accounts were automatically created and added to every web folder by IIS and were used as the account to access these pages. These are termed anonymous accounts because every request went through them and looked the same regardless of the user.

In Windows 2003 and with IIS V6, these anonymous accounts still exist but, depending on IIS's configuration, the account used for anonymous access may be different. If you tell IIS to use anonymous access it defaults to using the IUSR_machinename account. However, you can specify a different account to use when setting up the web site in IIS.

If you tell IIS not to allow anonymous access, you can instruct it to use Windows Authentication. In this case, the credentials of the user making the request are used to access resources. IIS will authenticate the user to verify they are a valid user. If so the request then goes to Windows.

Once Windows gets the request for a resource, it verifies the anonymous account or user account has sufficient access to it. For instance, the resource can be protected by a global group to which the account is not part of. If not, access is denied. Otherwise, the request is passed to ASP.NET.

The first thing ASP.NET does when it gets the request is look to see if impersonation is used. ASP.NET uses impersonation similar to how IIS uses anonymous accounts. If impersonation is not used, .NET uses a special account to process the request. Under IIS 5 on Windows 2000, NT or XP, ASP.NET uses the ASPNET account. When it spawns a worker process, the process uses the LOCAL SYSTEM account. .NET uses these accounts because of its dynamic compilation features. The IUSR and IWAM IIS accounts do not have write access to folders required to dynamically compile ASP.NET applications.

The ASPNET account is really a monikor. The real account name and password used are specified in the <processModel> section of the Machine.config file. Typically, they are Machine and AutoGenerate respectively. Confused? I don't blame blame you. It gets worse.

Under IIS 6, ASP.NET doesn't use the process model settings since IIS 6.0 uses application pools. Instead, it uses a NETWORK SERVICE account which is part of the IIS_WPG group.

When creating an ASP.NET application, you must make sure the ASPNET and/or NETWORK SERVICE accounts and/or IIS_WPG group have suficient authority to the application specific folders and files that are used.

Back to impersonation. If impersonation is not used, ASP.NET uses the ASPNET account or the IIS_WPG group regardless of the anonynous access settings. If impersonation is used, along with anynomous access, then .NET uses theses credentials as well.

If impersonation is used but anonymous access is not, .NET uses requesting client user's credentials if Windows Authentication is specified. That is, unless you tell it to use a different user ID and password!

You can use impersonation adding this line to the web.config file:

    <system.web>
    . . . .
    <identity impersonate="true" />
    . . . .
    </system.web>

To impersonate a specific user:

    <system.web>
    . . . .
    <identity impersonate="true" userName="username" password="password" />
    . . . .
    </system.web> 

This will impersonate a different user for the entire duration of your application's execution. You can programmatically turn impersonation on and off using the following VB.NET code.

    Imports System.Threading
    Imports System.Configuration
    Imports SR = System.Reflection
    Imports System.Text
    Imports System.Web.UI.WebControls
    Imports System.Security.Principal

    Public Class Utilities

        Private Const LOGON32_PROVIDER_DEFAULT As Integer = 0
        Private Const LOGON32_LOGON_INTERACTIVE As Integer = 2
        Private Const LOGON32_LOGON_NETWORK As Integer = 3
        Private Const LOGON32_LOGON_BATCH As Integer = 4
        Private Const LOGON32_LOGON_SERVICE As Integer = 5
        Private Const LOGON32_LOGON_UNLOCK As Integer = 7
        Private Const LOGON32_LOGON_NETWORK_CLEARTEXT As Integer = 8
        Private Const LOGON32_LOGON_NEW_CREDENTIALS As Integer = 9

        Private Shared ImpersonationContext As WindowsImpersonationContext

        Declare Function LogonUserA Lib "advapi32.dll" ( _
                                ByVal lpszUsername As String, _
                                ByVal lpszDomain As String, _
                                ByVal lpszPassword As String, _
                                ByVal dwLogonType As Integer, _
                                ByVal dwLogonProvider As Integer, _
                                ByRef phToken As IntPtr) As Integer

        Declare Auto Function DuplicateToken Lib "advapi32.dll" ( _
                                ByVal ExistingTokenHandle As IntPtr, _
                                ByVal ImpersonationLevel As Integer, _
                                ByRef DuplicateTokenHandle As IntPtr) As Integer
        Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Long
        Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long


        ' NOTE:
        ' The identity of the process that impersonates a specific user on a thread must have 
        ' "Act as part of the operating system" privilege. If the the Aspnet_wp.exe process runs
        ' under a the ASPNET account, this account does not have the required privileges to 
        ' impersonate a specific user. This information applies only to the .NET Framework 1.0. 
        ' This privilege is not required for the .NET Framework 1.1.
        '
        ' Sample call:
        '
        '    If impersonateValidUser("username", "domain", "password") Then
        '        'Insert your code here.
        '
        '        undoImpersonation()
        '    Else
        '        'Impersonation failed. Include a fail-safe mechanism here.
        '    End If
        '
        Public Shared Function ImpersonateValidUser(ByVal strUserName As String, _
               ByVal strDomain As String, ByVal strPassword As String) As Boolean
            Dim token As IntPtr = IntPtr.Zero
            Dim tokenDuplicate As IntPtr = IntPtr.Zero
            Dim tempWindowsIdentity As WindowsIdentity

            ImpersonateValidUser = False

            If RevertToSelf() <> 0 Then
                If LogonUserA(strUserName, strDomain, _
                   strPassword, _
                   LOGON32_LOGON_INTERACTIVE, _
                   LOGON32_PROVIDER_DEFAULT, token) <> 0 Then
                    If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
                        tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
                        ImpersonationContext = tempWindowsIdentity.Impersonate()

                        If Not (ImpersonationContext Is Nothing) Then
                            ImpersonateValidUser = True
                        End If
                    End If
                End If
            End If

            If Not tokenDuplicate.Equals(IntPtr.Zero) Then
                CloseHandle(tokenDuplicate)
            End If

            If Not token.Equals(IntPtr.Zero) Then
                CloseHandle(token)
            End If

        End Function

        Public Shared Sub UndoImpersonation()

            ImpersonationContext.Undo()

        End Sub
    End CLass




About TheScarms
About TheScarms


Sample code
version info

If you use this code, please mention "www.TheScarms.com"

Email this page


© Copyright 2024 TheScarms
Goto top of page