asp.net mvc 2 -- losing authorization when RedirectToAction with JSON data - asp.net-mvc

I'm refactoring some MVC code that originally used POST'ed form data. The form's fields are serialized using jquery's serialize() method and sent to an MVC controller Save Action that checks things out and redirects as appropriate (if errors in form values, redirect to the Edit Action, if fine then save and redirect to the Display Action). All actions are invoked via AJAX and return Partial Views. Everything works grand. Note: The site uses AD-based authorization, so users are prompted for their windows credentials upon first loading the site, but are never prompted again.
However, I'm now looking to interact with the server via JSON objects instead of form fields. Granted, I serialize the JSON object on the client and, with the aid of an imported MVC2 Futures/MVC3 class JsonValueProviderFactory, am able to correctly model bind the sent JSON object to a C# class in the Controller's parameters.
I maintain the same logic, but things start to blow up when I try to return a RedirectToAction ActionResult when the Controller accepts JSON objects. I lose authentication, the user is prompted for their credentials again, and I find myself in a infinite loop on the originally requested Action (save). Every time the user is prompted for credentials and simply runs through the Save Action again. The end result for the user is an unending alerts prompting for login credentials. Neither of the actions specified in the RedirectToAction calls are ever hit.
Can the fact that the original request uses a JSON contentType be interfering with the behavior of RedirectToAction? That's the only thing I can think of as it works fine when I don't use JSON to post and it works fine when I return PartialViews instead of using RedirectToAction. The infinite repeat of the Controller Action and continual loss of authorization credentials seems to suggest that RedirectToAction is not the way to go in this situation.
I can post code on request. I am also successfully handling stuff like copying the ModelState over to TempData and other RedirectToAction tricks. Again, it DOES work when using a non-JSON solution. Any insight is greatly appreciated!!
EDIT WITH FOLLOW-UP INFO:
Turns out, I get an "Unauthorized" error even when I completely disable NTLM authentication/authorization for the site. IIS server doesn't look for any authorization, web site doesn't look for any authorization, yet the error when trying to Redirect with JSON contentType request still occurs and complains of being "Unauthorized". This is WEIRD.

To update everyone, I haven't found a solution nor do I know for-sure what the situation is. However, I'm willing to bet it has to do with the fact that RedirectToAction issues http GET requests and the action I'm redirecting to only accepts POSTs. Even if I remove the restriction, it's still sending JSON data and it still needs to be done by POST.
In short, RedirectToAction with JSON data appears to be fundamentally undoable. You need to POST JSON data but RedirectToAction emits GET requests. That's my going theory, at least. =)

Related

ASP.NET MVC cookies are not included in the response headers

I have an ASP.NET MVC 5 application where I'm trying to set a cookie. (Specifically, it's being done by a custom SessionIDManager.)
When I debug the code where the cookie gets set, it gets called as expected. When I look at the context after the controller action finishes, the cookie is in the response CookieCollection.
However, Fiddler & the browser show that the actual cookie is sometimes missing from the HTTP response headers.
It's consistent on a per-action basis; that is, some controllers/actions are fine, and others aren't, and it's always consistent as far as I can tell.
I don't see anything to distinguish the actions that succeed and those that don't - no difference in the attributes/filters/return type. (So it's not like the broken ones are trying to do Response.Redirect, etc.)
It's not a problem with the cookie setting code (trying to set it in the request instead of the response, etc.), or else it would never work. Does anybody have any suggestions for where else I could look to explain what's going on?
EDIT: While I can't recreate the success, I've recreated the failure in a new solution, which can be found here. My SessionIDManager gets called, I see the cookie in the response in the controller when I peek with the debug tools, but it doesn't actually make it into the HTTP response.

MVC public ActionResults accessiblity from URL - is it safe?

I have being programing in MVC for a couple of months, recently I've been requested to revisit our authorization mechanism.
There is an attribute that checks weather a user can access an action result, but this attribute doesn't appear above all the public actions. There are plenty of JsonResults and other ActionResult actions which can be accessed from the URL bar.
My question is weather its worth adding that attribute to all the action results
or make some sort of attribute that won't allow access to the action unless its an ajax request or a post?
There is no functional difference between a browser request and an ajax request, they both come through the same http pipeline. Matter of a fact, sometimes executed outside of the forms authentication scheme, so adding [Authorize] attribute could block valid requests as well.
I would create some sort of authorization that requires the use of a header value of some sort to distinguish access to your Json methods.
You could add the header to every ajax request that was passed, but that would be easily visible in a program such as Fiddler or Firebug. You could use constantly changing authorization keys, but I think the headache of overhead would be at a higher cost than the data you're likely trying to protect.
You could decorate your methods with [AcceptVerbs(HttpVerbs.Post)] but again, those can be easily remedied using a program like Fiddler or Postman (chrome add-on)
You can use Request.IsAjaxRequest to ensure that the request came from an AJAX request. This will verify that the X-Requested-With header is present in the request, which is not present in a request that is made via the address bar.
What is the threat that are you trying to guard against? Checking the above is good to stop casual users from reading your JsonResults but ultimately you cannot protect public ActionResults or JsonResults because if someone wants to capture your response they can simply make their own request using curl:
curl --header "X-Requested-With: XmlHttpRequest" www.example.com/controller/method

AJAX CSRF attacks and .Net MVC

This post describes a tokening system for all JSON HttpGet and HttpPost AJAX calls:
In short, you use the AntiForgeryToken attribute to create a token on the page, and then manually validate that that value is sent back to the controller via the AJAX call.
http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-(csrf)-attacks
After hours of internet sleuthing, there are always references to this possibility, but no one actually implements it. Instead the commonly repeated techniques are 1) using only HttpPost AJAX requests (which breaks REST), 2) wrapping all json responses in an anonymous object, which results in significantly inelegant code in .net MVC4, 3) using an unparsable cruf, which breaks common libraries such as backbone.js
So why aren't we all using the tokening system linked above? What am I missing?
If you're concerned about CSRF, and your concerned about REST and doing REST correctly, then you shouldn't be doing anything in a GET that would be affected by a CSRF, since the entire purpose of AntiForgeryTokens is to deal with changing data (ie, you can't use an AntiForgeryToken without first getting the page anyways that contains the token).
So, saying using POST "breaks REST" seems to be misunderstanding what you're using the token for in the first place. It's true that a GET can expose sensitive information, but you have to have some way to get the token first if you want to use it with GET.
The real problem with Ajax and AntiForgeryToken with json and Ajax is that the "built-in" validation only works with form values, not json. So you have to do the validation yourself, and that article you linked to gives a good explanation of how to do that.

In an ASP.NET MVC 3 application, how can I save the post data in the where their session times out

I have an ASP.NET MVC 3 application. The site involves people writing lengthy responses using a textarea in a web form. Occasionally, users are complaining that they are getting redirected to the log in form after they post their data. I am not sure exactly why they are getting logged out because the users do not typically provide enough information on their errors. I believe it is due either to a session time out or the application has been restarted for some reason. This is on a shared web hosting site and it does not have its own app pool.
In any case, regardless of the reason, I would like to capture that post data and save it to a db or text file. How can I get the post data and save it while the controller redirects the user to the login screen.
I know the long term plan would be to identify why the timeout is occurring. But for now I want to be able to grab the post data and recover it at a later time.
First, in order to avoid timeouts, I would recommend using client-side heartbeat solution (like http://plugins.jquery.com/project/Heartbeat)
Second, assuming that you are using forms authentication, in order to save posted data, when Forms Authorization Module is redirecting your users, you will need to intercept redirects in EndRequest HttpApplication event handler in Global.asax or your own module.
The way to intercept those requests is not that straightforward, since on "EndRequest" pipeline step you will see 302 HTTP status code (redirect instruction), not 401 (Unauthorized error). So you may check if request is not authenticated (HttpContext.User.Identity.IsAuthenticated) and request is redirected - in this case you may save what you see in the request.
Otherwise you would need to disable forms authentication and use some solution, which is closer to ASP.NET MVC.
one solution can be to put a javasscript timer which keeps on hitting the server after specified interval to keep session alive until u figure out the cause of session time out (only i its the session timeout problem)
If you want to stop the session from timing out, you can add a hidden iframe on the page. For example, create a new page called KeepSessionAlive and do this:
<meta http-equiv="refresh" content="600">
where content = seconds.
I don't know about MVC 3, but the way you can get and store the post values is to catch them before redirecting the user to the Login page.

How to detect if the user of a Silverlight app is logged into server?

I'm looking for a good clean solution to detecting whether a user has been logged out of an ASP.NET MVC application from Silverlight when performing a web request.
The problem is that the website has a Silverlight component that the user could potentially spend a large part of his time in, thus letting him get logged out of the website. Some of the actions in the Silverlight component triggers a web request to the server (using WebClient), generally getting a JSON result. But if the user has been logged out, the result I get is the HTML for the login page of the system (As the request is redirected).
I could check if the response is a valid JSON result, but if I need to introduce other response types later this will fail. I can also begin parsing the response stream to see if it contains elements from the login page but this seems very inelegant and fragile. Perhaps configure MVC somehow to respond to requests from a specific source by returning a know error response.
EDIT
Using Fiddler I found out that I could look for the 302 response code of the HTTP request. However, it turns out that you can't derive from the WebClient class in Silverlight, so I couldn't easily get to the status code. I considered using the WebRequest class instead but it seems a bit too low level for what I want to do. My current solution is to parse the first line of the response stream.
If you are using forms authentication with cookies, you could try to check to see if the cookie is present.
The following link shows how to access cookies in SL:
http://msdn.microsoft.com/en-us/library/dd920298(VS.95).aspx

Resources