HttpActionContext.Request.Headers.Authorization is null - c#

I am using asp.net mvc 4 rest and write my own basec authentification logic.
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization == null)
{
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
}
else
{
//do staff here
}
}
It works on local iis. But it does not work on producation station. I always get null. I set basic authentification enabled on IIS. I am testing with Fiddler and my request looks like that:
User-Agent: darwin/1.0 CFNetwork/548.1.4 Darwin/11.0.0
Authorization: Basic cmFkaWt2b3N0b2tAZ21haWwuY65tJjE6QkFBREVEcHlQYmtjQkFOcXh4UmFrdG1JMUJ2bjBPYXVQVk9NcnFZMEg4V3BhakljSlk2WkJMTWtra1FIWHFrcEZmdEkyNmFEZEppYWlKVVZJOTZpUGJuMzRMc1luemJHM2FPV3paQk5DTG1Xak9FZGU3YTdGWVhVem1QeTlEWkM4cW02YWZoWkJGWkIzbGFXMTNaQjlKdQ==
Content-Length: 10128
Accept: application/json
Content-Type: application/json
Connection: keep-alive
Host: 192.168.7.4
Does anybody know why it happens?

First of all, implement OnAuthorization() instead of OnActionExecuting(). OnAuthorization() is executed prior to OnActionExecuting(). It's important to check for authorization even before the user reaches OnActionExecuting() codes.
But your answer: the most possible situation is that the <authentication> is set to "None" in production web.config file. Change it as follows and you'll be all set:
<authentication mode="Forms"/>

Related

.NET Core WebAPI / Angular project - Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response

I've been battling this issue now for around 30 hours, and I just cannot seem to get by it. I'm having an issue with CORS in a .NET CORE 3.0.1 WebAPI project throwing the following error when called by my Angular project:
Access to XMLHttpRequest at 'http://localhost:4200/#/emailverified'
(redirected from 'http://localhost:5000/api/auth/forgotpassword') from
origin 'http://localhost:4200' has been blocked by CORS policy:
Request header field content-type is not allowed by
Access-Control-Allow-Headers in preflight response.
I have CORS setup in my startup.cs file as follows:
ConfigureServices method in Startup.cs:
services.AddCors(options => options.AddPolicy("CorsPolicy", p => p
.WithOrigins("http://localhost:4200")
.AllowAnyMethod()
.WithHeaders("content-type")
.AllowCredentials()
));
Configure method in Startup.cs:
app.UseCors("CorsPolicy");
The API Call that is being made from the Angular service
resetpassword(model: any) {
return this.http.post(this.baseUrl + 'forgotpassword', model);
}
The controller:
[AllowAnonymous]
[EnableCors("CorsPolicy")]
[HttpPost("forgotpassword")]
public async Task<IActionResult> ForgotPassword(SendPasswordResetDto sendPasswordReset)
{
if (sendPasswordReset.Email == null)
{
return NotFound("Please enter a valid email address");
}
var user = await _userManager.FindByEmailAsync(sendPasswordReset.Email);
// If the email does not exist, return null
if (user == null)
{
return Redirect($"{_configuration["ViewUrl"]}/#/emailverified");
}
// If the user email does exist, create a password reset token and encode it in a browser friendly way
var forgotPasswordToken = await _userManager.GeneratePasswordResetTokenAsync(user);
var encodedToken = Encoding.UTF8.GetBytes(forgotPasswordToken);
var validToken = WebEncoders.Base64UrlEncode(encodedToken);
// Send an email to the user with the reset email link
string url = $"{_configuration["ViewUrl"]}/#/changepassword?email={user.Email}&token={validToken}";
await _MailRepository.SendEmailAsync(user.Email, "Password Reset", $"<h1>You have requested to reset your password.</h1> <p>Please click <a herf='{url}'>this link</a> to reset your password. If it does not work, please copy and paste this link into your browser " + url + "</p>");
return Redirect($"{_configuration["ViewUrl"]}/#/emailverified");
}
And lastly these are the headers being sent with the request:
Request URL: http://localhost:4200/
Request Method: OPTIONS
Status Code: 200 OK
Remote Address: 127.0.0.1:4200
Referrer Policy: no-referrer-when-downgrade
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Cache-Control: no-cache
Connection: keep-alive
Host: localhost:5000
Origin: http://localhost:4200
Pragma: no-cache
Referer: http://localhost:4200/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36
I seriously cannot get past this and it is driving me absolutely nuts. Is there something I am missing here? I have added the "content-type" header to the CORS policy directly, but it just ignores it. I have searched high and low, and attempted about 2 dozen different ways of setting this up in my project. I've also tried clearing browser cache and using different browsers that have not been used on this project yet in case the cache was affecting it, and looking at the placement of app.UseCors("CorsPolicy") within the configure method, nothing seems to be getting this to work.
Is there something anyone can spot that I have missed?
CORS seems to work just fine everywhere else within the project except when using the following statement.
return Redirect($"{_configuration["ViewUrl"]}/#/emailverified");
So after fighting with this for the better part of a week, I have decided not to use the redirect return statement in the controller and instead just let the front end angular project handle the redirect based off of the value of the return from he API.

Web api behaves "stateful" in some successive calls from different client issue

I have a web api consumed by mobile apps. I can reproduce case with postman also with appropriate params.
Here are my postman call captured by fiddler:
GET http://localhost/WebApi/api/User/GetAnnouncement?id=22 HTTP/1.1
Content-Type: application/json
ApiKey: someKey
AuthenticationToken: someGuid1
UserId: 6524
DeviceId: someGuid2
LocalDate: 538294155.662561
OsTypeId: 1
LoginToken: someGuid3
CompanyId: 2
cache-control: no-cache
Postman-Token: b863afdd-b04c-4a4d-b473-69d5ecef622e
User-Agent: PostmanRuntime/7.4.0
Accept: */*
Host: localhost
cookie: ASP.NET_SessionId=nk4g3zzfyi0n3xomfw5dxxxx
accept-encoding: gzip, deflate
Connection: keep-alive
and my issue occurs in authorize action filter:
public class BasicAuthorizeAttribute : FilterAttribute
{
}
public class BasicAuthorizeFilter : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
//!!!HERE when I debug, in watch I can see already authHeader has value "in some calls"
System.Threading.Thread.SetData( System.Threading.Thread.GetNamedDataSlot("authHeader"), "someValueComingFromRequestHeader" );
}
}
At the very beginning of the OnAuthorization (see !!!HERE line in the code), I can see in watch this expression:
System.Threading.Thread.GetData(System.Threading.Thread.GetNamedDataSlot("authHeader"))
has the value even though I expect it is always null. It has even the value from previous client.
Actually issue come to as a bug "session" mingled (I mean mixed).
This pieces code is on the my company's framework so something is weirdly wrong.
I can give as much as I can so far. Please ask any info necessary.
What could be the cause?
I am daring to ask this because it is possible the issue obvious may be.
Note: I have the same case while none debugging with two phones connected to my pc via proxy settings.

100K sized POST requests don't get to webAPI?

I'm using Fiddler (or post manager) to invoke requests to my WebApi. ( it's hosted as an ASP.net application in IIS)
This is the service :
[HttpPost]
[ActionName("uploadRessources")]
[AllowAnonymous]
public HttpResponseMessage uploadRessources(ResourcesJson json)
{
...
return Request.CreateResponse(HttpStatusCode.OK, result);
}
For short length body( 3 rows of data) length post data requests like :
POST http://something.com/api/services/uploadRessources HTTP/1.1
Cache-Control: no-cache
Connection: keep-alive
Pragma: no-cache
Accept: application/json
Accept-Encoding: gzip
Accept-Language: he-IL
User-Agent: Mozilla/5.0
Content-Length: 451
Content-Type: application/json
Host: es.com
{ "l":
[{"MasterEntity":2,"screen":"ConfirmHealthDetailsPage","Lbl":"ApproveTheFollowingDetails","enus":"Approve the Following Details:","device":"mobile","description":"NULL"},
{"MasterEntity":2,"screen":"ConfirmHealthDetailsPage","Lbl":"PersonalDetails","enus":"Personal Details","device":"mobile","description":"NULL"},
{"MasterEntity":2,"screen":"FingerPrintResources","Lbl":"CANCEL","enus":"CANCEL","device":"mobile","description":"NULL"}]
}
I DO get a successful response :
HTTP/1.1 200 OK
But for a long body length request ( 101K ) -
It is stuck (it even doesn't hit the breakpoint in my code , while in short request - it does )and I never see a response :
BTW - If later I do run again the short body length request( while still waiting for the previous large requests) - I do get 200 ( for the short length request).
In web.config I did set :
<httpRuntime enableVersionHeader="false" executionTimeout="100000000" maxRequestLength="999999999" />
In IIS : No requests filters
In Event Viewer - I don't see any exceptions or warnings
IIS version : 6.1 ( windows 7) - but it also happens at our server.
Question
Why doesn't my 101k length request - get to my webapi ?
Edit
I've found that it happens for >65k requests. Still don't know what is the problem
It's seems to be an issue with your serializer, tries to put a breakpoint there and see if hits it. If you are not using a custom serializer, creates one temporally just to see what's happen with your request.
It was stuck on request.Content.ReadAsStringAsync().Result ( and never released). Strange but setting it to async , solved the problem. I still don't know why. In General this is the solution - the left pane was the problematic one while the right pane is the working one. ( I must say that the left pane used to work , but after upgrading to 4.6.2 - it started doing problems) - Again - I don't know why

Return a custom response body for 401 with Windows Authentication with MVC under IIS

I'm currently working on an MVC app which has a particular URL which must be protected by Windows (NTLM) authentication.
Currently I have set up that particular URL to use Windows Authentication under IIS. This works, but I get the default HTML response:
401 - Unauthorized
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate,NTLM
X-Powered-By: ASP.NET
Date: Fri, 06 Dec 2013 14:53:11 GMT
Content-Length: 6347
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>IIS 7.5 Detailed Error - 401.2 - Unauthorized</title>
<!-- bla bla bla -->
</html>
I want this exact response - headers and whatnot as they are - but with a different body and content type, a bit like the following:
401 - Unauthorized
Cache-Control: private
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate,NTLM
X-Powered-By: ASP.NET
Date: Fri, 06 Dec 2013 14:53:11 GMT
Content-Length: <whatever>
{ "message": "Bummer, you're not authenticated" }
This seems almost impossible to achieve without screwing up all the headers (and probably causing the whole challenge/response to never even happen). This question seems to imply it just isn't doable at this level, which I find hard to believe but it is all happening a bit early so it makes sense.
My ideal solution would be to have the NTLM authentication logic to be handled inside my application instead of by IIS, but I know of no way to do this:
[WindowsAuthentication] // this filter would be under my control or customisable
public ActionResult ExampleWindowsAuth() {
// all my stuff
}
The problem here is that NTLM authentication is not the most straightforward, and re-inventing the whole thing seems a little daft.
Can someone point me in the direction of a solution?
I did something similar by implementing my own class inheriting from ActionFilterAttribute and perform validation in there (in this case, checking the current user was in an AD group). By overriding the OnActionExecuting method, you have access to the HttpActionContext and I think this happens early enough in the process for what you're trying to achieve. You can then throw an HttpResponseException and include a custom message like so:
var msg = string.Format("User {0} attempted to use {1} but is not a member of the AD group.", id, actionContext.Request.Method);
_logger.Info(msg);
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent(msg),
ReasonPhrase = msg
});
Hope this helps! There is a walkthrough on MSDN here

Web APi Void, IIS express content type, IIS no content Type

Okay, so I have a web api controller with put action and a return type of void. When I run it using VS's builtin iisepxress and call it, I get back a 204 as expected. The here are the headers:
Cache-Control no-cache
Connection close
Content-Type text/html
Date Thu, 10 Oct 2013 19:33:43 GMT
Expires -1
Pragma no-cache
Server Microsoft-IIS/8.0
X-AspNet-Version 4.0.30319
X-Powered-By ASP.NET
When I put the exact same code in our sbx environment, I get a 204, but with the following headers:
Cache-Control no-cache
Date Thu, 10 Oct 2013 19:39:59 GMT
Expires -1
Pragma no-cache
Server Microsoft-IIS/7.5
X-AspNet-Version 4.0.30319
X-Identifier 17253
X-Powered-By ASP.NET
The pertinent difference being the lack of contentType in the second one.
The problem this creates is that in firefox (and IE I think) it defaults to xml, tries to parse it and fails.
I know how to fix this by setting my contentType in my web api controller, but that doesn't seem like the best fix to me.
So, what I'm asking is what setting difference in IIS might be causing this?
Thanks
Note:
My url looks like this /foo/bar/2 so it isn't mimetype.
If your service is responding with a 204, the response should not contain a message-body. This is by spec. I can only assume you are responding with something in your message body.
Your response from the API method should be like this:
return new HttpResponseMessage { StatusCode = System.Net.HttpStatusCode.NoContent }
Edit. I noticed you mentioned you return "void". Your method should return HttpResponseMessage with the StatusCode I noted above.
That will solve the isssue:
protected internal virtual IHttpActionResult NoContent()
{
HttpResponseMessage responseMsg = new HttpResponseMessage(HttpStatusCode.NoContent) {Content = new StringContent(string.Empty, Encoding.UTF8)};
return this.ResponseMessage(responseMsg);
}
But still doesn't explain why IIS is adding by default:
Content-Type text/html
Or even better how to remove it using web.config or IIS config.
I use this:
Return StatusCode(HttpStatusCode.NoContent);

Categories