I need the ability to restrict what users can do in my application based on dynamic roles for CRUD.
For example the User/Index would need an authentication such as [ClaimsAuthorize("View", "User")] as oposed to [Authorise(Roles="Administrator")] so that I can check if the user has the security to view.
I have the user roles configured, but what the roles enable users to do is dynamic. An administrator can change the security levels with check boxes that will enable different security groups to do different things.
The main problem is doing this in Razor, I need something similar to #User.CanEditUsers, but I am not sure how I can go about doing this at all.
Any help would be greatly appreciated as I am having trouble finding the correct way to go about this.
Note that Authorizing users to see specific page elements differs from Authorizing for CRUD or other database operations, unless the elements point to operational Actions in Controller. Consider that you may have some elements that there's no need to be saw by a specific user, and don't have specific database operation. Till now we conclude that we need the following permissions :
Permission to See
Permission to Command
I believe that you can use Microsoft Role Provider for both parts. According to MSDN Documentation Considering that :
The Authorize attribute lets you indicate that authorization is
restricted to predefined roles or to individual users. This gives you
a high degree of control over who is authorized to view any page on
the site.
In The next step/question is how to do that?
I think 3 ways are available to meet our purpose:
Solution 1: Creating separate Views with specific page elements due to forwarding each user to related View. In this scenario we must
create separate controller actions too. we have to check user types
before each action like [Authorise(Roles="Administrator")]. We
forced to have static (Pre-defined) Roles and Accessibility. And in
one sentence Not a good solution because of redundancy and
instability.
Solution 2: Creating pages Dynamically simply by adding some if conditions for each access restricted element in One Page(for
example Edit Page). That is like employing #if
(User.IsInRole("Admin")) to authorize specific users and show
related page elements like buttons. In Controller side we can use
if conditions (not as FilterAttribute due to add dynamic
functionality based on generated/added new roles) and control valid
transactions against database. Although FilterAttributes add some great functionalists (like performance optimization). In one sentence A moderate solution.
Solution 3: Act like solution 2, just fix Controller problem by
creating our own custom FilterAttribute for authorization. That will
inherited from AuthorizeAttribute and overrides the OnAuthorize
method to do what you need only for Operations.
For Example :
public class TableAuthorizeAttribute : AuthorizeAttribute
{
public enum TableAction
{
Read,
Create,
Update,
Delete
}
public TableAction Action { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
//do custom authorizization using Action and getting TableEntryID
//from filterContext.HttpContext.Request.QueryString or
//filterContext.HttpContext.Request.Form
}
}
And its usage will be like this :
[TableAuthorize(Action=TableAuthorizeAttribute.TableAction.Update)]
Here is complete example about above concept. Here is complete example for creating dynamic AuthorizeAttribute for authorizing new roles added to application.
Solution 3 in one sentence A perfect but Complex Solution.
Note that by using FilterAttribute before Actions we have limited our application to static/predefined roles. No need to use another Data Structure or generate tables in Database.
You need to separate the concept of roles from groups in your design.
A role gives fixed permissions to perform certain actions in your application. A group is a set of users. What your administrator is really doing is to assign groups of users to different roles.
Your authorization code should be able to rely on fixed roles, e.g. an "ViewUserInfo" role. Then implement the administration interface so that when the admin enables a user to view userinfo, you add that user to the "ViewUserInfo" role.
The same goes with groups: If an entire user group is granted the right to view user info you should add that group to the "ViewUserInfo" role. To introduce the concept of groups and be able to add groups to roles you can't rely on the standard SimpleRoleProvider, so you probably have to implement your own role provider as well as a group provider.
In the end some workaround might be easier, but this is, in my opinion a cleaner architecture.
From the horse's mouth: "Role management helps you manage authorization, which enables you to specify the resources that users in your application are allowed to access. Role management lets you treat groups of users as a unit by assigning users to roles such as manager, sales, member, and so on." (ref: http://msdn.microsoft.com/en-us/library/5k850zwb%28v=vs.100%29.aspx)
Users can be in multiple roles, and you can leverage action filters to get fine-grained control of access to the various resources in your site:
[Authorize(Roles="Contributor, Designer, Reviewer")]
I think the "dynamic" aspect you are after revolves around Administrators being able to add and remove users on-demand from the roles which provide access to those resources, which is pretty typical.
The idea of constantly changing the permissions your roles grant would be a bad design choice.
Related
I have been reading and searching for a best practice for doing this.
I am "learning" about Web ASP .NET MVC and also Web Api 2.2.
I am in the point of Authentication and Authorization, I clearly understand the meanning and difference in one and another. My problem come with Authorization, I already know allow/deny access using Filter and use Roles.
But beside that I dont know where to implement the logic for authorize to some user to do some action, or to see some data, for example:
A user is Authenticated already and have the role Pilot
This user enter to a controller/action for example flight/getPassengers/1
Where getPassengers is an action to retreive all the passengers for the flight #1
Let's imagine that the current logged user on the role Pilot wants to view the list of that flight because He is allowed to, but he can't see the passengers of all flights, for example flight/passengers/3 the flight #3 is from another user Pilot.
Where is the best place to put this validation logic?
Inside the action: getPassengers? I don't think so, because if later in this controller (flight) we need validate if the same info belongs to the current user (pilot) we would have to repeat that piece of code (DRY)
So, maybe a Custom Filter?
I find an article (here) but I am not Sure if is in there and How gets implementated. I have an Implementation, something like this:
Public Class CustomFilter
Inherits ActionFilterAttribute
Implements IActionFilter
Public Overrides Sub OnActionExecuting(filterContext As ActionExecutingContext)
MyBase.OnActionExecuting(filterContext)
End Sub
Public Overrides Sub OnActionExecuted(filterContext As ActionExecutedContext)
MyBase.OnActionExecuted(filterContext)
End Sub
End Class
Is creating this type of Filters and after that using this on Controllers/Actions the correct way to achieve this?
Or how is this type of logic handled?
Thanks for your suggestions
You should implement a custom AuthorizeAttribute where you can encapsulate this logic. Just be careful in the way you implement them, try not to have several Authorize Filters. It could impact the perfomance of your application. Design a good one that can be used widely.
Suppose a web application which has three part or so-called three access level:
One for every visitor (just for seeing the content and no need for authentication)
One for Users (Authorized for users)
One for the Administrator (authorized for admin)
now, administrator has access for every content and every operation in the system and Users could do some operations. I don't wanna to create separate areas for Users and Administrator because I don't want to repeat the same code in every area. for example both admin and user can create product, see the list of products, create catalog and... and also every visitor can also sees the list of product, blog posts, ...
So it's not a good idea to separate and make the code duplicated just for separating the tasks. I haven't created any area and I want to control the authentication and authorization by defining the user role when he/she is in the system(ideas!?) but the main issue comes when I want to have separate user interface (views) for users and admin. as I want to use just one Controller for products, Catalog, ... and set authentication and authorization for them, how can I render different view for every request by admin and user? I also don't want to make my code dirty by putting bunch of if/else to define which view to render (I'd rather to duplicate the code in areas!), any solution?
Probably the easiest solution is to write your own RazorViewEngine(Assuming you are using razor).
Then when you want to retrieve a view for a user, you can check the user role and assign the view you want. This is a basic and crude example:
public override ViewEngineResult FindPartialView(
ControllerContext controllerContext,
string partialViewName,
bool useCache)
{
if (controllerContext.User.IsInRole("Admin"))
{
var adminViewLocations = new string[] {"~/AdminViews/" }
return new ViewEngineResult(adminViewLocations);
}
return base.FindPartialView(controllerContext, partialViewName, useCache);
}
Doing this means that all users use the same controllers and authentication, but the views change based on roles (or whatever you want).
You can read more about A Custom View Engine with Dynamic View Location.
Generally when implementing some sort of role based access control, we have the following well-known concepts:
Role
User
Permission
And users would be assigned to roles each of which have a set of permissions (to perform an operation / access a resource etc).
So users gain permissions to perform operations by being assigned to one or more roles (which have been assigned a set of permissions).
In any given application, permissions are defined at compile time since the code actually enforces the permissions at various places where access to resources .
My thinking is that if the set of possible permissions/operations changes – it requires changes to the code and recompilation any way, so having a lookup/reference table in the database won’t really provide any value beyond the fact that a db admin could do a quick sql query to list all permissions used by an app.
Yet most applications I’ve seen create a lookup table for the permissions and -also- map it to a enum in the code.
Given this, is there any reason to actually have a database table representing the list of possible permissions (other than the fact that it is probably easier for some to look in the db as opposed to digging into the code to find the list/enum of permissions)?
Checklist:
1) Do you need to make changes while the website is online, without downtime?
2) Will you be using built-in role/membership provider?
3) You want to use attributes (like mvc [Authorize]) etc?
4) You want to allow users to programatically change permissions/roles?
Any of the above means you have to store the info on DB.
For smaller scale apps I prefer to just create some static methods that also use some kind of inheritance, ie:
isadmin()
{
if (usernameArray.Contains[currentname])
return true;
[...]
}
ispublisher()
{
if (isadmin()) return true;
[...]
}
And a table with permissions for each user pseudo-class.
Update: DB schema for specific access: (* is key, & is foreign key)
Users:
Username *
[...]
UserClasses (EG: admin...)
ID *
description
AccessTypes (EG: can delete)
ID *
description
UserClassesAssign
classid *&
username *&
AccessPerClass
accessid *&
classid *&
So anytime you want to see if 'username' is able to 'CanDelete' you have to check if the User 'username' is linked to any classes that are linked to the access 'CanDelete', and these links can of course change during runtime
We know that authorization's stuff is a cross cutting concern, and we do anything we could to avoid merge business logic in our views.
But I still not find an elegant way to filter UI components (e.g. widgets, form elements, tables, etc) using the current user roles without contaminate the view with business logic. same applies for model binding.
Example
Form: Product Creation
Fields:
Name
Price
Discount
Roles:
Role Administrator
Is allowed to see and modify the Name field
Is allowed to see and modify the Price field
Is allowed to see and modify the Discount
Role Administrator assistant
Is allowed to see and modify the Name
Is allowed to see and modify the Price
Fields shown in each role are different, also model binding needs to ignore the discount field for 'Administrator assistant' role.
How would you do it?
On way I could think to do this is create your own versions of the input extension methods. For example instead of TextBox you could create TextBoxRoles and define it like this:
public static MvcHtmlString TextBoxRoles(
this HtmlHelper htmlHelper,
string name,
string RolesEdit,
string RolesView
)
Then in code it would look like this:
<%= Html.TextBoxRoles("Price", "Administrator","Administrator,Assistant") %>
Then your implementation of TextBoxRoles would check the roles of the current user via User.IsInRole() to determine what should appear on the page.
Of course you would have to do this for every input extension method you use.
Since you already have both the current user and access to the authorization provider in your controllers this is an ideal responsibility for them. Using a naive implementation you might pass a collection of widgets to your view after you filtered which widgets the current user has access to. In the case of your form field, things might get hairy when you consider client side validation.
The binding part would be the most straight forward of all, having a custom binder for these special cases will do the trick specially well since it will have access to the controller context and you can grab the current user from there and bind the values according to your role definitions.
What about something like LinFu, an AOP framework? If it's crosscutting, then declare it is so and treat it as such.
I have a classic 3-tier ASP.Net 3.5 web application with forms that display business objects and allow them to be edited. Controls on the form correspond to a property of the underlying business object. The user will have read/write, readonly, or no access to the various controls depending on his/her role. Very conventional stuff.
My question is: what is the object-oriented best practice for coding this? Is there anything more elegant than wrapping each control in a test for the user's role and setting its Visible and Enabled properties?
Thanks
You'll want to drive this off of data, trust me. You'll need a lot of tables to do it right, but it is so worth it in the end. Having to crack open code and edit a bunch of if-statements every time the business wants to change permissions is a killer.
You'll want a table for your main high-level types, things you probably already have business object clases for. Then a table for each status of them. Then a table for the fields of these classes. Then a table for user roles (admin, guest, etc.) Finally a table for the permissions themselves. This table will have columns for business class, status, field, user role, and then what permission they have. For permissions I would go with one field and use an enum: Hidden, ReadOnly, Editable, and Required. Required implies Editable. Anything but Hidden implies Visible. Finally put a Priority column on this table to control which permission is used when more than one might apply.
You fill out this table with various combinations of class, status, field, role, and permission. If a value is null then it applies to all possible values. So you don't need a trillion rows to cover all your bases. For example, 99% of the time, Guest users are read-only users. So you can put a single entry in the table with only the Guest role specified, everything else is null, and set it's Priority nice and high, and set the permission to Read Only. Now for all classes, all statuses, all fields, if the user is a Guest, they will have Read Only permission.
I added status to your list of concerns because in my experience, business all the time wants to constrain things by an object's status. So maybe users can edit an item's name while it is in Draft status, for example, but once it is in Posted status, the name is no longer editable. That is really common in my experience.
You'd want to bring this table into memory and store it in the app's cache, because it's not going to change very often, if ever, unless you do a whole new version.
Now the above is going to handle 90% of your needs, I suspect.
One area that will have to be handled in code, unless you want to get really fancy, is the cases where a user's permission is determined in part by the value of fields in the object itself. So say you have a Project class, which has a Project Manager class. Now the Percent Complete field of the class is basically read-only for everybody, except the Project Manager. How are you going to handle that? You'll need to provide a way to incorporate specific instances of a class into the decision making process. I do this in code.
To work properly, I have found that access levels should be in this increasing order:
NONE, VIEW, REQUIRED, EDIT.
Note that REQUIRED is NOT the top level as you may think it would be since EDIT (both populate & de-populate permission) is a greater privilege than REQUIRED (populate-only permission).
The enum would look like this:
/** NO permissions.
* Presentation: "hidden"
* Database: "no access"
*/
NONE(0),
/** VIEW permissions.
* Presentation: "read-only"
* Database: "read access"
*/
VIEW(1),
/** VIEW and POPULATE permissions.
* Presentation: "required/highlighted"
* Database: "non-null"
*/
REQUIRED(2),
/** VIEW, POPULATE, and DEPOPULATE permissions.
* Presentation: "editable"
* Database: "nullable"
*/
EDIT(3);
From the bottom layer (database constraints), create a map of fields-to-access. This map then gets updated (further restrained) at the next layer up (business rules + user permissions). Finally, the top layer (presentation rules) can then further restrain the map again if desired.
Important: The map must be wrapped so that it only allows access to be decreased with any subsequent update. Updates which attempt to increase access should just be ignored without triggering any error. This is because it should act like a voting system on what the access should look like. In essence, the subsequent layering of access levels as mentioned above can happen in any order since it will result in an access-level low-water-mark for each field once all layers have voted.
Ramifications:
1) The presentation layer CAN hide a field (set access to NONE) for a database-specified read-only (VIEW) field.
2) The presentation layer CANNOT display a field when the business rules say that the user does not have at least VIEW access.
3) The presentation layer CANNOT move a field's access up to "editable" (nullable) if the database says it's only "required" (non-nullable).
Note: The presentation layer should be made (custom display tags) to render the fields by reading the access map without the need for any "if" statements.
The same access map that is used for setting up the display can also be using during the submit validations. A generic validator can be written to read any form and its access map to ensure that all the rules have been followed.
I have often found that this is really the only real easy and understandable way to do it, as your interface needs to modify based on the information and level of editing that they can complete.
I do find typically though that depending on the needs, you can interject the "cannot edit" information by passing role information to the business level if you have plans to move to different presentation levels. but this adds complexity, and if you are only building for one interface it would most likely be overkill
For the website menus we can have different menus based on users role by using the Sitemaps. For controls like Buttons we will have to hide them using their Visible property. I think a good idea will be to create a server control (Button) and expose the Role property. This will hide the Button if the user is not in the correct role.
My first instinct for doing this in a more OO way would be to handle your roles and their implementations for this purpose (control permissions read/write/etc) is to use the abstract factory pattern for your roles. I will be happy to explain the ins and outs of what I am talking about if you'd like but there are probably 900 examples on the web. Here is one link (disclaimer: it's my blog but it does happen to talk to using abstract factory for roles specifically)
Using something like this you could then use a number of methods to display the correct controls for each of your business object properties with the correct attributes (read/write/hidden/displayed/etc).