12

I have a BasicAuthenticationAttribute that inspects the Authorisation header in the request but despite it being present, it still believes the Authorisation header is null:

public class BasicAuthenticationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (actionContext.Request.Headers.Authorization == null)
        {
            actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
        }

        ...

If I inspect actionContext.Request.Headers I can see Authorization listed:

{Connection: Keep-Alive
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-gb
Authorization: REDACTED_BUT_PRESENT==
Host: localhost:44300
Referer: https://localhost:44300/
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3; .NET4.0E)
}

Update

I have just inspected the full request headers and they look like this... I can see an Authorization header in the first section, but the Authorization header in the second section is clearly null.

request.Headers

{Connection: Keep-Alive
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-gb
Authorization: REDACTED_BUT_PRESENT==
Host: localhost:1734
Referer: http://localhost:1734/
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3; .NET4.0E)
}
    base {System.Net.Http.Headers.HttpHeaders}: {Connection: Keep-Alive
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-gb
Authorization: VXNlcjpQYXNzd29yZA==
Host: localhost:1734
Referer: http://localhost:1734/
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3; .NET4.0E)
}
    Accept: {*/*}
    AcceptCharset: {}
    AcceptEncoding: {gzip, deflate}
    AcceptLanguage: {en-gb}
    Authorization: null
    CacheControl: null
    ... removed for brevity ...
    Warning: {}
JackPoint
  • 3,705
  • 1
  • 28
  • 41
Fenton
  • 206,497
  • 63
  • 356
  • 369
  • are you trying Basic authentication. – satish Oct 11 '12 at 12:52
  • @satish - yes - so I'm setting the Authorisation header and inspecting it using my Action Filter. – Fenton Oct 11 '12 at 13:44
  • I have made a Message handler and it seems to work fine. I will try with action filter also. Can you check if this helps https://gist.github.com/3872727 -Handler ,https://gist.github.com/3872715 - Unit Test – satish Oct 11 '12 at 14:26
  • This essentially is the same for me - I can see the Authorization header just as posted, but in the Message Handler it thinks that `request.Headers.Authorization` is null. Let me inspect the headers generated by the unit tests and see if it looks different. – Fenton Oct 11 '12 at 15:15

5 Answers5

13

If you get stuck on this, you can get the header using:

var header = request.Headers.FirstOrDefault(h => h.Key.Equals("Authorization"));

But not via

var header = request.Headers.Authorization;
JackPoint
  • 3,705
  • 1
  • 28
  • 41
Fenton
  • 206,497
  • 63
  • 356
  • 369
8

I noticed myself that if the Authorization-header only contained the key/token, the request.Headers.Authorization wouldn't be initiated properly because it's looking for a scheme as well in the format <Scheme> <key/token>, i.e. Authorization: Token VXNlcjpQYXNzd29yZA==, then the Authorization wouldn't be null anymore and contain request.Headers.Authorization.Scheme = "Token" and request.Headers.Authorization.Parameter = "VXNlcjpQYXNzd29yZA=="

finstas
  • 91
  • 1
  • 3
5

I've posted my own example of a Basic Authentication Attribute. Maybe this gives you some hints.

I use:

HttpContext.Current.Request.Headers["Authorization"];

And here is the link to the complete solution:

http://remy.supertext.ch/2012/04/basic-http-authorization-for-web-api-in-mvc-4-beta/

JackPoint
  • 3,705
  • 1
  • 28
  • 41
Remy
  • 11,899
  • 13
  • 60
  • 97
  • Be aware though that in case of Web API, the HttpContext.Current can be null at times for older versions of .NET or for projects upgraded from an older version: http://stackoverflow.com/questions/24956178/using-httpcontext-current-in-webapi-is-dangerous-because-of-async. – Sudhanshu Mishra Feb 14 '16 at 11:16
1

Though, this thread is very old but it might help others if I share how did I resolve it in my case:

Request should contain

Authorization: Basic VXNlcjpQYXNzd29yZA==

instead of:

Authorization: VXNlcjpQYXNzd29yZA==

so following change in request may solve the problem:

client.Headers.Add("Authorization", "Basic VXNlcjpQYXNzd29yZA==");
ATTA
  • 269
  • 3
  • 7
0

Adding more information to @finstas's answer.

Authorization is null because well defined HTTP headers like Accept, Authorization and many more are parsed when creating the HttpRequestHeaders class. Hence if the request comes in with a format different from what .NET accepts for that header then that specific property will be null.

Below is the decompiled code from the AuthenticationHeaderValue class responsible for parsing the Authorization header. Similarly there are other classes for the different HTTP headers which do the same.

Hope this sheds more info into why there needs to be a space between Token and the value.

internal static int GetAuthenticationLength(string input, int startIndex, out object parsedValue)
{
  parsedValue = (object) null;
  if (string.IsNullOrEmpty(input) || startIndex >= input.Length)
    return 0;
  int tokenLength = HttpRuleParser.GetTokenLength(input, startIndex);
  if (tokenLength == 0)
    return 0;
  AuthenticationHeaderValue authenticationHeaderValue = new AuthenticationHeaderValue();
  authenticationHeaderValue.scheme = input.Substring(startIndex, tokenLength);
  int startIndex1 = startIndex + tokenLength;
  int whitespaceLength = HttpRuleParser.GetWhitespaceLength(input, startIndex1);
  int index = startIndex1 + whitespaceLength;
  if (index == input.Length || (int) input[index] == 44)
  {
    parsedValue = (object) authenticationHeaderValue;
    return index - startIndex;
  }
  if (whitespaceLength == 0)
    return 0;
  int startIndex2 = index;
  int parameterEndIndex = index;
  if (!AuthenticationHeaderValue.TrySkipFirstBlob(input, ref index, ref parameterEndIndex) || index < input.Length && !AuthenticationHeaderValue.TryGetParametersEndIndex(input, ref index, ref parameterEndIndex))
    return 0;
  authenticationHeaderValue.parameter = input.Substring(startIndex2, parameterEndIndex - startIndex2 + 1);
  parsedValue = (object) authenticationHeaderValue;
  return index - startIndex;
}
Vignesh
  • 464
  • 4
  • 13