views:

45

answers:

1

Im trying to log in using OpenID/Relying Party (Google, Yahoo!..). My login page is as follows.

What I want to do is simple:

Get the OpenID from an user, store it, and associate it with an user account. Every time that unique OpenID is returned from the provider, I would know that the user associated is now logged in. Simple.

The problem is that response.ClaimedIdentifier.OriginalString that is what I THINK to be the OpenID is not unique. It's almost unique. Most of the time the value returned is the same, but sometimes, not always, for some reasons (specially changing browsers or computers), this value changes and I create another account for the user.

What am I doing wrong? What is the TRUE OpenID code that I must store that is unique regardless of browsers or computers?

public partial class Pages_User_LoginOpenID : LivrePage
            {
                OpenIdRelyingParty relyingParty = new OpenIdRelyingParty();
                IAuthenticationResponse response = null;

                protected void Page_Load(object sender, EventArgs e)
                {
                    response = relyingParty.GetResponse();
                    if (response != null)
                    {
                        switch (response.Status)
                        {
                            case AuthenticationStatus.Authenticated:
                                // verifico se existe um usuário com este openid
                                OpenId openId = UserHelper.GetSession().CreateCriteria<OpenId>().Add(Expression.Eq("IdentifierString", response.ClaimedIdentifier.OriginalString)).UniqueResult<OpenId>();
                                if (openId == null)
                                {
                                    openId = new OpenId();
                                    openId.IdentifierString = response.ClaimedIdentifier.OriginalString;

                                    // não existe usuário com este OpenId
                                    User newUser = UserHelper.CreateUser(openId);
                                    SecurityManager.Login(newUser.Id);

                                }
                                else
                                    SecurityManager.Login(openId.User.Id);
                                Response.Redirect(UrlFactory.GetUrlForPage(UrlFactory.PageName.Home));
                                break;
                            default:
                                break;
                        }
                    }
                }
                // processes the login button click
                protected void ButtonLogin_Click(object sender, EventArgs e)
                {
                    if (response == null)
                        relyingParty.CreateRequest(TextBoxOpenID.Text).RedirectToProvider();
                }
            }
+1  A: 

You're close, but slightly off in your code. The unique identifier is not response.ClaimedIdentifier.OriginalString, but simply response.ClaimedIdentifier. OriginalString is slightly different, and actually it probably should have been marked internal to avoid confusion. Although ClaimedIdentifier is of type Identifier, it will actually automagically become a string when you assign it to a string variable, so don't worry about that.

Now about the splitting user accounts. Most likely what your problem is, is what OpenID calls "directed identity", which is where the OpenID Provider (Google in this case) sends a different OpenID for the same user, depending on what the value is for the IAuthenticationRequest.Realm property. It's very important that your site make sure that the Realm always has the same value so that Google recognizes your site as the same one every time, thus issuing to you the same ClaimedIdentifier for the same user each time.

So what may be going wrong? If you're not setting the Realm value explicitly, DotNetOpenAuth guesses that it is the URL of your home page. But that's based on the URL of the request that's coming in. For example, if users can visit your site using both http://www.yoursite.com/ and https://www.yoursite.com/ (note the https scheme on the second one) then both are legitimate home pages, and DotNetOpenAuth will use whichever scheme the user happens to be visiting your login page on. Similarly, if your site is available both at http://yoursite.com and http://www.yoursite.com (note the www) then that too becomes two different realm values. What you need to do then is set the realm explicitly, with something like:

relyingParty.CreateRequest(TextBoxOpenID.Text, "https://www.yoursite.com/").RedirectToProvider();

This will ensure that your users get the same ClaimedIdentifier each time.

Andrew Arnott
Thank you! May god save your soul
Ciwee