I'm in need of a RoleProvider with the following functionality:
Dynamic Assignment of Roles to Tasks
Authentication / Authorizaiton of IPrincipals based on the dynamically allocated tasks in the system they have privilege to access
Reporting showing who is currently logged in, and other common usage statistics.
I'm pretty sure I'm going to have to roll my own, but wanted to make sure I didn't miss out on something OSS or even from MS.
I'm also using ASP.NET MVC and so my basic plan is to write a custom attribute like: [Authorize(Task=Tasks.DeleteClient)]
and place it over the methods that need authorization.
Rather than authorizing against the Role, I'll authorize the task against the role based on whatever settings the user has configured in the DB.
Thoughts?
You might want to check out NetSqlAzMan. It allows you to define tasks and assign them to roles and then authenticate and authorise your IPrincipal objects.
You may need to roll your own security attribute but NetSqlAzMan should help make that a reasonably easy task.
We had a similar issue with one of our systems. The first thing I'd do is create more AuthorizeAttribute classes for your specific tasks - e.g. DeleteClientAuthorize etc. You can then add specific logic into your classes.
As long as you can access the routines that trigger the change of roles for the current user you should be OK. Just call Membership.DeleteCookie() and this will force the next authorisation request to re-query your data store. It's at that point that you can determine what roles are required now.
Related
I am developing a .NET MVC application, and currently using only Role Based Access Control. I am wrapping my controllers endpoints with [Authorize(Roles="Provider")] for example.
Now, I want to add the add permissions on resources as well, e.g. not only saying if a user can edit a document, but also to define which documents it can edit.
So I want it to look something like -
[Authorize(Roles="Provider")]
[Authorize("CanEditObject1")]
What is the best practice for doing so? What type of authorization is required here? Perhaps I need to mix some (Role Based Access + Policy Based Access)? Do I need to change my whole Authentication method or just add on top of it?
You will want to look into Policies. I too got schooled on this pretty fast when I tried submitting a PR for authorization tag helpers and never got back to it. In short define policies at your composition root and check those with Authorize attributes.
Row level access may require additional checking however unless you can establish membership levels.
Assuming that the authorization at the controller level is read-only, a more restrictive "Edit" role could be enforced at the controller's edit methods by using an authorization attribute on the edit methods. I would also conditionally hide links to edit methods in the view from end users without that role. Another option is to leverage claims that the authenticated user has to discriminate their access to certain resources.
I know this is a question that has been asked over and over but I'm attempting to implement permission based rather than role based authorization in an ASP.NET MVC application. So instead of just having high level roles like Manager, Admin, or User, I need to have permissions like ViewTask, AddTask, DeleteTask. I have read a ton of comments on this and it seems like the easiest solution is to just treat roles as permissions and define "roles" of ViewTask, AddTask, and DeleteTask.
Is such an approach really a good idea? Some of my concerns are that you could end up with over 100 roles depending on the size of the application which would then rule out the ability to do role caching in cookies and thus every call to User.IsInRole hits the database. If every action method is going to be decorated with [Authorize(Roles="XXXX")] am I going to see serious performance issues?
My other issue is that I still want to keep the concept of a role around so that an administrator can simply associate a user with a role that has a predefined set of permissions. Using the approach above my thought was to create a separate entity in my application named Group and that Group would be responsible for keeping track of the ASP.NET roles that are assigned to that Group. So, when a user is associated with a Group, I can retrieve the ASP.NET roles that need to be assigned to the user and add all the roles.
Has anyone implemented a system in such a way? Any opinions or thoughts on this approach would be appreciated.
Thanks
I agree with #jlew about caching the user's data and when the cache expires - just reload it. There's no use trying to force this data to stay persistent. Additionally, if you want to move away from the ASP.net role providers, you could roll your own security as I've described in this reply. This has the advantage of allowing very custom security solutions for roles/individual permissions.
The following is just an idea that I've been toying around with lately (just some food for thought). Why not use the RESTful urls of MVC to define "permissions". For example:
/tasks/add could define the permission for adding tasks. These could somehow be hierarchical so that giving a user permissions on /tasks/add also gives them permissions on /tasks. Then, you could use a global action filter that would build the URL given the route values. This would also allow really interesting approach for individual item security configurable via runtime. For example, /tasks/edit/23 could somehow grant edit permissions on task with id 23. Anyway, this might not even be helpful at at all... but it's just thought I thought you'd like to maybe consider.
Cheers!
We solve the problem by caching the principal on the server side, so that the "permission roles" do not need to be in the cookie and we do not have to re-load on every request. You can actually get around the cookie size limitation by chunking your cookie data into multiple cookies (Windows Identity Framework does this.) But, you may have bandwidth or other concerns with big cookies.
Background:
I'm incorporating the SqlMembership provider into an existing system where I'm building a web front end. The Membership database will be kept in a separate database.
Beyond the login account, there's an additional mapping between the accounts that needs to be in place in the main database in order for an account to be able to log in.
Let's say that this table gives the user the right to use the system.
My question:
I would like to somehow incorporate this into the provider. Is it possible without too much work? (Or is it better to keep it in the AccountMembershipService class?)
Actually regardless, I'm very interested in learning how to put additional login requirements into the provider.
I'm asking this because when I've been looking at creating a custom membership provider earlier it seemed at that time a little bit overwhelming.
In other words:
I want to understand how to extend the Membership Provider classes in general and how to extend the login method (ValidateUser) in particular.
Given the sample ODBC implementation It looks like one simply could subclass the default provider and override ValidateUser calling base.ValidateUser as the first step.
However it may or may not be that simple, and I'd be very happy to hear any first hand experiences from implementing or extending membership providers.
I wanted to do something similar, one of the requirements was to use an Oracle DB, so I implemented the OracleMembership provider, hence I could not waste my time rewriting the hole oracle membership provider (it works pretty fine), the second requirement was to use a custom authorization legacy system. So I realized that the Internet Application template which comes with the MVC 2 or 3 comes with a small implementation of the security for the site, specifically take a look on the AccountMembershipService class. You could move all of these elements out of the MVC app to a separate assembly so you could use it even on a client implementation. The AccountMembershipService uses the Membership provider as the underlying authentication system with the option of using FormsAuthentication.
So I recommend you to take a look on that implementation. You could put your additional authentication code there so your application would stay cleaner and your don't need to re-invent the wheel and you have the chance to add your own code.
best regards
In order to extend the membership provider make you own tables with one to one relationship with the main database and handle additional requirements through this table. Also while implementing and extending the default membership provider you may need to store extra information in authcookies you may get additional information from here , here and here
In GetUserCredentials you will do your stuff for additional checking and RoleID is some dropdown on your login page that you will receive in the post method of sign in.
FormsAuth.SignIn(userName, rememberMe);
ApplicationRepository _ApplicationRepository = new ApplicationRepository();
MembershipUser aspUser = Membership.GetUser(userName);
SessionUser CurrentUser = _ApplicationRepository.GetUserCredentials(aspUser.ProviderUserKey.ToString(), RoleID);
if (CurrentUser == null)
{
ModelState.AddModelError("_FORM", "Invalid Role ");
FormsAuth.SignOut();
return View("signin");
}
From what i have read from this paper
I understand that a role based access control system is one where users can be assigned to roles where roles specify permissions to perform operations on objects
But in asp.net we do not specify "Operations on objects", what i mean here is that how can we specify "All users in Role R can perform a delete on object O"
Where is the Object Part in ASP.Net
The security model is asp.net is pretty limited. In essence you only have control at the Role level. Which means that for any operation you have to test to see if the user is any of the roles that you want to allow that operation to be performed.
We took the path of defining our own model that gives much more granularity. Basically we define operations and assign those operations to various roles. This way we can test if they have a "delete account" right versus testing if they are in "Admin", "Account Admin", or any number of other roles. It's very similar to how Active Directory works. Further it allows us to reconfigure roles as needed.
There is a piece called Authorization Manager (AzMan) that ships with windows. It can work with your membership provider to provide operation level control. Some people have had success with it, but others have complained that it's difficult to get working. We used it about 5 years ago on a project and at that time it worked about 95% of the time. The other 5% it had communications issues with our AD controller.
Which leads us to your question: Is the built in ASP.Net membership provider a true role based access control system? No. It allows you to define Roles, not operations.
Check out rhino security if you need something more fine grained.
As suggested in previous posting, to achieve more granularity you would need to build up on the existing ASP.net membership and role providers. There are third party controls such as http://www.visualaccesscontrol.com that provide role based Module Access Security and Data Access Security as well. With Visual Access Controls you can add administrative functionalities to your ASP.net web application to dynamically restrict the users to the activities they are allowed to perform and the subset of data they are allowed to see based on their respective roles.
You are implementing the delete operation, so it is up to you to check if the logged in user has permission to delete the object. For example, you might create a role "CanDeleteOs". Then, your code would look like this:
if ( !Roles.IsUserInRole("CanDeleteOs") )
throw new Exception("User does not have permission to delete O's.");
Okay,
I know I'm doing something wrong - but can't figure out a better way.
I am developing a website which is going to allow users to setup their own mini-websites.
Something like Ning.
Also, I have only 1 basic login and access to each mini website is provided (right now) via roles.
So the way I am doing this right now is:
Everytime a new mini website is created - say blah, I create 2 roles in my application.
blah_users and blah_admin
The user creating the mini website is given the role - blah_admin and every other user wanting to join this mini website (or network) is given the role - blah_user.
Anyone can view data from any website. However to add data, one must be a member of that mini site (must have the blah_user role assigned)
The problem that I am facing is that by doing a role based system, I'm having to do loads of stuff manually. Asp.Net 2 controls which work on the User.IsAunthenticated property are basically useless to me now because along with the IsAuthenticated property, I must also check if the user has the proper role.
I'm guessing there is a better way to architect the system but I am not sure how.
Any ideas?
This website is being developed in ASP.Net 2 on IIS 6.
Thanks a tonne!
I afraid standard roles-related stuff of ASP.NET is not what you need. You can try to change authentication module so it will:
Log you in with cookie.
Determine what roles does your visitor have. Perhaps you will use some special table that corresponds user and site.
Make custom principal with user roles enumerated and assign Identity and Principal to the current request.
I also don't think that making special roles for each site is good idea. When you would have hundred sites, you would also have two hundred roles. Pretty unmanageable, I afraid.
When we were solving similar task, we were just not using standard controls. We had single set of roles used on all sites. Membership of concrete user is determined according to current site and his relations to this site.
Addition: Another possibility to investigate is Application that exists in ASP.NET authentication system. Maybe it's possible to isolate each subsite into separate application?
Update: Method that works for our application.
Do not make a lot of cloned roles. Use only two: users and admin. If your sites are public then "users" role could be just global - user on one site doesn't differ from user on another site. If "users" and "everyone" are different roles, then of course "users" should also be bound to a site.
Use standard ASP.NET Membership users, but do not use standard role mechanism.
Make a mechanism for storing relation between site and user. It could be simple table that holds site id, user is and role.
What you have to override is IsInRole method. (Methods to be exact, i'll cover it later). This method is in IPrinciple interface, so you have to make your own principal object. It's quite simple.
Method IsInRole of this type should look take current site (from HttpRequest) look into the site-user table and get roles
Then you have to associate your principal with a request. Do it in PostAuthenticateRequest event.
There is also RoleProvider. Honestly I'm not sure when is it used, but it also have IsInRole method. We can override it in the same way. But other methods of this provider are harder. For example AddUsersToRoles. It accepts array of user names and roles, but to what context (site) should it be added? To current? Not sure, because I don't know when this method is called. So it requires some experiments. I see (Reflector helps) that RopePrincipal by itself uses RoleProvider to fetch list of roles, so maybe it's implement only RoleProvider, using standard principal. For our application this is not a case, so I can't say what problems could be hidden here.