Http digest preemptive authentication

Aug 14, 2014 at 3:59 PM
As a client, I managed to authenticate to a server with digest authentication.
However, each of my requests are duplicated : first response has status 401, then the second request contains the required headers and the second response has status 200.
Keeping the same http_client object for all the following requests, I am surprised that the headers are not provided for the next requests, given that server nonce is constant (or changes seldomly).
This limitation is terrible in case of big POST (files uploads): each post is duplicated !

Found here that preemptive digest authentication does not seem to be supported (very surprising):
http://msdn.microsoft.com/en-us/library/windows/desktop/aa383144%28v=vs.85%29.aspx#supporting_authentication

(Tests performed with Win7 / msvc 2013 ; is it different with Win8 ?)

Any hint on how to solve that problem ?

Regards.
Coordinator
Aug 15, 2014 at 5:57 PM
Hi momaison,

What you are seeing is the normal authentication negotiation. The client initiates a connection, the server challenges the client for authentication and client resends the request with the necessary credentials. Once authentication occurs on a connection it is probably unlikely the server is going to challenge again for subsequent requests. Is it possible for you to first make a request that doesn't contain any payload data to establish the connection and then send after being authenticated?

I expect there to be no changes in behavior between Win7 an Win8. Our Windows Runtime implementation doesn't have any options for pre-authentication so I'm betting it behaves the same. In general our http_client API doesn't contain any options for pre-authentication and so doesn't provide any guarantees.

Steve
Aug 18, 2014 at 9:48 AM
Is it possible for you to first make a request that doesn't contain any payload data to establish the connection and then send after being authenticated?
I tried that: it does not work.
The same http_client instance is used for performing several GET before the POST, but each request is sent twice: once without any auth headers, then with headers (all requests are using the same tcp connection).

I have tried to use Expect: 100-continue header, but cpprest API does not allow sending headers only, does it ?

I have also tried a kludge: POSTing a fake empty content (with content_length=0), and then change the request body and content_length before cpprestsdk resend the request (when body streambuf is seeked back to 0), but without luck.

Could you indicate any advice for writing a patch in cpprestsdk implementation in order to enable pre-authentication ?
Aug 18, 2014 at 12:57 PM
Humm, after many experiments, I am afraid this is impossible to achieve natively with WinHttp (tried to call WinHttpSetCredentials before each request : no Authorization header is added with Digest, as per doc).
The best I can imagine is changing the request body (and accordingly content-length header) when resending request, after 401 server response.
Do you how I could do that ? I use a custom streambuf to intercept seek calls: can be used as a hook (WinHttp handle could be available and used at this step).
Coordinator
Aug 19, 2014 at 5:49 PM
Hi momaison,

Yes I think you are going to have some difficulty here. Unfortunately we are restricted by whatever is provided from the platform we build on. For Windows Desktop we build on top of WinHttp, as you've noticed.

Expect 100 continue - WinHttp doesn't support this scenario so that won't work.

What do you mean by changing the request body when resending? You can get access to the underlying WinHttp request handle with the http_client_config::set_nativehandle_options callback. The function you provide will be called for each HTTP request made, the parameter passed in is the HINTERNET request handle.

Steve
Aug 20, 2014 at 6:57 AM
Thank you for your answer.

My idea for mitigating the double big POST problem:
as this cannot be avoided, I planned to POST an empty (or very short) payload for first request, just to get the 401 response and server nonce.
Then http_client calls WinHttpSetCredentials() and seek request body stream to 0 to prepare the resend. This time, the idea is to provide the real POST payload stream.
This implies changing content length and body stream (well, changing the stream is not really required, we can provide another content with the same streambuf object ; but I did not succeed in changing content length). This can work only if digest is not payload dependent, RFC 2069 only.

This may be feasible, however I wonder if this would be applicable for Win8 RT ?
[by the way, is the Win7 client implementation usable under a Win8 desktop computer ?]
Coordinator
Aug 22, 2014 at 2:59 AM
Hi momaison,

I'm not entirely sure if this approach will work or not. In regards to using under Windows 8 store here is how our implementation works. There is a common cross platform piece that underneath is implemented on whatever is available on the platform being targeted. For Windows desktop XP and later we build on top of WinHttp. WinHttp is not available for Windows store and phone applications, so instead we use IXMLHttpRequest2. I suspect you will have similar issues there as well, I don't see any pre authenticate options available.

Steve