ASP.NET HTTP Authorization Header
Asked Answered
S

3

27

I would like to know why my asp.net application will not add the header to my post when it is named 'Authorization' but will work fine when I change one character, say "Authorizations". In documentation for other sites they always use the name "Authorization" so I would like to as well and at this point I just want to under stand why.

I have read a few topics about this but have not found any logical reason why.

Here is my code below:

string fileName = "c:\\xyz.xml";
string uri = "http://myserver/Default.aspx";
req = WebRequest.Create(uri);
req.Method = "POST";
req.ContentType = "text/xml";
byte[] authBytes = Encoding.UTF8.GetBytes("DDSServices:jCole2011".ToCharArray());
req.Headers.Add("Authorization", "BASIC " + Convert.ToBase64String(authBytes) );
req.Headers.Add("test", "test");
UTF8Encoding encoder = new UTF8Encoding();
byte[] data = encoder.GetBytes(this.GetTextFromXMLFile(fileName));
req.ContentLength = data.Length;
Stream reqStream = req.GetRequestStream();
reqStream.Write(data, 0, data.Length);
reqStream.Close();
req.Headers.Add("Authorization", "BASIC" + Convert.ToBase64String(authBytes));
System.Net.WebResponse response = req.GetResponse();
System.IO.StreamReader reader = new StreamReader(response.GetResponseStream());
string str = reader.ReadToEnd();

The other annoying this is when i add the watched variable through fiddler it works fine.

Superclass answered 12/1, 2011 at 23:19 Comment(0)
S
43

I was ran into a question how to add Authentication/Credentials to the headers. I found the solution in the following way.

string _auth = string.Format("{0}:{1}", "myUser","myPwd");
string _enc = Convert.ToBase64String(Encoding.ASCII.GetBytes(_auth));
string _cred = string.Format("{0} {1}", "Basic", _enc);
req.Headers[HttpRequestHeader.Authorization] = _cred;

Which gave me those headers I want (pasted Wireshark descriptions),

Authorization: Basic bXlVc2VyOm15UHdk\r\n
Credentials: myUser:myPwd

Sevenfold answered 14/3, 2012 at 9:34 Comment(2)
So how do you know for sure the encoding to use is ASCII?Quartana
Nice point. The choosen encoding looks like a possible "hard to find"-source for bugs. I add the link #7242816 for readers to find more information of how to decide.Sevenfold
W
11

For HTTP Basic Authorization, you should be using the Credentials property.

req.Credentials = new NetworkCredential("DDSServices", "jCole2011");

This should do what you want. Rather than setting the Authorization header.

Waldman answered 13/1, 2011 at 1:10 Comment(8)
or is there a logical reason? A very large third party company that we work with has documentation with their authorization in the same manner, so I would like to know the reason.Superclass
It is much better to use the NetworkCredential approach as Will suggests. However, your approach should also work fine, although I dont understand why you are doing it twice (one before call to GetRquestStream, and once after. You should do it jsut once before y ou call GetRequestStream. If it still doesnt work, get a trace log. Instructions at ferozedaud.blogspot.com/2009/08/tracing-with-systemnet.htmlDentate
Can you tell me why it is better? Or where i can read about why it is better? To me it seems NetworkCredentials would be tied in with ad or forms authentication, I would rather the connection be through anonymous, then just verify. Either way though can someone just tell me why? I almost don't care about what at this point.Superclass
Well A) Because it works, and B) Because .NET will do the authentication negotiation for you automatically. Is the third party also using .NET?Waldman
More information on using NetworkCredential is here: msdn.microsoft.com/en-us/library/… - it can be used for any of the authentication schemes supported, and only uses the credentials you pass in.Waldman
NetworkCredential only sends the Authentication header after a 401 is received. This is probably not what you want... Use the old fashion way: var credentialBuffer = new UTF8Encoding().GetBytes(aUserName + ":" + aPassword); request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(credentialBuffer);Toback
@Toback Unless you set PreAuthenticate=true. msdn.microsoft.com/en-us/library/…Waldman
@WillHughes That's not true. I tried to use the PreAuthenticate=true but it was not working. The link you posted verifies that you need to catch the 401 the first time. "Property Value Type: System.Boolean true to send an HTTP Authorization header with requests after authentication has taken place; otherwise, false. The default is false."Toback
T
3

NetworkCredential is a good solution but the site you are calling has to handle an unauthorized with a 401 AND a WWW-Authenticate header in the response.

Client:

request.Credentials = new CredentialCache {{aUri, "Basic", new NetworkCredential(aUserName, aPassword)}};

Server:

Response.ClearContent();
Response.StatusCode = 401;
Response.AddHeader("WWW-Authenticate", "Basic");
Response.End();

This will result in 2 hits to the server. The initial call will go to the server without credentials. When the server responds with a 401 AND the WWW-Authenticate header (with the type of authentication required), the request will be resent with the credentials in the request.

Toback answered 8/3, 2012 at 16:42 Comment(1)
This is true, but sending back 401 Unauthorized, and the WWW-Authenticate header is part of the HTTP Spec. If you want to force sending the header on the first request, you can do so through the PreAuthenticate method. In Addition - IIS automatically handles sending back this response, as do other well-written HTTP servers such as Apache. It's how browsers know to display the password prompt dialog.Waldman

© 2022 - 2024 — McMap. All rights reserved.