Add Google Oauth2 authenticator. The current Google OpenID authentication has been deprecated by Google and will NOT work for any new websites.
This commit is contained in:
parent
ca95bdb023
commit
742841ddce
1
Gemfile
1
Gemfile
|
@ -129,6 +129,7 @@ gem 'omniauth-facebook'
|
||||||
gem 'omniauth-twitter'
|
gem 'omniauth-twitter'
|
||||||
gem 'omniauth-github'
|
gem 'omniauth-github'
|
||||||
gem 'omniauth-oauth2', require: false
|
gem 'omniauth-oauth2', require: false
|
||||||
|
gem 'omniauth-google-oauth2'
|
||||||
gem 'oj'
|
gem 'oj'
|
||||||
# while resolving https://groups.google.com/forum/#!topic/ruby-pg/5_ylGmog1S4
|
# while resolving https://groups.google.com/forum/#!topic/ruby-pg/5_ylGmog1S4
|
||||||
gem 'pg', '0.15.1'
|
gem 'pg', '0.15.1'
|
||||||
|
|
|
@ -197,6 +197,9 @@ GEM
|
||||||
omniauth-github (1.1.1)
|
omniauth-github (1.1.1)
|
||||||
omniauth (~> 1.0)
|
omniauth (~> 1.0)
|
||||||
omniauth-oauth2 (~> 1.1)
|
omniauth-oauth2 (~> 1.1)
|
||||||
|
omniauth-google-oauth2 (0.2.4)
|
||||||
|
omniauth (~> 1.0)
|
||||||
|
omniauth-oauth2 (~> 1.1)
|
||||||
omniauth-oauth (1.0.1)
|
omniauth-oauth (1.0.1)
|
||||||
oauth
|
oauth
|
||||||
omniauth (~> 1.0)
|
omniauth (~> 1.0)
|
||||||
|
@ -436,6 +439,7 @@ DEPENDENCIES
|
||||||
omniauth
|
omniauth
|
||||||
omniauth-facebook
|
omniauth-facebook
|
||||||
omniauth-github
|
omniauth-github
|
||||||
|
omniauth-google-oauth2
|
||||||
omniauth-oauth2
|
omniauth-oauth2
|
||||||
omniauth-openid
|
omniauth-openid
|
||||||
omniauth-twitter
|
omniauth-twitter
|
||||||
|
|
|
@ -31,6 +31,7 @@ Discourse.LoginMethod.reopenClass({
|
||||||
* */
|
* */
|
||||||
|
|
||||||
[ "google",
|
[ "google",
|
||||||
|
"google_oauth2",
|
||||||
"facebook",
|
"facebook",
|
||||||
"cas",
|
"cas",
|
||||||
"twitter",
|
"twitter",
|
||||||
|
@ -41,7 +42,7 @@ Discourse.LoginMethod.reopenClass({
|
||||||
|
|
||||||
var params = {name: name};
|
var params = {name: name};
|
||||||
|
|
||||||
if (name === "google") {
|
if (name === "google" || name === "google_oauth2") {
|
||||||
params.frameWidth = 850;
|
params.frameWidth = 850;
|
||||||
params.frameHeight = 500;
|
params.frameHeight = 500;
|
||||||
} else if (name === "facebook") {
|
} else if (name === "facebook") {
|
||||||
|
|
|
@ -125,7 +125,7 @@
|
||||||
font-family: zocial;
|
font-family: zocial;
|
||||||
line-height: 0.9;
|
line-height: 0.9;
|
||||||
}
|
}
|
||||||
&.google {
|
&.google, &.google_oauth2 {
|
||||||
background: $google;
|
background: $google;
|
||||||
&:before {
|
&:before {
|
||||||
content: "G";
|
content: "G";
|
||||||
|
|
|
@ -8,6 +8,7 @@ class Users::OmniauthCallbacksController < ApplicationController
|
||||||
BUILTIN_AUTH = [
|
BUILTIN_AUTH = [
|
||||||
Auth::FacebookAuthenticator.new,
|
Auth::FacebookAuthenticator.new,
|
||||||
Auth::OpenIdAuthenticator.new("google", "https://www.google.com/accounts/o8/id", trusted: true),
|
Auth::OpenIdAuthenticator.new("google", "https://www.google.com/accounts/o8/id", trusted: true),
|
||||||
|
Auth::GoogleOAuth2Authenticator.new,
|
||||||
Auth::OpenIdAuthenticator.new("yahoo", "https://me.yahoo.com", trusted: true),
|
Auth::OpenIdAuthenticator.new("yahoo", "https://me.yahoo.com", trusted: true),
|
||||||
Auth::GithubAuthenticator.new,
|
Auth::GithubAuthenticator.new,
|
||||||
Auth::TwitterAuthenticator.new
|
Auth::TwitterAuthenticator.new
|
||||||
|
|
|
@ -27,6 +27,9 @@ class AdminDashboardData
|
||||||
gc_checks,
|
gc_checks,
|
||||||
sidekiq_check || queue_size_check,
|
sidekiq_check || queue_size_check,
|
||||||
ram_check,
|
ram_check,
|
||||||
|
old_google_config_check,
|
||||||
|
both_googles_config_check,
|
||||||
|
google_oauth2_config_check,
|
||||||
facebook_config_check,
|
facebook_config_check,
|
||||||
twitter_config_check,
|
twitter_config_check,
|
||||||
github_config_check,
|
github_config_check,
|
||||||
|
@ -45,6 +48,7 @@ class AdminDashboardData
|
||||||
].compact
|
].compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def self.fetch_stats
|
def self.fetch_stats
|
||||||
AdminDashboardData.new
|
AdminDashboardData.new
|
||||||
end
|
end
|
||||||
|
@ -106,8 +110,20 @@ class AdminDashboardData
|
||||||
I18n.t('dashboard.memory_warning') if MemInfo.new.mem_total and MemInfo.new.mem_total < 1_000_000
|
I18n.t('dashboard.memory_warning') if MemInfo.new.mem_total and MemInfo.new.mem_total < 1_000_000
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def old_google_config_check
|
||||||
|
I18n.t('dashboard.enable_google_logins_warning') if SiteSetting.enable_google_logins
|
||||||
|
end
|
||||||
|
|
||||||
|
def both_googles_config_check
|
||||||
|
I18n.t('dashboard.both_googles_warning') if SiteSetting.enable_google_logins && SiteSetting.enable_google_oauth2_logins
|
||||||
|
end
|
||||||
|
|
||||||
|
def google_oauth2_config_check
|
||||||
|
I18n.t('dashboard.google_oauth2_config_warning') if SiteSetting.enable_google_logins && (SiteSetting.google_oauth2_client_id.blank? || SiteSetting.google_oauth2_client_secret.blank?)
|
||||||
|
end
|
||||||
|
|
||||||
def facebook_config_check
|
def facebook_config_check
|
||||||
I18n.t('dashboard.facebook_config_warning') if SiteSetting.enable_facebook_logins and (SiteSetting.facebook_app_id.blank? or SiteSetting.facebook_app_secret.blank?)
|
I18n.t('dashboard.facebook_config_warning') if SiteSetting.enable_facebook_logins && (SiteSetting.facebook_app_id.blank? || SiteSetting.facebook_app_secret.blank?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def twitter_config_check
|
def twitter_config_check
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
class GoogleUserInfo < ActiveRecord::Base
|
||||||
|
belongs_to :user
|
||||||
|
end
|
|
@ -509,6 +509,9 @@ en:
|
||||||
google:
|
google:
|
||||||
title: "with Google"
|
title: "with Google"
|
||||||
message: "Authenticating with Google (make sure pop up blockers are not enabled)"
|
message: "Authenticating with Google (make sure pop up blockers are not enabled)"
|
||||||
|
google_oauth2:
|
||||||
|
title: "with Google"
|
||||||
|
message: "Authenticating with Google (make sure pop up blockers are not enabled)"
|
||||||
twitter:
|
twitter:
|
||||||
title: "with Twitter"
|
title: "with Twitter"
|
||||||
message: "Authenticating with Twitter (make sure pop up blockers are not enabled)"
|
message: "Authenticating with Twitter (make sure pop up blockers are not enabled)"
|
||||||
|
|
|
@ -518,6 +518,9 @@ en:
|
||||||
sidekiq_warning: 'Sidekiq is not running. Many tasks, like sending emails, are executed asynchronously by sidekiq. Please ensure at least one sidekiq process is running. <a href="https://github.com/mperham/sidekiq" target="_blank">Learn about Sidekiq here</a>.'
|
sidekiq_warning: 'Sidekiq is not running. Many tasks, like sending emails, are executed asynchronously by sidekiq. Please ensure at least one sidekiq process is running. <a href="https://github.com/mperham/sidekiq" target="_blank">Learn about Sidekiq here</a>.'
|
||||||
queue_size_warning: 'The number of queued jobs is %{queue_size}, which is high. This could indicate a problem with the Sidekiq process(es), or you may need to add more Sidekiq workers.'
|
queue_size_warning: 'The number of queued jobs is %{queue_size}, which is high. This could indicate a problem with the Sidekiq process(es), or you may need to add more Sidekiq workers.'
|
||||||
memory_warning: 'Your server is running with less than 1 GB of total memory. At least 1 GB of memory is recommended.'
|
memory_warning: 'Your server is running with less than 1 GB of total memory. At least 1 GB of memory is recommended.'
|
||||||
|
enable_google_logins_warning: "You are using a deprecated version of Google's OpenID authentication. Google will be ending support for OpenID by April 20, 2015. Start using Google Oauth2 as soon as possible."
|
||||||
|
both_googles_warning: "You have both enable_google_logins and enable_google_oauth2_logins checked in the site settings. Disable enable_google_logins."
|
||||||
|
google_oauth2_config_warning: 'The server is configured to allow signup and log in with Google Oauth2 (enable_google_oauth2_logins), but the client id and client secret values are not set. Go to <a href="/admin/site_settings">the Site Settings</a> and update the settings.'
|
||||||
facebook_config_warning: 'The server is configured to allow signup and log in with Facebook (enable_facebook_logins), but the app id and app secret values are not set. Go to <a href="/admin/site_settings">the Site Settings</a> and update the settings. <a href="https://meta.discourse.org/t/configuring-facebook-login-for-discourse/13394" target="_blank">See this guide to learn more</a>.'
|
facebook_config_warning: 'The server is configured to allow signup and log in with Facebook (enable_facebook_logins), but the app id and app secret values are not set. Go to <a href="/admin/site_settings">the Site Settings</a> and update the settings. <a href="https://meta.discourse.org/t/configuring-facebook-login-for-discourse/13394" target="_blank">See this guide to learn more</a>.'
|
||||||
twitter_config_warning: 'The server is configured to allow signup and log in with Twitter (enable_twitter_logins), but the key and secret values are not set. Go to <a href="/admin/site_settings">the Site Settings</a> and update the settings. <a href="https://meta.discourse.org/t/configuring-twitter-login-for-discourse/13395" target="_blank">See this guide to learn more</a>.'
|
twitter_config_warning: 'The server is configured to allow signup and log in with Twitter (enable_twitter_logins), but the key and secret values are not set. Go to <a href="/admin/site_settings">the Site Settings</a> and update the settings. <a href="https://meta.discourse.org/t/configuring-twitter-login-for-discourse/13395" target="_blank">See this guide to learn more</a>.'
|
||||||
github_config_warning: 'The server is configured to allow signup and log in with GitHub (enable_github_logins), but the client id and secret values are not set. Go to <a href="/admin/site_settings">the Site Settings</a> and update the settings. <a href="https://meta.discourse.org/t/configuring-github-login-for-discourse/13745" target="_blank">See this guide to learn more</a>.'
|
github_config_warning: 'The server is configured to allow signup and log in with GitHub (enable_github_logins), but the client id and secret values are not set. Go to <a href="/admin/site_settings">the Site Settings</a> and update the settings. <a href="https://meta.discourse.org/t/configuring-github-login-for-discourse/13745" target="_blank">See this guide to learn more</a>.'
|
||||||
|
@ -720,9 +723,13 @@ en:
|
||||||
sso_overrides_name: "Overrides local name with external site name from SSO payload (WARNING: discrepancies can occur due to normalization of local names)"
|
sso_overrides_name: "Overrides local name with external site name from SSO payload (WARNING: discrepancies can occur due to normalization of local names)"
|
||||||
|
|
||||||
enable_local_logins: "Enable traditional, local username and password authentication"
|
enable_local_logins: "Enable traditional, local username and password authentication"
|
||||||
enable_google_logins: "Enable Google authentication"
|
enable_google_logins: "(deprecated) Enable Google authentication. This is the OpenID method of authentication which Google has deprecated. New installs will NOT work with this. Use Google Oauth2 instead. Existing installs must move to Google Oauth2 by April 20, 2015."
|
||||||
enable_yahoo_logins: "Enable Yahoo authentication"
|
enable_yahoo_logins: "Enable Yahoo authentication"
|
||||||
|
|
||||||
|
enable_google_oauth2_logins: "Enable Google Oauth2 authentication. This is the method of authentication that Google currently supports. Requires key and secret."
|
||||||
|
google_oauth2_client_id: "Client ID of your Google application."
|
||||||
|
google_oauth2_client_secret: "Client secret of your Google application."
|
||||||
|
|
||||||
enable_twitter_logins: "Enable Twitter authentication, requires twitter_consumer_key and twitter_consumer_secret"
|
enable_twitter_logins: "Enable Twitter authentication, requires twitter_consumer_key and twitter_consumer_secret"
|
||||||
twitter_consumer_key: "Consumer key for Twitter authentication, registered at http://dev.twitter.com"
|
twitter_consumer_key: "Consumer key for Twitter authentication, registered at http://dev.twitter.com"
|
||||||
twitter_consumer_secret: "Consumer secret for Twitter authentication, registered at http://dev.twitter.com"
|
twitter_consumer_secret: "Consumer secret for Twitter authentication, registered at http://dev.twitter.com"
|
||||||
|
|
|
@ -114,8 +114,13 @@ users:
|
||||||
default: 8
|
default: 8
|
||||||
block_common_passwords: true
|
block_common_passwords: true
|
||||||
enable_google_logins:
|
enable_google_logins:
|
||||||
|
client: true
|
||||||
|
default: false
|
||||||
|
enable_google_oauth2_logins:
|
||||||
client: true
|
client: true
|
||||||
default: true
|
default: true
|
||||||
|
google_oauth2_client_id: ''
|
||||||
|
google_oauth2_client_secret: ''
|
||||||
enable_yahoo_logins:
|
enable_yahoo_logins:
|
||||||
client: true
|
client: true
|
||||||
default: true
|
default: true
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
class CreateGoogleUserInfos < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :google_user_infos do |t|
|
||||||
|
t.integer :user_id, null: false
|
||||||
|
t.string :google_user_id, null: false
|
||||||
|
t.string :first_name
|
||||||
|
t.string :last_name
|
||||||
|
t.string :email
|
||||||
|
t.string :gender
|
||||||
|
t.string :name
|
||||||
|
t.string :link
|
||||||
|
t.string :profile_link
|
||||||
|
t.string :picture
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
add_index :google_user_infos, :user_id, unique: true
|
||||||
|
add_index :google_user_infos, :google_user_id, unique: true
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
class GoogleOpenidDefaultHasChanged < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
result = Category.exec_sql("SELECT count(*) FROM site_settings WHERE name = 'enable_google_logins'")
|
||||||
|
if result[0]['count'].to_i == 0
|
||||||
|
# The old default was true, so add a row to keep it that way.
|
||||||
|
execute "INSERT INTO site_settings (name, data_type, value, created_at, updated_at) VALUES ('enable_google_logins', 5, 't', now(), now())"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
# No need to undo.
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,3 +6,4 @@ require_dependency 'auth/facebook_authenticator'
|
||||||
require_dependency 'auth/open_id_authenticator'
|
require_dependency 'auth/open_id_authenticator'
|
||||||
require_dependency 'auth/github_authenticator'
|
require_dependency 'auth/github_authenticator'
|
||||||
require_dependency 'auth/twitter_authenticator'
|
require_dependency 'auth/twitter_authenticator'
|
||||||
|
require_dependency 'auth/google_oauth2_authenticator'
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
class Auth::GoogleOAuth2Authenticator < Auth::Authenticator
|
||||||
|
|
||||||
|
def name
|
||||||
|
"google_oauth2"
|
||||||
|
end
|
||||||
|
|
||||||
|
def after_authenticate(auth_hash)
|
||||||
|
session_info = parse_hash(auth_hash)
|
||||||
|
google_hash = session_info[:google]
|
||||||
|
|
||||||
|
result = Auth::Result.new
|
||||||
|
result.email = session_info[:email]
|
||||||
|
result.email_valid = session_info[:email_valid]
|
||||||
|
result.name = session_info[:name]
|
||||||
|
|
||||||
|
result.extra_data = google_hash
|
||||||
|
|
||||||
|
user_info = GoogleUserInfo.find_by(google_user_id: google_hash[:google_user_id])
|
||||||
|
result.user = user_info.try(:user)
|
||||||
|
|
||||||
|
if !result.user && !result.email.blank? && result.user = User.find_by(email: Email.downcase(result.email))
|
||||||
|
GoogleUserInfo.create({user_id: result.user.id}.merge(google_hash))
|
||||||
|
end
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def after_create_account(user, auth)
|
||||||
|
data = auth[:extra_data]
|
||||||
|
GoogleUserInfo.create({user_id: user.id}.merge(data))
|
||||||
|
end
|
||||||
|
|
||||||
|
def register_middleware(omniauth)
|
||||||
|
omniauth.provider :google_oauth2,
|
||||||
|
:setup => lambda { |env|
|
||||||
|
strategy = env["omniauth.strategy"]
|
||||||
|
strategy.options[:client_id] = SiteSetting.google_oauth2_client_id
|
||||||
|
strategy.options[:client_secret] = SiteSetting.google_oauth2_client_secret
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def parse_hash(hash)
|
||||||
|
extra = hash[:extra][:raw_info]
|
||||||
|
|
||||||
|
h = {}
|
||||||
|
|
||||||
|
h[:email] = hash[:info][:email]
|
||||||
|
h[:name] = hash[:info][:name]
|
||||||
|
h[:email_valid] = hash[:extra][:raw_info][:email_verified]
|
||||||
|
|
||||||
|
h[:google] = {
|
||||||
|
google_user_id: hash[:uid] || extra[:sub],
|
||||||
|
email: extra[:email],
|
||||||
|
first_name: extra[:given_name],
|
||||||
|
last_name: extra[:family_name],
|
||||||
|
gender: extra[:gender],
|
||||||
|
name: extra[:name],
|
||||||
|
link: extra[:hd],
|
||||||
|
profile_link: extra[:profile],
|
||||||
|
picture: extra[:picture]
|
||||||
|
}
|
||||||
|
|
||||||
|
h
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,58 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
# For autospec:
|
||||||
|
Auth.send(:remove_const, :GoogleOAuth2Authenticator)
|
||||||
|
load 'auth/google_oauth2_authenticator.rb'
|
||||||
|
|
||||||
|
describe Auth::GoogleOAuth2Authenticator do
|
||||||
|
|
||||||
|
context 'after_authenticate' do
|
||||||
|
it 'can authenticate and create a user record for already existing users' do
|
||||||
|
authenticator = described_class.new
|
||||||
|
user = Fabricate(:user)
|
||||||
|
|
||||||
|
hash = {
|
||||||
|
:uid => "123456789",
|
||||||
|
:info => {
|
||||||
|
:name => "John Doe",
|
||||||
|
:email => user.email
|
||||||
|
},
|
||||||
|
:extra => {
|
||||||
|
:raw_info => {
|
||||||
|
:email => "user@domain.example.com",
|
||||||
|
:email_verified => true,
|
||||||
|
:name => "John Doe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = authenticator.after_authenticate(hash)
|
||||||
|
|
||||||
|
result.user.id.should == user.id
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'can create a proper result for non existing users' do
|
||||||
|
hash = {
|
||||||
|
:uid => "123456789",
|
||||||
|
:info => {
|
||||||
|
:name => "Jane Doe",
|
||||||
|
:email => "jane.doe@the.google.com"
|
||||||
|
},
|
||||||
|
:extra => {
|
||||||
|
:raw_info => {
|
||||||
|
:email => "jane.doe@the.google.com",
|
||||||
|
:email_verified => true,
|
||||||
|
:name => "Jane Doe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticator = described_class.new
|
||||||
|
result = authenticator.after_authenticate(hash)
|
||||||
|
|
||||||
|
result.user.should be_nil
|
||||||
|
result.extra_data[:name].should == "Jane Doe"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in New Issue