Zayko in the Net

Personal blog of Vitaly Zayko

NAVIGATION - SEARCH

Impersonalized service calls in C#

As you know, any Windows Service operates under certain rights. It could be Network Service, Local System or a specific user. IIS process is not an exception. However, sometimes it is necessary to refer to the operating system using a different user account. In such cases your calls to the resources should be impersonalized. Below I'm glad to offer a way you can do it.

 class UserImpersonation : IDisposable
 {
     private bool disposed = false;
 
     [DllImport("advapi32.dll")]
     public static extern int LogonUser(String lpszUserName,
         String lpszDomain,
         String lpszPassword,
         int dwLogonType,
         int dwLogonProvider,
         ref IntPtr phToken);
 
     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
     public static extern int DuplicateToken(IntPtr hToken,
         int impersonationLevel,
         ref IntPtr hNewToken);
 
     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
     public static extern bool RevertToSelf();
 
     [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
     public static extern bool CloseHandle(IntPtr handle);
 
     const int LOGON32_PROVIDER_DEFAULT = 0;
     const int LOGON32_LOGON_INTERACTIVE = 2;
 
     WindowsImpersonationContext wic;
     string _userName;
     string _domain;
     string _passWord;
 
     public UserImpersonation(string userName, string domain, string passWord)
     {
         _userName = userName;
         _domain = domain;
         _passWord = passWord;
     }
 
     public bool ImpersonateValidUser()
     {
         WindowsIdentity wi;
         IntPtr token = IntPtr.Zero;
         IntPtr tokenDuplicate = IntPtr.Zero;
 
         if (RevertToSelf())
         {
             if (LogonUser(_userName, _domain, _passWord, LOGON32_LOGON_INTERACTIVE,
                 LOGON32_PROVIDER_DEFAULT, ref token) != 0)
             {
                 if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                 {
                     wi = new WindowsIdentity(tokenDuplicate);
                     wic = wi.Impersonate();
                     if (wic != null)
                     {
                         CloseHandle(token);
                         CloseHandle(tokenDuplicate);
                         return true;
                     }
                 }
             }
         }
         if (token != IntPtr.Zero)
             CloseHandle(token);
         if (tokenDuplicate != IntPtr.Zero)
             CloseHandle(tokenDuplicate);
         return false;
     }
 
     private void CleanUp(bool disposing)
     {
         if (!this.disposed)
         {
             if (disposing)
             {
                 if (wic != null)
                     wic.Dispose();
             }
 
             RevertToSelf();
         }
 
         disposed = true;
     }
 
     public void Dispose()
     {
         CleanUp(true);
         GC.SuppressFinalize(this);
     }
 
     ~UserImpersonation()
    {
        CleanUp(false);
    }
 }

And here is how to use this class:

 using (UserImpersonation user = new UserImpersonation(UserName, Domain, Password))
 {
     if (user.ImpersonateValidUser())
     {
         // Do your work here.
  }
     else
  {
         // Something goes wrong. Check it here.
  }
 
 }
 

Add comment