MVC 4 : Passing around user group data - asp.net-mvc-4

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

Related

How to manage multiple user types in IdentityServer4 using AspNet Identity?

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

MVC And Control Based Authorization

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

What sort of membership system should I use?

[Problem]
I have a pre-built database with user credentials. The only thing I can change about this database is how the passwords are hashed. (Don't ask about that...let's just say it's dumb and I'm fixing it, please.) It's populated with credentials, so whatever I use has to mold to it. We are switching to the ASP.net MVC4 framework, and starting from scratch.
[Question]
What membership system should I use for the problem, if any?
It should:
a) allow me to check against the database using SHA512 for the password
b) set roles depending on the results
c) decorate the actions in the controller so I can feel like a boss
[Details]
Assume I've had a website for people who love to roleplay as toothbrushes. There's -a lot- (for a small- to mid-range website) of data already in the existing database. I'm moving to a brand new database layout and will be converting from the old one. We could change how the user system is managed, but to be honest we'd rather not do so. We have a user table with username and password. Very simple.
I have googled, and googled, and Stack Overflow'd, and Stack Overflow'd. What I have found is essentially a choose-your-own-adventure book where they either have blank page numbers, or the give me a page to an older book whose adventure isn't quite like this one.
I'm hoping that either a) someone will call me a dumb butt and point out I'm asking a duplicate question that leads to a resource with some complete example and/or documentation on how to do what I want or b) help me find a way.
As of right now I'm contemplating writing my own user management/authentication filtering system. I was going to go with the MembershipProvider but that seemed like overkill and didn't appear to do what I wanted it to. Maybe I'm narrowing my vision down too much.
I'm more than willing to hack my own way through and work to solve a problem, but I don't want to roll my own thing if there is something available that I can hook in to.
Update 1
Win made a comment about the MembershipProvider being independent of the MVC system which gave me an "Aha!" moment as things come together. I'm re-evaluating my research to see if I simply didn't put the puzzle pieces together correctly.
Update 2
After much help from dkroy and Win, I got a bit deeper into what is going on here. Once I have everything done I will include it in an edit for anyone else looking for information. Essentially, I was on the right track before I was thinking about scrapping it. I hadn't implemented a GetUser call, and I wasn't calling SetAuthCookie, so it wasn't working correctly. I'm now in the process of writing a RoleProvider.
a) allow me to check against the database using SHA512 for the password
Membership provider support SHA512.
b) set roles depending on the results
c) decorate the actions in the controller so I can feel like a boss
If you want to restrict user by role, you want to implement both Custom Memebership Provider and Custom Role Provider.
However, you do not need to override all. Here are the main ones -
// Membership provider
public override bool ValidateUser(string username, string password)
public override MembershipUser GetUser(string username, bool userIsOnline)
public override string GetUserNameByEmail(string email)
// Role provider
public override bool IsUserInRole(string username, string roleName)
public override string[] GetRolesForUser(string username)
You can Create your own custom RoleProvider and MembershipProvider. That way you will be able to use your existing database structures, and still leverage the MembershipProvider and RoleProvider contracts that ASP.NET implements to provide membership services. Minimal searching on custom MembershipProviders should get you started.

Yii RBAC, Role change in runtime

I am building up a dynamic RBAC system for Yii and I don't know how to handle this problem:
The moderators can change the roles of the Users, furthermore the User can change it too by getting a different qualification (let's say achievement, so s/he can do more stuff and it can happen both ways).
What happens, when the role is changed Backwards (a role with less right) or Forwards (a role with more right) when s/he is logged in? Cannot access the functions he just got the right to use? Or can still access the functions until a logout/relog action?
Thanks your help in advance.
The effect of changing the authorization assignment will be inmediate.
Only the successive calls to IWebUser::checkAccess() issued in the same request may return cached values, since the default implementation of IWebUser, i.e. CWebUser, uses a static attribute to cache the calculated permissions.
To clarify the procedure, you will be calling IAuthManager::revoke() on the old permissions and IAuthManager::assign() on the new ones.
Edit
Sometimes you store session information through the IWebUser::setState() method; if the state of the currently logged user shall change along with the permissions, e.g. you store the current user's role name, you must take this into account and either call IWebUser::clearState() or IWebUser::logout() followed by IWebUser::login() –the latter also clears the cached permissions in the CWebUser implementation.
CWebUser::_access is declared private, so you will have to declare a new attribute if you want to override the default implementation.

Customizing SimpleMembership Provider

I am using simple membership provider in mvc4 application and I can see five tables generated for that. In that i can see username and password are stored on different tables. I want to save username and password on the same table with some custom fields. So I am creating my own Membership Provider by inheriting ExtendingMembership Provider. I have some queries over that.
My application uses 3-tier architecture(BLL, DAL and Presentation layers) and created 2 areas for account and admin. So here i dont know where to place my membership provider which are then accessed with every part of application for using Authorize Attribute.
I am overriding this method CreateUserAndAccount, Do i need to implement my own logic for saving user registration datas to database. But i find only some parameters are passed, how to pass my remaining custom fields from view to the controller using the dictionary object ?
public override string CreateUserAndAccount(string userName, string password, bool requireConfirmation, IDictionary<string, object> values)
{
throw new NotImplementedException();
}
As for question #2: Check out this question I asked this weekend... SimpleMemership CreateUserAndAccount Customization - specifically the blog post I linked in the question as it's very helpful about extending SimpleMembership.
For #1: Use DI to inject ExtendedMembershipProvider into your BLL layer as required. Map it in your DI configuration to Membership.Provider. This is effectively a DAL and should not contain business logic. Better still create a facade around WebSecurity and inject that into your BLL instead.
For #2: Yes the ExtendedMembershipProvider interface uses a dictionary of Key/Value pairs which can be used to map user profile properties to the database schema using an implementation of your choosing.
SimpleMembershipProvider does this by mapping the dictionary keys to corresponding database columns. Once the record has been created, you can then manage the user data using EF and the UserProfile model directly.
Implementing your own ExtendedMembershipProvider is a lot of work and I wouldn't recommend it. The SimpleMembershipProvider schema is relatively clean compared to legacy iterations, and I think you would need a very good reason for wanting to move password column to the user table, rather than just configuring SimpleMembershipProvider to use your own schema, and leaving password where it rightly belongs.