From be3d03608400b810d5d4c1818c023bf57725308b Mon Sep 17 00:00:00 2001 From: xdite Date: Tue, 12 Feb 2013 14:51:44 +0800 Subject: [PATCH] use omniauth-openid to replace google id --- Gemfile | 3 +- Gemfile.lock | 13 +- .../views/modal/login_view.js.coffee | 4 +- app/controllers/user_open_ids_controller.rb | 184 +++--------------- config/initializers/omniauth.rb | 15 ++ config/routes.rb | 8 +- 6 files changed, 65 insertions(+), 162 deletions(-) create mode 100644 config/initializers/omniauth.rb diff --git a/Gemfile b/Gemfile index a2a6e994d..bdc99261d 100644 --- a/Gemfile +++ b/Gemfile @@ -27,6 +27,8 @@ gem 'koala', require: false gem 'multi_json' gem 'mustache' gem 'nokogiri' +gem "omniauth" +gem "omniauth-openid" gem 'oauth', require: false gem 'oj' gem 'pbkdf2' @@ -37,7 +39,6 @@ gem 'redis' gem 'redis-rails' gem 'rest-client' gem 'rinku' -gem 'ruby-openid', require: 'openid' gem 'sanitize' gem 'sass' gem 'seed-fu' diff --git a/Gemfile.lock b/Gemfile.lock index 5b15df96b..08ad61e1a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -174,6 +174,7 @@ GEM spork (>= 0.8.4) haml (3.1.7) has_ip_address (0.0.1) + hashie (1.2.0) hike (1.2.1) hiredis (0.4.5) hpricot (0.8.6) @@ -220,6 +221,12 @@ GEM nokogiri (1.5.6) oauth (0.4.7) oj (2.0.3) + omniauth (1.1.1) + hashie (~> 1.2) + rack + omniauth-openid (1.0.1) + omniauth (~> 1.0) + rack-openid (~> 1.3.1) pbkdf2 (0.1.0) pg (0.14.1) polyglot (0.3.3) @@ -233,6 +240,9 @@ GEM rack (1.4.5) rack-cache (1.2) rack (>= 0.4) + rack-openid (1.3.1) + rack (>= 1.1.0) + ruby-openid (>= 2.1.8) rack-protection (1.3.2) rack rack-ssl (1.3.3) @@ -406,6 +416,8 @@ DEPENDENCIES nokogiri oauth oj + omniauth + omniauth-openid pbkdf2 pg pry-rails @@ -420,7 +432,6 @@ DEPENDENCIES rest-client rinku rspec-rails - ruby-openid sanitize sass sass-rails diff --git a/app/assets/javascripts/discourse/views/modal/login_view.js.coffee b/app/assets/javascripts/discourse/views/modal/login_view.js.coffee index da07746d6..756c4ae5f 100644 --- a/app/assets/javascripts/discourse/views/modal/login_view.js.coffee +++ b/app/assets/javascripts/discourse/views/modal/login_view.js.coffee @@ -60,9 +60,9 @@ window.Discourse.LoginView = window.Discourse.ModalBodyView.extend Discourse.Pre top = @get('lastY') - 200 if(provider == "yahoo") @set("authenticate", 'yahoo') - window.open("/user_open_ids/frame?provider=yahoo", "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top) + window.open("/auth/yahoo", "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top) else - window.open("/user_open_ids/frame?provider=google", "_blank", "menubar=no,status=no,height=500,width=850,left=" + left + ",top=" + top) + window.open("/auth/google", "_blank", "menubar=no,status=no,height=500,width=850,left=" + left + ",top=" + top) @set("authenticate", 'google') authenticationComplete: (options)-> diff --git a/app/controllers/user_open_ids_controller.rb b/app/controllers/user_open_ids_controller.rb index dce4933c0..58a8a0acb 100644 --- a/app/controllers/user_open_ids_controller.rb +++ b/app/controllers/user_open_ids_controller.rb @@ -1,11 +1,5 @@ -require 'openid' -require 'openid/extensions/sreg' -require 'openid/extensions/ax' -require 'openid/store/filesystem' - require_dependency 'email' - class UserOpenIdsController < ApplicationController layout false @@ -15,16 +9,6 @@ class UserOpenIdsController < ApplicationController # must be done, cause we may trigger a POST skip_before_filter :verify_authenticity_token, :only => :complete - def frame - if params[:provider] == 'google' - params[:user_open_id] = {url: "https://www.google.com/accounts/o8/id"} - end - if params[:provider] == 'yahoo' - params[:user_open_id] = {url: "https://me.yahoo.com"} - end - create - end - def destroy @open_id = UserOpenId.find(params[:id]) if @open_id.user.id == current_user.id @@ -37,156 +21,52 @@ class UserOpenIdsController < ApplicationController @open_id = UserOpenId.new end - def create - url = params[:user_open_id] - - begin - # validations - @open_id = UserOpenId.new(url) - open_id_request = openid_consumer.begin @open_id.url - return_to, realm = ['complete','index'].map {|a| url_for :action => a, :only_path => false} - - add_ax_request(open_id_request) - add_sreg_request(open_id_request) - - # immediate mode is not required - if open_id_request.send_redirect?(realm, return_to, false) - redirect_to open_id_request.redirect_url(realm, return_to, false) - else - logger.warn("send_redirect? returned false") - render :text, open_id_request.html_markup(realm, return_to, false, {'id' => 'openid_form'}) - end - rescue => e - flash[:error] = "There seems to be something wrong with your open id url" - logger.warn("failed to load contact open id: " + e.to_s) - render :text => 'Something went wrong, we have been notified, try again soon' - end + def complete + auth_token = env["omniauth.auth"] + create_or_sign_on_user(auth_token) end - def complete - current_url = url_for(:action => 'complete', :only_path => false) - parameters = params.reject{|k,v|request.path_parameters[k]}.reject{|k,v| k == 'action' || k == 'controller'} - open_id_response = openid_consumer.complete(parameters, current_url) + def create_or_sign_on_user(auth_token) - case open_id_response.status - when OpenID::Consumer::SUCCESS - data = {} - if params[:did_sreg] - data = get_sreg_response(open_id_response) - end + data = auth_token[:info] + identity_url = auth_token[:extra][:identity_url] - if params[:did_ax] - info = get_ax_response(open_id_response) - data.merge!(info) - end + email = data[:email] - trusted = open_id_response.endpoint.server_url =~ /^https:\/\/www.google.com\// || - open_id_response.endpoint.server_url =~ /^https:\/\/me.yahoo.com\// + user_open_id = UserOpenId.find_by_url(identity_url) - email = data[:email] - user_open_id = UserOpenId.where(url: open_id_response.display_identifier).first + if user_open_id.blank? && user = User.find_by_email(email) + # we trust so do an email lookup + user_open_id = UserOpenId.create(url: identity_url , user_id: user.id, email: email, active: true) + end - if trusted && user_open_id.nil? && user = User.where(email: email).first - # we trust so do an email lookup - user_open_id = UserOpenId.create(url: open_id_response.display_identifier, user_id: user.id, email: email, active: true) - end + authenticated = user_open_id # if authed before - authenticated = !user_open_id.nil? - - if authenticated - user = user_open_id.user - - # If we have to approve users - if SiteSetting.must_approve_users? and !user.approved? - @data = {awaiting_approval: true} - else - log_on_user(user) - @data = {authenticated: true} - end + if authenticated + user = user_open_id.user + # If we have to approve users + if SiteSetting.must_approve_users? and !user.approved? + @data = {awaiting_approval: true} else - @data = { - email: email, - name: User.suggest_name(email), - username: User.suggest_username(email), - email_valid: trusted, - auth_provider: "Google" - } - session[:authentication] = { - email: @data[:email], - email_valid: @data[:email_valid], - openid_url: open_id_response.display_identifier - } + log_on_user(user) + @data = {authenticated: true} end else - # note there are lots of failure reasons, we treat them all as failures - logger.warn("Verification #{open_id_response.display_identifier || "" }"\ - " failed: #{open_id_response.status.to_s}" ) - logger.warn(open_id_response.message) - flash[:error] = "Sorry, I seem to be having trouble confirming your open id account, please try again!" - render :text => "Apologies, something went wrong ... try again soon" + @data = { + email: email, + name: User.suggest_name(email), + username: User.suggest_username(email), + email_valid: true , + auth_provider: data[:provider] + } + session[:authentication] = { + email: @data[:email], + email_valid: @data[:email_valid], + openid_url: identity_url + } end end - - protected - - - def persist_session - if s = UserSession.find - s.remember_me = true - s.save - end - end - - def openid_consumer - @openid_consumer ||= OpenID::Consumer.new(session, - OpenID::Store::Filesystem.new("#{Rails.root}/tmp/openid")) - end - - def get_sreg_response(open_id_response) - data = {} - sreg_resp = OpenID::SReg::Response.from_success_response(open_id_response) - unless sreg_resp.empty? - data[:email] = sreg_resp.data['email'] - data[:nickname] = sreg_resp.data['nickname'] - end - data - end - - def get_ax_response(open_id_response) - data = {} - ax_resp = OpenID::AX::FetchResponse.from_success_response(open_id_response) - if ax_resp && !ax_resp.data.empty? - data[:email] = ax_resp.data['http://schema.openid.net/contact/email'][0] - end - data - end - - def add_sreg_request(open_id_request) - sreg_request = OpenID::SReg::Request.new - sreg_request.request_fields(['email'], true) - # optional - sreg_request.request_fields(['dob', 'fullname', 'nickname'], false) - open_id_request.add_extension(sreg_request) - open_id_request.return_to_args['did_sreg'] = 'y' - - end - - def add_ax_request(open_id_request) - ax_request = OpenID::AX::FetchRequest.new - requested_attrs = [ - ['namePerson', 'fullname'], - ['namePerson/friendly', 'nickname'], - ['contact/email', 'email', true], - ['contact/web/default', 'web_default'], - ['birthDate', 'dob'], - ['contact/country/home', 'country'] - ] - - requested_attrs.each {|a| ax_request.add(OpenID::AX::AttrInfo.new("http://schema.openid.net/#{a[0]}", a[1], a[2] || false))} - open_id_request.add_extension(ax_request) - open_id_request.return_to_args['did_ax'] = 'y' - end end diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb new file mode 100644 index 000000000..a525180c7 --- /dev/null +++ b/config/initializers/omniauth.rb @@ -0,0 +1,15 @@ +require 'openid/store/filesystem' +require 'openssl' +module OpenSSL + module SSL + remove_const :VERIFY_PEER + end +end + +OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE + +Rails.application.config.middleware.use OmniAuth::Builder do + provider :open_id, :store => OpenID::Store::Filesystem.new('/tmp'), :name => 'google', :identifier => 'https://www.google.com/accounts/o8/id', :require => 'omniauth-openid' + provider :open_id, :store => OpenID::Store::Filesystem.new('/tmp'), :name => 'yahoo', :identifier => 'https://me.yahoo.com', :require => 'omniauth-openid' + +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 9da1c5765..87d5d3b0b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -111,12 +111,8 @@ Discourse::Application.routes.draw do resources :notifications resources :categories - resources :user_open_ids do - collection do - get 'frame' - get 'complete' - end - end + + match '/auth/:provider/callback', to: 'user_open_ids#complete' get 'twitter/frame' => 'twitter#frame' get 'twitter/complete' => 'twitter#complete'