Add support for Google OAuth2 authentication

This replaces OpenID authentication, which is going away soon, but
provides an upgrade path where we can migrate users that already have
a Google OpenID setup to the new system transparently.
This commit is contained in:
Tom Hughes 2015-02-28 15:56:41 +00:00
parent 7ed50894e2
commit eeb9866d50
10 changed files with 51 additions and 12 deletions

View file

@ -57,6 +57,7 @@ gem "actionpack-page_caching"
# Omniauth for authentication
gem "omniauth"
gem "omniauth-openid"
gem "openstreetmap-omniauth-google-oauth2", ">= 0.2.6.1", :require => "omniauth-google-oauth2"
# Markdown formatting support
gem "redcarpet"

View file

@ -150,11 +150,21 @@ GEM
omniauth (1.2.2)
hashie (>= 1.2, < 4)
rack (~> 1.0)
omniauth-oauth2 (1.2.0)
faraday (>= 0.8, < 0.10)
multi_json (~> 1.3)
oauth2 (~> 1.0)
omniauth (~> 1.2)
omniauth-openid (1.0.1)
omniauth (~> 1.0)
rack-openid (~> 1.3.1)
openstreetmap-i18n-js (3.0.0.rc5.3)
i18n
openstreetmap-omniauth-google-oauth2 (0.2.6.1)
jwt (~> 1.0)
multi_json (~> 1.3)
omniauth (>= 1.1.1)
omniauth-oauth2 (>= 1.1.1)
paperclip (4.2.1)
activemodel (>= 3.0.0)
activesupport (>= 3.0.0)
@ -305,6 +315,7 @@ DEPENDENCIES
omniauth
omniauth-openid
openstreetmap-i18n-js (>= 3.0.0.rc5.3)
openstreetmap-omniauth-google-oauth2 (>= 0.2.6.1)
paperclip (~> 4.0)
pg
poltergeist

View file

@ -227,7 +227,7 @@ class UserController < ApplicationController
@user.status = "pending"
if @user.auth_provider.present? && @user.auth_uid.present? && @user.pass_crypt.empty?
if @user.auth_provider.present? && @user.pass_crypt.empty?
# We are creating an account with external authentication and
# no password was specified so create a random one
@user.pass_crypt = SecureRandom.base64(16)
@ -237,7 +237,7 @@ class UserController < ApplicationController
if @user.invalid?
# Something is wrong with a new user, so rerender the form
render :action => "new"
elsif @user.auth_provider.present? && @user.auth_uid.present?
elsif @user.auth_provider.present?
# Verify external authenticator before moving on
session[:new_user] = @user
redirect_to auth_url(@user.auth_provider, @user.auth_uid)
@ -250,9 +250,9 @@ class UserController < ApplicationController
end
def login
if params[:username] || params[:openid_url]
session[:referer] ||= params[:referer]
session[:referer] = params[:referer] if params[:referer]
if params[:username] || params[:openid_url]
if params[:openid_url].present?
session[:remember_me] ||= params[:remember_me_openid]
redirect_to auth_url("openid", params[:openid_url])
@ -496,11 +496,21 @@ class UserController < ApplicationController
when "openid"
email_verified = uid.match(%r{https://www.google.com/accounts/o8/id?(.*)}) ||
uid.match(%r{https://me.yahoo.com/(.*)})
when "google"
email_verified = true
else
email_verified = false
end
if user = User.find_by_auth_provider_and_auth_uid(provider, uid)
user = User.find_by_auth_provider_and_auth_uid(provider, uid)
if user.nil? && provider == "google"
openid_url = auth_info[:extra][:id_info]["openid_id"]
user = User.find_by_auth_provider_and_auth_uid("openid", openid_url) if openid_url
user.update(:auth_provider => provider, :auth_uid => uid) if user
end
if user
case user.status
when "pending" then
unconfirmed_login(user)
@ -668,8 +678,7 @@ class UserController < ApplicationController
user.preferred_editor = params[:user][:preferred_editor]
end
if params[:user][:auth_provider].nil? || params[:user][:auth_provider].blank? ||
params[:user][:auth_uid].nil? || params[:user][:auth_uid].blank?
if params[:user][:auth_provider].nil? || params[:user][:auth_provider].blank?
user.auth_provider = nil
user.auth_uid = nil
end

View file

@ -48,7 +48,7 @@ module UserHelper
image_tag "openid_small.png", :alt => t("user.login.openid_logo_alt"), :class => "openid_logo"
end
def auth_button(name, provider, options)
def auth_button(name, provider, options = {})
link_to(
image_tag("#{name}.png", :alt => t("user.login.auth_providers.#{name}.alt")),
auth_path(options.merge(:provider => provider)),

View file

@ -48,7 +48,7 @@
<fieldset>
<div class="form-row">
<label class="standard-label"><%= t 'user.account.external auth' %></label>
<%= f.select :auth_provider, { "None" => "", "OpenID" => "openid" } %>
<%= f.select :auth_provider, Auth::PROVIDERS %>
<%= f.text_field :auth_uid %>
<span class="form-help deemphasize">(<a href="<%= t 'user.account.openid.link' %>" target="_new"><%= t 'user.account.openid.link text' %></a>)</span>
</diV>

View file

@ -42,7 +42,9 @@
<ul class='clearfix' id="login_auth_buttons">
<li><%= link_to image_tag("openid.png", :alt => t("user.login.auth_providers.openid.title")), "#", :id => "openid_open_url", :title => t("user.login.auth_providers.openid.title") %></li>
<li><%= auth_button "google", "openid", :openid_url => "https://www.google.com/accounts/o8/id" %></li>
<% if defined?(GOOGLE_AUTH_ID) -%>
<li><%= auth_button "google", "google" %></li>
<% end -%>
<li><%= auth_button "yahoo", "openid", :openid_url => "yahoo.com" %></li>
<li><%= auth_button "wordpress", "openid", :openid_url => "wordpress.com" %></li>
<li><%= auth_button "aol", "openid", :openid_url => "aol.com" %></li>

View file

@ -45,7 +45,7 @@
<label for="openid_url" class="standard-label">
<%= raw t 'user.new.external auth' %>
</label>
<%= select(:user, :auth_provider, { "None" => "", "OpenID" => "openid" }, { :default => "", :tabindex => 4 }) %>
<%= select(:user, :auth_provider, Auth::PROVIDERS, { :default => "", :tabindex => 4 }) %>
<%= text_field(:user, :auth_uid, { :tabindex => 5 }) %>
<%= error_message_on(:user, :auth_uid) %>
</div>

View file

@ -88,6 +88,10 @@ defaults: &defaults
- ".*\\.google\\.ru/.*"
# URL of Overpass instance to use for feature queries
overpass_url: "//overpass-api.de/api/interpreter"
# External authentication credentials
#google_auth_id: ""
#google_auth_secret: ""
#google_openid_realm: ""
development:
<<: *defaults

View file

@ -19,8 +19,16 @@ else
openid_store = OpenID::Store::Filesystem.new(Rails.root.join("tmp/openids"))
end
openid_options = { :name => "openid", :store => openid_store }
google_options = { :name => "google", :scope => "email", :access_type => "online" }
if defined?(GOOGLE_OPENID_REALM)
google_options[:openid_realm] = GOOGLE_OPENID_REALM
end
Rails.application.config.middleware.use OmniAuth::Builder do
provider :openid, :name => "openid", :store => openid_store
provider :openid, openid_options
provider :google_oauth2, GOOGLE_AUTH_ID, GOOGLE_AUTH_SECRET, google_options if defined?(GOOGLE_AUTH_ID)
end
# Pending fix for: https://github.com/intridea/omniauth/pull/795

4
lib/auth.rb Normal file
View file

@ -0,0 +1,4 @@
module Auth
PROVIDERS = { "None" => "", "OpenID" => "openid" }
PROVIDERS["Google"] = "google" if defined?(GOOGLE_AUTH_ID)
end