13.15 Impersonate a Windows User


13.15 Impersonate a Windows User

Problem

You need your code to run in the context of a Windows user other than the currently active user account.

Solution

Obtain a System.Security.Principal.WindowsIdentity object representing the Windows user you need to impersonate, and then call the Impersonate method of the WindowsIdentity object.

Discussion

Every Windows thread has an associated access token , which represents the Windows account on whose behalf the thread is running. The Windows operating system uses the access token to determine whether a thread has the appropriate permissions to perform protected operations on behalf of the account, such as read and write files, reboot the system, and change the system time.

By default, a managed application runs in the context of the Windows account that executed the application. This is normally desirable behavior, but sometimes you will want to run an application in the context of a different Windows account. This is particularly true in the case of server-side applications that process transaction on behalf of the users remotely connected to the server. It's common for a server application to run in the context of a Windows account created specifically for the application ”a service account. This service account will have minimal permissions to access system resources. Enabling the application to operate as though it were the connected user permits the application to access the operations and resources appropriate to that user's security clearance. When an application assumes the identity of another user, it's known as impersonation . Correctly implemented, impersonation simplifies security administration and application design, while maintaining user accountability.

Important  

As discussed in recipe 13.14, a thread's Windows access token and its .NET principal are separate entities and can represent different users. The impersonation technique described in this recipe changes only the Windows access token of the current thread; it doesn't change the thread's principal. To change the thread's principal, code must have the ControlPrincipal element of SecurityPermission and assign a new System.Security.Principal.IPrincipal object to the CurrentPrincipal property of the current System.Threading.Thread .

The System.Security.Principal.WindowsIdentity class provides the functionality through which you invoke impersonation. However, the exact process depends on which version of Windows your application is running on. If running on Windows Server 2003 or later, the WindowsIdentity class supports constructor overloads that create WindowsIdentity objects based on the account name of the user you want to impersonate. On all previous versions of Windows, you must first obtain a System.IntPtr containing a reference to a Windows access token that represents the user to impersonate. To obtain the access token reference, you must use a native method such as the function LogonUser from the Win32 API.

Note  

A major issue with performing impersonation on Windows 2000 and Microsoft Windows NT is that an account must have the Windows privilege SE_TCB_NAME to execute LogonUser . This requires you to configure Windows security policy and grant the account the right to "Act as part of operating system". This grants the account a very high level of trust. You should never grant the privilege SE_TCB_NAME directly to user accounts.

Once you have a WindowsIdentity object representing the user you want to impersonate, call its Impersonate method. From that point on, all actions your code performs occur in the context of the impersonated Windows account. The Impersonate method returns a System.Security.Principal.WindowsSecurityContext object, which represents the active account prior to impersonation. To revert to the original account, call the Undo method of this WindowsSecurityContext object.

The console application ImpersonationExample shown here demonstrates impersonation of a Windows user. The example expects two command-line arguments: the account name of the user to impersonate and the account's password. The example uses the LogonUser function of the Win32 API to obtain a Windows access token for the specified user, impersonates the user, and then reverts to the original user context. For example, the command ImpersonationExample Bob password would impersonate the user Bob as long as that user existed in the local accounts database.

 using System; using System.IO; using System.Security.Principal; using System.Security.Permissions; using System.Runtime.InteropServices; // Ensure the assembly has permission to execute unmanaged code // and control the thread principal. [assembly:SecurityPermission(SecurityAction.RequestMinimum,     UnmanagedCode=true, ControlPrincipal=true)] public class ImpersonationExample {     // Define some constants for use with the LogonUser function.     const int LOGON32_PROVIDER_DEFAULT = 0;     const int LOGON32_LOGON_INTERACTIVE = 2;     // Import the Win32 LogonUser function from advapi32.dll. Specify     // "SetLastError = true" to correctly support access to Win32 error     // codes.      [DllImport("advapi32.dll", SetLastError=true)]     static extern int LogonUser(string userName, string domain,          string password, int logonType, int logonProvider,         ref IntPtr accessToken);     public static void Main(string[] args) {         // Create a new IntPtr to hold the access token returned by the          // LogonUser function.         IntPtr accessToken = IntPtr.Zero;                  // Call LogonUser to obtain an access token for the specified user.         // The accessToken variable is passed to LogonUser by reference and          // will contain a reference to the Windows access token if          // LogonUser is successful.         int result = LogonUser(             args[0],                    // user name to log on.             ".",                        // use the local account database.             args[1],                    // user's password.             LOGON32_LOGON_INTERACTIVE,  // create an interactive login.             LOGON32_PROVIDER_DEFAULT,   // use the default logon provider.             ref accessToken             // receives access token handle.         );                  // If the LogonUser return code is zero an error has occurred.          // Display the error and exit.         if (result == 0)  {                     Console.WriteLine("LogonUser returned error {0}",                  Marshal.GetLastWin32Error());                      } else {                      // Create a new WindowsIdentity from the Windows access token.             WindowsIdentity identity = new WindowsIdentity(accessToken);                  // Display the active identity.             Console.WriteLine("Identity before impersonation = {0}",                 WindowsIdentity.GetCurrent().Name);             // Impersonate the specified user, saving a reference to the              // returned WindowsImpersonationContext, which contains the              // information necessary to revert to the original user              // context.             WindowsImpersonationContext impContext =                  identity.Impersonate();             // Display the active identity.             Console.WriteLine("Identity during impersonation = {0}",                 WindowsIdentity.GetCurrent().Name);             // *****************************************                     // Perform actions as the impersonated user.             // *****************************************                   // Revert to the original Windows user using the              // WindowsImpersonationContext object.             impContext.Undo();             // Display the active identity.             Console.WriteLine("Identity after impersonation  = {0}",                 WindowsIdentity.GetCurrent().Name);         }     } } 



C# Programmer[ap]s Cookbook
C# Programmer[ap]s Cookbook
ISBN: 735619301
EAN: N/A
Year: 2006
Pages: 266

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net