I have a system that is multi-homed, that is, our customers share a database. Using MVC Routing, I can pass the customer name as the first portion of the domain ({customer}.server.tld), and have it translated into a parameter to my controller actions.
Problems include:
Authorization: how can I do this transparently, so that developers making controller actions don't have to remember to do this, and someone not authorized will automatically receive a 403 if they are not authorized to view a particular customer?
Parameter passing: I don't want for every controller action to have a parameter called "customerId". The data has GUID primary keys, so customerId isn't required at the data access level.
What should I do here? I don't want a user changing the URL and getting access to all of our customers' data!
Have you considered using Windows Identity Foundation (WIF)?
May sound like an overkill, but it will allow you to not only separate AuthN from AuthZ, but also have code logic (in one spot!) where you can check each customer claim (maybe based on route data) and act accordingly...Check out some of these links:
Windows Identity Foundation Simplifies User Access for Developers
A Guide to Claims–based Identity and Access Control
WIF and MVC – How it works
ASP.NET MVC 2 and authentication using WIF (Windows Identity Foundation)
Related
net mvc 5 application using entity frame work etc and am new to .net c# etc (used to php & sessions)
so i have read allot about using .nets authentication service and that is some how registers a user upon login using FormsAuthentication.SetAuthCookie.
however i need to authenticate a user group for example admin or moderator. and from what i understand this can be achieved and be set using [authenticate(roles="admin")].
but surely if this is using a set cookie a user if they knew how could just change their registered role from user to admin to access restricted content?
so in as simple terms as possible how does .net mvc ensure security in authenticating users? can i use sessions instead of cookies? do i need to create my own authentication system.?
i have searched and read all i can find and most resources just explain how cookies work or how to implement authentication using cookies but very little about sessions.
I'll try to be as concise as possible:
Yes, ASP.NET MVC 5 uses cookies out of the box (if you chose Individual User Accounts in the project wizard)
The authorization of a group or role by means of an [Authorize(Roles="bla")] attribute to decorate controllers and/or controller methods will do just that. It's as if you would be writing
if(!User.IsInRole("bla"))
{
return new HttpUnauthorizedResult();
}
else
{
//here's your ultra-secret View
return View();
}
What if a user changes role while in-session or if he or she has a persistent cookie?
Indeed, you'll need to handle the interval between role change and cookie update.
Read up on it here
Long story short: the design decision is yours whether you think it better to log off a user when re-assigning roles or to make db roundtrips at every authorization check.
Can you use a session variable like in PHP? Sure (the Session object exists), but you shouldn't.
If and when the situation arises where you absolutely NEED to pass some arbitrary data however, there's ViewBag, ViewData and TempData.
I won't go as far as to say, that these constructs are superfluous, they certainly have their use from time to time, but do try and design your application to maximize the use of strongly-typed models, viewmodels and make use of the REST-based url architecture to get or put your data.
So I have been happily building my ASP.Net MVC 4 application for a month now. I have the security model in place, users can log in and secure information is being stored in the users session for subsequent page requests. This all works great. I then implement some ajax calls to get additional data into the page. I do this by making a call to a Web API interface. In the Web API call I try access Session and low and behold Session is null. Now I get that Web API is supposed to be "stateless". All the parameters for a web api call should be passed in. But what if some of those parameters are sensitive and can not be passed up from the client when making the ajax call?
I've read about the hacks to get access to session in WebAPI. I would prefer not to do this and violate the tenants of web api. ?
So do you store this information in the database and pull it out in the web api call? Seem like a PITA to do that.
So how would could keep certain parameters secure when making the web api ajax call?
Or do you break down and just get access to session?
Each service call could accept a user id.
The WebAPI controller method uses the user id to do further data look ups, such as looking up sensitive order details.
The way I do it is inheriting from a Base Class, and this base class has the following:
public string UserName
{
get
{
return User.Identity.Name;
}
}
The WebAPI can see this UserName and each UserName is unique, so you can do a user lookup based on this variable.
If you're wanting to send any further data to the WebAPI then you're going to have to send, say, an ID to the Controller and validate it against the UserName to see if they have access to it.
Psuedo...
I want a Policy!
Client side
Sends Policy ID (1234 to WebAPI, meaningless to a hacker if they can't get info from it)
This ID is validated against
User.Identity.Name to see if information can be retrieved
A common use case for WebAPI would be to have shell views rendered by MVC controllers, which contain javascript that then hit your API to access data.
But let's say you have some expensive API operations and you don't want people remotely accessing those endpoints -- you only want your MVC views, delivered by your application, to access them. How could you go about protecting them?
In this case Request.IsLocal doesn't work, because javascript is invoking it from the client's browser on their machine. Even if it did work, you need to dig to get the real HttpContext in order to find this property -- and that solution wouldn't work in self-hosted WebAPI.
For API endpoints that require a valid IPrincipal, you could protect them with the [Authorize] attribute. But what about API endpoints that you want your app to be able to access for anonymous users?
I have tried a solution and will post it separately as an answer, because I'm not sure if it's the best (or even a good) approach.
If your MVC site uses authentication, you could enable forms authentication for your Web API methods. You could write a custom [Authorize] attribute that will check for the presence of a forms authentication cookie which will be sent from the AJAX call and if present construct the principal.
Another possible solution is to protect your API with tokens which is a more RESTful style. The idea here is that when a user authenticates on your MVC website you could generate and pass a token to the view which will be used when sending the AJAX request to the Web API which in turn will verify the validity of the token and its signature.
If on the other hand your site doesn't use authentication, then things will get very complicated because you have no way of knowing whether the request comes from a trusted client since you are using javascript to call your API methods.
Before you go harping about "what have you tried", here is what I have tried. It works. Just not sure if there is a better way.
Create an MVC action filter and add it as a global filter during Application_Start.
Create an Http (WebAPI) action filter and use it on actions that should reject remote requests.
The global MVC filter does this:
Looks for a specific cookie in the request. If the cookie is there, its value is decrypted. The decrypted value should be a string representation of a DateTime, so use DateTime.TryParse to get it out. If the value is correctly parsed to a DateTime, and that DateTime is less than a day old, STOP HERE and do nothing else.
If the cookie is not there, or cannot be decrypted / parsed, or is older than a day, write a new cookie to the browser. Use the current DateTime.UtcNow.ToString() as the value, encrypt it, and write it with HttpOnly = false.
The WebAPI filter does this:
Looks for a specific cookie in the request. If the cookie is there, decrypt its value and try to parse it out as a DateTime.
If the value is a valid DateTime and is less than 2 days old, STOP HERE and do nothing else.
Otherwise, throw a 403 Forbidden exception.
A couple of notes about my current implementation of this. First of all, I use AES encryption with a shared secret and a salt. The shared secret is stored as an appSetting in web.config. For the salt, I enabled anonymous identification and used Request.AnonymousID as the salt. I'm not entirely fond of the salt because it's tricker to get at in a WebAPI controller, but not impossible as long as it is not self-hosted.
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.
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.