Thursday, September 6, 2007

Impersonating a user programmatically in C# code

Here is how to call it.... public void SampleCallingMethod(Object s, EventArgs e) { if(ImpersonateUser("username", "domain", "password")) { //Insert your code that runs under the security context of a specific user here. doSomethingHere(); UnImpersonation(); } else { //Your impersonation failed. Therefore, include a fail-safe mechanism here. } } Here is the source code.... using System; using System.Web; using System.Web.Security; using System.Security.Principal; using System.Runtime.InteropServices; namespace AuthenticationMapper { /// /// Use this class to run a section of code as a different user. /// Most of this code was copied from: http://support.microsoft.com/kb/306158 /// Modifications by: Brent Vermilion 9/5/2007 /// public class Impersonation { WindowsImpersonationContext impersonationContext; #region WIN32 definitions public const int LOGON32_LOGON_INTERACTIVE = 2; public const int LOGON32_PROVIDER_DEFAULT = 0; [DllImport("advapi32.dll")] public static extern int LogonUserA(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); #endregion public Impersonation() { } #region SampleUsage public void SampleCallingMethod(Object s, EventArgs e) { if(ImpersonateUser("username", "domain", "password")) { //Insert your code that runs under the security context of a specific user here. UnImpersonation(); } else { //Your impersonation failed. Therefore, include a fail-safe mechanism here. } } #endregion public bool ImpersonateUser(String userName, String domain, String password) { WindowsIdentity tempWindowsIdentity; IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; if(RevertToSelf()) { if(LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0) { if(DuplicateToken(token, 2, ref tokenDuplicate) != 0) { tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); impersonationContext = tempWindowsIdentity.Impersonate(); if (impersonationContext != null) { CloseHandle(token); CloseHandle(tokenDuplicate); return true; } } } } if(token!= IntPtr.Zero) CloseHandle(token); if(tokenDuplicate!=IntPtr.Zero) CloseHandle(tokenDuplicate); return false; } public void UnImpersonation() { impersonationContext.Undo(); } } }

2 comments:

Farzad Jalali said...

It doesn't work for me?

I used it like below:

protected void Page_Load(object sender, EventArgs e)
{
this.Title = this.User.Identity.Name;
Impersonation m = new Impersonation();
if (m.ImpersonateUser("myUser", "myDomain", "password"))
{
this.Title = this.User.Identity.Name;
m.UnImpersonation();
}
else
{
this.Title = this.User.Identity.Name;
}
this.Title = this.User.Identity.Name;
}

Brent V said...

Hi Farzad Jalali,

It doesn't affect the User.Identity since this is based on the server variable HttpContext.Current.Request.ServerVariables["AUTH_USER"]. Assuming you don't allow anonymous on your site, this value will be populated and that what User.Identity.Name is equal to.

The purpose of this code is to be able to elevate the execution permissions to some level regardless of the current authentication (including anonymous), do your stuff, then return to a safe security level.

If you want to change the User.Identity.Name to something else for say testing, etc, I recommend my other blog entry. on this. Using that code it will be like you logged in as another user.

I hope that helps.

Brent