I'm developing an MVC4/Razor site for which the client requested the ability for users to be able to sign in with Facebook/Google accounts. Fortunately, this is fairly straightforward using Forms authentication.
However, I'm faced with the issue of: what if the user's email address which is returned by the provider matches an existing username?
For example, tim#rocketeerconsulting.com previously exists as a native account. For whatever reason, the user wants to use Facebook to login. Facebook returns that tim#rocketeerconsulting is the user's email address. If the user attempts to create an account using that information, MVC4 will state that the account already exists.
There are a few concerns:
Should users be allowed to merge accounts if an email address provided by an OAuth provider matches an existing account?
This presents a potential security risk. Can I rely on the OAuth provider to confirm that the address is valid? If not, a malicious user can create a Facebook account and then gain access to another user's account.
How should such a thing be implemented, if at all?
I recognize there is a similar question here, but my question pertains specifically to the context of Forms auth in MVC4.
You are right: it's easy to impersonate this way
Indeed, to add more to the problem, not all the OAuth providers give you the user email address (LinedId).
Every OAuth provider use an email address for initial validation, however, the user can have more than one, indeed some encurages you have them as backup.
So the email is not a good 'key' to identify the user.
Probably your solution will be to have a table with your own internal id and the relate this to the OAuth provider unique user identification: some use the email address, others screen name or similar.
This will allow the user to have more than one OAuth validator on your site.
I implemented this with: Linkedin, Twitter, Amazon, Google+, Microsoft and Facebook. Additionaly, our users can use their domain account to login, but this is another story...
Related
I am using the Firebase authentication functionality. I am using Facebook, Google, Twitter and email and password as providers. The default functionality is to use a single email by authentication.
If I authenticate with an account with Facebook, Twitter or Google and then try to enter but using email and password to do it, it shows me a warning where it says that I already use another authentication method and it allows me to do it with the previous one.
If I authenticate with email and password and then try to authenticate with Google, Twitter or Facebook these authentication methods overlap, that is, take both and in the Firebase console I can see that they are both.
Now, if I authenticate with email and password, Facebook (I think) or Twitter and then try to authenticate with Google, it deletes the previous authentication methods. That is, if with the first authentication methods I had id1 after authenticating with Google, the entry with id1 is deleted and one is created with id2.
This generates a problem in my application because it is a way to lose the user's registry previously created with id1.
I'm not sure if this is the expected behavior but I do not think so. Obviously whenever I refer to doing a 'new authentication' with another method I make sure to use the same email.
It sounds like you are looking for account-linking. This is possible in Firebase-authentication. Users are identified by their Firebase Userid and you can link multiple authentication providers to a userid.
Try to check this documentation. I think this is what you are looking for: https://firebase.google.com/docs/auth/web/account-linking
I hope it helps.
The Google provider overwriting the existing providers is due to Google emails being verified as Google owns these email addresses.
To work around this, you will need to verify the email after the user signs up by sending an email verification. This guarantees that Google sign-in will not unlink the providers as the email is considered to be verified. So if a user signs up with Facebook (using a Google email), verify the email so next time the user signs in with the same Google email, the Facebook provider would remain on the user.
There doesn't seem to be any mention of this in the documentation, and all I found was this and this, where I would like to confirm this:
If there is an existing account with the same email address but
created with other credentials (e.g. password or non-trusted
provider), the previous credentials are removed for security reasons.
If a user signs in through Facebook or email/password and later through Google, their account sign in method is converted to Google. It only happens with Google and the setting for one account only is active.
Is it intended to be like this and is there any way to stop it?
As the documentation says: certain email domains have a trusted provider. Most prominently: Google is the trusted provider for #gmail.com addresses, since it's the only issuer of these email addresses.
If a user first registers their gmail address with say Facebook, and later there is a registration with that same gmail address from the Google provider, the latter registration is considered to overrule the former. If the user later signs in with Facebook again, the two accounts can be linked.
As far as I know, the only way to prevent this is to allow multiple accounts per email address.
Also see these posts by some of the Firebase Authentication engineers:
Firebase, login by same email different provider
https://github.com/firebase/FirebaseUI-Android/issues/1180
https://groups.google.com/d/msg/firebase-talk/ms_NVQem_Cw/8g7BFk1IAAAJ
On our app we are using "One account per email address". We want users to sign up using a specific authentication provider, which we keep track of, and stick with it.
What I've noticed today is that if I log in using a Google or Facebook provider I can then send myself a password reset link to the associated email address, which allows me to use the email/password provider instead.
There is a slight difference in behaviour depending on the first provider:
If I use Google first, after I use the password reset link I can now user either provider to log in, and both are linked to the same firebase uid. If I debug, I can see both in the providerDetails array on the authData object I get back from Firebase.
If I use Facebook first, after I use the password link the password provider replaces the Facebook one completely, although it retains the old firebase uid. At this point I can no longer use the Facebook login.
My questions are: is this behaviour intended, and, is there any way to switch it off?
This can cause confusion if say a user logs in using Facebook (which we track) and then later forgets and sends a password reset. It isn't the end of the world because they can carry on using the password login, but it certainly muddies the water.
Thanks
The behavior is intentional.
For end users, if they had signed into the app using Google or Facebook, and later they want to recover the password, the most likely reason is they (or an attacker) can not login with that identity provider.
After the user clicks the password reset link, Firebase removes the non-email identity providers to prevent other people from accessing the account silently. If the user still wants to add Facebook/Twitter login, they can do that via manual account linking (if the app supports).
In case the user's email service is the same as identity provider (e.g. #gmail.com users login into the app using Google), Firebase has an optimization to keep the identity provider since there is no security risk.
If I register with Facebook (x#x.com) and later log in with Google (y#y.com), but I do not have the same email address on both providers, there are 2 users created. How can I handle this situation?
Linking is typically used in three cases:
Automatically requested by the backend for security reasons: when a user signs in to google for example with email x#x and then logs out and tries to sign in with a new facebook account x#x. In this case the backend will not complete the second sign in without verifying that the second user is the same as the first user (since both use the same email). So in this case, the user has to sign to the google account and then link the second facebook account to the initial one.
Manually triggered by the developer: One common case here is that the user signs in to google with email x#x and remains signed in. The developer wants access to the user's facebook friends. So the developer will ask the user to link their facebook account to the already logged in google user.
Upgrading an anonymous user: Developer could automatically sign in users initially as anonymous and then prompt them to upgrade to a registered user. In this case you can call link on the anonymous user.
So auth.currentUser.link can be made on all kinds of users as long as the account you are linking is new and not already linked.
You'll want to use the Account Linking APIs to authenticate multiple providers for the same account. Docs for Web, Android, and iOS are available.
I just don't still get Claim Based Authentication/Authorization workflow.
The application allows authentication via Facebook.com
After the user is authenticated, an admin can give her/him a claim of having the role of Manager, which creates another claim (where?)
Of course, this claim won't be on the facebook.com server, question 1: where should that claim be stored?
When the user log in again later, I get the claim of facebook.com and I should get the claim from the application. and merge them?
How is the workflow? Trying to understand claims in practical usage.
Basically, Facebook tells me that I'm john#doe.com, and 'field in the blanks' adds a claim that I'm also a manager of domain.com
then I pass those claims to domain.com?
How should I configure in asp.net the application at domain.com to trust Facebook and 'filled in the blank piece' and request claims from both?
I guess I'm using external providers for Authentication and my own provider for Authorization, how this is created on ASP.NET (web API / MVC)?
UPDATE (for clarification)
Let's get backwards. I create a web application where users can register.
'Somehow' there's an trusted ClaimsBased authority somewhere (this should be another application??) where I request the claims for a particular user to see if have particular rights on my application.
So I imagine something like :
/authserver/claims
and my validation checks if X claim is met to do certain operations.
later I add to Facebook. now I have
/facebook/claims
which tells me the user is X
and
/authserver/claims to see if can do operation X on resource Y.
how this is managed on ASP.NET? and where my own claims should be created/exposed/developed.
I think I'm missing something fundamental here.
I think the important thing to understand is the difference between authentication and authorization.
Authentication - the act of confirming the truth of an attribute of a datum or entity.
Authorization - the function of specifying access rights to resources, which is related to information security and computer security in general and to access control in particular.
So, typically for secured system, the workflow starts with Authentication. When a user first connects/uses a system, then are not authenticated (lets say this user is of a type/group Anonymous). The act of the system determining the user is not authenticated is an Authentication in and of it self. Based on being Anonymous, then the act of the system determining what that type of user anonymous has access too is now authorizing what the user can do. For very secure system, the only access anonymous has is to the login screen/page. Once logged in the user is assigned a unique identity and assigned some type of group policy/role (if not already created).
with a web-based application and having a website (#1) authenticate for another website(#2) it becomes a bit more complicated. When I log into StackOverflow(#1), I use my Gmail(#2) account. I get redirected to Google with some special way for Google to know that the page I came from/to go back to. This could be a special key/url combination or for less restrictive access, usually has to do with return url (after I say, yes, where I go back too). Google will create a special authentication token that is specific to the url I am returning to. It is tied to the URL because that means that my token on StackOverflow won't allow me or anyone else to log into say NewEgg for example (in other words someone at StackOverflow with access to the database can't use my token to authenticate as me on some other website, but technically they could log in as me on StackOverflow, but they own the website, so that doesn't really matter). Now I am authenticated on StackOverflow (but technically StackOverflow doesn't even need to know any information about me, just my Token).
On StackOverflow as a new user, a new account is created. This account probably has a one to many relationship to my unique account on Stack Overflow and multiple of logins (and type of logins, OAuth, OpenID or SO Login). Once the account is created, I have whatever access they have setup by default. If I need more or some trigger (lets say based on my Reputation points :) I now have access to Administrative functionality (given some role). That role is tied to my account and indirectly tied to my authentication. This means that I can create additional logins (say a Local SO Login) but keep my Account.
As for each Authentication resource (Google, Facebook, etc) there will be difference schemes for Authentication, but there will always be at least a token (or more than one token) for a website to say who I am (in a generic way).
So website #1 (Stack Overflow) has requested website #2 (Google) to Authenticate me. But only website #1 knows what am I Authorized for.
For role specific functionality, there are a good number of answer on SO dealing with ASP.Net Identity and the Role Manager:
Creating Roles in Asp.net Identity MVC 5
mvc 5 check user role
A much more Indepth look into Identity with MVC - Extending Identity Accounts and Implementing Role-Based Authentication in ASP.NET MVC 5
If you're using ASPNET.Identity (http://www.asp.net/identity/overview/getting-started/introduction-to-aspnet-identity), you can add a Role claim type to the user. It'll be associated with the userlogin, so when the user authenticates with Facebook, these user claims will be added and available in MVC.
See the following code fragment:
var acRes = await UserManager.AddClaimAsync(userId, new Claim(ClaimTypes.Role, "MyRole"));