What is a good practice when setting up a users table? Looking at some newbie tutorials, but not sure how to "really" do it right - sql

I'm tinkering around with building a rest API that connects to a database. I'm following tutorials, but the table set ups are all really basic and one of my issues has been that in the "real world" the way its done is a lot more complex and different :(
However, I'm wondering for my actual application (really small) how can I properly set up the User table?
For example, I have set the primary key to userid because that should never be changing. Is it fine to use long for the userid?
Also, is it fine to lump a bunch of things together that are related to the user.. in the User table? I know its a stupid question.. For example, I want to know if the user has signed up for the service, so isMember. Or, is the user signed up for fast service, so hasFastService. Or, should these things be put into a UserAttributes table by the userid?
Finally, I looked up UUIDs and I'm wondering where those fit in, in which scenarios, etc.
Thanks

I'll try to answer this based on my own experience of creating users table in a project recently. The things you have to take care are basically these:
Authentication: Determine your login process and things like credential fields, user types (admin/guest/normal), whether OAuth is required or not, etc. before creating the users table. For example, whether you need a username/password to authenticate or email/password or either "username or email" with a password. The modern practice is to do away with a "username" since its redundant - an email is unique and acts as a username for all intents.
OAuth: If you are giving facebook/google/twitter logins, make provisions for that in your users table. How will you determine whether the user was a normal signup or a social login signup? A field such as "login_method" or something is useful in this regard. A second field called "user_type" maybe created for identifying the type of user account: admin/guest/employee/etc.
Profile fields: Its upto you to determine profile variables. In my last project, I used a few fields like FirstName, LastName, Theme, Timezone, etc. for the profile, but your mileage may vary.
For user-ids, it is usually best to have an auto generated integer primary key which is available in all modern databases.
Needless to say, never store the actual password in the password field. Just has your password and store the has instead. When the user logs in, you can hash the user-input and compare with the user table value.
Finally, DON'T confuse the user table by including related data like clients, employees, etc. All clients are users, but all users are not clients! Keep your design flexible, so as to include all kinds of users like admins, employees, etc.

Related

Realistic Usage of Identity and Roles in .Net 5.0

I am fairly new to coding in the .Net environment. I am having trouble finding "real-world" examples on authentication/authorization using Identity. Most examples I come across are primarily textbook examples that use the ASP .Net registration template.
I am trying to find guidance on where to look (yes, I Googled and I get very unrealistic/unusable use cases or "classroom" examples) or how to do this.
I work for a small school and I am trying to build an application (possibly Blazor - just experimenting with various technologies now) that allows both students and employees to login into a portal and view their relevant data. I have an Employee table and a Student table based on POCO classes. When I add identity to the project it creates Users and Roles tables as well.
I would like to have the "Users" table based on the Student and Employee tables - not have a separate users table. I do not want to have a "registration" option either. I would like the option for an Admin (which would fall under an "Employee") to be able to add users, but not use a registration page.
How would I implement Identity and Roles without using all the extras added? I am using .Net 5.0.
Thank you for your time and pelase forgive the English - it's new to me as well.
I understand what you're trying to do. It IS possible to Create a Custom AuthenticationStateProvider
But unless you have a VERY robust database already, I wouldn't do it. Getting the default system set up and migrating users will take at most an hour. Setting up your own custom authorization system is likely to take you MUCH MUCH longer.
Having different users in different tables is not a good design plan. They all have names, phone numbers, e-mails and so on-- put them on one table.
Hi Derrick and welcome to the community! #Bennyboy1973 is correct, in that both your Students and Employees are all "Users", so they should all be stored in the same table. To add to that response a bit, probably the simplest way for you to manage them is by using Roles, so the Students could be in one role and the Employees could be in another. By having a role attached to each, you can then use the roles as a filter in your queries and you could also restrict the access and actions each type will have based on the role they are in.
Regarding having administrators add the users to the database without public access, this can be done as well. Once you get the default identity system up and running, you can scaffold out the whole system so it can be modified, and probably the easiest way to achieve what you are after is to then modify the default registration (signup) page so that it requires the user to be authenticated to reach it, and then implement a confirmation email to activate each new account.
There are a few things with this approach that you need to be aware of as well.
Since the admin will be setting up all the other user accounts, you should modify the email confirmation chain to require a password reset at some point. The administrators can have access to the user's information as needed but shouldn't have the user's passwords.
Identity Server will store passwords in an encrypted format, and you'll need an initial user in your database. What this means is that you will have to "seed" an initial admin user into the database that you can use to sign in and get started with everything else. You'll have to research how to do this, as it isn't as simple as just accessing the database directly and adding the user and roles because of the encryption. The program you build should be designed to do this for you on either the first run or if you are connecting to a new database, using a username and password that you know. It will then store the user properly that you can use to sign in as Admin, then change the admin password. This makes the whole thing more secure.
This all sounds like a headache, but it's worth it to work through and know how it all fits together. The, as mentioned in other answers, you can migrate existing data into the database.

Auth0 database and social connections, unique email addresses

Maybe I am missing something here, or this is a flaw in Auth0? I'll give an example of my issue:
Let's say I have my Default App (client), hooked up to that I have Username-Password-Authentication (database connection) and google-oauth2 (social connection).
A user comes to my site, signs up via google-oauth2 (social connection) using joe#gmail.com. Once complete, he gets added to my users in Auth0, all great.
A few months later, Joe comes back to my site, and being a busy guy, he forgets he signed up to my site before. This time, he decides to sign up using my custom Email and Password form, that will add the user to the Username-Password-Authentication (database connection). so he signs up there using joe#gmail.com again, and everything goes well, he is now listed in my user's section in my Auth0 dashboard.
This is the problem, I now have two joe#gmail.com accounts, one with google-outh2 and one with Username-Password-Authentication. I really can't have this, I need a unique email address, regardless of the ID Auth0 supplies.
Does anyone know how I can make email address in my user section 100% unique? I'd think a rule would do this, but it appears rules only apply AFTER a user has been registered, so I can't run a rule before adding?
the only way I can see doing this right now is make my own checks and delete via the management API, but that is a really long and messy way to do it I feel.
Any help will be appreciated here!
Thanks!
Auth0's default behavior is to create a new account in the database for every unique entry. Since the user created using Google has a unique id (based on google-oauth2), and the user created using the sign-up form has a unique id - they will technically be considered two separate accounts. In order to resolve this disparity, you can establish a means with which the account data can be merged. In the documentation linked provided above, there are examples of three possible ways of doing this:
Automatic Linking - which involves creating a specific rule to merge users based on matching emails
User-Initiated Linking - which involves providing a UI for users to opt into merging users with matching emails
Suggested Account Linking - which involves setting up a rule that is linked into the UI
One important thing to consider is that the data returned from different social identity providers may not be normalized the way that data is normalized onto the Username-Password-Database. For example, while auth0's default for emails is to lowercase the information, google-oauth2 may return emails as Uppercased - creating the potential for non-matching emails when checks are made using strict equality
The option you are looking for is called account linking.
You can find more info at https://auth0.com/docs/link-accounts

User authentication design, are users people?

The application is written in Ruby on Rails but the problem I am facing is more a design matter than language related.
the system provides service to a number of users to maintain a registry. So it relates persons to things. As such it has a model called Person representing owners and it has a model called User representing those who manage the registry.
Now a new requirement has arisen to allow People to log in and be able to change personal details which it was not required for the original design.
The question is how to refactor the application to allow this new requirement in?
One easy solution is to create Users for each person who request login credentials and link user to person entity but that is not very DRY as some fields such as firstname, surname etc. are in both classes and in particular, that is precisely the data people will be able to change. Besides User and Person are stored in separate tables.
The other possibility I was considering is to make one to extend the other but having data in separated tables it makes it a bit messy. Additionally the logical extension would be User <- Person as an user is (generally) a person but thinking on the implementation Person <- User is quite a lot easier.
One last option could be to scrap User and move login credentials into Person leaving logon fields empty for those who won't log in and half of the fields empty for those just login in.
Can you think of a better solution?
You could think about how this should ideally work if you were to write the application bottom-up, and then figure out how to make a reasonable compromise between that and your current setup. Here are some generic inputs.
As authentication is involved, you need an "Identity" that can be authenticated. This can be e.g. an email address and an associated password, with email verification.
An Identity can potentially be associated to multiple "Roles" and someone authenticated with the identity can choose which role to perform, e.g. "I am now an administrator" vs. "I am now a regular site user", and the role defines the user's current rights for the logged in identity. Or if you don't need that level of complexity, you can say that an Identity is a (single) Role.
You need some tracking between possible "Rights" and the Role the user is performing. E.g. the simplest setup could be the Identity or Role has some boolean can_edit_profile or can_modify_registry properties.
Whenever a user attempts to perform an action which requires certain Rights, it is simply a matter of looking up the corresponding rights set for the Role being performed by the user, to check whether the user is allowed to proceed.
For your application this may just involve adding a 'can_change_registry' property for your user objects, and check whether that property is True for any code accessing that part of the site.

Preventing Duplicate Login Records

We have a a large set of users who use our web application fairly infrequently (i.e. they don't visit every day or every week). As a result, they often:
forget the password they used
forget which e-mail they used on signup OR
may have actually had their e-mail address change since the last time they signed in
Often, when facing the login signup form, they'll simply create a new login record with a new/different e-mail address.
This is a problem because it's important they stay linked to their previous records, and it can cause problems if there are duplicate records for a single person in the database (note that these are not duplicate records in a database sense; from a data standpoint they're not duplicates at all, but they are duplicates in the sense that they point to a single real human being).
Right now I have a check in place that sees if there is already someone with the last name and first initial, and asks them to confirm if they are or aren't one of these other people. Obviously this is very clunky and falls flat when dealing with very common names. Also, it's confusing to display a page to a user that says, "I think you're actually this other person. Please let me know if you are this person or not."
I'm looking to hear from other developers who have had to deal with this problem, and what they came up with. I'm also interested in solutions that gracefully merge two logins.
You could easily prevent the user from signing up if they entered a duplicate username or e-mail address from what already exists in your database. You could present the user with a page that asks them to recover their password for the existing account. If the user is going to sign up with a different username and e-mail, I'd argue at that point it may be out of your control to stop the user from creating another account (unless you are gathering some sort of unique identifier from the user (e.g. social security number, etc). I wouldn't do any filtering based on name as it's never going to work 100% of the time.
Otherwise maybe a simple UI change could help alleviate the problem as well (e.g. "Returning user? Login"). Make sure the user sees that they can login with their existing account, and on that screen make sure the user can easily see that they can recover their account information if they can't remember it.

Storing a Windows SID in a Database for Lookup

I have an ASP.NET MVC application where I need to allow to customers configure MembershipProviders based on their environment, but still be able to map that MembershipUser to a concrete User model in our database.
Membership.GetUser() will give me access to the logged-in user's Membership.ProviderUserKey. I can use this to relate to a User record. Our custom SQL provider will just return the User.Id, but AD is a different story. In that case, ProviderUserKey is an IdentityReference.
These lookups will happen very frequently, as you can imagine (although caching can assist in reducing the lookups at the database level).
I can't decide which route is better to go: Storing the SID as a varbinary or varchar column. This column would not be a primary key and would not have a clustered index. Knowing that I can index strings pretty well, and reading a SID in string format is certainly nicer than binary. Anyone willing to share how they solved such a situation?
Update
I don't know how I missed this SO question when I was searching before I posted, but it seems pretty clear that ActiveDirectoryMembershipProvider and ActiveDirectoryMembershipUser are not quite cut out for the task at hand, as they exist today.
An answer in that SO question linked the following article, where the following was stated:
The relative identifier portion of a
SID is unique relative to the domain,
so if the domain changes, the relative
identifier also changes.
Thus when a User object moves from one
domain to another, a new SID must be
generated for the user account and
stored in the Object-SID property.
However, each group and user has an Object-GUID, which will never change, even if the account is moved. Therefore, it would behoove me to use Object-GUID in my User class, and not Object-SID. Otherwise, someone's User record will be abandoned if they are moved and therefore breaking the relationship between their principal and the data they created.
Unfortunately, ActiveDirectoryMembershipUser doesn't let me get at Object-GUID. So, I'll either have to translate the SID to a GUID after ActiveDirectoryMembershipUser does its work, or create my own MembershipProvider that does everything I need on the spot. Unfortunately, this means I might have to duplicate effort already done for me by ActiveDirectoryMembershipProvider.
Microsoft stores SIDs as varbinary(85) in sys.server_principals
This is also a unique column, so it must have an index...
username is the LAST thing you want to index on.
SIDs only change in an AD when you change a user from one domain to another. RIDs are split into 2 groups - inbuilt (< 1000) and user RIDs. Pre-defined users such as Administrator, Guest etc always have the same RID.
If you want to handle movement of users etc, then GUID is the way to go.
username can be changed at any time in Users and Groups management.
this is different to the object name, which is invariant, but I don't believe is mandated unique across a forest. You can have any number of John Smith users.
I'd look into the ADSI objects. These are COM objects which should be accessible from ASP. MSDN explains pretty well. an ADSearch object can be used to return user attributes (e.g. including DN) from a GUID.
Sounds like you're making this a lot more difficult than it needs to be. What do you need a SID or GUID for? You already have a unique, perfectly readable identifier for the users account maintained in ActiveDirectory.
It's called "the username". Hopefully it's the same username as stored in your apps "user" table.
Your app just needs to know if that username successfully authenticated with ActiveDirectory. So if they successfully log in - you just store the fact that they are authenticated in your Session variables.
If they are configured to use the db user login, if successful set the same Session variable indicating that they successfully logged in.
No fancy GUIDs or SIDs ... simple.