How to secure a JsonResult? - asp.net-mvc

The very first part of this answer on another question explains how an existing MVC site can very quickly have added to it the ability to expose its data (e.g. to a Winforms app requesting the data), all for a couple of lines of code (without having to convert to WCF/Web API and add extra layers - our project is pretty small and basic):
public JsonResult GetCategoryList()
{
var list = //return list
return Json(list, JsonRequestBehavior.AllowGet);
}
So we've tested the above as a quick and easy solution and it's clearly very nearly working because in the stream we get the html source for our MVC app's login.
And indeed if we add the AllowAnonymous annotation we do get the Json stream that we're after.
However we don't want to allow anonymous, we want some protection. Have tried adding:
Dim nc As New NetworkCredential("username", "password")
request.Credentials = nc
just before firing request.GetResponse but that isn't working (this may be completely ignorant but it seemed worth a shot). When I say it isn't working, I mean we go back to getting the login page's html source in the stream.
So how to allow the winforms app to incude some kind of authentication (which will work) with its request for the data? As I say, getting the data is working (proved by AllowAnonymous).

You should separate the authentication code for the web application (the one returning the login) from the one that you are exposing the API.
Looks like you are using forms authentication for the WebSite part and you should keep it that way. However, in the public API GetCategoryList you should either implement a different authentication strategy with ActionFilters for example.

Related

Can you run an asp.net MVC web app inside an iframe?

My company has an asp.net mvc app that they want to run inside another webapp (probably React right now). If I just put the app inside an iframe( no react, just a static html page). It will render the inital page ok, but the first partial control fails because it cannot find the session keys.
public virtual UserModel LoggedInUser
{
get
{
return Session[SessionKeys.LOGGED_IN_USER] as UserModel; //THIS FAILS. No keys in the session
}
set
{
Session[SessionKeys.LOGGED_IN_USER] = value;
}
I'm not too suprised by this, but I don't know of a workaround. I tried a cookieless session to no avail (the app didn't run even outside the iframe). Would it help if the containing webpage was another mvc app? It seems the only option is to port all the razor pages over to react and refactor the controllers to not return view.
Any help is appreciated.
you may publish your application in another domain. thereby, you can serve it in the iframe. If you want to match with these two applications to use login, session, etc. then you can use Uniqidentifier in your query string so your MVC application would know which user sent the request

SessionSecurityTokenReceived called too many times

I have a Web Forms application which makes use of WIF and Claims based authorization. Im using Thinktecture IdentityServer v2.5 for my STS with my custom login page and custom authentication against database and then issuing the token.
Its all working fine at the moment and no issues, the only problem came when I was configuring Sliding Sessions as shown by Brock Allen in this post
http://brockallen.com/2013/02/17/sliding-sessions-in-wif-with-the-session-authentication-module-sam-and-thinktecture-identitymodel/
My problem is that the event mentioned in the post SessionSecurityTokenReceived is getting called too many times per page load. I just wanted to know what is the reason behind that and could this be a performance hit ?
I'm doing something similar and have come across the same issue. It is because the event is called for every single resource the page consumes (css, js, etc) that is also secured by the web application. In global.asax.cs, in the event, if you insert the line...
var requestContext = HttpContext.Current.Request.RequestContext.HttpContext.Request;
...and put a breakpoint on this line, you can observe this behavior by inspecting the value.

ASP.NET MVC - Forms Authentication interferes with video playback

I need to be able to support "auxiliary" content on a MVC (4) web site -- images, PDFs, videos, etc. Most of this content is provided by the customer using the site so it should not be accessible to unauthenticated users.
(We're using Forms Authentication to generate an authentication ticket. Note, we are not necessarily using the built-in membership/identity providers, as some of our customers want to use authenticate via other means e.g. a federated identity service.)
I've secured the static content by setting up the site to route/authorize all requests through ASP.NET (via runAllManagedModulesForAllRequests) as described here.
I found that I needed to allow anonymous access to the Content and Scripts folders (via location) ... but this configuration works for most content types.
It does not however work for video content, specifically in Internet Explorer. Media Player comes up but reports that it cannot play the file. "The player might not support the file type or coded that was used to create the file."
(Interestingly enough, there's no error in Chrome or Firefox. The video plays in a new tab.)
I'm fairly certain it's Media Player that is the issue. If I add a location element and allow anonymous access to the video, it plays just fine. And we've had similar problems in the past where the root cause ultimately turned out to be security- / authentication- related.
But obviously I can't change Media Player. And I have to support IE. So ... does anyone know of a way to work around this issue programmatically in ASP.NET MVC? Any help would be appreciated.
I seem to recall seeing an SO post about sending the authentication information not just with HTTP requests. I can't locate that post now. But according to Fiddler the request is in fact an HTTP GET. And we're not sending an authentication header, but we are sending an authentication cookie.
Update:
I thought I would be able to adapt the answer to this question.
It involves appending a flag and the authorization cookie value to the content URL, and hooking in to the Application_BeginRequest event.
In the view:
var asset = ...;
var authToken = Request.Cookies[FormsAuthentication.FormsCookieName].Value;
var assetUri = string.Format("~/Media/{0}?requireAuthSync=true&token={1}",
asset.ID, Url.Encode(authToken));
Then in Global.asax.cs:
protected void Application_BeginRequest()
{
if (!string.IsNullOrEmpty(Context.Request["requireAuthSync"]))
{
AuthCookieSync();
}
}
private void AuthCookieSync()
{
var authParamName = "token";
var authCookieName = FormsAuthentication.FormsCookieName;
try
{
if (!string.IsNullOrEmpty(Context.Request[authParamName]))
{
var authCookieValue = Context.Request.QueryString[authParamName];
var authCookie = Context.Request.Cookies.Get(authCookieName)
?? new HttpCookie(authCookieName);
authCookie.Value = authCookieValue;
Context.Request.Cookies.Set(authCookie);
}
}
catch
{
}
}
Using this approach, the video does in fact play in IE.
However, it's now possible to bookmark the video (or other content) and use the bookmark to access the content without being authenticated ... so the site security is effectively broken.
So it seems, in order to preserve site security, I shouldn't be creating the cookie if it doesn't already exist. But with Media Player, creating the cookie is the only way to get the video to play. I appear to be stuck in a Catch-22.
Any insight would be much appreciated.
so the site security is effectively broken
First of all, the site is not broken. Although a user can tag it, the forms cookie will expire (depending on the token validity time you set when you issue the cookie) and the link will stop to work.
But then, note that you don't really have to pass the forms authentication cookie value as the token in the query string.
You could for example generate one-time GUID-like tokens and the very first time the token is used, it is marked at the server side and cannot be used again. Or even you could somehow encrypt or sign the token validitity time in the token so that the link is valid for a short period of time but the token is independent on the forms cookie but you don't need an auxiliary storage of used tokens.

Asp.net MVC Pass onetime authentication to controller through Url.Action()

Background
I have an ASP.net MVC 4 web application with Forms authentication and a custom AuthorizeAttribute controlling access to all controllers minus the login screen. I am adding to some of the controllers, an action that allows the user to download a server generated PDF whose content and layout is being defined in a Razor View.
To carry out the conversion between Html and PDF, im using a trial version of ABCPdf9 and the bulk of the conversion works perfectly with all CSS, Text, static images, etc being displayed as required.
The problem is that I have images in the HTML that must also be rendered into the PDF file, but these images come from a controller which requires authentication.
Since the Html to PDF conversion takes place in ABCPdf using the Gecko engine, the existing user authentication cookies, etc are not available and as such the GET requests to the Image Controller are not authenticated and will not return anything. (This is the problem).
What I've discovered
From the research I have done, I came across the HttpAdditionalHeaders Property of ABCPdf which (from my understanding) is there to allow you to set header cookies, etc that will be sent with the requests made by the Gecko engine when fetching resources.
I have spent a good few hours trying to set the existing cookies from the originating request and pass them through to ABCPdf but this does not appear to work. Nor does creating a new set of authenticated cookies and pass them either.
So from what I gather, this solution is not possible....
My question
Does anyone know if it is possible to modify the Url.Action helper so it will generate and include a one-time authentication key in the url? Then implement some code in my custom AuthorizeAttribute that strip the key parameter and if valid, provide an alternative method of authentication to access the necessary image controller. This way, I can run the ABCPdf conversion process and it will be able to access the normally restricted resources in the image controller.
For example:
<img src="http://somesite.com/Image/Retrieve/1234?key=WFD6312DFV154WHSF3B1SGB69SB" />
The custom AuthorizeAttribute code should then recognise the key parameter passed in the requests query string and then bypass existing authentication processes.
Any help or even suggestions for where to look would be greatly appreciated!

MVC3 mixed forms and Windows authentication

I currently have an intranet site that is accessed by external customers. I therefore set this up using Forms Authentication. However the powers that be (my bosses) want all our domain users to not have to enter their username and password to access the site.
I've done a bit or reading and everything seems to point to setting up a WinLogin.aspx page that you alter to use WindowAuthenthication and then redirect from there.
I have a problem with this as I don't like the idea of putting an aspx form in my mvc application.
Can anyone tell me how to achieve mixed authentication using a strictly MVC Controller/Action setup without a second application?
NOTES: running MVC 3 on an IIS 7 box.
Forms Authentication is not related to the URL or physical structure of your files. What matters is that a URL should ultimately map to a physical (or virtual) resource on the server, and be processed, and be returned back to the user.
Thus, somewhere in between for each incoming call (each HTTP request, even those for CSS and JavaScript files), you have to see if the current user has enough permission to access it or not. If no, then you might redirect him to the login page.
If you want, you can have a URL like /user/windowslogin where user is the name of the controller, and windowslogin is the name of your action method. Then you can create a custom authentication attribute (something like [WindowsAuthentication]) on your windowslogin action, and in that attribute (which is an MVC filter in essence), you can see if the current request comes from within your domain, and if so, talk to Active Directory for authentication or stuff like that, and on case of successful authentication, create an authentication cookie using FormsAuthentication class, and the rest of the story.
However, I don't think this would be an easy task. Others might introduce better solutions.

Resources