My application had a WindowsIdentity crisis

The project I have been working on this week to test computer environments needs to do various actions as a user other than the one running the application. For instance, it looks up an installed Windows Service, finds out who the startup user is, and tries to connect to a database as that Windows user. Later on, it will need to access a file in the context of the currently logged-in user. With ASP .NET, this is super-easy: just go into Web.Config and set up the “identity impersonate” node, which can either impersonate a named user or the one who had logged into the website if authentication was enabled. With Windows applications, this is not so straightforward. There may be something I am overlooking, but the limitation seems to be that you can only change the security context on the current thread: any threads spawned by the impersonated thread also inherit the impersonated credentials. Impersonation is easy enough to do, once you figure out how. Here is my code for impersonating a user on the current thread:

  1.         using System;
  2.         using System.ComponentModel;
  3.         using System.Runtime.InteropServices;
  4.         using System.Security.Principal;
  5.         public class ImpersonateUser
  6.         {
  7.                 IntPtr userHandle;
  8.   [DllImport(“advapi32.dll”, SetLastError = true)]
  9.                 static extern bool LogonUser(
  10.                         string lpszUsername,
  11.                         string lpszDomain,
  12.                         string lpszPassword,
  13.                         LogonType dwLogonType,
  14.                         LogonProvider dwLogonProvider,
  15.                         out IntPtr phToken
  16.                         );
  17.  
  18.  
  19.                 [DllImport(“kernel32.dll”, SetLastError = true)]
  20.                 static extern bool CloseHandle(IntPtr hHandle);
  21.  
  22.  
  23.                 enum LogonType : int
  24.                 {
  25.                         Interactive = 2,
  26.                         Network = 3,
  27.                         Batch = 4,
  28.                         Service = 5,
  29.                         NetworkCleartext = 8,
  30.                         NewCredentials = 9,
  31.                 }
  32.  
  33.  
  34.                 enum LogonProvider : int
  35.                 {
  36.                         Default = 0,
  37.                 }
  38.                 public static WindowsImpersonationContext Impersonate(string user, string domain, string password)
  39.                 {
  40.   IntPtr userHandle = IntPtr.Zero;
  41.                         bool loggedOn = LogonUser(
  42.                                 user,
  43.                                 domain,
  44.                                 password,
  45.                                 LogonType.Interactive,
  46.                                 LogonProvider.Default,
  47.                                 out userHandle);
  48.  
  49.  
  50.  
  51.                         if (!loggedOn)
  52.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  53.  
  54.                         WindowsIdentity identity = new WindowsIdentity(userHandle);
  55.                         WindowsPrincipal principal = new WindowsPrincipal(identity);
  56.                         System.Threading.Thread.CurrentPrincipal = principal;
  57.                         return identity.Impersonate();
  58.   }
  59.         }
  60.  
  61. /* Call impersonation */
  62. ImpersonateUser.Impersonate(“UserName”,”DomainName”,”Password”);
  63. /* When you want to go back to the original user */
  64. WindowsIdentity.Impersonate(IntPtr.Zero);

When you want to stop impersonating, you can call Impersonate() again with a null pointer. This will allow you to simulate a variety of different Windows users from the same applicaiton.