ASP.NET Web API Basic Authentication Authorisation Header - authorization

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: {}

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;

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=="

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/

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==");

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;
}

Related

How do I deserialize to object with default formatter in net core 5 webapi when supporting multipart/form-data?

If I make a typical controller and action, with a parameter that comes from the body, the webapi will deserialize the body content into an instance of the class type using the appropriate deserializer, based on the content-type header:
[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
[System.Runtime.Serialization.DataContract]
public class MyObject
{
[System.Runtime.Serialization.DataMember]
public string Text { get; set; }
}
[HttpPost()]
public void Test([FromBody] MyObject value)
{
}
}
If I make a request to it, the request looks like this if using json:
POST https://localhost:44380/Message HTTP/1.1
Host: localhost:44380
Connection: keep-alive
Content-Length: 22
accept: */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Content-Type: application/json
Referer: https://localhost:44380/swagger/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
{"Text":"123 abc 123"}
Or this if xml (my web api is set up to support json and xml):
POST https://localhost:44380/Message HTTP/1.1
Host: localhost:44380
Connection: keep-alive
Content-Length: 82
accept: */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Content-Type: application/*+xml
Referer: https://localhost:44380/swagger/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
<?xml version="1.0" encoding="UTF-8"?>
<MyObject>
<Text>string</Text>
</MyObject>
If I am changing my webapi to use multipart mime, I can't rely on the automated deserialization of the content body. As I loop through each part, how would I deserialize each sections content based on the content-type header and the configured formatters of the webapi? I could hard code a specific serializer but I'd like to use what's configured.
var boundary = HeaderUtilities.RemoveQuotes(Request.ContentType.Boundary).Value;
MultipartReader reader = new MultipartReader(boundary, HttpContext.Request.Body);
var section = await reader.ReadNextSectionAsync();
while (section != null)
{
ContentDispositionHeaderValue contentDispositionHeaderValue = section.GetContentDispositionHeader();
Stream strData = null;
if (contentDispositionHeaderValue.IsFileDisposition())
{
FileMultipartSection fileSection = section.AsFileSection();
strData = fileSection.FileStream;
fileName = fileSection.FileName;
name = fileSection.Name;
}
else if (contentDispositionHeaderValue.IsFormDisposition())
{
FormMultipartSection formSection = section.AsFormDataSection();
name = formSection.Name;
strData = section.Body;
}
//How to deserialize strData to MyObject using the webap's configured formatters?
section = await reader.ReadNextSectionAsync();
}

How to handle Compressed Request in WCF service

We have a WCF REST service hosted on IIS 7 with .NET Framework 4.5. The client is sending data in GZip compressed format with request headers:
Content-Encoding:gzip
Content-Type: application/xml
But we are getting bad request from the server, if the request is in compressed format. We enabled Request compression by implementation of IHttpModule that will filter/modify incoming requests. From my understanding, this is failing because WCF uses original content length (that of compressed data) instead of Decompressed data. So here are my questions:
Is there any way we can fix this content length issues in IIS7/.NET 4.5? My HTTP module implementation is given below:
httpApplication.Request.Filter = New GZipStream(httpApplication.Request.Filter, CompressionMode.Decompress)`
If fixing the content length issue is not possible at server side, is there any way I can send original content length from client with a compressed request? Client side implementation is as follows:
using (Stream requeststream = serviceRequest.GetRequestStream())
{
if (useCompression)
{
using (GZipStream zipStream = new GZipStream(requeststream, CompressionMode.Compress))
{
zipStream.Write(bytes, 0, bytes.Length);
zipStream.Close();
requeststream.Close();
}
serviceRequest.Headers.Add("Content-Encoding", "gzip");
}
else
{
requeststream.Write(bytes, 0, bytes.Length);
requeststream.Close();
}
}
I was able to get gzip working in WCF using wsHTTPBinding and this as the base of the web request:
private HttpWebRequest GetWebRequest()
{
dynamic objHTTPReq = (HttpWebRequest)WebRequest.CreateDefault(_URI);
objHTTPReq.ContentType = "text/xml; charset=\"utf-8\"";
objHTTPReq.Method = "POST";
objHTTPReq.Accept = "gzip, deflate";
objHTTPReq.UserAgent = "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; InfoPath.2; OfficeLiveConnector.1.3;OfficeLivePatch.0.0; Zune 3.0; MS-RTC LM 8)";
objHTTPReq.Headers.Add("SOAPAction", "http://xxx.yyyy.zzzz");
return objHTTPReq;
}
So give that a try. Good luck.

How can I replace the 'Accept' http header in AS3

all
I send a http request from flash client(AS3) to a RESTFull service. The server side response json or xml data depend on the 'Accept' parameter in http header. But, I always accept xml format data even if I set the 'Accept' to 'application/json' in the client side. With wireshark I found that there are double 'Accept' parameter in the http header. Can somebody tell me why ? And/or how to get out of this.
POST /psplatform/rest/szdata/all HTTP/1.1
Host: 203.175.156.88:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:26.0) Gecko/20100101 Firefox/26.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-type: application/json
Accept: application/json
Content-length: 8
public function reload():void{
data = new Object();
new URLLoader(createJSONURLRequest("http://203.175.156.88:8080/psplatform/rest/szdata/all")).addEventListener(Event.COMPLETE, loaderCompleteHandler);
}
private function createJSONURLRequest(url:String):URLRequest{
var urlRequest:URLRequest = new URLRequest(url);
urlRequest.method = URLRequestMethod.POST;
urlRequest.contentType = "application/json";
//var urlVariables:URLVariables = new URLVariables("{}");
urlRequest.data = "{name:0}";
urlRequest.requestHeaders.push(new URLRequestHeader("Accept", "application/json"));
return urlRequest;
}

Deserialize Key:Value pairs to Dictionary

I am working on deserializing data passed to a Microsoft Web API in MVC4 RC into objects of the following class:
public class EditorCreateEditSubmission
{
public string action { get; set; }
public string table { get; set; }
public string id { get; set; }
public Dictionary<string, string> data { get; set; }
}
Whenever a Web API method gets data which should map to the EditorCreateEditSubmission, the "data" field is empty, like so:
(It's okay for Table and ID to be empty)
My controller method:
public EditorServerResponse Post(EditorCreateEditSubmission ajaxSubmission)
{
//...Handle data
}
The raw header:
POST http://localhost:64619/API/Species HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://localhost:64619/Manage/Species
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host: localhost:64619
Content-Length: 134
Connection: Keep-Alive
Pragma: no-cache
action=create&table=&id=&data%5Bamu%5D=1&data%5BchemicalFormula%5D=H&data%5BcommonName%5D=Hydrogen&data%5Bstatus%5D=N&data%5Bnotes%5D=
More readable view:
action create
table
id
data[amu] 1
data[chemicalFormula] H
data[commonName] Hydrogen
data[status] N
data[notes]
Do I need to manually create a class with get/set values every possible set of incoming values? It seems like deserialization of this data into a Dictionary should be straightforward, but I'm having some difficulty finding examples inthe new RC release of Microsoft's MVC4.
I don't think that the FormUrlEncodedMediaTypeFormatter does handle this.

GET webrequest parameters

I am sending a GET request to a site and would like to know what would be the proper way to do this based on the following parameters.
Host: www.somesite
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625
Firefox/3.6.6 GTB7.1 ( .NET CLR 3.5.30729; .NET4.0E)
Accept: text/javascript, text/html, application/xml, text/xml, /
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
X-Requested-With: XMLHttpRequest
X-Prototype-Version: 1.6.1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://www.somewebsite.com/search/
Content-Length: 19
Cookie: __some cookie
Pragma: no-cache
Cache-Control: no-cache
I did use firebug to get this and now am trying to create my own request header as follows:
webRequest = TryCast(System.Net.WebRequest.Create(url), HttpWebRequest)
Thread.Sleep(New TimeSpan(0, 0, 10))
'webRequest.Credentials = credentials
webRequest.Headers.Add("Cookie", cookielogin)
webRequest.Method = method__1.ToString()
webRequest.ServicePoint.Expect100Continue = True
webRequest.ContentType = "application/x-www-form-urlencoded"
webRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 GTB7.1 ( .NET CLR 3.5.30729; .NET4.0E)"
webRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
webRequest.KeepAlive = True
my url that I have shows in firebug post header the following parameters:
ajax 1
page 2
q item
Now I have included this in my get request since I need to retrieve multiple pages but I only get page 1 back. Am I missing something
Get firebug, you can view the request header and set your custom request header to/from server
I was able to resolve this; thanks for the response.
It involved placing parameters within the body of the request.