Storing a Windows SID in a Database for Lookup - sql

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.

Related

Can the Auth0 User ID change over time?

Theoretically speaking, if I wanted to base my Users database table on the Auth0 returned data and maintain a unique ID in my Users table based on the Auth0 user profile id, will I ever encounter a situation where the Auth0 user id has been changed? If so, what are the situations when a user id changes?
The simple answer here is that the User Id will not change after creation for a given user profile in Auth0. However, there are a few other factors to consider, in particular:
Namespacing userids
Account linking
Auth0 will place a connection type prefix in-front of userIds to effectively namespace just the Id part - this is done with a pipe. For example, auth0|12345 or auth0|MyCustomDB|12345 etc. You need to ensure you use the entire userId, and not just the numeric value after the last pipe. The reason for this, is to ensure there are no collisions between Ids in IdP/Datastores in which Auth0 is the Service provider, & not the Identity Provider.
With regards to account linking, if you have two separate User Profiles - each has its own UserId. When you account link, one will become effectively the "primary" or "top-level" user profile, and the other profile becomes sub-ordinated as a "secondary" identity. And you can link multiple user profiles together as a single user profile in this way, but only one shall be the primary. You could consistently account link, so for example the DB Connection remains the primary, or you may just make the most recently created user profile (with a shared "email" in common to another profile) the primary... In this situation, the "tertiary" user profiles will retain their original userId, but if you were querying for the user profile only (and not trawling the identities array for that user profile also), then the effect on the search would appear to be the userId had changed. In actual fact, this is because what was originally a "top level" user profile, is now nested inside another use profile.
Finally, and slightly orthogonal to your original question - but where you state if I wanted to base my Users database table on the Auth0 returned data, hope here you were not referring to using the Auth0 user profile userId as a primary key in say a relational database. You would be better served creating a Surrogate key (unique key with no business meaning / outside dependency) as your primary key, Then store the Auth0 userId as a separate attribute on each tuple.
Hope the above made sense, please leave comments below if still unsure.

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

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.

How do you solve a relational database paradox?

I have a website in progress where users create posts in a feed, and may have many feeds. Their profile will display a default feed of their choosing.
The 3 tables in this paradox are "accounts", "profiles", and "feeds".
An entry in profiles contains additional information about a user. This is in a separate table because it may be modified more often, and many queries use the accounts table without needing this information.
A field in accounts (profile) must reference a profile. I've done this, instead of having profiles reference accounts, because otherwise an account could exist without a profile. A profile existing without an account would be the result of a deactivated account (provided the user explicitly chose not to have their profile removed from the site).
A field in profiles (default_feed) must reference a feed. This may be changed often, and isn't needed by most queries, so this seems a sensible place for this data.
A field in feeds must reference an account; all feeds have a creator.
You may be able to see my problem already, but I'll elaborate:
I can't make an account without making a profile, which I can't make without making a feed, which I can't make without making an account, etc...
Must I give up the functionality of profiles for deactivated accounts (which wouldn't be a huge deal, but I'd like to know if there's another way), or is there a sensible trick that will allow me to solve the paradoxical nature of this relationship?
EDIT: I've realized I could simply set the default_feed field so it's allowed to be null, and have the application handle this special case (which should never happen anyway, since a feed is created with the account) with a "this user has no default feed" message. I'd still like to know if I've missed a more creative solution though.
One simple way to break the dependency is to make default_feed in profile nullable.
Start by creating a profile with the default feed set to null
Create the account that references that profile.
Once the account is set up, create the default feed with the account that has been created as owner.

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.