From: Tom Hughes Date: Sat, 21 May 2011 11:14:56 +0000 (+0100) Subject: Merge branch 'master' into openid X-Git-Tag: live~6859 X-Git-Url: https://git.openstreetmap.org./rails.git/commitdiff_plain/832b96b75ac05177e6baad7b414066ccfd7cfa51?ds=inline Merge branch 'master' into openid Conflicts: app/controllers/user_controller.rb app/views/user/terms.html.erb test/fixtures/users.yml --- 832b96b75ac05177e6baad7b414066ccfd7cfa51 diff --cc app/controllers/user_controller.rb index 1193ec910,97b0de73c..a066c1c63 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@@ -24,25 -25,9 +25,25 @@@ class UserController < ApplicationContr if request.xhr? render :update do |page| - page.replace_html "contributorTerms", :partial => "terms", :locals => { :has_decline => params[:has_decline] } + page.replace_html "contributorTerms", :partial => "terms" end + elsif using_open_id? + # The redirect from the OpenID provider reenters here + # again and we need to pass the parameters through to + # the open_id_authentication function + @user = session.delete(:new_user) + + openid_verify(nil, @user) do |user| + end + + if @user.openid_url.nil? or @user.invalid? + render :action => 'new' + else + render :action => 'terms' + end else + session[:referer] = params[:referer] + @title = t 'user.terms.title' @user = User.new(params[:user]) if params[:user] @@@ -104,14 -93,15 +124,15 @@@ @user.creation_ip = request.remote_ip @user.languages = request.user_preferred_languages @user.terms_agreed = Time.now.getutc - + @user.terms_seen = true + if @user.save flash[:notice] = t 'user.new.flash create success message', :email => @user.email - Notifier.deliver_signup_confirm(@user, @user.tokens.create(:referer => params[:referer])) + Notifier.deliver_signup_confirm(@user, @user.tokens.create(:referer => session.delete(:referer))) session[:token] = @user.tokens.create.token - redirect_to :action => 'login' + redirect_to :action => 'login', :referer => params[:referer] else - render :action => 'new' + render :action => 'new', :referer => params[:referer] end end end @@@ -469,164 -476,6 +490,171 @@@ private + ## + # handle password authentication + def password_authentication(username, password) + if user = User.authenticate(:username => username, :password => password) + successful_login(user) + elsif user = User.authenticate(:username => username, :password => password, :pending => true) + failed_login t('user.login.account not active', :reconfirm => url_for(:action => 'confirm_resend', :display_name => user.display_name)) + elsif User.authenticate(:username => username, :password => password, :suspended => true) + webmaster = link_to t('user.login.webmaster'), "mailto:webmaster@openstreetmap.org" + failed_login t('user.login.account suspended', :webmaster => webmaster) + else + failed_login t('user.login.auth failure') + end + end + + ## + # handle OpenID authentication + def openid_authentication(openid_url) + # If we don't appear to have a user for this URL then ask the + # provider for some extra information to help with signup + if openid_url and User.find_by_openid_url(openid_url) + required = nil + else + required = [:nickname, :email, "http://axschema.org/namePerson/friendly", "http://axschema.org/contact/email"] + end + + # Start the authentication + authenticate_with_open_id(openid_expand_url(openid_url), :required => required) do |result, identity_url, sreg, ax| + 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. + # + # For example, you can simply enter yahoo.com in the login box rather + # than a user specific url. Only once it comes back from the provider + # provider do we know the unique address for the user. + if user = User.find_by_openid_url(identity_url) + case user.status + when "pending" then + failed_login t('user.login.account not active') + when "active", "confirmed" then + successful_login(user) + when "suspended" then + webmaster = link_to t('user.login.webmaster'), "mailto:webmaster@openstreetmap.org" + failed_login t('user.login.account suspended', :webmaster => webmaster) + else + failed_login t('user.login.auth failure') + end + else + # We don't have a user registered to this OpenID, so 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. + nickname = sreg["nickname"] || ax["http://axschema.org/namePerson/friendly"] + email = sreg["email"] || ax["http://axschema.org/contact/email"] + redirect_to :controller => 'user', :action => 'new', :nickname => nickname, :email => email, :openid => identity_url + end + elsif result.missing? + failed_login t('user.login.openid missing provider') + elsif result.invalid? + failed_login t('user.login.openid invalid') + else + failed_login t('user.login.auth failure') + end + end + end + + ## + # verify an OpenID URL + def openid_verify(openid_url, user) + user.openid_url = openid_url + + authenticate_with_open_id(openid_expand_url(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. + # + # For example, you can simply enter yahoo.com in the login box rather + # than a user specific url. Only once it comes back from the provider + # provider do we know the unique address for the user. + user.openid_url = identity_url + yield user + elsif result.missing? + flash.now[:error] = t 'user.login.openid missing provider' + elsif result.invalid? + flash.now[:error] = t 'user.login.openid invalid' + else + flash.now[:error] = t 'user.login.auth failure' + end + end + end + + ## + # special case some common OpenID providers by applying heuristics to + # try and come up with the correct URL based on what the user entered + def openid_expand_url(openid_url) + if openid_url.nil? + return nil + elsif openid_url.match(/(.*)gmail.com(\/?)$/) or openid_url.match(/(.*)googlemail.com(\/?)$/) + # Special case gmail.com as it is potentially a popular OpenID + # provider and, unlike yahoo.com, where it works automatically, Google + # have hidden their OpenID endpoint somewhere obscure this making it + # somewhat less user friendly. + return 'https://www.google.com/accounts/o8/id' + else + return openid_url + end + end + + ## + # process a successful login + def successful_login(user) + session[:user] = user.id - + session_expires_after 1.month if session[:remember_me] + - if user.blocked_on_view - redirect_to user.blocked_on_view, :referer => params[:referer] - elsif session[:referer] - redirect_to session[:referer] ++ target = params[:referer] || url_for(:controller => :site, :action => :index) ++ ++ # The user is logged in, so decide where to send them: ++ # ++ # - If they haven't seen the contributor terms, send them there. ++ # - If they have a block on them, show them that. ++ # - If they were referred to the login, send them back there. ++ # - Otherwise, send them to the home page. ++ if REQUIRE_TERMS_SEEN and not user.terms_seen ++ redirect_to :controller => :user, :action => :terms, :referer => target ++ elsif user.blocked_on_view ++ redirect_to user.blocked_on_view, :referer => target + else - redirect_to :controller => 'site', :action => 'index' ++ redirect_to target + end + + session.delete(:remember_me) + session.delete(:referer) + end + + ## + # process a failed login + def failed_login(message) + flash[:error] = message + + redirect_to :action => 'login', :referer => session[:referer] + + session.delete(:remember_me) + session.delete(:referer) + end + + ## + # update a user's details + def update_user(user) + if user.save + set_locale + + if user.new_email.nil? or user.new_email.empty? + flash.now[:notice] = t 'user.account.flash update success' + else + flash.now[:notice] = t 'user.account.flash update success confirm needed' + + begin + Notifier.deliver_email_confirm(user, user.tokens.create) + rescue + # Ignore errors sending email + end + end + end + end + ## # require that the user is a administrator, or fill out a helpful error message # and return them to the user page. diff --cc app/views/user/terms.html.erb index 3e93ff20c,5160716d1..ded9b4db6 --- a/app/views/user/terms.html.erb +++ b/app/views/user/terms.html.erb @@@ -39,12 -39,9 +39,10 @@@ <%= hidden_field('user', 'display_name') %> <%= hidden_field('user', 'pass_crypt') %> <%= hidden_field('user', 'pass_crypt_confirmation') %> + <%= hidden_field('user', 'openid_url') %> <% end %>
- <% if @user.new_record? %> - <%= submit_tag(t('user.terms.decline'), :name => "decline", :id => "decline") %> - <% end %> + <%= submit_tag(t('user.terms.decline'), :name => "decline", :id => "decline") %> <%= submit_tag(t('user.terms.agree'), :name => "agree", :id => "agree") %>

diff --cc test/fixtures/users.yml index 9802783fd,98517fd2a..360738c22 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@@ -68,13 -73,14 +73,24 @@@ administrator_user creation_time: "2008-05-01 01:23:45" display_name: administrator data_public: true - terms_seen: true - openid_user: + terms_not_seen_user: id: 7 + email: not_agreed@example.com + status: active + pass_crypt: <%= Digest::MD5.hexdigest('test') %> + creation_time: "2011-03-22 00:23:45" + display_name: not_agreed + data_public: true + terms_seen: false ++ ++openid_user: ++ id: 8 + email: openid-user@example.com + status: active + pass_crypt: <%= Digest::MD5.hexdigest('test') %> + creation_time: "2008-05-01 01:23:45" + display_name: openIDuser + data_public: true + openid_url: http://localhost:1123/john.doe?openid.success=true ++ terms_seen: true diff --cc test/integration/user_blocks_test.rb index 942a94302,b4ca49022..7003d7692 --- a/test/integration/user_blocks_test.rb +++ b/test/integration/user_blocks_test.rb @@@ -38,11 -38,8 +38,8 @@@ class UserBlocksTest < ActionController # revoke the ban get '/login' - assert_response :redirect - assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true" - follow_redirect! assert_response :success - post '/login', {'user[email]' => moderator.email, 'user[password]' => "test", :referer => "/blocks/#{block.id}/revoke"} + post '/login', {'username' => moderator.email, 'password' => "test", :referer => "/blocks/#{block.id}/revoke"} assert_response :redirect follow_redirect! assert_response :success