1

There are quite a few questions like this and this which all claims that ClaimedIdentifier should be used to uniquely identify each user.

After successful login I am storing ClaimedIndentifier in database. Whenever a user logs in, I traverse through my records looking for the ClaimedIdentifier. However I noticed that ClaimedIdentifiers are changing. What should I store in database to identify my users. I am using Google account. This is how I am retrieving storing it into database

OpenIdRelyingParty rp = new OpenIdRelyingParty();
IAuthenticationResponse r = rp.GetResponse();
UserController.addUser(new UserController.User(r.ClaimedIdentifier.ToString(), 0));
Community
  • 1
  • 1
DarknessBeginsHere
  • 592
  • 1
  • 5
  • 20
  • 1
    ClaimedIdentifiers should be unique and consistent per user so there might be something else fishy going on. Can you provide relevant code for how you're storing the identifier and logging in users? – drch Jan 31 '13 at 01:48
  • And you're seeing new ClaimedIdentifier's each time the same user logs in? What does the 0 in ``new User()`` indiciate? – drch Jan 31 '13 at 02:02
  • @drch I comparedd the ClaimedIdentifier yesterday and today and those were different for the same users. The 0 is just a bit field indicating a user role. – DarknessBeginsHere Jan 31 '13 at 02:11

1 Answers1

5

This isn't a DotNetOpenAuth unique issue. This is a Google behavior. Google's OpenID Provider issues what are called pairwise-unique identifiers. They will always be the same for a given user so long as your OpenID realm is constant.

If you log users in without explicitly supplying a realm to DotNetOpenAuth's OpenIdRelyingParty.CreateRequest method, DotNetOpenAuth simply uses the current web application root URL. This is a reasonable default, except that if your site is accessible in more than one way (e.g. http and https, or with and without the www. host name) than the default realm will vary based on the URL the user happened to use to reach your login page. And when the realm varies, so do Google's generated claimed identifier.

The fix then, is for you to pick one realm (preferably one with an https scheme if that's an option) and explicitly supply it to the CreateRequest method. You must also ensure that your return_to argument to the same method shares a common root with the realm you've chosen. For example, if the realm you choose is: https://www.mysite.com/ Then you must ensure that your return_to is based on that. Something like: https://www.mysite.com/login.aspx

If the user has browsed to http://mysite.com/login.aspx, that would be the default URL for the return_to, which would not match the realm you've chosen.

So altogether, it may look like this:

var request = relyingParty.CreateRequest(
    "https://www.google.com/accounts/o8/id",
    "https://www.mysite.com/",
    new Uri("https://www.mysite.com/login.aspx"));

Note that your return_to does not need to be exactly the same with each request as the realm does. So you could have several login page URLs and each one specify its own URL as the return_to parameter. But all return_to URLs must be based on the realm URL.

With that change consistently applied to everywhere you allow users to log in, you should see consistent claimed identifiers from google. Unfortunately, the claimed identifiers you have already obtained using other realms won't match the ones you'll get after this fix. If you need to merge these user accounts, and if you have email addresses for the users you might try merging based on that. But be very wary of this step. It can only be safely done if you're sure the email addresses you have on file belong to those users. If you obtained those email addresses via OpenID when the users logged in, and double checked that it was from an OpenID Provider you trust and that verifies emails, then you're probably OK. Note that just hard-coding Google OP Identifier into CreateRequest does not guarantee that only Google users log in. To make sure of that, you'd have had to be checking that the IAuthenticationResponse.Provider.Uri property matches https://www.google.com/accounts/o8/ud when the positive assertion comes in.

Andrew Arnott
  • 80,040
  • 26
  • 132
  • 171
  • Nice detailed response. If you support OpenId, users might sometimes try to authenticate through their various OpenId accounts - Google, Yahoo, etc. As a non-technical user, they will expect to still retain the same user account on your website, upon successful authentication. Isn't it beneficial to then store other tokens such as email address in order to help increase the change of property user identification? – Shan Plourde Jan 31 '13 at 05:16
  • @ShanPlourde you have to remember that email is not part of the verified path of OpenID 2.0. Do automatically linking accounts because email addresses match generally opens a door wide open to user spoofing and other threats because people can create their own OpenID Providers that will provide an email address that doesn't belong to them. Generally to achieve what you're describing, users log in with one Provider then log in with another while still logged in, in order to intentionally link accounts. But I agree, it's not the best UX, and OpenID Connect is supposed to help there. – Andrew Arnott Jan 31 '13 at 07:05