In this example we will Imperatively Impersonate a User so that we can run code with increased permissions and then undo the Impersonation so that we are running using the standard ASP.NET permissions.
The ImpersonationSettings Class is used to get the Username, Domain and Password from the Application Settings
using System; using System.Configuration; namespace ImpersonateUserTestApp { public class ImpersonationSettings { public string Username { get; set; } public string Password { get; set; } public string Domain { get; set; } public ImpersonationSettings() { Username = GetAppSetting("Impersonation.Username"); Password = GetAppSetting("Impersonation.Password"); Domain = GetAppSetting("Impersonation.Domain"); } private string GetAppSetting(string key) { if (string.IsNullOrEmpty(ConfigurationManager.AppSettings[key])) throw new NullReferenceException(string.Format("Application Setting '{0}' is Null or Empty", key)); return ConfigurationManager.AppSettings[key]; } } }
The Application Settings are in the web.config file
The UserImpersonation takes the ImpersonationSettings in it constructor.
using System; using System.Runtime.InteropServices; using System.Security.Principal; namespace ImpersonateUserTestApp { public class UserImpersonation { public const int Logon32LogonInteractive = 2; public const int Logon32ProviderDefault = 0; private readonly ImpersonationSettings _settings; private WindowsImpersonationContext _impersonationContext; public UserImpersonation(ImpersonationSettings settings) { _settings = settings; } [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); public bool Impersonate() { WindowsIdentity windowsIdentity; IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; if (RevertToSelf()) { if (LogonUserA(_settings.Username, _settings.Domain, _settings.Password, Logon32LogonInteractive, Logon32ProviderDefault, ref token) != 0) { if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) { windowsIdentity = new WindowsIdentity(tokenDuplicate); _impersonationContext = windowsIdentity.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 UndoImpersonation() { _impersonationContext.Undo(); } } }
When you call the Impersonate method it starts the Impersonation.
Once you have completed the actions that require increased permissions you call the UndoImpersonation method to stop the Impersonation.
You could use this in a standard ASPX when you need to increase your permissions for accessing a network drive for example.
using System; using System.Web.UI; namespace ImpersonateUserTestApp { public partial class _Default : Page { protected void Page_Load(object sender, EventArgs e) { ImpersonationSettings settings = new ImpersonationSettings(); UserImpersonation userImpersonation = new UserImpersonation(settings); try { userImpersonation.Impersonate(); //perform action with increased permissions } finally { userImpersonation.UndoImpersonation(); } } } }
Notice now the Impersonation is performed in the Try Finally, this will force the Impersonation to undo even if there is a problem, therefore not leaving your web application with increased permissions.