runtime: ASP.NET core 2.2.4 impersonation not working with SocketsHttpHandler

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:

var windowsIdentity = (WindowsIdentity)this.HttpContext.User.Identity;

await (WindowsIdentity.RunImpersonated(windowsIdentity.AccessToken, async () =>
{
	
    using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, "http://winsvr12r2-1.jiangya1.lab:4000/api/values"))
    {
		
        string user_name = WindowsIdentity.GetCurrent().Name;
        
		try
        {
			
            var response = await _client.SendAsync(requestMessage);
            
			var responseString = await response.Content.ReadAsStringAsync();
            
			result = ($"Called API as: {WindowsIdentity.GetCurrent().Name}.\n\n" +
                               $"{responseString}\n");
        
		}
        
		catch (Exception ex)
        {
        
			result = ex.ToString();
        }
    }
}));
return result;

expected scenario: the impersonation process would succeed,and server2 gets requests from the initial credential. real scenario: server1 would throw following exception:

System.Net.Http.HttpRequestException: 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.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask`1 creationTask)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.AuthenticationHelper.SendWithAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean preAuthenticate, Boolean isProxyAuth, Boolean doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at WebApplication2.Controllers.PassThroughController.<>c__DisplayClass5_0.<<Get>b__0>d.MoveNext() in C:\Users\jiangya\source\repos\WebApplication2\WebApplication2\Controllers\PassThroughController.cs:line 92

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:

0:030> !\\**********\shared\Microsoft.NETCore.App\2.2.4\sos.clrstack
OS Thread Id: 0xe00 (30)
        Child SP               IP Call Site
000000d9e19fbf78 00007ffca5a60160   Interop+Winsock.GetAddrInfoExW(System.String, System.String, Int32, IntPtr, System.Net.Sockets.AddressInfoEx ByRef, System.Net.Sockets.AddressInfoEx* ByRef, IntPtr, System.Threading.NativeOverlapped ByRef, LPLOOKUPSERVICE_COMPLETION_ROUTINE, IntPtr ByRef)
000000d9e19fbf78 00007ffc343c65a4   Interop+Winsock.GetAddrInfoExW(System.String, System.String, Int32, IntPtr, System.Net.Sockets.AddressInfoEx ByRef, System.Net.Sockets.AddressInfoEx* ByRef, IntPtr, System.Threading.NativeOverlapped ByRef, LPLOOKUPSERVICE_COMPLETION_ROUTINE, IntPtr ByRef)
000000d9e19fbf20 00007ffc343c65a4 DomainBoundILStubClass.IL_STUB_PInvoke(System.String, System.String, Int32, IntPtr, System.Net.Sockets.AddressInfoEx ByRef, System.Net.Sockets.AddressInfoEx* ByRef, IntPtr, System.Threading.NativeOverlapped ByRef, LPLOOKUPSERVICE_COMPLETION_ROUTINE, IntPtr ByRef)
000000d9e19fc040 00007ffc8aaafba8 System.Net.NameResolutionPal.GetAddrInfoAsync(System.Net.DnsResolveAsyncResult)  
000000d9e19fc110 00007ffc8aaac27b System.Net.Dns.HostResolutionBeginHelper(System.String, Boolean, Boolean, System.AsyncCallback, System.Object)  
000000d9e19fc190 00007ffc8aaacea8 System.Net.Dns.BeginGetHostAddresses(System.String, System.AsyncCallback, System.Object)  
000000d9e19fc1e0 00007ffc8ab1bcc2 System.Net.Sockets.MultipleConnectAsync.StartConnectAsync(System.Net.Sockets.SocketAsyncEventArgs, System.Net.DnsEndPoint)  
000000d9e19fc250 00007ffc8ab08f23 System.Net.Sockets.Socket.ConnectAsync(System.Net.Sockets.SocketType, System.Net.Sockets.ProtocolType, System.Net.Sockets.SocketAsyncEventArgs)  
000000d9e19fc2b0 00007ffc343c5d98 System.Net.Http.ConnectHelper+d__2.MoveNext()  
000000d9e19fc3a0 00007ffc343c5759 System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start 
000000d9e19fc410 00007ffc8a95726e System.Net.Http.ConnectHelper.ConnectAsync(System.String, Int32, System.Threading.CancellationToken)
000000d9e19fc4d0 00007ffc8a95afae System.Net.Http.HttpConnectionPool+d__44.MoveNext()  
000000d9e19fc6e0 00007ffc343c51e9 System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start 
000000d9e19fc750 00007ffc8a95950e System.Net.Http.HttpConnectionPool.CreateConnectionAsync(System.Net.Http.HttpRequestMessage, System.Threading.CancellationToken)
000000d9e19fc850 00007ffc343c4d29 System.Net.Http.HttpConnectionPool.GetConnectionAsync(System.Net.Http.HttpRequestMessage, System.Threading.CancellationToken)  
000000d9e19fc9f0 00007ffc8a95a662 System.Net.Http.HttpConnectionPool+d__39.MoveNext()  
000000d9e19fcaf0 00007ffc343c3ff9 System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start 
000000d9e19fcb60 00007ffc8a959225 System.Net.Http.HttpConnectionPool.SendWithRetryAsync(System.Net.Http.HttpRequestMessage, Boolean, System.Threading.CancellationToken)
000000d9e19fcc00 00007ffc8a9593ee System.Net.Http.HttpConnectionPool.SendWithProxyAuthAsync(System.Net.Http.HttpRequestMessage, Boolean, System.Threading.CancellationToken)  
000000d9e19fcc60 00007ffc8a9457a2 System.Net.Http.AuthenticationHelper+d__16.MoveNext()  
000000d9e19fcd60 00007ffc343c3cf9 System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start 
000000d9e19fcdd0 00007ffc8a9443fb System.Net.Http.AuthenticationHelper.SendWithAuthAsync(System.Net.Http.HttpRequestMessage, System.Uri, System.Net.ICredentials, Boolean, Boolean, Boolean, System.Net.Http.HttpConnectionPool, System.Threading.CancellationToken)
000000d9e19fce90 00007ffc8a95946c System.Net.Http.HttpConnectionPool.SendAsync(System.Net.Http.HttpRequestMessage, Boolean, System.Threading.CancellationToken)  
000000d9e19fcef0 00007ffc8a95c79c System.Net.Http.HttpConnectionPoolManager.SendAsyncCore(System.Net.Http.HttpRequestMessage, System.Uri, Boolean, Boolean, System.Threading.CancellationToken)  
000000d9e19fcfd0 00007ffc8a95c93a System.Net.Http.HttpConnectionPoolManager.SendAsync(System.Net.Http.HttpRequestMessage, Boolean, System.Threading.CancellationToken)  
000000d9e19fd030 00007ffc8a958cea System.Net.Http.HttpAuthenticatedConnectionHandler.SendAsync(System.Net.Http.HttpRequestMessage, System.Threading.CancellationToken)  
000000d9e19fd060 00007ffc8a95f388 System.Net.Http.RedirectHandler+d__4.MoveNext()  
000000d9e19fd100 00007ffc343c2729 System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start 
000000d9e19fd170 00007ffc8a95efba System.Net.Http.RedirectHandler.SendAsync(System.Net.Http.HttpRequestMessage, System.Threading.CancellationToken)
000000d9e19fd1f0 00007ffc8a95ead2 System.Net.Http.SocketsHttpHandler.SendAsync(System.Net.Http.HttpRequestMessage, System.Threading.CancellationToken)  
000000d9e19fd240 00007ffc8a93a259 System.Net.Http.HttpClientHandler.SendAsync(System.Net.Http.HttpRequestMessage, System.Threading.CancellationToken)  
000000d9e19fd290 00007ffc8a93ce42 System.Net.Http.HttpMessageInvoker.SendAsync(System.Net.Http.HttpRequestMessage, System.Threading.CancellationToken)  
000000d9e19fd2e0 00007ffc8a936954 System.Net.Http.HttpClient.SendAsync(System.Net.Http.HttpRequestMessage, System.Net.Http.HttpCompletionOption, System.Threading.CancellationToken)  
000000d9e19fd350 00007ffc343bf2fd Error: Failed to load C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.2.4\coreclr.dll
WebApplication2.Controllers.PassThroughController+c__DisplayClass5_0+b__0>d.MoveNext()
000000d9e19fd3c0 00007ffc343bf109 System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start 
000000d9e19fd430 00007ffc343bf098 WebApplication2.Controllers.PassThroughController+c__DisplayClass5_0.b__0()
000000d9e19fd4a0 00007ffc8ba09446 System.Security.Principal.WindowsIdentity+c__DisplayClass60_0`1 .b__0()
000000d9e19fd4d0 00007ffc8ba09517 System.Security.Principal.WindowsIdentity+c__DisplayClass64_0.b__0(System.Object)  
000000d9e19fd510 00007ffc8d3c2019 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)  
000000d9e19fd590 00007ffc8ba07993 System.Security.Principal.WindowsIdentity.RunImpersonatedInternal(Microsoft.Win32.SafeHandles.SafeAccessTokenHandle, System.Action)  
000000d9e19fd5e0 00007ffc8ba077df System.Security.Principal.WindowsIdentity.RunImpersonated 
000000d9e19fd630 00007ffc343be842 WebApplication2.Controllers.PassThroughController+d__5.MoveNext()
000000d9e19fd690 00007ffc343be5d9 System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start 
000000d9e19fd700 00007ffc343be558 WebApplication2.Controllers.PassThroughController.Get()

working callstack with HttpClientHandler:

0:014> k
Child-SP          RetAddr           Call Site
00 000000b3`80a7e140 00007ffc`a5a5ec39 
ws2_32!WinsockThreadpool_CreateWorkContext+0x9b   
01 000000b3`80a7e180 00007ffc`a5a59684 ws2_32!WinsockThreadpool_SubmitWork+0x45   
02 000000b3`80a7e1d0 00007ffc`a5a58009 ws2_32!NSQUERY::LookupServiceNextAsync+0x154   
03 000000b3`80a7e250 00007ffc`a5a56b67 ws2_32!WSALookupServiceNextAsyncW+0x169   
04 000000b3`80a7e2b0 00007ffc`a5a57070 ws2_32!NSSUBJOB::LookupAsyncAndHandleResultsQDNS4F+0xb7   
05 000000b3`80a7e340 00007ffc`a5a5717e ws2_32!NSSUBJOB::TrySubmitQDNS4F+0x6c   
06 000000b3`80a7e390 00007ffc`a5a56814 ws2_32!NSSUBJOB::TrySubmit+0x8e   
07 000000b3`80a7e3f0 00007ffc`a5a55f06 ws2_32!NSJOB::SubmitChild+0x44   
08 000000b3`80a7e440 00007ffc`a5a56329 ws2_32!NSJOB::ForEachChild+0xd6   
09 (Inline Function) --------`-------- ws2_32!NSJOB::ForEachChild+0x12   
0a 000000b3`80a7e490 00007ffc`a5a57201 ws2_32!NSJOB::TrySubmit+0x89   
0b 000000b3`80a7e4f0 00007ffc`a5a56814 ws2_32!NSSUBJOB::TrySubmit+0x111   
0c 000000b3`80a7e550 00007ffc`a5a55f06 ws2_32!NSJOB::SubmitChild+0x44   
0d 000000b3`80a7e5a0 00007ffc`a5a56329 ws2_32!NSJOB::ForEachChild+0xd6   
0e (Inline Function) --------`-------- ws2_32!NSJOB::ForEachChild+0x12   
0f 000000b3`80a7e5f0 00007ffc`a5a55913 ws2_32!NSJOB::TrySubmit+0x89   
10 000000b3`80a7e650 00007ffc`a5a6145c ws2_32!NSMASTERJOB::TrySubmit+0x53   
11 000000b3`80a7e690 00007ffc`99109ac1 ws2_32!GetAddrInfoExW+0x12fc   
12 000000b3`80a7e8d0 00007ffc`991099d1 webio!WapDnsResolveGeneric+0xd9   
13 000000b3`80a7e9c0 00007ffc`99108e3e webio!WapStartDnsIoContext+0x31   
14 000000b3`80a7e9f0 00007ffc`99108a6e webio!WaStartDnsQuery+0x21e   
15 000000b3`80a7eab0 00007ffc`99108fa4 webio!WapTcpStartDnsQuery+0x38e   
16 000000b3`80a7eb40 00007ffc`991090b7 webio!WaTcpConnectRequest+0x54   
17 000000b3`80a7eb90 00007ffc`99102f44 webio!WapHttpConnect+0x107   
18 000000b3`80a7ec20 00007ffc`99102da8 webio!WaQueueHttpRequest+0x144   
19 (Inline Function) --------`-------- webio!WapStartQueueRequest+0x1c   
1a (Inline Function) --------`-------- webio!WapGetConnectionCompletionRoutine+0x5c   
1b 000000b3`80a7ecc0 00007ffc`99102c88 webio!WapStartGetConnection+0xf8   
1c 000000b3`80a7ed10 00007ffc`99102b16 webio!WapStartGetEndpoints+0x44   
1d 000000b3`80a7ed40 00007ffc`99105008 webio!WapAsynchronousSendHttpRequest+0x266   
1e (Inline Function) --------`-------- webio!WapSendHttpRequest+0x2f   
1f 000000b3`80a7ee20 00007ffc`9f001c65 webio!WebSendHttpRequest+0x38   
20 (Inline Function) --------`-------- winhttp!WEBIO_SENDER::SendRequest+0x21d   
21 000000b3`80a7ee80 00007ffc`9f007528 winhttp!WEBIO_REQUEST::SendRequest+0x415   
22 000000b3`80a7ef70 00007ffc`9f007b60 winhttp!HTTP_USER_REQUEST::_SysSendRequest+0x1028   
23 000000b3`80a7f170 00007ffc`9f00783b winhttp!HTTP_USER_REQUEST::_SendRequestWithDrainComplete+0x2d0   
24 000000b3`80a7f200 00007ffc`9f0023fb winhttp!HTTP_USER_REQUEST::_SendRequestWithProxyInitialized+0x6b   
25 000000b3`80a7f230 00007ffc`9efe3a57 winhttp!HTTP_USER_REQUEST::OnProxyResolvedOnSend+0xbf   
26 000000b3`80a7f280 00007ffc`9efe3710 winhttp!UserRequestProxyCompletion::OnProxyResolved+0x27   
27 000000b3`80a7f2b0 00007ffc`9efe351e winhttp!WxProxyManager::WxProxyFailoverCompletionRoutine+0x90   
28 000000b3`80a7f2e0 00007ffc`a60dec59 winhttp!RefCountWorkItemThread+0x1e   
29 000000b3`80a7f310 00007ffc`a60c328a ntdll!RtlpTpWorkCallback+0x129   
2a 000000b3`80a7f3f0 00007ffc`a4e98364 ntdll!TppWorkerThread+0x4aa   
2b 000000b3`80a7f7f0 00007ffc`a60f7091 KERNEL32!BaseThreadInitThunk+0x14   
2c 000000b3`80a7f820 00000000`00000000 ntdll!RtlUserThreadStart+0x21   

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 29 (15 by maintainers)

Most upvoted comments

@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.

BeginGetHostAddresses doesn’t work with impersonation. GetHostAddresses internally call NameResolutionPal.TryGetAddrInfo, while BeginGetHostAddresses calls NameResolutionPal.GetAddrInfoAsync. Both method have different way for resolving host. TryGetAddrInfo uses Interop.Winsock.GetAddrInfoW for resolving host GetAddrInfoAsync uses Interop.Winsock.GetAddrInfoExW for resolving host which always returns “WSATRY_AGAIN” as error code. Surely, their is some problem with Dns.BeginGetHostAddress

this is the callstack i got while debugging:

Interop+Winsock.GetAddrInfoExW(System.String, System.String, Int32, IntPtr, System.Net.Sockets.AddressInfoEx ByRef, System.Net.Sockets.AddressInfoEx* ByRef, IntPtr, System.Threading.NativeOverlapped ByRef, LPLOOKUPSERVICE_COMPLETION_ROUTINE, IntPtr ByRef)
Interop+Winsock.GetAddrInfoExW(System.String, System.String, Int32, IntPtr, System.Net.Sockets.AddressInfoEx ByRef, System.Net.Sockets.AddressInfoEx* ByRef, IntPtr, System.Threading.NativeOverlapped ByRef, LPLOOKUPSERVICE_COMPLETION_ROUTINE, IntPtr ByRef)
DomainBoundILStubClass.IL_STUB_PInvoke(System.String, System.String, Int32, IntPtr, System.Net.Sockets.AddressInfoEx ByRef, System.Net.Sockets.AddressInfoEx* ByRef, IntPtr, System.Threading.NativeOverlapped ByRef, LPLOOKUPSERVICE_COMPLETION_ROUTINE, IntPtr ByRef)
System.Net.NameResolutionPal.GetAddrInfoAsync(System.Net.DnsResolveAsyncResult) 
System.Net.Dns.HostResolutionBeginHelper(System.String, Boolean, Boolean, System.AsyncCallback, System.Object) 
System.Net.Dns.BeginGetHostAddresses(System.String, System.AsyncCallback, System.Object) 
System.Net.Sockets.MultipleConnectAsync.StartConnectAsync(System.Net.Sockets.SocketAsyncEventArgs, System.Net.DnsEndPoint) 
000000e588c7c390 00007ffc7d598f23 System.Net.Sockets.Socket.ConnectAsync
........

and i found inner exception is access deny error when opening thread token:


0:001> k
 # Child-SP          RetAddr           Call Site
00 000000e5`88c7bbe8 00007ffc`a5a5ef5d KERNELBASE!OpenThreadToken  
01 000000e5`88c7bbf0 00007ffc`a5a5ec39 ws2_32!WinsockThreadpool_CreateWorkContext+0x91  
02 000000e5`88c7bc30 00007ffc`a5a5722c ws2_32!WinsockThreadpool_SubmitWork+0x45  
03 000000e5`88c7bc80 00007ffc`a5a56814 ws2_32!NSSUBJOB::TrySubmit+0x13c  
04 000000e5`88c7bce0 00007ffc`a5a55f06 ws2_32!NSJOB::SubmitChild+0x44  
05 000000e5`88c7bd30 00007ffc`a5a56329 ws2_32!NSJOB::ForEachChild+0xd6  
06 (Inline Function) --------`-------- ws2_32!NSJOB::ForEachChild+0x12  
07 000000e5`88c7bd80 00007ffc`a5a55913 ws2_32!NSJOB::TrySubmit+0x89  
08 000000e5`88c7bde0 00007ffc`a5a6145c ws2_32!NSMASTERJOB::TrySubmit+0x53  
09 000000e5`88c7be20 00007ffc`210753c4 ws2_32!GetAddrInfoExW+0x12fc  
0a 000000e5`88c7c060 00007ffc`8037128f System_Runtime_Extensions!DomainBoundILStubClass.IL_STUB_PInvoke(System.String, System.String, Int32, IntPtr, System.Net.Sockets.AddressInfoEx ByRef, System.Net.Sockets.AddressInfoEx* ByRef, IntPtr, System.Threading.NativeOverlapped ByRef, LPLOOKUPSERVICE_COMPLETION_ROUTINE, IntPtr ByRef)+0x154
0b 000000e5`88c7c068 00000000`00000000 coreclr!MarshalNative::GCHandleInternalFree+0x3cf

0:001> !gle
LastErrorValue: (Win32) 0x5 (5) - Access is denied.
LastStatusValue: (NTSTATUS) 0xc0000022 - {Access Denied}  A process has requested access to an object, but has not been granted those access rights.

and, if you need a lab to do debugging, i can share mine to you through Microsoft corporate network.