[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.
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...
Hard to find a meaningful title. I hope I get clearer now.
I'm building a service which is similar to doodle regarding the authentication model. The user can "create" something (using a form). There will be two different views. One for the creator where he can modify his settings and another one for public access.
I don't want to force users to register / log in. So I came up with a URL structure like doodle has:
/{some-id} -> public access
/{some-id}/admin/{some-token} -> settings page for the owner
The question now is how I can deal with this best. Currently I pass the token to all admin related Methods. But I don't feel comfortable with that.
I also thought about some server side session. I found two meteor packages but they are both not actively maintained anymore.
Another idea was to misuse the built in user management but without the user to recognize it. But I don't think that's feasible.
So now I'm asking you if you have a nice way of dealing with this. I hope I made clear what I want to do.
There are many ways of doing it. One way is to reuse Accounts package.
You user id is {some-id} and the password is {some-token}.
When you create new page. You create new user on server side using Account.createUser.
When you enter url /{some-id}/admin/{some-token}Meteor.loginWithPassword.
I've been knocking my head up against this problem for a few days now and after seeing dozens of examples all over the web I'm no closer to a solution.
I need to to various types of login, eventually. For right now I'd settle for one. I would like to login using fields other than username and password. Let's say I want to use name, last name and birthdate.
I thought the easiest way to go was to just implement my own UserDetailsService and plug it into my provider. But UserDetailsService only has one method, loadByUsername, which doesn't seem to be the most intuitive way to load my user.
So then I thought it would be better to implement my own AuthenticationProvider ... or simply extend DaoAuthenticationProvider, and override the authenticate() method. But that method takes an Authentication as a parameter ... can I used a POJO, with only name, last name and birthdate fields, as an Authentication object?
Ditto for Authentication Manager. In fact, in the api for AbstractUserDetailsAuthenticationProvider (where the authenticate() method lives) it says that it "Performs authentication with the same contract as AuthenticationManager.authenticate(Authentication)"
But people seem to implement Providers more than Managers. oddly enough, most examples of "custom" Providers and UserDetailsServices ... all implement authentication with username and password, which is was Spring Security does by default anyway!
Can anyone shed some light on this subject? As I said, there are tons of examples but they are all very similar and none that I can find use an Authentication Object that isn't username/password.
Bonus points if someone could also tell me the best way to go about having more than one Provider/Manager -- for example, one like the one described above, and another that authenticates using name and social security number, for example -- and to use one or the other (not both, and not the second one if the first one fails!) depending on a parameter pass from the url, for example.
I'm not sure if you had already solved this challenge. But, it seems that I have a similar case with you. My login page requires additional field 'organisation' aside from 'username' and 'password'. Here is what I did:
I've used custom AuthenticationManager and custom UsernameAndPasswordAuthenticationFilter.
The custom filter is for retrieving the additional field from HttpServletRequest. I added the field to the session and retrieved it inside custom AuthenticationManager.
Performed authentication with the three fields using another bean/service.
I'm building a couple of ASP.NET MVC websites that will share a database (because they share data under the hood). That said, logins between sites will not be shared at the moment. For reference, I'm using NHibernate for data access with SQL Server under the hood (currently).
As currently laid out, the system has tables for Sites, Roles, Users, and Rights. Sites have sets of users, rights, and roles. Users can be in many roles. Roles have a set of rights. Users will be able to sign in with a username and password, but I don't want to paint myself into a corner - I might want them to be able to use a google or facebook login later.
Now, I'm a little confused as to which path to take with regard to securing the site. I'm not enamored of the old school membership and role providers for several reasons. Chief among these is that I won't be restricting very many things by roles; things will be restricted based on user access rights. I'm looking at the following few scenarios for authentication.
1) I want to be able to specify rights required to use a controller method via an attribute.
2) I want to be able to quickly query and see if a user is in a particular role or has a particular right.
So, I actually have a set of questions, but they are kind of intertangled. First, what should I do? Just a custom authorization attribute? Second, what's the workflow on login and the like? What are the steps required for this to work properly and securely?
I realize these are sort of noobish questions, but in the past I've gotten by with the old provider way of doing things. I don't particularly care for that and would really like some better suggestions. So I guess everything old is new again for me.
I would flee the Membership provider from MS like the pest. It was already badly implemented when it came out with .NET 2.0, and the recent refresh is no better.
Roles, Users, ..that's not bound to the Membership provider, you can use those on your own. Set up Authentification, create a httmodule that handles said Authentification (a simple userId for the Context.User.Identity suffices)
All you need is a User that derives from IIdentity and in your httmodule
string[] roles = new[] {"Admin", "CoolDude"};
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(user, roles);
..and now in your mvc controller simply add the necessary authentication attributes, game played !
Make custom roles, custom mvc attributes, or query if a user is in a specific role directly
if (HttpContext.Current.User.IsInRole("Admin")) { ...
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