3

Edit: Using:

byte[] authBytes = System.Text.Encoding.UTF8.GetBytes(user + ":" + password);
wr.Headers["Authorization"] = "Basic " + Convert.ToBase64String(authBytes);

Seems to work fine.

I have an application that communicates with a CMS. I'm currently trying to get this client to be able to upload text/xml data to the CMS using a "POST" method.

I can pass this through using curl perfectly fine:

curl -u user:password -H "Content-Type:text/xml" -d "<element>myXML</element>" serverURL

However, trying to use the HttpWebRequest in C# I can't get the server to return what I want it to. So I fired up Wireshark and had a look at what was actually being passed through, and it's pretty much identical except for the fact that when using curl I can see:

Authorization: Basic <a bunch of hex>=\r\n
Credentials: user:password

In the HTTP header fields, while in the output from my client, these header fields are simply not present. ("Credentials:" isn't actually there in plain text, it's a subtree of "Authorization:" - so I'm not sure where it's getting it from, but the username and password are correct.)

The C# code I'm trying to use to set the credentials for the webrequest is something like this:

NetworkCredential myCred = new NetworkCredential(
                    user, password, serverURL);

CredentialCache myCache = new CredentialCache();

myCache.Add(new Uri(serverURL), "Basic", myCred);

HttpWebRequest wr = (HttpWebRequest) HttpWebRequest.Create(serverURL);
wr.Credentials = myCache;

I've tried just setting the credentials like this too (and without specifying serverURL):

wr.Credentials = new NetworkCredential(user,password,serverURL);

But that still doesn't make it show up in wireshark. Does anyone have any idea if:

A) That authorization information should actually be in the HTTP header for this to work, and

B) If it is - then how do I make C# put it in? I only seem to be able to find decent examples using the default credentials, which doesn't apply to what I'm doing.

Thanks in advance.

1 Answers1

5

.NET's WebRequest has an infuriating default behavior where it only sends credentials after receiving an HTTP 401 Not Authorized response.

Manually adding the credentials header (as you've done) seems to be the best solution available.

More details in this post

Community
  • 1
  • 1
arid1
  • 116
  • 1
  • 2
  • Ah I see. My server just returns a different, but still 200 OK response for unauthorised users, so that would be why it wasn't working. Now I need to find out how to select this answer... – confused_person Aug 19 '11 at 07:29
  • We ran into a similar problem. It took ages to track down. – arid1 Aug 19 '11 at 14:36
  • This solution solved my current problem and one that I had given up on months ago. Thanks! – ChandlerPelhams May 08 '13 at 15:01
  • *".NET's WebRequest has an infuriating default behavior where it only sends credentials after receiving an HTTP 401 Not Authorized response."*: WebRequest is actually doing the right thing here; clients are not supposed to send the Authorization header with every request. They should only send it in response to a 401 with a WWW-Authenticate challenge, where the authentication scheme is specified. – Thomas Levesque Feb 22 '16 at 18:01
  • Typically that's so that the browser can prompt the user for credentials. If you explicitly provide credentials before the request there's a reasonable expectation that they will end up in the request and browsers do so when they have already logged into a site in the current session. Otherwise they'd be making two requests all the time. WebRequest could instead provide an event and callback in this case to make the behavior explicit. My use was something similar to a curl/wget one-shot request where the provided credentials are used immediately. I'm curious how other platforms behave. – arid1 Feb 23 '16 at 18:35
  • Also note that the request was explicitly setup as using Basic auth, furthering the expectation that the credentials would be sent. – arid1 Feb 23 '16 at 18:37