Impersonation in ASP.NET is easy as you can do it from the web.config as given below:
<identity impersonate="true" />
Doing this would impersonate the IIS authenticating user on every request for every page in your ASP.NET application.
You can also impersonate a specific user like such:
<identity impersonate="true" userName="username" password="password" />
That’s the easy part, but if you want it to be doing it only on specific parts of the application, it's where the fun begins.
Now doing it in Windows Forms Application is similar to doing it in ASP if you want to specify a specific user to do specific tasks on your application. Now why would you want to do that? I guess you need to perform specific tasks on a machine with different identity context, for example, you have 10 remote machines not on your domain with 20 different admin users not on Active Directory and you want to perform File Copy operation on the C$
drive. Doing this manually would be a great deal of copy and pasting and logging in as a specific user.
Now here is the class to do the impersonation for a specific user which you can use on certain parts of your code.
using System;
using System.Security.Principal;
using System.Runtime.InteropServices;
public static class Impersonate
{
public static WindowsImpersonationContext oImpersonatedUser;
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser
(string sUsername, string sDomain, string sPassword,
int iLogonType, int iLogonProvider, ref IntPtr oToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private unsafe static extern int FormatMessage
(int iFlags, ref IntPtr oSource, int iMessageId,
int iLanguageId, ref String sBuffer, int iSize, IntPtr* Arguments);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool CloseHandle(IntPtr oHandle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken
(IntPtr oExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL,
ref IntPtr oDuplicateTokenHandle);
const int LOGON32_LOGON_INTERACTIVE = 2;
const int LOGON32_LOGON_NETWORK = 3;
const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_PROVIDER_WINNT35 = 1;
const int LOGON32_PROVIDER_WINNT40 = 2;
const int LOGON32_PROVIDER_WINNT50 = 3;
const int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
public static void ImpersonateNow(string sServer, string sUserName, string sPassword)
{
string sIP = sServer;
IntPtr oTokenPointer = IntPtr.Zero;
IntPtr oDuplicateToken = IntPtr.Zero;
bool isSuccess = LogonUser(sUserName, sIP, sPassword,
LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref oTokenPointer);
if (!isSuccess) { RaiseLastError(); }
isSuccess = DuplicateToken(oTokenPointer, 2, ref oDuplicateToken);
if (!isSuccess) { RaiseLastError(); }
WindowsIdentity oNewIdentity = new WindowsIdentity(oDuplicateToken);
oImpersonatedUser = oNewIdentity.Impersonate();
}
public static void ImpersonateEnd()
{
oImpersonatedUser.Undo();
}
private static void RaiseLastError()
{
int iErrorCode = Marshal.GetLastWin32Error();
string sErrorMessage = GetErrorMessage(iErrorCode);
throw new ApplicationException(sErrorMessage);
}
public unsafe static string GetErrorMessage(int iErrorCode)
{
int iMessageSize = 255; string sMessageBuffer = "";
int iFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
IntPtr oSourcePointer = IntPtr.Zero;
IntPtr oArgumentsPointer = IntPtr.Zero;
int iReturnValue = FormatMessage(iFlags, ref oSourcePointer,
iErrorCode, 0, ref sMessageBuffer, iMessageSize, &oArgumentsPointer);
if (iReturnValue == 0)
{
throw new ApplicationException(string.Format
("Format message failed with error code '{0}'.", iErrorCode));
}
return sMessageBuffer;
}
}
And this is how you use it.
Impersonate.ImpersonateNow(sServerIP,
sUserName, sPassword);
Now one more final note. Since you are using Pointers and Fixed Size Buffers, it means you have to use the method in an unsafe context which means by default if you debug the application, you will be having an error message of “Unsafe code may only appear if compiling with /unsafe
”. You can change the Project Build Properties to ignore the error or allow the unsafe code.