I'm building an application in an environment that's configured with Kerberos authentication. My application uses .NET's HttpClient
to POST some data to an API hosted in IIS on a different server. GET requests seem to be working fine, but POSTs to the same service instantly implode with the following exception:
System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.IO.IOException: The read operation failed, see inner exception. ---> System.Net.WebException: The request was aborted: The request was canceled. at System.Net.ConnectStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state) at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state) --- End of inner exception stack trace --- at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state) at System.Net.Http.StreamToStreamCopy.StartRead()
I tried looking at the requests using Fiddler, which as I understand it injects a HTTP proxy that it uses to view HTTP requests. And when using Fiddler, my POST request succeeds.
Here's what I see:
- Request 1 results in a
401 Unauthorized
. When I inspect the request headers, there's noAuthorization
. The response headers containWWW-Authenticate: Negotiate
andWWW-Authenticate: NTLM
. - Request 2 also results in a
401 Unauthorized
. This time, it sends aAuthorization: Negotiate YIGeBgYrBgEFBGQKgg (...)
header with the request. The response headers now comes back with aWWW-Authenticate: Negotiate oRUwE6A (...)
. - Request 3 again results in a
401 Unauthorized
. It sends a newAuthorization: Negotiate oTMwMaADCg (...)
header with the request, and gets a newWWW-Authenticate: Negotiate oYIBCzCCAQe (...)
header with the response. - Request 4 finally results in a
200 OK
, with the expected response body. It also has aAuthorization: Negotiate oYICRzCCAkOg (...)
header in the request, and anotherWWW-Authenticate: Negotiate oRswGaADCg (...)
in the response.
This appears to match the Kerberos message flow as I understand it - the first request is attempted anonymously, and gets a reply that authentication is needed. The second request asks for a ticket to the API server, which is then passed to the Kerberos controller, which again returns a ticket and a key for the client/server to use. The third request goes directly to the API server to verify that both of them can use the ticket, and the server confirms this. The fourth request uses the ticket and all is well.
However, using Fiddler as some ghetto-proxy on the server is not a viable option. So, my question:
How can I handle this in my code? My HttpClient
has both PreAuthenticate
and UseDefaultCredentials
set to true, and WindowsIdentity.GetCurrent()
returns my user with the correct domain name. However, it seems to do nothing. Without Fiddler I have no way of seeing the HTTP request, but I assume it just tries the first request and commits suicide once that fails. Do I have to apply some custom proxy to make this work? Or should it work out of the box?