Created
November 24, 2017 14:08
-
-
Save lakeman/26af3a6d047d3de84c710711781ea709 to your computer and use it in GitHub Desktop.
Win32 Impersonate Middleware
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
public class Impersonate | |
{ | |
private readonly RequestDelegate next; | |
private ILogger<Impersonate> logger; | |
private readonly IServiceProvider _provider; | |
public Impersonate(ILogger<Impersonate> logger, RequestDelegate next, IServiceProvider provider) { | |
this.next = next; | |
this.logger = logger; | |
this._provider = provider; | |
} | |
private static AsyncLocal<WindowsIdentity> currentToken = new AsyncLocal<WindowsIdentity>(TokenChanged); | |
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] | |
internal static extern bool ImpersonateLoggedOnUser(SafeAccessTokenHandle userToken); | |
[DllImport("advapi32.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)] | |
internal static extern bool RevertToSelf(); | |
private static void TokenChanged(AsyncLocalValueChangedArgs<WindowsIdentity> args) | |
{ | |
if (args.CurrentValue == args.PreviousValue) | |
return; | |
if (args.PreviousValue != null) | |
{ | |
if (!RevertToSelf()) | |
throw new Win32Exception(); | |
} | |
if (args.CurrentValue != null) | |
{ | |
// A call occurs *after* setting the current token to null, with a closed but not invalid token. | |
if (!args.CurrentValue.AccessToken.IsClosed && !args.CurrentValue.AccessToken.IsInvalid) | |
{ | |
if (!ImpersonateLoggedOnUser(args.CurrentValue.AccessToken)) | |
throw new Win32Exception(); | |
} | |
} | |
} | |
public async Task Invoke(HttpContext context) { | |
var winIdent = context.User.Identity as WindowsIdentity; | |
if (winIdent == null) | |
{ | |
logger.LogDebug($"Ignoring Impersonation, no windows identity"); | |
await next.Invoke(context); | |
}else { | |
logger.LogDebug($"Impersonating {winIdent.Name}"); | |
currentToken.Value = winIdent; | |
try | |
{ | |
using (var scope = _provider.GetRequiredService<IServiceScopeFactory>().CreateScope()) | |
{ | |
await next.Invoke(context); | |
} | |
} | |
catch | |
{ | |
currentToken.Value = null; | |
logger.LogDebug($"Impersonation complete"); | |
throw; | |
} | |
currentToken.Value = null; | |
logger.LogDebug($"Impersonation complete"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment