| | 1 | | //credit to Phillip Allan-Harding (Twitter @phillipharding) for this library. |
| | 2 | |
|
| | 3 | | using System; |
| | 4 | | using System.ComponentModel; |
| | 5 | | using System.Runtime.InteropServices; |
| | 6 | | using System.Security.Principal; |
| | 7 | | using System.Xml.Linq; |
| | 8 | |
|
| | 9 | | namespace Impersonate { |
| | 10 | | public enum LogonType { |
| | 11 | | LOGON32_LOGON_INTERACTIVE = 2, |
| | 12 | | LOGON32_LOGON_NETWORK = 3, |
| | 13 | | LOGON32_LOGON_BATCH = 4, |
| | 14 | | LOGON32_LOGON_SERVICE = 5, |
| | 15 | | LOGON32_LOGON_UNLOCK = 7, |
| | 16 | | LOGON32_LOGON_NETWORK_CLEARTEXT = 8, // Win2K or higher |
| | 17 | | LOGON32_LOGON_NEW_CREDENTIALS = 9 // Win2K or higher |
| | 18 | | }; |
| | 19 | |
|
| | 20 | | public enum LogonProvider { |
| | 21 | | LOGON32_PROVIDER_DEFAULT = 0, |
| | 22 | | LOGON32_PROVIDER_WINNT35 = 1, |
| | 23 | | LOGON32_PROVIDER_WINNT40 = 2, |
| | 24 | | LOGON32_PROVIDER_WINNT50 = 3 |
| | 25 | | }; |
| | 26 | |
|
| | 27 | | public enum ImpersonationLevel { |
| | 28 | | SecurityAnonymous = 0, |
| | 29 | | SecurityIdentification = 1, |
| | 30 | | SecurityImpersonation = 2, |
| | 31 | | SecurityDelegation = 3 |
| | 32 | | } |
| | 33 | |
|
| | 34 | | class Win32NativeMethods { |
| | 35 | | [DllImport("advapi32.dll", SetLastError = true)] |
| | 36 | | public static extern int LogonUser(string lpszUserName, |
| | 37 | | string lpszDomain, |
| | 38 | | string lpszPassword, |
| | 39 | | int dwLogonType, |
| | 40 | | int dwLogonProvider, |
| | 41 | | ref IntPtr phToken); |
| | 42 | |
|
| | 43 | | [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] |
| | 44 | | public static extern int DuplicateToken(IntPtr hToken, |
| | 45 | | int impersonationLevel, |
| | 46 | | ref IntPtr hNewToken); |
| | 47 | |
|
| | 48 | | [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] |
| | 49 | | public static extern bool RevertToSelf(); |
| | 50 | |
|
| | 51 | | [DllImport("kernel32.dll", CharSet = CharSet.Auto)] |
| | 52 | | public static extern bool CloseHandle(IntPtr handle); |
| | 53 | | } |
| | 54 | |
|
| | 55 | | /// <summary> |
| | 56 | | /// Allows code to be executed under the security context of a specified user account. |
| | 57 | | /// </summary> |
| | 58 | | /// <remarks> |
| | 59 | | /// |
| | 60 | | /// Implements IDispose, so can be used via a using-directive or method calls; |
| | 61 | | /// ... |
| | 62 | | /// |
| | 63 | | /// var imp = new Impersonator( "myUsername", "myDomainname", "myPassword" ); |
| | 64 | | /// imp.UndoImpersonation(); |
| | 65 | | /// |
| | 66 | | /// ... |
| | 67 | | /// |
| | 68 | | /// var imp = new Impersonator(); |
| | 69 | | /// imp.Impersonate("myUsername", "myDomainname", "myPassword"); |
| | 70 | | /// imp.UndoImpersonation(); |
| | 71 | | /// |
| | 72 | | /// ... |
| | 73 | | /// |
| | 74 | | /// using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) ) |
| | 75 | | /// { |
| | 76 | | /// ... |
| | 77 | | /// 1 |
| | 78 | | /// ... |
| | 79 | | /// } |
| | 80 | | /// |
| | 81 | | /// ... |
| | 82 | | /// </remarks> |
| | 83 | | public class Impersonator : IDisposable { |
| | 84 | | private WindowsImpersonationContext _wic; |
| | 85 | |
|
| | 86 | | /// <summary> |
| | 87 | | /// Begins impersonation with the given credentials, Logon type and Logon provider. |
| | 88 | | /// </summary> |
| | 89 | | ///<param name = "userName" > Name of the user.</param> |
| | 90 | | ///<param name = "domainName" > Name of the domain.</param> |
| | 91 | | ///<param name = "password" > The password. <see cref = "System.String" /></ param > |
| | 92 | | ///< param name="logonType">Type of the logon.</param> |
| | 93 | | ///<param name = "logonProvider" > The logon provider. <see cref = "Mit.Sharepoint.WebParts.EventLogQuery.Networ |
| 0 | 94 | | public Impersonator(string userName, string domainName, string password, LogonType logonType, |
| 0 | 95 | | LogonProvider logonProvider) { |
| 0 | 96 | | Impersonate(userName, domainName, password, logonType, logonProvider); |
| 0 | 97 | | } |
| | 98 | |
|
| | 99 | | /// <summary> |
| | 100 | | /// Begins impersonation with the given credentials. |
| | 101 | | /// </summary> |
| | 102 | | ///<param name = "userName" > Name of the user.</param> |
| | 103 | | ///<param name = "domainName" > Name of the domain.</param> |
| | 104 | | ///<param name = "password" > The password. <see cref = "System.String" /></ param > |
| 0 | 105 | | public Impersonator(string userName, string domainName, string password) { |
| 0 | 106 | | Impersonate(userName, domainName, password, LogonType.LOGON32_LOGON_INTERACTIVE, |
| 0 | 107 | | LogonProvider.LOGON32_PROVIDER_DEFAULT); |
| 0 | 108 | | } |
| | 109 | |
|
| | 110 | | /// <summary> |
| | 111 | | /// Initializes a new instance of the <see cref="Impersonator"/> class. |
| | 112 | | /// </summary> |
| 0 | 113 | | public Impersonator() { |
| 0 | 114 | | } |
| | 115 | |
|
| | 116 | | /// <summary> |
| | 117 | | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. |
| | 118 | | /// </summary> |
| 0 | 119 | | public void Dispose() { |
| 0 | 120 | | UndoImpersonation(); |
| 0 | 121 | | } |
| | 122 | |
|
| | 123 | | /// <summary> |
| | 124 | | /// Impersonates the specified user account. |
| | 125 | | /// </summary> |
| | 126 | | ///<param name = "userName" > Name of the user.</param> |
| | 127 | | ///<param name = "domainName" > Name of the domain.</param> |
| | 128 | | ///<param name = "password" > The password. <see cref = "System.String" /></ param > |
| | 129 | | ///< param name="logonType">Type of the logon.</param> |
| | 130 | | ///<param name = "logonProvider" > The logon provider. <see cref = "Mit.Sharepoint.WebParts.EventLogQuery.Networ |
| | 131 | | public void Impersonate(string userName, string domainName, string password, LogonType logonType = LogonType.LOG |
| 0 | 132 | | LogonProvider logonProvider = LogonProvider.LOGON32_PROVIDER_DEFAULT) { |
| 0 | 133 | | UndoImpersonation(); |
| | 134 | |
|
| 0 | 135 | | IntPtr logonToken = IntPtr.Zero; |
| 0 | 136 | | IntPtr logonTokenDuplicate = IntPtr.Zero; |
| 0 | 137 | | try { |
| | 138 | | // revert to the application pool identity, saving the identity of the current requestor |
| 0 | 139 | | _wic = WindowsIdentity.Impersonate(IntPtr.Zero); |
| | 140 | |
|
| | 141 | | // do logon & impersonate |
| 0 | 142 | | if (Win32NativeMethods.LogonUser(userName, |
| 0 | 143 | | domainName, |
| 0 | 144 | | password, |
| 0 | 145 | | (int)logonType, |
| 0 | 146 | | (int)logonProvider, |
| 0 | 147 | | ref logonToken) != 0) { |
| 0 | 148 | | if (Win32NativeMethods.DuplicateToken(logonToken, (int)ImpersonationLevel.SecurityImpersonation, |
| 0 | 149 | | ref logonTokenDuplicate) != 0) { |
| 0 | 150 | | var wi = new WindowsIdentity(logonTokenDuplicate); |
| 0 | 151 | | wi.Impersonate(); // discard the returned identity context (which is the context of the applicat |
| 0 | 152 | | } |
| | 153 | | else |
| 0 | 154 | | throw new Win32Exception(Marshal.GetLastWin32Error()); |
| 0 | 155 | | } |
| | 156 | | else |
| 0 | 157 | | throw new Win32Exception(Marshal.GetLastWin32Error()); |
| 0 | 158 | | } |
| 0 | 159 | | finally { |
| 0 | 160 | | if (logonToken != IntPtr.Zero) |
| 0 | 161 | | Win32NativeMethods.CloseHandle(logonToken); |
| | 162 | |
|
| 0 | 163 | | if (logonTokenDuplicate != IntPtr.Zero) |
| 0 | 164 | | Win32NativeMethods.CloseHandle(logonTokenDuplicate); |
| 0 | 165 | | } |
| 0 | 166 | | } |
| | 167 | |
|
| | 168 | | /// <summary> |
| | 169 | | /// Stops impersonation. |
| | 170 | | /// </summary> |
| 0 | 171 | | private void UndoImpersonation() { |
| | 172 | | // restore saved requestor identity |
| 0 | 173 | | if (_wic != null) |
| 0 | 174 | | _wic.Undo(); |
| 0 | 175 | | _wic = null; |
| 0 | 176 | | } |
| | 177 | | } |
| | 178 | | } |