I've been using Authorize to verify that the user has logged in but I was told in a previous post that it was used to make sure their role has access to that method.
Does that mean I should be using something else to allow/disallow access to a web page or is using Authorize the right way?
I have a handful of pages that I want to prevent users who are not logged in from getting to.
What is the right way of checking this and can it be done at class level?
Thanks!
Authorization and Authentication are two different things. It sounds like you are trying to use the AuthorizeAttribute to authenticate which should actually be happening by your membership provider.
So in short, authentication is a way for you to identify who your users are and authorization is how you identify what access a user has, identified or not.
One thing to mention from the docs on AuthorizeAttribute:
"When you mark an action method with AuthorizeAttribute, access to that action method is restricted to users who are both authenticated and authorized. If you mark a controller with the attribute, all action methods in the controller are restricted."
So it isn't performing the authentication for you but checking it.
Related
I have an ASP.NET MVC API that serves both regular users and admin users. Admin users can do everything regular users can do plus additional functionality.
The HttpContext of requests stores user info which indicates the role of a user. Some endpoints are for use by admin users only. All other endpoints are accessible by all users. Currently, a single controller is being used for both types of user with permissions being used to restrict access accordingly.
However, I'm unsure if this is a good approach because a permission could mistakenly be assigned to the wrong role, or a developer may check the wrong permission for a new endpoint that should be for admin users only.
So, I'm considering two solutions to separate the concerns:
Add a Boolean attribute (e.g., IsAdminUseOnly) to the endpoints. This seems like a quick decision, but would cause code pollution as every endpoint that is for admin use would require true to be specified in the endpoint decorator.
Create a subclass "admin" controller that derives from the regular user controller (in a similar way to described in this question). The parent and child controllers would effectively each have a different Route (e.g., MyController and MyAdminController). The child (admin) controller would inherit all endpoints from the parent controller. Of course, role access would be specified in the child controller as described in this answer using [Authorize(Roles = RolesConvention.Administrator)] for example.
Would either of the above be a suitable solution for this problem, or are there other more suitable methods to achieve the SoC described above?
I'm using a custom AuthenticationHandler and only some of my controller methods have the [Authorize] attribute. I log on Info level and it creates a log entry for any method call. Now I can't tell apart if somebody actually tried accessing a method that requires authorization and failed or if it's a call to a method that doesn't even need authorization and it fails because it's supposed to.
Is there a way to tell them apart or preferably to keep MVC from calling HandleAuthenticateAsync when it's not needed?
It sounds like you might be misusing the AuthenticationHandler. You are not supposed to immediately reject access if the user fails to authenticate. If you do so, it doesn't even reach the MVC context in the pipeline.
Unless you intentionally want to reject any access to unauthenticated users, you should only either authenticate or pass it through as anonymous user. After that at some point AuthorizeAttribute will kick in and check whether user has access to the requested resource or not. If he is not authenticated, the authorization will reject the request.
After they type in their password, should I keep a variable in server session storage like Session["loggedIn"] = true that I check when requests are made to pages that require a login, or is there a better/safer way this is traditionally done in ASP.NET?
No, do not keep this in a session variable. In fact, I would argue you should try not to use session for anything. Try to keep the HTTP communication as stateless as possible.
For authentication in ASP.NET MVC, you have 2 alternatives, but ultimately, the both end up working the same way: by writing an encrypted authentication cookie to the browser after you successfully log a user in.
The newer alternative was mentioned in a comment to the OP: Microsoft.AspNet.Identity. To use this, you should be using a newer version of ASP.NET MVC with the OWIN pipeline (though I am not sure if you have to). The older alternative is called Forms Authentication, and can be used with any version of MVC except version 6 (the new vNext / core 1.0 stuff) I believe.
When you have successfully integrated one of these 2 tools into your MVC application, after a user logs on, your Controllers will have a non-null User property of type IPrincipal. You can use this property to determine whether or not a user is authenticated:
// in a controller
bool isThereAUserLoggedIn = this.User != null && this.User.Identity.IsAuthenticated;
If you are using the newer Microsoft.AspNet.Identity, then this IPrincipal User property will be implemented as a ClaimsPrincipal with one or more ClaimsIdentitys. Forms Authentication does not do claims like this, so if you want claims, or social login, etc, use Microsoft.AspNet.Identity.
The way that this is traditionally done in ASP.NET and by my opinion also better and safer is by making use of the ASP.NET Identity package.
ASP.NET Identity handles all aspects around user accounts in a web application:
database for users, including roles and more
user registration and management, like register, email verification, log in, remember me option, forgot my password action and more.
user authentication & authorization
Just to make things more clear, authentication means that the user making the request is actually a valid application user and authorization means that the user has the authority to perform the requested action.
Practically, when a user logs in, Identity automatically keeps that information and makes it available in all controllers and views under User property. So you know at any time which user made the request. Identity also supplies each request with a cookie used for user authentication and authorization.
To check for user authentication you use the User.Identity.IsAuthenticated in a view and the Authorize attribute in a controller:
[Authorize]
public ActionResult Create( ... ){ ... }
The above use of the Authorize attribute will allow only to registered users to request this page.
It is also very common to extend the functionality of your application to include roles for the users and user authorization. Identity creates a "Users" table, a "Roles" table and a many to many relationship between them. After assigning roles to your users you can authorize their requests by using User.Identity.IsInRole("YourRoleName") in a view and in a controller:
[Authorize("YourRoleName")]
public ActionResult Create( ... ){ ... }
The above use of the Authorize attribute will allow only to registered users having the "YourRoleName" role to request this page. In any case if Identity fails to authenticate or authorize the request will prompt to the log in page.
ASP.NET Identity is simple to use, it works and it is easy to extend the membership functionality of your application both by making use the many tools supplied with it and overriding its classes to give them a more specific or complex behaviour.
You will find infinite help on the web on how to use it or a step by step guide.
I'm building an web application that I want users to have specific permissions to perform a specific action. I don't want to use the default permission and role providers in ASP.NET.
I was thinking of having each User associated with a Role. Each Role is mapped to a set of Permissions (CreatePost, ReadPost, UpdatePost, DeletePost and so on).
I have a couple of questions regarding this. Would it be best to have a boolean property for each Permission on the role or some sort of bitfield? I like the idea of having methods for this but properly need to map these to the permissions stored for the role in the database.
Also, how would I implement this for each action/request? I'm thinking something along the lines of what was posted here but I'm not really sure.
Thanks!
Make your own role provider and register it in the web.config. Look at the MSDN for a sample. Once it is registered it will associate the roles you provide with the principal.
I've just done that for one of my project and it works fine.
To check whether the user has permission to execute a task you'll have to see whether the user is in the required role. In "normal" ASP.NET you will have to do this in code. In MVC you can do that with attributes on each class/method in the controller.
I am writing an MVC app that has two branches to travel along right from the beginning. On path authorizes with a PIN and I am using forms authentication to limit access to this section of the code. However, the other path will accept an AD log in and I need stop people from move between the branches using URLs. Should I be using a custom routing or should I create two separate authorization attributes to restrict access.
Thanks
You could use Roles to handle this with the existing AuthorizeAttribute. Simply put your AD-authorized users into a particular role, then in the paths that require an AD-logon set the Roles for that controller/method to require the AD role. This would entail implementing a RoleProvider which can seem somewhat daunting, but really isn't all that bad. Cache the user's roles in a cookie so that you don't need to look them up every time. The advantage here is that this will scale to additional roles as your application gets more complex.
Alternatively, you could extend the existing AuthorizeAttribute, overriding OnAuthorization and use your custom version. This attribute could check to make sure that not only is the request authorized, but that it has the proper credential type. The credential type could be stored in the session on login and retrieved from there for authenticated users. This is simpler to write, but doesn't scale as well.