ASP.Net Web API - Authorization Header Blank

I need to overwrite the existing REST API using .NET (originally written with Ruby). From the point of view of the client, it should work just like the old API, that is, the client code should not be changed. The current API requires basic authentication. Thus, to call the old API, it works fine: -

var wc = new System.Net.WebClient(); var myCache = new CredentialCache(); myCache.Add(new Uri(url), "Basic", new NetworkCredential("XXX", "XXX")); wc.Credentials = myCache; var returnBytes = wc.DownloadData("http://xxxx"); 

(I had to trick the real URL / username / password, etc. for security reasons).

Now I am writing a new API using ASP.Net Web API with MVC4. I have a strange problem and I cannot find someone else with exactly the same problem. To support basic authentication, I followed the recommendations here:

http://sixgun.wordpress.com/2012/02/29/asp-net-web-api-basic-authentication/

One thing, I put the code in the β€œhook in handler” in the Global.asax.cs file in the Application_Start () event (this was not explained, so I guessed it).

In any case, if I call my API (which I deployed in IIS) using the above code, the authorization header is always null, and the above does not work with 401 Unauthorized. However, if I manually configure the header using this code, it works fine - that is, the authorization header exists and I can authenticate the user.

  private void SetBasicAuthHeader(WebClient request, String userName, String userPassword) { string authInfo = userName + ":" + userPassword; authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo)); request.Headers["Authorization"] = "Basic " + authInfo; } ....... var wc = new System.Net.WebClient(); SetBasicAuthHeader(request, "XXXX", "XXXX"); var returnBytes = wc.DownloadData("http://xxxx"); 

Although this works, I feel bad because existing users of the existing API will not manually configure the header.

Considering how basic authentication works, the initial request should be anonymous, then the client returns 401, then the client must try again. However, if I set a breakpoint in my code, it will never hit the code again in Anthony's example. I expected my breakpoint to be deleted twice.

Any ideas how I can make this work?

+7
source share
1 answer

You expect the right behavior. System.Net.WebClient does not automatically include authorization headers on initial request. It sends them only when the dispute is correctly challenged, which, as far as I know, is a 401 status code and the corresponding WWW-Authenticate header. See here and here for more details.

I assume that your primary authentication handler does not return a WWW-Authenticate header, and therefore such a WebClient never tries to send credentials on the second request. You should be able to watch this in Fiddler or a similar tool.

If your handler did something similar, you should see how the WebClient approach works:

 //if is not authenticated or Authorization header is null return base.SendAsync(request, cancellationToken).ContinueWith(task => { var response = task.Result; response.StatusCode = HttpStatusCode.Unauthorized; response.Headers.Add("WWW-Authenticate", "Basic realm=\"www.whatever.com\""); return response; }); //else (is authenticated) return base.SendAsync(request, cancellationToken); 

As you noticed, if you include authorization headers for each request (as in your alternative approach), your handler already works as it is. Thus, this may be enough - it is just not for WebClient and other clients that work the same way.

+9
source

All Articles