Best Practices for controlling access to form fields - asp.net

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).

Related

Dynamic Access Control for entities in symfony 4

I try to manage the access rights for users to edit or view different articles.
Articles can be created dynamically and the rights should be editable for every article.
In my case, I have a User object and multiple other objects (Article, and more...).
I need to check if a User can read or write any kind of object.
I actually see there is a method Voters, but they only can manage User groups?
Can somebody help me?
A Voter can decide almost anything - usually it's based on a user's permission, but it doesn't have to be - I've used one as a 'feature flag' check, with a value fetched from a configuration, or database entry to show something - or not, as an example.
The page on voters has an example on viewing, or editing a database record (a Post entity, via a $this->denyAccessUnlessGranted('edit', $post);.
In your instance, the voter would be passed the 'attribute', the object (Article, etc) you want to check on, and gets the current user from a service. If that user has the appropriate permission to read/edit/delete the Article or other object, it returns true.

ASP.NET MVC Authorisation with CRUD roles

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.

Flex-Cairngorm/Hibernate - Is EAGER fetching strategy pointless?

I will try to be as concise as possible. I'm using Flex/Hibernate technologies for my app. I also use Cairngorm micro-architecture for Flex. Because i'm beginner, i have probably misunderstand something about Caringorm's ModelLocator purpose. I have following problem...
Suppose that we have next data model:
USER ----------------> TOPIC -------------> COMMENT
1 M 1 M
User can start many topics, topics can have many comments etc. It is pretty simple model, just for example. In hibernate, i use EAGER fetching strategy for unidirectional USER->TOPIC and TOPIC->COMMENT relations(here is no question about best practices etc, this is just example of problem).
My ModelLocator looks like this:
...
public class ModelLocator ....
{
//private instance, private constructor, getInstance() etc...
...
//app state
public var users:ArrayCollection;
public var selectedUser:UserVO;
public var selectedTopic:TopicVO;
}
Because i use eager fetching, i can 'walk' through all object graph on my Flex client without hitting the database. This is ok as long as i don't need to insert, update, or delete some of the domain instances. But when that comes, problems with synchronization arise.
For example, if i want to show details about some user from some UserListView, when user(actor) select that user in list, i will take selected index in UserList, get element from users ArrayCollection in ModelLocator at selected index and show details about selected user.
When i want to insert new User, ok, I will save that user in database and in IResponder result method i will add that user in ModelLocator.users ArrayCollection.
But, when i want to add new topic for some user, if i still want to use convenience of EAGER fetching, i need to reload user list again... And to add topic to selected user... And if user is in some other location(indirectly), i need to insert topic there also.
Update is even worst. In that case i need to write even some logic...
My question: is this good way of using ModelLocator in Cairngorm? It seems to me that, because of mentioned, EAGER fetching is somehow pointless. In case of using EAGER fetching, synchronization on Flex client can become big problem. Should I always hit database in order to manipulate with my domain model?
EDIT:
It seems that i didn't make myself clear enough. Excuse me for that.
Ok, i use Spring in technology stack also and DTO(DVO) pattern with flex/spring (de)serializer, but i just wanted to stay out of that because i'm trying to point out how do you stay synchronized with database state in your flex app. I don't even mention multi-user scenario and poling/pushing topic which is, maybe, my solution because i use standard request-response mechanism. I didn't provide some concrete code, because this seems conceptual problem for me, and i use standard Cairngorm terms in order to explain pseudo-names which i use for class names, var names etc.
I'll try to 'simplify' again: you have flex client for administration of above mentioned domain(CRUD for each of domain classes), you have ListOfUsersView(shows list of users with basic infos about them), UserDetailsView(shows user details and list of user topics with delete option for each of topic), InsertNewUserTopicView(form to insert new topic) etc.
Each of view which displays some infos is synchronized with ModelLocator state variables, for example:
ListOfUsersView ------binded to------> users:ArrayCollection in ModelLocator
UserDetailsView ------binded to------> selectedUser:UserVO in ModelLocator
etc.
View state transition look like this:
ListOfUsersView----detailsClick---->UserDetailsView---insertTopic--->InsertTopicView
So when i click on "Details" button in ListOfUsersView, in my logic, i get index of selected row in ListOfUsers, after that i take UserVO object from users:ArrayCollection in ModelLocator at mentioned index, after that i set that UserVO object as selectedUser:UserVO in ModelLocator and after that i change view state to UserDetailsView(it shows user details and selectedUser.topics) which is synchronized with selectedUser:UserVO in ModelLocator.
Now, i click "Insert new topic" button on UserDetailsView which results in InsertTopicView form. I enter some data, click "Save topic"(after successful save, UserDetailsView is shown again) and problem arise.
Because of my EAGER-ly fetched objects, i didn't hit the database in mentioned transitions and because of that there are two places for which i need to be concerned when insert new topic for selected user: one is instance of selectedUser object in users:ArrayCollection (because my logic select users from that collection and shows them in UserDetailsView), and second is selectedUser:UserVO(in order to sync UserDetailsView which comes after successfull save operation).
So, again my question arises... Should i hit database in every transition, should i reload users:ArrayCollection and selectedUser:UserVO after save in order to synchronize database state with flex client, should i take saved topic and on client side, without hitting the database, programmatically pass all places which i need to update or...?
It seems to me that EAGER-ly fetched object with their associations is not good idea. Am i wrong?
Or, to 'simplify' :) again, what should you do in the mentioned scenario? So, you need to handle click on "Save topic" button, and now what...?
Again, i really try to explain this as plastic as possible because i'm confused with this. So, please forgive me for my long post.
From my point of view the point isn't in fetching mode itself but in client/server interaction. From my previous experience with it I've finally found some disadvantages of using pure domain objects (especially with eager fetching) for client/server interaction:
You have to pass all the child collections maybe without necessity to use them on a client side. In your case it is very likely you'll display topics and comments not for all users you get from server. The most like situation you need to display user list then display topics for one of the selected users and then comments for one of the selected topics. But in current implementation you receive all the topics and comments even if they are not needed to display. It is very possible you'll receive all your DB in a single query.
Another problem is it can be very insecure to get all the user data (or some other data) with all fields (emails, addresses, passwords, credit card numbers etc).
I think there can be other reasons not to use pure domain objects especially with eager fetching.
I suggest you to introduce some Mapper (or Assembler) layer to convert your domain objects to Data Transfer Objects aka DTO. So every query to your service layer will receive data from your DAO or Active Record and then convert it to corresponding DTO using corresponding Mapper. So you can get user list without private data and query some additional user details with a separate query.
On a client side you can use these DTOs directly or convert them into client domain objects. You can do it in your Cairngorm responders.
This way you can avoid a lot of your client side problems which you described.
For a Mapper layer you can use Dozer library or create your own lightweight mappers.
Hope this helps!
EDIT
What about your details I'd prefer to get user list with necessary displayable fields like first name and last name (to display in list). Say a list of SimpleUserRepresentationDTO.
Then if user requests user details for editing you request UserDetailsDTO for that user and fill tour selectedUser fields in model with it. The same is for topics.
The only problem is displaying list of users after user details editing. You can:
Request the whole list again. The advantage is you can display changes performed by other users. But if the list is too long it can be very ineffective to query all the users each time even if they are SimpleUserRepresentationDTO with minimal data.
When you get success from server on user details saving you can find corresponding user in model's user list and replace changed details there.
Tell you the truth, there's no good way of using Cairngorm. It's a crap framework.
I'm not too sure exactly what you mean by eager fetching (or what exactly is your problem), but whatever it is, it's still a request/response kind of deal and this shouldn't be a problem per say unless you're not doing something right; in which case I can't see your code.
As for frameworks, I recommend you look at RobotLegs or Parsley.
Look at the "dpHibernate" project. It implements "lazy loading" on the Flex client.

ASP.Net MVC elegant UI and ModelBinder authorization

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.

Best practices for control permissions?

Hey all, I need some advice on this...
We have certain permissions setup in the database for certain levels of control a user can have over the application. Disabled, ReadOnly and Edit.
My question is: Are there more generic/better ways to handle permissions applied to a form element on the page than writing a security method/check per page to enable/disable/hide/show proper controls depending on the permissions allowed?
Anyone have any experience handling this in different ways?
Edit:
I just thought about the possibility of adding constants for each layer that needs security and then adding an IsAuthorized function in the user class that would accept a constant from the form that the control is on, and return boolean to enable/disable controls, this would really reduce the amount of places I'd have to hit when/if I ever need to modify the security for all forms.
Cheers!
Sorry for going slightly off-topic here, but learn from my mistake:
I had a simple web app one time that I was developing and I thought that I'd setup 3 levels of security: limited read-only (public), read-limited write (user), read-write (admin). The users table had a level of security in it and everything worked fine... until I needed finer control over security levels as the project grew. It all started with a user that needed more than user control in one area of the program but not full admin control.
What I should have done was setup an expandable system with finer control even though I didn't need it at first. This would have saved me sooo much time.
I think there are more possibilities than you are considering.
Hidden/Visible - is the field visible or not
Blanked/System/Unchanged - does the system initially set the value to blank, or to some business-rule-provided value, or is it left as-is
ReadOnly/Editable - can the user change the value
Required/LeaveBlank/Optional - is the field required to not be blank, or can it be left blank assuming it was blank to begin with, or is it optional and can be blank in any case
Also you need to consider a lot of factors that go into making the decision
Role - usually the user has 1 or more roles, and those roles can allow or disallow different possibilities
Status - the status of the object in question often controls which fields are editable, regardless of role
Object - often the values of the object itself determine what is allowed when, beyond just's it's status
Task - you might break down editing things into more than just read and edit
Section - I often want to control the settings for an entire section of the object or screen, and all the controls inherit those settings, but can override them on an individual basis if needed
Implementation?
First, make sure you have a clear vision of how the page lifecycle is handled. Mine usually goes something like this.
Get the object they are editing, usually from session state, sometimes if they are doing a "new" operation you may need to create a stub data structure for them to work on
If this is the first time the page is loading up, populate choices into dropdowns, this is usually a generic process, done only once
If this is a postback, update the object being edited by reading in values off the controls
Process events such as button clicks
Run through all your business edits, these should alter the data structure they are editing
Update the visibility and editability of the controls based on all the data you have on hand
Populate the controls with the data from the object being edited, including validation messages, or error messages
You may want to check how django handles forms and validates them. Forms are handled like models, they have their own class, so their field list, validation rules and display logic is no more scattered throughout the view, the controller and the helper. With such a structure, it's pretty clear where the hidden/readonly/editable logic belong.
It seems that such a feature is not yet implemented in rails. It's not only a time-saver, it keeps your code clean and structured. You could start by creating a base class for forms, where validation is separated from the controller.
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.
(Also see thread: Best Practices for controlling access to form fields)

Resources