+ def openid_specialcase_mapping(openid_url)
+ #Special case gmail.com, as it is pontentially a popular OpenID provider and unlike
+ #yahoo.com, where it works automatically, Google have hidden their OpenID endpoint
+ #somewhere obscure making it less userfriendly.
+ if (openid_url.match(/(.*)gmail.com(\/?)$/) or openid_url.match(/(.*)googlemail.com(\/?)$/) )
+ return 'https://www.google.com/accounts/o8/id'
+ end
+
+ return nil
+ end
+
+ def openid_verify(openid_url,account_create)
+ authenticate_with_open_id(openid_url) do |result, identity_url|
+ if result.successful?
+ #We need to use the openid url passed back from the OpenID provider
+ #rather than the one supplied by the user, as these can be different.
+ #e.g. one can simply enter yahoo.com in the login box, i.e. no user specific url
+ #only once it comes back from the OpenID provider do we know the unique address for
+ #the user.
+ @user = session[:new_usr] unless @user #this is used for account creation when the user is not yet in the database
+ @user.openid_url = identity_url
+ elsif result.missing?
+ mapped_id = openid_specialcase_mapping(openid_url)
+ if mapped_id
+ openid_verify(mapped_id, account_create)
+ else
+ flash.now[:error] = t 'user.login.openid missing provider'
+ end
+ elsif result.invalid?
+ flash.now[:error] = t 'user.login.openid invalid'
+ else
+ flash.now[:error] = t 'user.login.auth failure'
+ end
+ end
+ end
+
+ def open_id_authentication(openid_url)
+ #TODO: only ask for nickname and email, if we don't already have a user for that openID, in which case
+ #email and nickname are already filled out. I don't know how to do that with ruby syntax though, as we
+ #don't want to duplicate the do block
+ #On the other hand it also doesn't matter too much if we ask every time, as the OpenID provider should
+ #remember these results, and shouldn't repromt the user for these data each time.
+ user = nil
+ authenticate_with_open_id(openid_url, :return_to => request.protocol + request.host_with_port + '/login?referer=' + params[:referer], :optional => [:nickname, :email]) do |result, identity_url, registration|
+ if result.successful?
+ #We need to use the openid url passed back from the OpenID provider
+ #rather than the one supplied by the user, as these can be different.
+ #e.g. one can simply enter yahoo.com in the login box, i.e. no user specific url
+ #only once it comes back from the OpenID provider do we know the unique address for
+ #the user.
+ user = User.find_by_openid_url(identity_url)
+ if user
+ if user.visible? and user.active?
+ session[:user] = user.id
+ session_expires_after 1.month if session[:remember]
+ return user
+ else
+ user = nil
+ flash.now[:error] = t 'user.login.account not active'
+ end
+ else
+ #We don't have a user registered to this OpenID. Redirect to the create account page
+ #with username and email filled in if they have been given by the OpenID provider through
+ #the simple registration protocol
+ redirect_to :controller => 'user', :action => 'new', :nickname => registration['nickname'], :email => registration['email'], :openid => identity_url
+ end
+ else if result.missing?
+ #Try and apply some heuristics to make common cases more userfriendly
+ mapped_id = openid_specialcase_mapping(openid_url)
+ if mapped_id
+ open_id_authentication(mapped_id)
+ else
+ flash.now[:error] = t 'user.login.openid missing provider'
+ end
+ else if result.invalid?
+ flash.now[:error] = t 'user.login.openid invalid'
+ else
+ flash.now[:error] = t 'user.login.auth failure'
+ end
+ end
+ end
+ end
+ return user
+ end
+