MVC3 mixed forms and Windows authentication - asp.net-mvc

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.

Related

Umbraco 7 custom cookies

I am running an MVC site along side Umbraco. The MVC site handles its own authentication completely separate to Umbraco, and ASP.NET Forms authentication for that matter. It sets a cookie and uses that internally to keep track of things.
Everything works fine for the most part, but if I am logged into my MVC site with the aforementioned cookie set, I try to login to the Umbraco admin section using the correct Umbraco credentials, it authenticates me and redirects me to the admin section but the WebAPI calls start to fail. The first is a call to: /umbraco/backoffice/UmbracoApi/UpdateCheck/GetCheck which returns a 417 Missing token null HTTP error response.
If I delete my custom cookie and refresh the page everything works fine.
I don't understand how my cookie can interfere with Umbraco's. It's not using ASP.NET Forms authentication or anything.
This error occurs because your request is not sending up the required angular CSRF headers + cookie. I'm not sure why this would be the case but it does seems strange if it is a fault of your custom cookie. Perhaps you can tell us some more information about your issue: Cookie name/value, steps to reproduce, specific version of Umbraco, hosting environment, etc....
Some info as to what is going on, the code that returns this error is here:
https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/WebApi/Filters/AngularAntiForgeryHelper.cs#L94
This is where the CSRF cookies are set:
https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/WebApi/Filters/SetAngularAntiForgeryTokensAttribute.cs
and this attribute is applied to two actions, one for login and one when we retrieve the current user data:
https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/Editors/AuthenticationController.cs#L103
https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/Editors/AuthenticationController.cs#L84
This is where the header is set in the JS:
https://github.com/umbraco/Umbraco-CMS/blob/5b9a98ad6ae9e63322c26f7b162204e34f7fcb54/src/Umbraco.Web.UI.Client/src/init.js#L11
Depending on your hosting environment/setup there has been strange reports of some firewalls stripping/changing data, for example:
http://our.umbraco.org/forum/umbraco-7/using-umbraco-7/47340-Umbraco-7-plus-ISA-Server-2006
Hopefully given the info above you might be able to pinpoint where the problem starts.
My initial thought is that you by accident used a key value for your cookie that is reserved by Umbraco, which could result in the wrong cookie being read, causing issues. The solution to this would be to simply rename your cookie.
If this is not the case I have another theory:
HTTP requests will always include all cookies which path/domain matches the domain of the resource you are requesting. They are sorted by path length primarily, and secondarily by creation time. If Umbraco backend for some reason finds the cookie used for authentication by its index number (wouldn't even be surprised) in the list, rather than key value, your custom cookie would cause the index to shift, thus making Umbraco look at the wrong cookie
So, if renaming the cookie didn't do anything, a fun thing to try could be to set path of the cookie to the shortest possible path, which would make your browser put the cookie further down the list, so the index won't shift.
It's just a theory though, so I'm interested in hearing how it goes :)

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!

How to authenticate from a token in a URL?

I need to create a website with non standard authorizaion logic (or rather not exactly the site. It should be separate Area in existing ASP.NET MVC3 application). Access to most of the pages sould be available only to authorized users. Authorization is carried out on the token passed in the link. After the user arrived to this area, the token should be checked and if it’s valid site will create a session key for 30 minutes (we already have our own mechanisms of session managment and it should be used).
Workflow example :
Third-party website generates a link for user, e.g. https://example.com/securedPage/?accountId=123456&token=XXXXX
Our site check this token (it depends on the page from URL, in this case https://example.com/securedPage/)
If the token is valid, example.com obtains a session key for the user and stores it in cookies.
Then user continues browsing whole website and only session is checked.
I’m new to MVC framework, so I’d like to ask several questions about architecture.
What is an apropriate place for this logic? ActionInvoker, Global.asax etc.?
Currently I'm trying to create my own ActionInvoker and keep this logic there, but I'm afraid that it could be a wrong way.
If I understand correctly you want yo extend the Action of the controller to inject/check your token.
I think the global action filters should help you.

ASP.NET MVC suggested routing for URL with session token

I'm trying to implement a small ASP.NET MVC site which interacts with another site. In short, sessions are managed between the main site and satellite sites through tokens in the URL. I can specify the url format but I can't remove the requirement that a session token is submitted as part of the URL.
I'm trying to work out how to set up the routing and am in a few minds here. I can't decide which would be best, or if there is perhaps a better way to do it. The main ways I'm thinking:
routes.MapRoute("Main", "{controller}/{action}/{id}/{token}");
Gives URLs like http://mysite.com/Products/Detail/5/5f1c8bbf-d4f3-41f5-ac5f-48f5644a6d0f
Pro: mostly keeps with existing MVC convention for site nagivation
Con: Adds complication to routing when supporting defaults for ID and Action.
routes.MapRoute("Main", "{token}/{controller}/{action}/{id}/");
Gives URLs like http://mysite.com/5f1c8bbf-d4f3-41f5-ac5f-48f5644a6d0f/Products/Detail/5
Pro: simplifies routing - can still apply action/id defaults as per standard MVC convention
Con: very "un-web-like" URLs. Requires regex to validate that the first variable is a valid GUID / token before moving on to next route in the table.
The other possibility coming to mind, passing sessions like:
http://mysite.com/Home/Index?session=5f1c8bbf-d4f3-41f5-ac5f-48f5644a6d0f
The related problem with that is I have a base class derived from Controller which all other secure pages are going through. The SecureController class overrides Execute() and checks for the validity of the token taken from the URL. Both approaches (GET and routing) seem like it would be easy enough to get the token within the controller Execute() function, but the GET approach feels kind of tacky whereas the routing approach feels like it's, for lack of better explanation, breaking the elegance of the MVC routing design.
Has anyone else out there taken on a similar problem and had any particular successes or difficulties to share?
It seems no matter you do, your URLs will be pretty messy with that token.
I have had to handle this kind of single sign-on functionality in an ASP.NET MVC app as well, but I went for a slightly different and much simpler approach: I created a GatewayController with a SignOn action that took a session token and a URL as parameters.
Then this SignOn action would just check the validity of the session token and then sign the user on to my site, redirecting to the supplied URL. From then on, the session token is not needed anymore, as authentication from then on would be cookie-based.
It might not be entirely applicable in your case, depending on your requirements. If you are required to continuously check the validity of the session token somewhere, you could however just do the same thing as I did and then store the session token in the user's session data, allowing you to check the token in each request.

Setting up a private beta for a website

I'm trying to setup a "private beta" for a site that I'm working on. The site uses open id. I don't want anyone to even browse the pages if they aren't part of the beta. What's the best way to implement this? Any suggestions?
For example:
When the site goes live, users will go to http://www.mydomain.com which will not require them to log in.
For the beta I want to restrict access. Users that go to http://www.mydomain.com will be redirected to a login page. Anyone attempting to access ANY PART OF THE SITE who is not authenticated will be redirected back to the login page.
I could stick [Authorize] attributes all over my controller actions, but that seems stupid.
If you're using ASP.NET MVC, it comes with authentication/authorization out of the box. You should be able to use that to setup authentication on your site.
Alternatively you could setup app server settings - IIS lets you setup username/password on a specific site it's serving, regardless of what the actual application may do. If you have access to the app server this might be the best solution.
If you're using IIS6, you can setup authorization easily. Right-click on your site > Properties > Directory Security Tab > Authentication and Access Control > Edit, and enter a username/pwd of your choice. Done.
The real question is how are they being invited to the private beta?
You could setup a password which drops a cookie much like serverfault.com does.
OR
If you know who you are inviting: you could add them to the system before hand using the email/login information that you already know about them (assuming you are inviting them via email)
I have implemented a function in a web application a while ago where we go the possibility to block access to the full website unless the user was an administrator (which in our case meant that the user account was a member of a specific group in Active Directory).
It was based on two things. First, all pages in the web application inherited not directly from the Page class, but from a custom page class in our web application. Second, we had a value like this in the appSettings section of web.config file:
<add key="adminaccessonly" value="0" />
The custom page class would check that value when loading. If it was not 0 it would redirect to a page (that did not inherit the same custom page class, though) informing the user that "the site is not available right now". If the value was 0 the page would load as usual.
In that application we used this to be able to take the site "offline" when we deployed a new version, giving us some time to verify that all was good before we let in the users again.
Best way are invitation system (based on invitation code) or manually confirmation access after create profile in your system. imho
Or you could host the site on a private server, and set up a VPN to use it. Depending on your resources and needs this may be the easiest and most secure way to do what you want without modifying your codebase.
OR alternatively you could use Apache or IIS to force authentication on access to the website directory. Keeping the authentication info in .htaccess for a while.
Even though you use open id authentication, you may still need some form of authorization mechanism. The simplest form would be a user-roles system in your database that assigns different roles to users
In your case, just assign the private_beta role to your private beta invitees and ensure you your authorization mechanism that all users have private_beta privilege before they may continue.
If you don't want to provide authorization for the public site (where everyone can do everything, once authenticated), then, you may only need to do a quick-and-dirty post-processing (for private beta only) on your open_id authenticated users to check them off a short list (which you can store on a text file.

Resources