How to impersonate a user from Active Server Pages (248187)



The information in this article applies to:

  • Microsoft Active Server Pages
  • Microsoft Internet Information Server 4.0
  • Microsoft Internet Information Server 5.0

This article was previously published under Q248187

SUMMARY

This article describes impersonation and the security context for Active Server Pages (ASP) pages. It provides sample code for a Microsoft Visual Basic ActiveX dynamic-link library (DLL) that can be instantiated from an ASP page to impersonate a user and change the security context of the current thread.

By default, ASP runs in the security context of the impersonated user. When a request for an ASP file is made, the Web server utilizes a worker thread and sets the security context of that thread to an impersonated user. The Internet Information Server (IIS) authentication method (Anonymous, Basic, NT Integrated, and so on) determines the impersonated user. Then, the ASP code runs in the context of that user.

When you impersonate a user, you can resolve the following security conflicts in your application:
  • An application that uses NT Integrated (NTLM) security or Kerberos to authenticate that needs to access a network resource (such as a file, an Access database, or a SQL Server) through the Named Pipes protocol.
  • An application that accesses a network resource from the Session_OnEnd or Application_OnEnd event.

    The Session_OnEnd and Application_OnEnd events run with the identity of the process. For in-process or Low application protection applications, this is the SYSTEM user ID, and the process is the Inetinfo.exe file. Rather than impersonating, you can run in a separate memory process or with High (isolated) application protection and set the identity of the Microsoft Transaction Server (MTS) package or COM+ application to the desired user ID.
  • An application that supports multiple users who are connecting to the WinNT:// namespace through Microsoft Active Directory Services Interface (ADSI).

    These connections are cached with the security credentials of the first user that opens the connection. Impersonating ensures that a single user opens the connection; as a result, that user's credentials match the cached credentials.

MORE INFORMATION

Impersonation uses these three functions:
  1. The LogonUser function receives the logon information (user ID, password, and so on) and returns the security token for a valid logon.
  2. The ImpersonateLoggedOnUser function receives the security token from LogonUser and applies it to the current thread.
  3. The RevertToSelf function returns the thread to the security context of the originating process.

    RevertToSelf is extremely important when you impersonate from ASP. It is called before LogonUser and ImpersonateLoggedOnUser to ensure that the current security context has the ability to impersonate. (If you are already impersonated, which you are from ASP, you most likely do not have the necessary authority to impersonate.) RevertToSelf is called at the end of the page processing to ensure that the next use of the thread has the appropriate security context, that is, the identity of the originating process.
The following ActiveX DLL has two methods: Logon and Logoff. Logon changes the context of the thread to a new user ID, and Logoff reverts to the identity of the originating process. To create the DLL, perform the following steps:
  1. In Visual Basic 6.0, create a new ActiveX DLL project named LoginAdmin.
  2. Change the name of the initial class module to ImpersonateUser.
  3. Add a module, named LogonAPIs.bas, to the project, and then paste the following code to make the API calls available to your class:
       Public Declare Function LogonUser Lib "advapi32.dll" _
    Alias "LogonUserA" (ByVal lpszUsername As String, _
    ByVal lpszDomain As String, ByVal lpszPassword As String, _
    ByVal dwLogonType As Long, ByVal dwLogonProvider As Long, _
    phToken As Long) As Long
    
       Public Declare Function ImpersonateLoggedOnUser Lib "advapi32.dll" (ByVal hToken As Long) As Long
    
       Public Declare Function RevertToSelf Lib "advapi32.dll" () As Long
    
       Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
  4. Open the ImpersonateUser class module, and then paste the following code to create the Logon and Logoff methods:
       Private Const LOGON32_LOGON_INTERACTIVE = 2
       Private Const LOGON32_PROVIDER_DEFAULT = 0
    
       Public Sub Logon(ByVal strAdminUser As String, ByVal _
    strAdminPassword As String, ByVal strAdminDomain As String)
         Dim lngTokenHandle, lngLogonType, lngLogonProvider As Long
         Dim blnResult As Boolean
         
         lngLogonType = LOGON32_LOGON_INTERACTIVE
         lngLogonProvider = LOGON32_PROVIDER_DEFAULT
         
         blnResult = RevertToSelf()
         
         blnResult = LogonUser(strAdminUser, strAdminDomain, strAdminPassword, _
                                              lngLogonType, lngLogonProvider, _
                                              lngTokenHandle)
                                                              
         blnResult = ImpersonateLoggedOnUser(lngTokenHandle)
         CloseHandle (lngTokenHandle)
    
       End Sub
    
       Public Sub Logoff()
         Dim blnResult As Boolean
         
         blnResult = RevertToSelf()
       End Sub
    NOTE: The call to LogonUser passes a logon type of LOGON32_LOGON_INTERACTIVE. The Interactive logon allows us to access network resources that other logon types do not.
  5. Save the project files.
  6. On the File menu, click Make LoginAdmin.dll to compile the ActiveX DLL.
  7. Copy LoginAdmin.dll to the Web server, and then use Regsvr32.exe to register it (type regsvr32.exe c:\components\LoginAdmin.dll at a command prompt).
  8. After the ActiveX DLL is registered, you can call it from an ASP page as follows:
       <%
         Option Explicit
         Dim objLogon
    
         Set objLogon = Server.CreateObject("LoginAdmin.ImpersonateUser")
         objLogon.Logon "Userid", "Password", "Domain"
    
         'Body of code for the page.
    
         objLogon.Logoff
         Set objLogon = Nothing
       %>
    					
NOTE: When you call RevertToSelf, the ASP page will be running under the security context of the process. For in-process applications, this is the System account. However, for pooled or isolated applications, this is the identity of the COM+ package that is configured either for pooled applications or for the isolated application itself. By default, the identity of these COM+ packages is set to IWAM_<computername>. If this account does not have "Act as part of the operating system" privileges, the subsequent call to LogonUser fails because of a permissions violation. As a workaround, either enable "Act as part of the operating system" privileges for the IWAM_<computername> account, or configure the COM+ package identity to run under an account that has these privileges.

Modification Type:MinorLast Reviewed:7/8/2005
Keywords:kbhowto kbSecurity KB248187