Click here to Skip to main content
15,884,099 members
Articles / Desktop Programming / Windows Forms

User Impersonation in Windows Forms Application

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
3 Aug 2010CPOL1 min read 45K   13   4
User Impersonation in Windows Forms Application

Impersonation in ASP.NET is easy as you can do it from the web.config as given below:

ASP.NET
<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:

ASP.NET
<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.

C#
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);

// Log On Types
const int LOGON32_LOGON_INTERACTIVE = 2;
const int LOGON32_LOGON_NETWORK = 3;
const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

// Log On Providers
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;

/// <summary>
/// Performs the Impersonation
/// </summary>
/// <param name="sServer">The machine you want to log in</param>
/// <param name="sUserName">The username in that machine</param>
/// <param name="sPassword">The password for the username</param>
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();
}

/// <summary>
/// Terminated the Impersonation
/// </summary>
public static void ImpersonateEnd()
{
 oImpersonatedUser.Undo();
}

/// <summary>
/// Raises the last error on the Marshal object
/// </summary>
private static void RaiseLastError()
{
 int iErrorCode = Marshal.GetLastWin32Error();
 string sErrorMessage = GetErrorMessage(iErrorCode);

 throw new ApplicationException(sErrorMessage);
}

/// <summary>
/// Returns the readable error message
/// </summary>
/// <param name="iErrorCode">Error code thrown by the Marshall</param>
/// <returns></returns>
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);//Do your own stuff hereImpersonate.ImpersonateEnd();

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.

Image 1

Image 2 Image 3 Image 4 Image 5 Image 6 Image 7

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
New Zealand New Zealand
http://nz.linkedin.com/in/macaalay
http://macaalay.com/

Comments and Discussions

 
QuestionHelp With Windows 7 Pin
jishnusygal20-Sep-12 19:06
jishnusygal20-Sep-12 19:06 
QuestionThanks, you save my life Pin
yeya8a4-Aug-11 7:42
yeya8a4-Aug-11 7:42 
GeneralWorks for .NET libs but not so good with Excel COM Interop library Pin
Jonathan Kosbab15-Jun-10 8:42
Jonathan Kosbab15-Jun-10 8:42 
GeneralRe: Works for .NET libs but not so good with Excel COM Interop library Pin
Member 45143508-Feb-12 6:37
Member 45143508-Feb-12 6:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.