Each Windows process runs under a specific identity. If it's an interactive process, it gets the identity of the logged-on user; if it's a Windows Service, a COM+ server application, or an IIS Web application, it gets the identity specified by its configuration. The process identity is represented by an access token (called the primary access token).
By default, when a thread accesses a protected resource, the access token of the process the thread belongs to is used. A thread can, however, set up an alternate access token for itself (called an impersonation access token). While impersonating, all access checks for that thread will be done using the impersonation token. The thread can at any time revert its active identity back to the process identity.
Impersonation is a feature that typically turns useful in distributed environments. As already stated, the primary reason for impersonation is actually to cause access checks to be performed against the client's identity.
Whether this can happen depends on the technology used for the remote call. Under the hood, there are basically just two options, however.
In the first one, the username-password pair travels together with the remote call (as in HTTP basic authentication). The server process calls LogonUser using the provided username-password and then, if the call is successful, calls ImpersonateLoggedOnUser to start impersonating. In .NET, you must resort to P/Invoke to call LogonUser. Once an access token has been obtained, you can create a WindowsIdentity providing the access token as constructor parameter. Finally, call the Impersonate method on the WindowsIdentity object to start impersonating. The Impersonate method returns a WindowsImpersonationContext object. Calling the Undo method on this object, the thread stops impersonating. The C# code below shows you how to do this:
[DllImport("C:\\WINNT\\System32\\advapi32.dll")] public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out int phToken); [DllImport("C:\\WINNT\\System32\\Kernel32.dll")] public static extern int GetLastError(); private void DoWorkImpersonating(string p_username,string p_pwd, string p_domain) { int l_token1; int ret=0 ; bool loggedOn = LogonUser(p_username, p_domain , p_pwd, // Logon type = LOGON32_LOGON_NETWORK_CLEARTEXT. 3, // Logon provider = LOGON32_PROVIDER_DEFAULT. 0, // The user token for the specified user is returned here. out l_token1); // Call GetLastError to try to determine why logon failed if it did not succeed. if (loggedOn == false) ret = GetLastError(); if (ret != 0) throw new Exception ("Invalid Username or Password"); IntPtr token2 = new IntPtr(l_token1); WindowsIdentity l_Wid = new WindowsIdentity (token2); WindowsImpersonationContext l_mWIC = l_Wid.Impersonate(); //do work here impersonating the caller Identity //RevertToself l_mWIC.Undo (); }
This approach to impersonation has some advantages and some drawbacks. It makes implementing a custom mechanism for identity flow and impersonation easy; additionally, it doesn't pose interoperability issues between the client and the server. The problem is that you must guarantee secure transmission of the username password pair across the network, which can be done using an existing high-level security infrastructure such as https (if you are hosting the server in IIS) or using low-level symmetric cryptographic functions based on a shared secret.
Another problem is that on Windows 2000, the process calling LogonUser requires the "Act as Part of the Operating System" (SE_TCB_NAME) privilege, which is quite a powerful one. Fortunately, this requirement has been relaxed on Windows XP and Windows 2003.
The alternative to this approach for impersonation is to take advantage of built-in remote authentication functionalities provided by Windows Security providers such as Kerberos or NTLM. These protocols use different mechanisms to achieve the same goal: authenticate the client to the server and exchange a session ticket securely (to guarantee encrypted communication between them). The net effect is that the server can construct a client access token that the server thread can use to impersonate the client identity. This second option presents fewer vulnerabilities because the username password pair is never transmitted over the wire; however, it requires windows on both side of the communication.