I have a .NET 6 web application that needs to impersonate the current domain user to perform some operations on their behalf.
Users authenticate through OAuth, so all I have is a ClaimsIdentity
from which I can extract the user's UPN.
I have a working solution with .NET Framework 4.8. My problem is that I cannot find a way to do the same with .NET 6.
Below are all the details of the setup and what I tried already.
Working solution with .NET Framework 4.8
On the web server I have configured the Claims to Windows Token service (c2wts) to allow the application pool identity to impersonate users.
I have also granted to the application pool identity the following privileges through the local policy editor:
- Act as part of the operating system
- Allow log on locally
- Generate security audits
- Impersonate a client after authentication
- Log on as a service
With this setup, using .NET Framework 4.8 I could impersonate the current user with something like this:
void WorksWithFramework_4_8(string userUpn) {
var windowsIdentity = S4UClient.UpnLogon(userUpn);
WindowsImpersonationContext context = windowsIdentity.Impersonate();
// Do something...
context.Undo();
}
.NET 6 attempt 1: S4UClient.UpnLogon
If I try to call S4UClient.UpnLogon
, I get this exception:
The type initializer for 'Microsoft.IdentityModel.WindowsTokenService.S4UClient' threw an exception.
Inner Exception: FileNotFoundException: Could not load file or assembly 'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. The system cannot find the file specified.
Things I tried that did not work:
- Adding a reference to the package
System.ServiceModel.Primitives
as suggested in this answer - Uninstalling and reinstalling the framework as suggested in this answer
.NET 6 attempt 2: WindowsIdentity.RunImpersonated
static void RunImpersonatedTest(string upn) {
WindowsIdentity identity = new WindowsIdentity(upn);
WindowsIdentity.RunImpersonated(identity.AccessToken, () => {
// This prints the expected output
Console.WriteLine(WindowsIdentity.GetCurrent().Name);
// If I try to access something that actually requires privileges, nothing works...
foreach (var file in Directory.EnumerateFiles(@"\\SOME-MACHINE\C$\tmp")) {
Console.WriteLine(file);
}
});
}
If I use WindowsIdentity.RunImpersonated
, as soon as I try to do anything I get an access denied error, or this exception:
Either a required impersonation level was not provided, or the provided impersonation level is invalid. (Exception from HRESULT: 0x80070542)