Created
July 21, 2015 02:53
-
-
Save noseratio/940c21b488e59d502dd1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// http://stackoverflow.com/q/31522642/1768303 | |
using System; | |
using System.Diagnostics; | |
using System.Runtime.CompilerServices; | |
using System.Runtime.InteropServices; | |
using System.Security; | |
using System.Security.Principal; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace ConsoleApplication | |
{ | |
class Program | |
{ | |
static async Task TestAsync() | |
{ | |
ShowIdentity(); | |
// substitute your actual test credentials | |
using (ImpersonateIdentity( | |
userName: "TestUser", domain: "sammy", password: "TestPassword")) | |
{ | |
ShowIdentity(); | |
int threadId = -1; | |
await Task.Run(() => | |
{ | |
ShowIdentity(); | |
Thread.Sleep(100); | |
threadId = Environment.CurrentManagedThreadId; | |
ImpersonateIdentity(userName: "TestUser1", domain: "sammy", password: "TestPassword1"); | |
ShowIdentity(); | |
}).ConfigureAwait(false); | |
ShowIdentity(); | |
// switch to a non-pool thread | |
await Task.Factory.StartNew(() => { }, TaskCreationOptions.LongRunning); | |
ShowIdentity(); | |
GoThruThreads(threadId); | |
} | |
ShowIdentity(); | |
} | |
static void GoThruThreads(int threadId) | |
{ | |
var more = true; | |
while (more) | |
{ | |
var tcs = new TaskCompletionSource<object>(); | |
ThreadPool.UnsafeQueueUserWorkItem(_ => | |
{ | |
if (Environment.CurrentManagedThreadId == threadId) | |
{ | |
more = false; | |
ShowIdentity(); | |
} | |
tcs.SetResult(Type.Missing); | |
}, null); | |
tcs.Task.Wait(); | |
} | |
} | |
static WindowsImpersonationContext ImpersonateIdentity(string userName, string domain, string password) | |
{ | |
var userToken = IntPtr.Zero; | |
var success = NativeMethods.LogonUser( | |
userName, | |
domain, | |
password, | |
(int)NativeMethods.LogonType.LOGON32_LOGON_INTERACTIVE, | |
(int)NativeMethods.LogonProvider.LOGON32_PROVIDER_DEFAULT, | |
out userToken); | |
if (!success) | |
{ | |
throw new SecurityException("Logon user failed"); | |
} | |
try | |
{ | |
return WindowsIdentity.Impersonate(userToken); | |
} | |
finally | |
{ | |
NativeMethods.CloseHandle(userToken); | |
} | |
} | |
static void Main(string[] args) | |
{ | |
TestAsync().Wait(); | |
Console.ReadLine(); | |
} | |
static void ShowIdentity( | |
[CallerMemberName] string callerName = "", | |
[CallerLineNumber] int lineNumber = -1, | |
[CallerFilePath] string filePath = "") | |
{ | |
// format the output so I can double-click it in the Debuger output window | |
Debug.WriteLine("{0}({1}): {2}", filePath, lineNumber, | |
new { Environment.CurrentManagedThreadId, WindowsIdentity.GetCurrent().Name }); | |
} | |
static class NativeMethods | |
{ | |
public enum LogonType | |
{ | |
LOGON32_LOGON_INTERACTIVE = 2, | |
LOGON32_LOGON_NETWORK = 3, | |
LOGON32_LOGON_BATCH = 4, | |
LOGON32_LOGON_SERVICE = 5, | |
LOGON32_LOGON_UNLOCK = 7, | |
LOGON32_LOGON_NETWORK_CLEARTEXT = 8, | |
LOGON32_LOGON_NEW_CREDENTIALS = 9 | |
}; | |
public enum LogonProvider | |
{ | |
LOGON32_PROVIDER_DEFAULT = 0, | |
LOGON32_PROVIDER_WINNT35 = 1, | |
LOGON32_PROVIDER_WINNT40 = 2, | |
LOGON32_PROVIDER_WINNT50 = 3 | |
}; | |
public enum ImpersonationLevel | |
{ | |
SecurityAnonymous = 0, | |
SecurityIdentification = 1, | |
SecurityImpersonation = 2, | |
SecurityDelegation = 3 | |
} | |
[DllImport("advapi32.dll", SetLastError = true)] | |
public static extern bool LogonUser( | |
string lpszUsername, | |
string lpszDomain, | |
string lpszPassword, | |
int dwLogonType, | |
int dwLogonProvider, | |
out IntPtr phToken); | |
[DllImport("kernel32.dll", SetLastError=true)] | |
public static extern bool CloseHandle(IntPtr hObject); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment