-
Notifications
You must be signed in to change notification settings - Fork 4.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ASP.NET core 2.2.4 impersonation not working with SocketsHttpHandler #29351
Comments
|
Duplicate of #24009. |
This doesn't sound like the story for me.. |
HttpClientHandler is either SocketsHttpHandler or WinHttpHandler. By default it is SocketsHttpHandler unless you use the AppContext switch to turn that off. Does your scenario work with SocketsHttpHandler if you remove async from your repro code? This code is invalid: await (WindowsIdentity.RunImpersonated(windowsIdentity.AccessToken, async () => RunImpersonated() is sync only. So, you can not use 'async' or 'await' modifiers in your code. If you need to call async calls within the RunImpersonated() you need to wait for them to complete with .Result or something. If you can reproduce the impersonation problem using SocketsHttpHandler (which is the default of HttpClientHandler) when you fix the repro code by removing the 'await' and 'async' code, then there would be something to investigate as a possible bug. The fact that this works with the invalid async repro code by disabling SocketsHttpHandler (and thus uses WinHttpHandler) might be due to race conditions on the underlying async calls completing fast enough before the RunImpersonated call finishes. |
as you suggested, here is my new code, but i'm still experiencing the same issue, unless i disable SocketsHttpHandler, and use winHttpHandler instead by adding environment variable WindowsIdentity.RunImpersonated(windowsIdentity.AccessToken, async () =>
{
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, URL);
string user_name = WindowsIdentity.GetCurrent().Name;
result += ($"\n\nimpersonated as: {user_name}\n\n");
try
{
var response = _client.SendAsync(requestMessage).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
result += ($"Called API as: {WindowsIdentity.GetCurrent().Name}.\n\n" +
$"{responseString}\n");
}
catch (Exception ex)
{
result += ex.ToString();
}
}); this is the expcetion thrown, and through further debugging, it's the same callstack with the initial one.
|
Can you remove the 'async' keyword from this code? Using the 'async' keyword will still result in the body of the method potentially running async. |
This is the new code WindowsIdentity.RunImpersonated(windowsIdentity.AccessToken, () =>
{
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, URL);
string user_name = WindowsIdentity.GetCurrent().Name;
result += ($"\n\nimpersonated as: {user_name}\n\n");
try
{
var response = _client.SendAsync(requestMessage).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
result += ($"Called API as: {WindowsIdentity.GetCurrent().Name}.\n\n" +
$"{responseString}\n");
}
catch (Exception ex)
{
result += ex.ToString();
}
}); and i'm still getting the same error. the workaround still works. |
@Tratcher Any thoughts? I thought impersonation worked ok as long as it was synchronous code? |
More likely we've ruled out the async impersonation as the cause of the error. I just wanted to make sure before we looked deeper.
Do you still get this error if you completely remove RunImpersonated? |
The error on my side is only with RunImpersonated, but its only effecting some people in my domain |
this is the callstack i got while debugging:
and i found inner exception is access deny error when opening thread token:
and, if you need a lab to do debugging, i can share mine to you through Microsoft corporate network. |
I still get the DNS error for some users , environmentVariable name="DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER" value="0" doesnt work for me . WinHttpHandler works for me but than i need the password for the NetworkCredential to be able to do an authenticated call , i previuous used UseDefaultCredentials with HttpClientHandler |
i don't understand. if you set the environment variable, then you should be using WinHttpHandler, like davidsh explained above. |
when i set that in the config it still has the error only when i change HttpClient to use WinHttpHandler than it works but than i have a problem with credentials |
Its working now with WinHttpHandler |
I am also getting same error. I am getting this error in both version Net Core 2.1 and 2.2 . SocketHttpHandler is unable to resolve host if we use it with RunImpersonated. Strangely, it is working perfectly in Win 7 machine but failing in Win 10 machine |
Can you try a scoped repro that calls Dns rather than HttpClient inside RunImpersonated? I think SocketHttpHandler is using Dns.BeginGetHostAddresses. You could also try GetHostAddresses. |
I have seen this error before. It usually happens when trying to forward resolve a DNS name but then the reverse DNS resolution is broken. We've had issues before with the how the System.Net Dns class implements GetHostAddresses() because there are cases when it does forward and reverse lookups before returning the results. I'm not sure if this is happening in this repro. And I do think that this DNS problem should be reduced down to try and isolate it. |
@Tratcher , I tried running Dns.GetHostAddress inside RunImpersonated. It is returning correct IP address. But with HttpClient I am getting error. |
Interesting, I wonder if BeginGetHostAddresses is any different. |
BeginGetHostAddresses doesn't work with impersonation. |
I agree this difference needs to be investigated. We should be using the same underlying Windows Winsock APIs for of the different overloads of the |
Is it possible this PR dotnet/corefx#37327 will fix this? |
I'm still running into this issue on 3.0 preview 5. I notice the linked PR is not going to be merged due to failed checks. Any chance this is going to be fixed? |
Sorry. It appears I used the wrong PR number in the link above. That link isn't related to this issue at all. And this issue has not been resolved in .NET Core 3.0 branches yet. It still needs more investigation. But https://github.com/dotnet/corefx/issues/37120#issuecomment-487868688 points to a possible area that might be causing the problem. |
I did some more tests and seem related to usage with impersonation of different user(also on same machine, no domain) .NET Core SDK (reflecting any global.json): class Program
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeAccessTokenHandle phToken);
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
static void Main(string[] args)
{
SafeAccessTokenHandle tokenin;
bool returnValue = false;
Console.WriteLine("Current User");
returnValue = LogonUser("marco", "xxxxx", "xxxxx", LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out tokenin);
Debug.Assert(returnValue);
Run(tokenin);
tokenin.Dispose();
Console.WriteLine("-------");
Console.WriteLine("Another User");
returnValue = LogonUser("anotheruser", "xxxx", "xxxxx", LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out tokenin);
Debug.Assert(returnValue);
Run(tokenin);
tokenin.Dispose();
Console.WriteLine("-------");
return;
static void Run(SafeAccessTokenHandle token)
{
string host = "www.google.it";
WindowsIdentity.RunImpersonated(token, () =>
{
Console.WriteLine($"{WindowsIdentity.GetCurrent().Name} {WindowsIdentity.GetCurrent().ImpersonationLevel}");
Console.WriteLine("Dns.GetHostAddresses(host) " + Dns.GetHostAddresses(host)[0].ToString());
Console.WriteLine("Dns.GetHostAddressesAsync(host) " + Dns.GetHostAddressesAsync(host).Result[0].ToString());
});
}
}
}
...
Current User
xxx\Marco Impersonation
Dns.GetHostAddresses(host) 216.58.198.3
Dns.GetHostAddressesAsync(host) 216.58.198.3
-------
Another User
xxx\AnotherUser Impersonation
Dns.GetHostAddresses(host) 216.58.198.3
Unhandled Exception: System.AggregateException: One or more errors occurred. (This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server.) ---> System.Net.Sockets.SocketException: This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server.
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw(Exception source)
at System.Net.Dns.HostResolutionEndHelper(IAsyncResult asyncResult)
at System.Net.Dns.EndGetHostAddresses(IAsyncResult asyncResult)
at System.Net.Dns.<>c.<GetHostAddressesAsync>b__25_1(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task`1.GetResultCore(Boolean w
For async scenario |
@MarcoRossignoli Thanks for the additional repro case! I have done further analysis and opened up a new issue, dotnet/corefx#38646 that is the root cause of this issue. |
Just to add further information to this, we are were having the same problem for some of our users. We narrowed it down to users that are local admins on the web server are fine but other users will fail unless we turn off the SocketsHttpHandler as was suggested by OP. |
environment:
DC: windows server 2012R2
server1: windows server 2016, ASP.NET core 2.2.4 web API on IIS with windows authentication enabled
server2: windows server 2012R2, ASP.NET core 2.2 web api on IIS with windows authentication enabled
client: any browsers
client -> server1 -> server2.
the ASP.NET core app in server1 will impersonate the authenticated user then call server 2 web api.
i have configured app pools on both servers to use service account, and have configured SPN accordingly, added delegation setting for the service account of server1.
sample code of how i do impersonate:
expected scenario: the impersonation process would succeed,and server2 gets requests from the initial credential.
real scenario: server1 would throw following exception:
further troubleshooting:
while doing debugging, i found that if i turn off SocketsHttpHandler following this
and use HTTPClientHandler, the issue will get resolved. which seems indicate that ASP.NET core impersonation is not working with SocketsHttpHandler.
i also attached full callstack here:
working-callstack.txt
non-working-callstack.txt
I understand the new socket handler is designed to eliminate platform dependencies, however can you suggest how to make it work with impersonation?
non-working callstack with SocketsHttpHandler:
working callstack with HttpClientHandler:
The text was updated successfully, but these errors were encountered: