Automatic Logon Policy in http_client

Mar 1, 2013 at 3:17 PM
Edited Mar 1, 2013 at 3:17 PM
Hello,

When using http_client I'm failing to authenticate to a local server. Stepping through the code it doesn't look like the "Automatic Logon Policy" of WinHttp is supported. ie. we fail at this point:
if( !(can_resend && got_credentials) )
    {
        // Either we cannot resend, or the user did not provide non-empty credentials.
        // Return the authentication failure to the user.
        return true;
    }
We have our own winhttp wrapper that uses Automatic Logon and I've been trying to port across those changes, but before I spend too much time on it I wonder if someone can help?

Regards,

David
Mar 1, 2013 at 3:50 PM
David,

You are correct in that this is not something the implementation currently supports.

If you want to add it, I would advise you to add an option to the http_client_config class (use "guarantee_order()" as an example) and then add the proper call to WinHttpSetOption() in the winhttp_client::open() function. You can follow the example of how guarantee_order() is used there, around line 1200 in http_client.cpp. Make sure to set the default value of the option to the right level, so that you don't inadvertently get a security problem.

We'll add it to our backlog!

Niklas
Mar 1, 2013 at 4:06 PM
Hello,

we currently play with the december release - as I see in the new codeplex relase IIS-hosting capabilities and the self hosting server are gone. Is this true? What must I do to achive hosting in IIS/Azure or self hosting?

Regards
Martin
Mar 1, 2013 at 4:08 PM
Martin,

Since this is a different topic than what David asked about, I'll copy your question to a new thread and answer it there.

Niklas
Mar 1, 2013 at 6:27 PM
Hi. Thanks very much for your quick response and advice. Hopefully I'll have time to have another go otherwise I look forward to a future update.

Regards.

David.
Jun 14, 2013 at 8:36 AM
Hello,

I just wondered if there has been any progress on automatic logon? It's a requirement for us to put casablanca into production code so we decided to develop a patch ourselves, but because of our limited experience with the code we're not particularly confident.

I could fork / provide it in patch form if its helps show what we're looking for.

Regards,

David.
Jun 14, 2013 at 5:03 PM
David,

We have not made progress on this, but thank you for reminding us. I'll take a look at how hard it would be to implement (not hard, I believe) to see if we can include it in our next release, which is a few weeks away.

Niklas
Jun 14, 2013 at 5:11 PM
What we currently do vis-à-vis auto-logon is to set the policy to HIGH if you have provided credentials, otherwise we leave it at MEDIUM. Can you tell us more about the circumstances where you see this failing, and whether what you need is to set the policy to LOW.

Niklas
Jun 15, 2013 at 11:05 AM
Hi,

Typical client. Windows 7 Enterprise
Typical sever. Windows Server 2008 R2 enterprise.

Basically, we find that on our LAN / single domain, the MEDIUM policy will not authenticate. This was surprising to us as looking at the documentation we'd expect WinHttp to consider it as a trusted/intranet. Possibly we have an issue with our network setup that prevents this from working as expected. However, we also need to make this work on our client's corporate intranets where we have no control so we decided to go ahead and set it to LOW. Our client app will also be set up to connect to some known internal url so we don't believe this is a risk in practice. We've made this change to our local TFS version and happy with the way it's working.

I also wanted to mention another more complicated change we had to make to get default credentials working. We observed that authentication using default credentials does not work for a PUT operation (GET is fine though). Is this a limitation or bug in the current version? We ended up making changes to handle_authentication_failure and I'd be happy to share those changes with you - perhaps by creating a git fork?

Regards,

David.
Jun 19, 2013 at 7:06 PM
David,

For the first issue, it sounds like allowing you to set the policy to LOW will take care of your needs. It would be an option passed at http_client construction time.

Regarding the second issue, it sounds like a bug, right. If the fix is fairly trivial and contains no intellectual property, you can just share it, otherwise, you would have to follow our contribution guidelines in order for us to be able to pick it up and use it.


Niklas
Jun 19, 2013 at 8:15 PM
Hi

Yes - being able to pass in the option at construction time would be a good feature. We didn't quite go that far in our changes but clearly the best way to implement it.

I pushed our changes into my fork:

http://casablanca.codeplex.com/SourceControl/network/forks/davidjward30/dev/changeset/f216d7eea14385a2dae25e4d0510a826ca5f147e

It also contains the previously mentioned changes to make PUT & autologon work. It's not quite trivial but contains no intellectual property. It is by no means a good solution but it's the best we could do given our experience with casablanca and WinHttp. It's entirely possible that we've broken password authentication but I'm hoping it is a starting point for getting this working.

I look forward to your response.

thanks.

David.
Jun 21, 2013 at 7:16 PM
David,

I looked briefly at your edits, but it's not clear from them what it is that is being fixed. Especially since you are raising some doubts about unintended side-effects of your edits, I would much prefer to have you describe what the original code is doing incorrectly.

Thanks,

Niklas
Jun 21, 2013 at 10:33 PM
Hi.

Here's the problem as I see it. When doing a PUT, the original casablanca code fails with an exception "The request must be resent". With fiddler we observe a 401 response.

The source of the exception is that the callback reaches

case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR :

When we wrote our original WinHttp wrapper we also struggled with such problems when using WinHttpWriteData to upload the data which is what happens here. Using WinHttpWriteData seems to significantly alter the logic required. We ended up sending the whole data with WinHttpSendRequest but that of course has limitations. Being able to stream upload and download is exactly the reason why we're looking to switch to casablanca. I believe the following document indicates the issues when using WinHttpWriteData:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa384120(v=vs.85).aspx

Specifically, the following seems relevant:

"Two issues can arise when attempting to POST (or PUT) data to proxies or servers that challenge using NTLM or Negotiate authentication."....

"Secondly, NTLM and Negotiate may require multiple handshakes to complete authentication, which requires data to be re-POST'ed for each authentication legs. This can be very inefficient for large data uploads."

In the code I shown you, we are basically trying to implement these multiple handshakes to complete authentication. Admittedly, we are doing this on a trial and error basis because we don't fully understand how to use WinHttp correctly. As I said previously, we've already failed to get this working with our wrapper and was hoping that casablanca would do this correctly.

The bottom line is that the following simple code will not authenticate;

TEST(body)
{
using namespace web;
using namespace http;
using namespace client;
using namespace concurrency::streams;

http_client client(U("http://server/send.ashx"));

const size_t rawDataSize = 8;

std::vector<unsigned char> data(rawDataSize);
memcpy(&data[0], "raw data", rawDataSize);

http_request request;
request.set_method(methods::POST);
request.set_body(data);
auto responseTask = client.request(request);

http_response response;

response = responseTask.get();

VERIFY_ARE_EQUAL(200, response.status_code());
}

Result:

d:....\release\tests\functional\davidjward30\vs10\tests.cpp(61): error: Failure in body: Unhandled exception: The request must be resent

I hope that if you can try this simple test with any server accepting a POST, you'll be able to reproduce this. Our server is Windows 2008 R2 enterprise running a very simple asp.net website under IIS. Only Windows Authenticatoin is enabled.

Regards,

David.
Jun 25, 2013 at 3:52 PM
David,

Thank you for taking the time to explain! I will turn this over to Artur, our auth guy :-), for further examination.

Niklas
Sep 5, 2013 at 12:43 PM
Hi,

Just wondered if there is any progress on this? We're holding back using this into production until it's fully supported.

Thanks very much.

David.
Sep 11, 2013 at 3:08 AM
David,

Yes, We plan to fix this in our next codeplex release, 1.3.0.

Thanks
Kavya
Oct 15, 2013 at 7:41 PM
Hi David,

The 1.3 release has the following fixes:
  1. Resend the request when ERROR_WINHTTP_RESEND_REQUEST is received. Now, when attempting to POST/PUT data to servers that challenge requests, we will resend the request.
  2. We now expose a method to set custom options on the request handle. http_client_config::set_nativehandle_options takes a function object. One can set custom options on the WinHTTP request handle. You can use this feature to set the auto logon policy.
    Refer to test case TEST_FIXTURE(server_properties, set_user_options, at Release/tests/Functional/http/client/authentication_tests.cpp for an example.
Let us know if you have any feedback.

Kavya.
Oct 20, 2013 at 2:56 PM
Hi,

Yes I've just managed to download and compile the 1.3.0 tag.

I've successfully run our simple unit tests and can confirm that the simple authentication tests now pass against our ASP.NET IIS server using integrated authentication. I've successfully used the set_nativehandle_options to set the security level to LOW (seemingly a requirement to connect across our LAN). We still have a little work to integrate the changes into production code but it all seems promising at this stage.

An issue around producer_consumer_buffer stills remains when using authentication (https://casablanca.codeplex.com/workitem/22) so we look forward to a fix for that in future.

In summary - thanks for the changes.

Regards,

David.