ASP.Net MVC ReturnUrl Practice - asp.net-mvc

I have a question about the returnUrl querystring parameter that is appended by ASP.Net when attempted to hit a page that requires authentication. In looking at Microsoft NerdDinner Sample's LogOn action (along with every other 'sample authentication code' I see on the 'net), it just has the ReturnUrl parameter declared in the action's signature and uses it directly in a Redirect() call. However, back in the WebForms days and using Membership Controls, we use to use the FormsAuthentication.GetReturnUrl() call. Besides returning the 'default url' if no url was specified in the querystring, it also does a few security checks (Cross App Redirect and 'IsDangerousUrl()'). Are those no longer a concern or are all the sample 'log on' actions I'm seeing all over the 'net just ignoring those issues?

I'm not sure about the samples that you've looked at, but it's entirely possibly to use Forms Authentication as is in MVC and benefit from the checks performed in The FormsAuthenticationModule processing (or using the FormsAuthentication class directly).
IIRC, the default MVC application in Visual Studio includes an adapter around forms authentication (AuthenticationService) which can be easily adapted to use the ReturnUrl querystring.
I imagine the samples in question have simply overlooked XSR attacks.

Related

How [Authorize] attribute get to know that the user is authenticate in ASP.NET MVC, is it by using authentication token?

I would like to know that how [Authorize] attribute recognize that this user is authenticate?
If user is valid then we call FormsAuthentication.SetAuthCookie() method and as per MSDN this method:
Creates an authentication ticket for the supplied user name and adds it to the cookies collection of the response, or to the URL if you are using cookieless authentication.
Is [Authorize] attribute checks authentication ticket or cookies collection?
[Authorize] does not deal with any authentication mechanism itself. It merely looks in the users IIdentity for the IsAuthenticated flag. It will also look in the users IsMemberOf method, for authorization based on roles.
All the work to decode the authentication ticket is done in the early stages of the app pipeline, which sets those flags. By the time the Authorization Attribute methods are called, all that work has already been done and is stored in the users runtime data.
You can easily check the source code for the Authorize attribute, and you will see that it's quite simple in nature. It just returns true or false based on some simple lookups.
It's become more complicated in .net core, where it's based on policies and what not, but the original MVC implementation was quite simple.
My answer relates to ASP.NET Core I'm not sure if you asked about classic ASP.NET but this should be similar.
There's a middleware that you have to add for [Authorize] to work. ASP.NET Core provides this middleware out of the box and you can add your custom authentication handlers too.
You can check how it's implemented by reading: https://github.com/aspnet/Security/tree/dev/src
For example you want to use JWT bearer authentication, you have to add JWT bearer middleware, this is simply extension of AuthenticationBuilder: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerExtensions.cs which calls AddScheme under the hood.
You want to use cookie based authentication you just call AddCookie which is also extension that calls AddScheme under the hood: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.Cookies/CookieExtensions.cs
Usage of it is documented here: https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x?view=aspnetcore-2.1
See also Using the [Authorize] Attribute
Web API provides a built-in authorization filter, AuthorizeAttribute. This filter checks whether the user is authenticated. If not, it returns HTTP status code 401 (Unauthorized), without invoking the action.
If you are interested how this filter works under the hood you can check it here.
You must be authenticated before you can be authorized, this is the logic responsible for it: https://github.com/aspnet/Security/blob/644f34e90d35b369efdce9c11ab1db42e0a7f4a7/src/Microsoft.AspNetCore.Authorization.Policy/PolicyEvaluator.cs#L91
In summary
how [Authorize] attribute knows that this user is authenticated.
Authorize attribute alone doesn't know if this user is authenticated. This is handled by authentication middleware and depends stricly on the scheme it tries to authenticate with. It simply tries to authenticate with schemes you have added(cookie,jwt etc.) by calling HttpContext.AuthenticateAsync which is simply calling AuthenticationService.AuthenticateAsync under the hood and sets HttpContext.User from the result ClaimsPrincipal, which is simply result from schema handler like jwt handler for instance. I think this should give you more in-depth idea how this works.
Generally if you're starting new project I don't recommend using classic ASP.NET and prepare for the future with .NET Core as everything is now going in this direction. ASP.NET 5 ( I also refer to it as "classic") is pretty much dead now.

Rotativa + WkhtmltoPDF + ADFS not rendering PDF

I have an ASP.net MVC application where I can't get the MVC Views to render as a PDF after the introduction of the ADFS authentication.
Earlier, the application had Forms authentication and PDF rendering using Rotativa (which uses WkhtmltoPDF library) worked like a charm. After the introduction of the ADFS it just won't work.
What I get is a blank PDF with the title: "Sign In" without any elements on the page/PDF itself.
As it's pretty indicative that it tries to connect somewhere I believe the problem lies somewhere in the authentication parameters of the WkhtmltoPDF i.e. I probably have to add some additional parameters in order to support ADFS, but I'm not sure which ones. I've already tried using --username and --password parameters but they didn't help.
The question is: What to do to make it work (again)?
Try using the [AllowAnonymous] attribute on the action that calls the view you turn into PDF
Example:
For the action that calls rotativa you'd have something like this maybe
return new Rotativa.ViewAsPdf("ViewToPdf", model);
and the action called would look like
[AllowAnonymous]
public ActionResult ViewToPdf(ViewModel model)
{
return View(model);
}
I hope you understand my formatting
I wasn't able to fix the problem the way I wanted it to, but for those interested in the solution the next steps describe what I did.
As the page I was trying to render with Rotativa required authentication I added the logic to create an "one-time access token" which redirects the user to the another application that renders the same page but without any ADFS authentication check. In this case you have to modify Rotativa's logic to return UrlAsPdf instead of ActionAsPdf.
The only authorization thing I did was checking the validity of the token. Since the token has a fast expiration time (it is valid only for the next couple of minutes) I don't think the security of the web app was negatively affected since no one can access the version without authentication without the access token.

MVC AntiForgeryToken reused previous generated tokens

currently i'm working on ASP .NET MVC 4 application. We are using the provided [ValidateAntiForgeryToken] and the corresponding #Html.AntiForgeryToken() to generate the hidden field in our forms which are submitted using POST.
So far the mechanism seems to be working properly because if I don't provided the token as input hidden field to the target Action annotated with [ValidateAntiForgeryToken] an error is raised as expected.
However i found really strange that if i captured several generated token using Firebug or Chrome inspector, copy them into notepad and then go to a different page which also uses the AntiForgeryToken and basically replace the hidden field with any of the previous token generated, an error is not raised. I was expecting to always have a 1:1 relation (Page Hidden Field - ValidationAtServer], since if someone is able to obtain that value, will be able to forge any request to any form in the application which need the AntiForgeryToken
I was under the impression that once a token was generated it should not be possible to reuse the same token over an over, I see this a security flaw in the Framework itself.
If someone can provide more insight will be greatly appreciate it.
AntiForgeryToken is session base, so that each user has the same token but another user will have a different token. This descussion may be usefull for you: AntiForgeryToken changes per request
It's normal behaviour, because it's supposed that antiforgery token isn't compromised. If an atacker was able to compromise token, that means that atacker already has opportunity to compromise any other tokes, that would be generated. E.g. man in middle attacks.
So basically there is no need to gereate Antiforgery token per each request, and it will allow you to use already generated one for Ajax requests on current page.

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.

Unauthorized request does not redirect to login page with returnUrl query string parameter

Setup
In my MVC3 app, MembersController is decorated with an [Authorize] attribute.
MembersController has an Action called MyPage. Due to the Authorize attribute on the controller, MyPage can only be requested by authorized users.
Problem
When an unauthorized user tries to request /Members/MyPage they are correctly redirected to the Login page.
However, the ReturnUrl parameter is not passed into the login page, so when the user authenticates, they are taken to the default page (lets call it /Members/Home) instead of /Members/MyPage.
Question
Why?!
In another app, developed in MVC2, the returnUrl QS parameters is there and works as expected.
Other Issues:
The Autorize attribute is being ignored when decorating both controllers and actions.
Resolution:
Sections of web.config not properly updated between .NET 3.5 and .NET 4. See answers below.
#Marcind put me on the right track, #Darin Dimitrov's answer very instructive of the process involved.
Diagnosis
It seems that the issue was related to a web.config that I did not update properly when merging an existing Web Forms .NET 3.5 app to a .NET 4.0 app. I can't recall how I went about this.
Anyway, by comparing the web.config of my app with a new MVC 3 web.config, I was able to find the extra bits that should not have been there, left over from 3.5 days.
Resolution:
The issue was resolved by correcting the bits in the <authentication><forms> tag in the web.config, as well as the <membership> tag.
Other Issues Caused by this:
Another issue caused by this was the fact that if I decorated a controller with the Authorize attribute, it was ignored, so the controller tried to process info based on the current user, that obviously was null, so all manner of exceptions were fired.
It works for me. I created a new project using the ASP.NET MVC 3 RC2, default template, added a MembersController, decorated it with the [Authorize] attribute, run the application, requested /members/index, was redirected to /Account/LogOn?ReturnUrl=%2fmembers%2findex, logged in, was redirected to /members/index. There must be something else wrong with your code.
Here's how it works:
The [Authorize] attribute checks if the user is authenticated and if it is not it returns 401 status code.
The FormsAuthenticationModule which is part of ASP.NET and handles forms authentication intercepts the 401 status code and redirects to the login page by appending the ReturnUrl parameter to the request which points to the initial request.
The FormsAuthenticationModule module is not specific to ASP.NET MVC, this is standard ASP.NET stuff

Resources