diff --git a/Gemfile b/Gemfile index 6a1bbc66e..a459fabc4 100644 --- a/Gemfile +++ b/Gemfile @@ -42,7 +42,6 @@ gem "rails-i18n", "~> 4.0.0" gem "dynamic_form" gem "rinku", ">= 1.2.2", :require => "rails_rinku" gem "oauth-plugin", ">= 0.5.1" -gem "open_id_authentication", ">= 1.1.0" gem "validates_email_format_of", ">= 1.5.1" gem "composite_primary_keys", "~> 8.0.0" gem "http_accept_language", "~> 2.0.0" @@ -52,8 +51,9 @@ gem "openstreetmap-i18n-js", ">= 3.0.0.rc5.3", :require => "i18n-js" gem "rack-cors" gem "actionpack-page_caching" -# We need ruby-openid 2.2.0 or later for ruby 1.9 support -gem "ruby-openid", ">= 2.2.0" +# Omniauth for authentication +gem "omniauth" +gem "omniauth-openid" # Markdown formatting support gem "redcarpet" diff --git a/Gemfile.lock b/Gemfile.lock index f40dc2b72..7c8691a22 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -79,6 +79,7 @@ GEM multipart-post (>= 1.2, < 3) globalid (0.3.3) activesupport (>= 4.1.0) + hashie (3.4.0) hike (1.2.3) htmlentities (4.3.3) http_accept_language (2.0.5) @@ -134,8 +135,12 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (~> 1.2) - open_id_authentication (1.2.0) - rack-openid (~> 1.3) + omniauth (1.2.2) + hashie (>= 1.2, < 4) + rack (~> 1.0) + omniauth-openid (1.0.1) + omniauth (~> 1.0) + rack-openid (~> 1.3.1) openstreetmap-i18n-js (3.0.0.rc5.3) i18n paperclip (4.2.1) @@ -156,7 +161,7 @@ GEM r2 (0.2.5) rack (1.6.0) rack-cors (0.3.1) - rack-openid (1.4.2) + rack-openid (1.3.1) rack (>= 1.1.0) ruby-openid (>= 2.1.8) rack-test (0.6.3) @@ -268,7 +273,8 @@ DEPENDENCIES libxml-ruby (>= 2.0.5) minitest (~> 5.1) oauth-plugin (>= 0.5.1) - open_id_authentication (>= 1.1.0) + omniauth + omniauth-openid openstreetmap-i18n-js (>= 3.0.0.rc5.3) paperclip (~> 4.0) pg @@ -281,7 +287,6 @@ DEPENDENCIES redcarpet rinku (>= 1.2.2) rubocop - ruby-openid (>= 2.2.0) sanitize sass-rails (~> 5.0) soap4r-ruby1.9 diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 6cb0b60db..b1d6c86f7 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -1,7 +1,7 @@ class UserController < ApplicationController layout "site", :except => [:api_details] - skip_before_filter :verify_authenticity_token, :only => [:api_read, :api_details, :api_gpx_files] + skip_before_filter :verify_authenticity_token, :only => [:api_read, :api_details, :api_gpx_files, :auth_success] before_filter :disable_terms_redirect, :only => [:terms, :save, :logout, :api_details] before_filter :authorize, :only => [:api_details, :api_gpx_files] before_filter :authorize_web, :except => [:api_read, :api_details, :api_gpx_files] @@ -126,18 +126,11 @@ class UserController < ApplicationController # valid OpenID and one the user has control over before saving # it as a password equivalent for the user. session[:new_user_settings] = params - openid_verify(params[:user][:openid_url], @user) + openid_url = openid_expand_url(params[:user][:openid_url]) + redirect_to auth_path(:provider => "openid", :openid_url => openid_url, :origin => request.path) else update_user(@user, params) 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 - settings = session.delete(:new_user_settings) - openid_verify(nil, @user) do |user| - update_user(user, settings) - end end end @@ -205,23 +198,7 @@ class UserController < ApplicationController @title = t "user.new.title" @referer = params[:referer] || session[:referer] - if 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, verified_email| - user.status = "active" if user.email == verified_email - end - - if @user.openid_url.nil? || @user.invalid? - render :action => "new" - else - session[:new_user] = @user - redirect_to :action => "terms" - end - elsif @user + if @user # The user is logged in already, so don't show them the signup # page, instead send them to the home page if @referer @@ -262,7 +239,8 @@ class UserController < ApplicationController elsif @user.openid_url.present? # Verify OpenID before moving on session[:new_user] = @user - openid_verify(@user.openid_url, @user) + openid_url = openid_expand_url(@user.openid_url) + redirect_to auth_path(:provider => "openid", :openid_url => openid_url, :origin => request.path) else # Save the user record session[:new_user] = @user @@ -272,12 +250,13 @@ class UserController < ApplicationController end def login - if params[:username] || using_open_id? + if params[:username] || params[:openid_url] session[:referer] ||= params[:referer] - if using_open_id? + if params[:openid_url].present? session[:remember_me] ||= params[:remember_me_openid] - openid_authentication(params[:openid_url]) + openid_url = openid_expand_url(params[:openid_url]) + redirect_to auth_path(:provider => "openid", :openid_url => openid_url, :origin => request.path) else session[:remember_me] ||= params[:remember_me] password_authentication(params[:username], params[:password]) @@ -498,6 +477,52 @@ class UserController < ApplicationController end end + ## + # omniauth success callback + def auth_success + auth_info = env["omniauth.auth"] + + openid_url = auth_info[:uid] + name = auth_info[:info][:name] + email = auth_info[:info][:email] + + if user = User.find_by_openid_url(openid_url) + case user.status + when "pending" then + unconfirmed_login(user) + when "active", "confirmed" then + successful_login(user) + when "suspended" then + failed_login t("user.login.account is suspended", :webmaster => "mailto:webmaster@openstreetmap.org") + else + failed_login t("user.login.auth failure") + end + elsif settings = session.delete(:new_user_settings) + @user.openid_url = openid_url + + update_user(@user, settings) + + redirect_to :action => "account", :display_name => @user.display_name + elsif session[:new_user] + session[:new_user].openid_url = openid_url + + if email == session[:new_user].email && openid_email_verified(email) + session[:new_user].status = "active" + end + + redirect_to :action => "terms" + else + redirect_to :action => "new", :nickname => name, :email => email, :openid => openid_url + end + end + + ## + # omniauth failure callback + def auth_failure + flash[:error] = t("user.auth_failure." + params[:message]) + redirect_to params[:origin] + end + private ## @@ -514,96 +539,6 @@ class UserController < ApplicationController 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 && 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), :method => :get, :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 - unconfirmed_login(user) - when "active", "confirmed" then - successful_login(user) - when "suspended" then - failed_login t("user.login.account is suspended", :webmaster => "mailto:webmaster@openstreetmap.org") - else - failed_login t("user.login.auth failure") - end - else - # Guard against not getting any extension data - sreg = {} if sreg.nil? - ax = {} if ax.nil? - - # 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"].first - email = sreg["email"] || ax["http://axschema.org/contact/email"].first - - 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), :method => :get, :required => [:email, "http://axschema.org/contact/email"]) do |result, identity_url, sreg, ax| - if result.successful? - # Do we trust the emails this provider returns? - if openid_email_verified(identity_url) - # Guard against not getting any extension data - sreg = {} if sreg.nil? - ax = {} if ax.nil? - - # Get the verified email - verified_email = sreg["email"] || ax["http://axschema.org/contact/email"].first - end - - # 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, verified_email - 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 diff --git a/app/helpers/user_helper.rb b/app/helpers/user_helper.rb index a3d598086..d48837166 100644 --- a/app/helpers/user_helper.rb +++ b/app/helpers/user_helper.rb @@ -51,8 +51,8 @@ module UserHelper def openid_button(name, url) link_to( image_tag("#{name}.png", :alt => t("user.login.openid_providers.#{name}.alt")), - "#", - :class => "openid_button", :data => { :url => url }, + auth_path(:provider => "openid", :openid_url => url), + :class => "openid_button", :title => t("user.login.openid_providers.#{name}.title") ) end diff --git a/app/views/user/login.html.erb b/app/views/user/login.html.erb index 2b667c725..9fdeb3ab3 100644 --- a/app/views/user/login.html.erb +++ b/app/views/user/login.html.erb @@ -42,8 +42,8 @@