We are creating an MVC 4 application that requires the user to be authorized to view and/or interact with certain model fields based on his/hers role membership.
For example if the model has a field SSN, the user should be allowed to view this field only if he/she is a member of the admin role. Once displayed the user should be able to modify it only if member of the profile_admin role. In other words, the SSN field should not be rendered if the user is not a member of the admin role and should be disabled if the user is not a member of the profile_admin role. Which roles have the permissions should be controlled by the site admin via the admin UI.
One possible solution is to wrap the SSN field in a partial view and then handle the rendering in our custom view engine. However, this method will require every field that we want to control to be in a partial view and it would require code change if the user wants to control another field (say HireDate)
We were hoping that we could achieve this by using a custom attributes in the metadata class like so:
[CustomFieldAuthorizeAttribute]
public string SSN { get; set; }
We would keep the authorization information for each field in the database like so:
FieldName RoleId AllowView AllowEdit
SSN 1 True False
When the attribute executes it will check the role membership of the currently logged user and will determine the permissions to view and edit for this field and then it will inject the appropriate html attributes like class="hidden" or disabled="disabled".
This way if the user wants to add authorization for another field, all we need to do is create a record in the database for this field. The custom attribute will pick it up from there.
Is it possible to achieve such functionality
Thank you.
For those of you that are facing this situation, I used the concept described in this article to create the necessary functionality. With a little tweaking, the solution worked exactly as required.
Thanks.
Related
What is the best way to store your user information per client? I have several applications which all use the same IdentityServer instance for authenticating. ASP.NET Identity shows how to extend a user by inheriting from IdentityUser.
public class CustomUser : IdentityUser
{
public Int32 CompanyId { get; set; }
}
However, I have applications that have mutually exclusive user information(eg. other applications don't need CompanyId and have properties the the CustomUser's application doesn't need.).
One way would just to create a single type containing all the properties for both. There could be a problem when a property overlaps where both applications need CompanyIds for different companies, not to mention that every column would always be queried every time a lookup was done, so this doesn't seem right. The other option is that I could just create a UserData table in the client applications and query from there as needed which is probably what I have to do since I don't think there is a better option.
If anyone knows a better way let me know.
If would be perfect if UserManager allowed for registration with multiple custom user types and you could get different subsets of data based your choice while each query was optimized for only the data it needed. Then you could put an SQL index per type and maybe even user TPH in entity framework to organize the information.
Unless diving too deep into too app-specific stuff, it looks like a normal user profile.It contains a number of claims describing the user. Let's consider only user specific, not application specific. For instance there are age, country, postal address, gender, whatever. And some apps need only age and country to restrict some content, while the others need postal address or email.Authorization request can contain a set of claims and scops to fulfill these requirements.All above is just about user information, not access rules, and all above is already in the protocol.
Regarding more app-specific... why not to store such stuff more close to the apps and link by user id...
I have developed a pretty standard and common authorization permission system for an internal business web application.
There are some roles with permission sets; system administrator can create new roles and assign permissions to them; every web controller method has an attribute to check for specific permission. So far so good.
But then I have the following conversation with the customer:
Customer: "Please, make it possible to hide specific form fields in specific forms for a specific role".
I: "Ok, so the users of this role shouldn't have permissions to modify these fields, right? I can also add a permission check to the method that saves the data."
Customer: "No, no, it's not a permission issue as such, it's just about convenience - this role doesn't need to work with these fields and we want to make the UI less cluttered. The users of this role shouldn't see these fields in this form only; however, there are other forms where it's totally OK to see these fields. Of course, we might later create new roles that will need to see these fields in this form, but by default the fields should be hidden."
And so the permission system gets cluttered with "pseudo-permissions", such as "See field X in form Y". They exist for UI convenience purposes only and have nothing to do with authorization for performing activities on data.
Is it a good practice to control UI through roles & permissions, even when the specific permission has nothing to do with data processing authorization? Is there a clean solution to avoid cluttering the permission system implementation with such UI-only pseudo-permissions and still provide the customer with granular control to achieve cleaner UI for specific roles?
I changed the user store to our custom oracle db. so, there are some fields that should be added to user profile when set the user profile of a user. How can I add some new properties to user profile GUI and map those to related fields in um_user table? thanks for your response!
you may want to have a look in the administrative console ( /carbon ) for the claim management.
Locate claims in the claim dialect http://wso2.org/claims, there you can define additional user attributes and their attribute names (field name in the underlying userstore).
good luck
Is it possible to define authorization at control level ? If so what is the best practice ?
Consider I have input control named daily wages (text box). userRoleOne is an user role who supposed to see this field, other user roles should not see this field . what is the best practice to do this ?
Yes, it's possible. Current instance of HttpContext is accessible in Razor's views by name Context, so you can check is user in role, or not:
#if (Context.User.IsInRole("userRoleOne"))
{
Html.TextBox("dailyWages", "")
}
It should work without any additional code with ActiveDirectoryMembershipProvider and Windows Authentication, but may not work with Forms Authentication and other memberships.
In last case you should manually create an object of GenericPrincipal class in Application_AuthenticateRequest method of Global.asax (see details).
I am in the process of rewriting my PHP website in ASP.NET and writing the membership system.
I understand I can extend MembershipUser to add member specific properties but how can I pass around boolean group information such as Use Search, Edit Posts etc which are not user specific? Is there a framework item I am missing or should I just create a super object to pass this and other settings around?
Essentially what I want it an efficient way to access the users group properties in my controllers.
Apart from extending the MembershipProvider, you can also extend RoleProvider. RoleProvider is in charge of checking to which group a user belongs to, registering new roles, adding user to role(s), etc. To work with roles you will use Roles class which contains a lot of static methods.
In addition to this, each time you hit a Controller, you can query HttpContext.User property which implements IPrincipal. This property has method IsInRole that is used to communicate with RoleProvider to obtain information if a user is in specific group or not.
Also, in order to allow access to controllers or actions you can use Authorization attribute and list specific roles that have access to the controller.
The roles can be stored in a cookie (to cache them) or you can implement Application_AuthenticateRequest in global.asax and initialize GenericPrincipal manually. This object is passed over to HttpContext.User. The constructor of this object accepts an array of roles that are queried with IsInRole method.
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
// Check if user is authenticated
if (HttpContext.User != null)
{
// Extract roles from a cookie if you used FormsAuthentication
// or read them from a cookie or from some other cached location
// Split roles into array of strings
var roles = listOfRoles.ToArray(); // If it is stored in a List<string>.
var identity = HttpContext.User.Identity;
var principal = new GenericPrincipal(identity, roles);
HttpContext.User = principal;
}
}
The above code is not tested. I wrote it from top of my mind. It should give you a pretty good picture how to cache roles and to use them in the most efficient way.
UPDATE: In case that you need more advanced options where each role can have one or more functionality like your "Use search", "Can do something", "Can do that", I would implement the following security logic:
Users
Roles (users belong to roles)
AccessRight (Role can have one or more access right).
UsersRoles table would be for adding users to specific roles.
RolesAccessRights table is where you define specific rights to each role.
User never talks to Functionality. (BTW, this naming convention is just an example, you will follow your naming conventions).
At my last work this is how we implemented the Audit system (it was Web Forms based). However, in MVC you could override AuthorizationAttribute to check user's role and to check if Role has defined access rights. Considering that you have specific security requirement, you would have to use this attribute on every action where you see the need and necessity.
If you plan to implement this logic, forget about Membership, MembershipUser and Roles. Honestly, I don't use these classes any more. I have my own custom security that I implement and which I used in the last 4 projects without any need for update or modification.
UPDATE 2: The security solution that we used was based on custom MembershipProvider and RoleProvider. Thinking about it now, it was a mistake to rely on that because access to AccessLevel table had to be mapped via Entity Framework. Therefore we had to ways to query our security tables.
My suggestion to you would be to ignore Membership- and Role-related classes completely. The first reason is that you would avoid bothering yourself with unnecessary methods and properties when you override the providers. There would be too many methods with throw new NotSupportedException() in the method body.
Suggested implementation
You will need the following tables:
Users - (You need at least three columns UserId, UserName, Password). If you want to hash the password, you might have to store salt as well. Other columns like FirstName, LastName, etc. I would suggest you to store in a different table and link it with UserId. As for UserId type it's up to you whether you would use int or Guid.
Roles - (You need at least two columns RoleId, RoleName). Again, as with UserId, it is up to you which data type you want to use.
UsersRoles - Store UserId and RoleId. You might want to store properties such as whether the role IsActive which is a bit value.
AccessRights - This is where you would store a key of your access right. In your case that is like UseSearch, EditPosts, DeletePosts, etc. Here you should use at least three columns AccessRightId, AccessRightKey and AccessRightDescription. This description field will turn to be pretty valuable if you have a lot of access right keys.
RolesAccessRights - This is where you define to which role you have added specific access rights. Also have IsActive bit value in order to disable the specific access right to a role.
In MVC you would override AuthorizationAttribute. In this attribute you would specify a list of access rights that have access to controller and/or actions. How you plan to do this is entirely up to you, but I would create an enum with a list of values that are the same as AccessRightsKeys. That way you can use strongly typed access rights instead of string based list. For more information about implementing custom authorization attribute have a look at the references list.
Inside of this attribute, you would read User ID and retrieve the roles. Compare the AccessRightsKeys that you specified against the roles (RolesAccessRights table) to see if the role has access right and whether the rule is active.
As for the solution based implementation I would implement Security service layer which communicates with Security-based repository and unit of work solutions. Because you are using MySQL I don't know which ORM you can use or would you have to rely on ADO.NET with OLEDB providers for MySQL.
My usual approach is a top-down approach. I implement from the high up (like Presentation layer) and go down towards data access layer. That way at the end I have only those methods which I really use and there is no redundancy.
Well, I hope this gives you some picture on how to this. As for time it takes, you can do this in about 8-10 hours.
Reference:
Implementing a Role Provider
Roles Class
How to: Create a Custom AuthorizationAttribute