Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I make HttpWebRequest include windows credentials without waiting for a 401 challenge?

My app communicates with an internal web API that requires authentication.

When I send the request I get the 401 challenge as expected, the handshake occurs, the authenticated request is re-sent and everything continues fine.

However, I know that the auth is required. Why do I have to wait for the challenge? Can I force the request to send the credentials in the first request?

My request generation is like this:

   private static HttpWebRequest BuildRequest(string url, string methodType)
   {
       var request = HttpWebRequest.CreateHttp(url);
       request.PreAuthenticate = true;
       request.AuthenticationLevel = AuthenticationLevel.MutualAuthRequested;
       request.Credentials = CredentialCache.DefaultNetworkCredentials;
       request.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
       request.ContentType = CONTENT_TYPE;
       request.Method = methodType;
       request.UserAgent = BuildUserAgent();
       return request;
   }

Even with this code, the auth header isn't included in the initial request.

I know how to include the auth info with basic.... what I want to do is to use Windows Auth of the user executing the app (so I can't store the password in a config file).

UPDATE I also tried using a HttpClient and its own .Credentials property with the same result: no auth header is added to the initial request.

The only way I could get the auth header in was to hack it in manually using basic authentication (which won't fly for this use-case)

like image 939
Matthew Avatar asked Jun 03 '14 17:06

Matthew


2 Answers

Ntlm is a challenge/response based authentication protocol. You need to make the first request so that the server can issue the challenge then in the subsequent request the client sends the response to the challenge. The server then verifies this response with the domain controller by giving it the challenge and the response that the client sent. Without knowing the challenge you can't send the response which is why 2 requests are needed.

Basic authentication is password based so you can short circuit this by sending the credentials with the first request but in my experience this can be a problem for some servers to handle.

More details available here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378749(v=vs.85).aspx

like image 196
Mike Avatar answered Sep 20 '22 11:09

Mike


I'm not 100% sure, but I suspect that there is no way around this; it's simply the way HttpWebRequest works.

In the online .NET source, function DoSubmitRequestProcessing which is here, you can see this comment just after the start of the function, line 1731:

        // We have a response of some sort, see if we need to resubmit
        // it do to authentication, redirection or something
        // else, then handle clearing out state and draining out old response.

A little further down (line 1795) (some lines removed for brevity)

if (resubmit)
{   
   if (CacheProtocol != null && _HttpResponse != null) CacheProtocol.Reset();
   ClearRequestForResubmit(ntlmFollowupRequest);
   ...
}

And in ClearRequestForResubmit line 5891:

// We're uploading and need to resubmit for Authentication or Redirect.

and then (Line 5923):

// The second NTLM request is required to use the same connection, don't close it
     if (ntlmFollowupRequest) {....}

To my (admittedly n00bish) eyes these comments seem to indicate that the developers decided to follow the "standard" challenge-response protocol for NTML/Kerberos and not include any way of sending authentication headers up-front.

like image 37
Stephen Byrne Avatar answered Sep 20 '22 11:09

Stephen Byrne