Commit 777e8348b5fb6a22cbe21c5981cb700b5224810a

Authored by Stephen Crosby
2 parents 6ef69937 4a7c9f73
Exists in master

Merge pull request #1078 from 8398a7/add_omniauth_for_google

Add omniauth by google
@@ -23,3 +23,5 @@ GITHUB_API_URL=https://api.github.com @@ -23,3 +23,5 @@ GITHUB_API_URL=https://api.github.com
23 GITHUB_ACCESS_SCOPE='[repo]' 23 GITHUB_ACCESS_SCOPE='[repo]'
24 GITHUB_SITE_TITLE=GitHub 24 GITHUB_SITE_TITLE=GitHub
25 DEVISE_MODULES='[database_authenticatable,recoverable,rememberable,trackable,validatable,omniauthable]' 25 DEVISE_MODULES='[database_authenticatable,recoverable,rememberable,trackable,validatable,omniauthable]'
  26 +GOOGLE_AUTHENTICATION=true
  27 +GOOGLE_SITE_TITLE=Google
@@ -50,6 +50,8 @@ gem 'flowdock' @@ -50,6 +50,8 @@ gem 'flowdock'
50 # --------------------------------------- 50 # ---------------------------------------
51 # GitHub OAuth 51 # GitHub OAuth
52 gem 'omniauth-github' 52 gem 'omniauth-github'
  53 +# Google OAuth
  54 +gem 'omniauth-google-oauth2'
53 55
54 gem 'ri_cal' 56 gem 'ri_cal'
55 gem 'yajl-ruby', platform: 'ruby' 57 gem 'yajl-ruby', platform: 'ruby'
@@ -228,6 +228,11 @@ GEM @@ -228,6 +228,11 @@ GEM
228 omniauth-github (1.1.2) 228 omniauth-github (1.1.2)
229 omniauth (~> 1.0) 229 omniauth (~> 1.0)
230 omniauth-oauth2 (~> 1.1) 230 omniauth-oauth2 (~> 1.1)
  231 + omniauth-google-oauth2 (0.4.0)
  232 + jwt (~> 1.5.0)
  233 + multi_json (~> 1.3)
  234 + omniauth (>= 1.1.1)
  235 + omniauth-oauth2 (>= 1.3.1)
231 omniauth-oauth2 (1.3.1) 236 omniauth-oauth2 (1.3.1)
232 oauth2 (~> 1.0) 237 oauth2 (~> 1.0)
233 omniauth (~> 1.2) 238 omniauth (~> 1.2)
@@ -460,6 +465,7 @@ DEPENDENCIES @@ -460,6 +465,7 @@ DEPENDENCIES
460 mongoid-rspec (~> 3.0.0) 465 mongoid-rspec (~> 3.0.0)
461 mongoid_rails_migrations 466 mongoid_rails_migrations
462 omniauth-github 467 omniauth-github
  468 + omniauth-google-oauth2
463 pjax_rails 469 pjax_rails
464 poltergeist 470 poltergeist
465 pry-byebug 471 pry-byebug
@@ -149,6 +149,26 @@ few others that could make sense for your needs: @@ -149,6 +149,26 @@ few others that could make sense for your needs:
149 organization can log in to Errbit through GitHub. Errbit will provision 149 organization can log in to Errbit through GitHub. Errbit will provision
150 accounts for new users. 150 accounts for new users.
151 151
  152 +### Configuring Google authentication:
  153 +* Set GOOGLE_AUTHENTICATION=true
  154 +* Register your instance of Errbit at https://console.developers.google.com/apis/api/plus/overview
  155 +
  156 +If you host Errbit at errbit.example.com, you would fill in:
  157 +
  158 +<dl>
  159 +<dt>URL
  160 +<dd>http://errbit.example.com
  161 +<dt>Callback URL
  162 +<dd>http://errbit.example.com/users/auth/github
  163 +</dl>
  164 +
  165 +* After you have registered your app, set GOOGLE_CLIENT_ID and GOOGLE_SECRET
  166 + with your app's Client ID and Secret key.
  167 +
  168 +When you start your application, you should see the option to **Sign in with
  169 +Google** on the Login page. You will also be able to link your Google profile
  170 +to your user account on your **Edit profile** page.
  171 +
152 ### Configuring LDAP authentication: 172 ### Configuring LDAP authentication:
153 173
154 * Set USER_HAS_USERNAME=true 174 * Set USER_HAS_USERNAME=true
app/assets/stylesheets/errbit.css.erb
@@ -231,6 +231,7 @@ a.action { float: right; font-size: 0.9em;} @@ -231,6 +231,7 @@ a.action { float: right; font-size: 0.9em;}
231 } 231 }
232 232
233 #action-bar span.github a:before { font-family: FontAwesome; content: "\f09b"; margin-right: 8px; position: relative; top: 4px; font-size: 26px; } 233 #action-bar span.github a:before { font-family: FontAwesome; content: "\f09b"; margin-right: 8px; position: relative; top: 4px; font-size: 26px; }
  234 +#action-bar span.google a:before { font-family: FontAwesome; content: "\f1a0"; margin-right: 8px; position: relative; top: 4px; font-size: 26px; }
234 235
235 #action-bar span a.issue-tracker-button { 236 #action-bar span a.issue-tracker-button {
236 padding-left: 5px; 237 padding-left: 5px;
app/controllers/users/omniauth_callbacks_controller.rb
@@ -39,6 +39,32 @@ class Users::OmniauthCallbacksController &lt; Devise::OmniauthCallbacksController @@ -39,6 +39,32 @@ class Users::OmniauthCallbacksController &lt; Devise::OmniauthCallbacksController
39 end 39 end
40 end 40 end
41 41
  42 + def google_oauth2
  43 + google_uid = env['omniauth.auth'].uid
  44 + google_email = env['omniauth.auth'].info.email
  45 + google_user = User.where(google_uid: google_uid).first
  46 + google_site_title = Errbit::Config.google_site_title
  47 + # If user is already signed in, link google details to their account
  48 + if current_user
  49 + # ... unless a user is already registered with same google login
  50 + if google_user && google_user != current_user
  51 + flash[:error] = "User already registered with #{google_site_title} login '#{google_email}'!"
  52 + else
  53 + # Add github details to current user
  54 + current_user.update(google_uid: google_uid)
  55 + flash[:success] = "Successfully linked #{google_email} account!"
  56 + end
  57 + # User must have clicked 'link account' from their user page, so redirect there.
  58 + redirect_to user_path(current_user)
  59 + elsif google_user
  60 + flash[:success] = I18n.t 'devise.omniauth_callbacks.success', kind: google_site_title
  61 + sign_in_and_redirect google_user, event: :authentication
  62 + else
  63 + flash[:error] = "There are no authorized users with #{google_site_title} login '#{google_email}'. Please ask an administrator to register your user account."
  64 + redirect_to new_user_session_path
  65 + end
  66 + end
  67 +
42 private def update_user_with_github_attributes(user, login, token) 68 private def update_user_with_github_attributes(user, login, token)
43 user.update_attributes( 69 user.update_attributes(
44 github_login: login, 70 github_login: login,
app/controllers/users_controller.rb
@@ -51,6 +51,11 @@ class UsersController &lt; ApplicationController @@ -51,6 +51,11 @@ class UsersController &lt; ApplicationController
51 redirect_to user_path(user) 51 redirect_to user_path(user)
52 end 52 end
53 53
  54 + def unlink_google
  55 + user.update(google_uid: nil)
  56 + redirect_to user_path(user)
  57 + end
  58 +
54 protected 59 protected
55 60
56 def require_user_edit_priviledges 61 def require_user_edit_priviledges
app/models/user.rb
@@ -8,6 +8,7 @@ class User @@ -8,6 +8,7 @@ class User
8 field :email 8 field :email
9 field :github_login 9 field :github_login
10 field :github_oauth_token 10 field :github_oauth_token
  11 + field :google_uid
11 field :name 12 field :name
12 field :admin, type: Boolean, default: false 13 field :admin, type: Boolean, default: false
13 field :per_page, type: Fixnum, default: PER_PAGE 14 field :per_page, type: Fixnum, default: PER_PAGE
@@ -71,6 +72,10 @@ class User @@ -71,6 +72,10 @@ class User
71 self[:github_login] = login 72 self[:github_login] = login
72 end 73 end
73 74
  75 + def google_account?
  76 + google_uid.present?
  77 + end
  78 +
74 def ensure_authentication_token 79 def ensure_authentication_token
75 if authentication_token.blank? 80 if authentication_token.blank?
76 self.authentication_token = generate_authentication_token 81 self.authentication_token = generate_authentication_token
app/views/devise/sessions/new.html.haml
@@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
5 - content_for :action_bar do 5 - content_for :action_bar do
6 %div.action-bar 6 %div.action-bar
7 %span.github= link_to "Sign in with #{Errbit::Config.github_site_title}", user_omniauth_authorize_path(:github) 7 %span.github= link_to "Sign in with #{Errbit::Config.github_site_title}", user_omniauth_authorize_path(:github)
  8 + %span.google= link_to "Sign in with #{Errbit::Config.google_site_title}", user_omniauth_authorize_path(:google_oauth2)
8 9
9 = form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| 10 = form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f|
10 .required 11 .required
app/views/shared/_link_google_account.html.haml 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +- if Errbit::Config.google_authentication && user == current_user
  2 + - if user.google_account?
  3 + %span.google= link_to "Unlink #{Errbit::Config.google_site_title} account", unlink_google_user_path, method: :delete, data: { confirm: 'Are you sure?' }
  4 + - else
  5 + %span.google= link_to "Link #{Errbit::Config.google_site_title} account", user_omniauth_authorize_path(:google_oauth2)
app/views/users/edit.html.haml
1 - content_for :title, "Edit #{user.name}" 1 - content_for :title, "Edit #{user.name}"
2 - content_for :action_bar do 2 - content_for :action_bar do
3 = render 'shared/link_github_account', :user => user 3 = render 'shared/link_github_account', :user => user
  4 + = render 'shared/link_google_account'
4 = link_to('cancel', user_path(user), :class => 'button') 5 = link_to('cancel', user_path(user), :class => 'button')
5 6
6 = form_for user, :html => {:autocomplete => "off"} do |f| 7 = form_for user, :html => {:autocomplete => "off"} do |f|
app/views/users/show.html.haml
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 7
8 - content_for :action_bar do 8 - content_for :action_bar do
9 = render 'shared/link_github_account' 9 = render 'shared/link_github_account'
  10 + = render 'shared/link_google_account'
10 = link_to 'edit', edit_user_path(user), :class => 'button' 11 = link_to 'edit', edit_user_path(user), :class => 'button'
11 = link_to 'destroy', user_path(user), :method => :delete, 12 = link_to 'destroy', user_path(user), :method => :delete,
12 :data => { :confirm => t('users.confirm_delete') }, :class => 'delete button' 13 :data => { :confirm => t('users.confirm_delete') }, :class => 'delete button'
config/initializers/devise.rb
@@ -252,6 +252,12 @@ Devise.setup do |config| @@ -252,6 +252,12 @@ Devise.setup do |config|
252 github_options 252 github_options
253 end 253 end
254 254
  255 + if Errbit::Config.google_authentication || Rails.env.test?
  256 + config.omniauth :google_oauth2,
  257 + Errbit::Config.google_client_id,
  258 + Errbit::Config.google_secret
  259 + end
  260 +
255 # ==> Warden configuration 261 # ==> Warden configuration
256 # If you want to use other strategies, that are not supported by Devise, or 262 # If you want to use other strategies, that are not supported by Devise, or
257 # change the failure app, you can configure them inside the config.warden block. 263 # change the failure app, you can configure them inside the config.warden block.
config/load.rb
@@ -39,6 +39,11 @@ Errbit::Config = Configurator.run( @@ -39,6 +39,11 @@ Errbit::Config = Configurator.run(
39 github_access_scope: ['GITHUB_ACCESS_SCOPE'], 39 github_access_scope: ['GITHUB_ACCESS_SCOPE'],
40 github_api_url: ['GITHUB_API_URL'], 40 github_api_url: ['GITHUB_API_URL'],
41 github_site_title: ['GITHUB_SITE_TITLE'], 41 github_site_title: ['GITHUB_SITE_TITLE'],
  42 + # google
  43 + google_authentication: ['GOOGLE_AUTHENTICATION'],
  44 + google_site_title: ['GOOGLE_SITE_TITLE'],
  45 + google_client_id: ['GOOGLE_CLIENT_ID'],
  46 + google_secret: ['GOOGLE_SECRET'],
42 47
43 email_delivery_method: ['EMAIL_DELIVERY_METHOD', lambda do |values| 48 email_delivery_method: ['EMAIL_DELIVERY_METHOD', lambda do |values|
44 values[:email_delivery_method] && values[:email_delivery_method].to_sym 49 values[:email_delivery_method] && values[:email_delivery_method].to_sym
config/routes.rb
@@ -9,6 +9,7 @@ Rails.application.routes.draw do @@ -9,6 +9,7 @@ Rails.application.routes.draw do
9 resources :users do 9 resources :users do
10 member do 10 member do
11 delete :unlink_github 11 delete :unlink_github
  12 + delete :unlink_google
12 end 13 end
13 end 14 end
14 15
docs/configuration.md
@@ -79,6 +79,16 @@ In order of precedence Errbit uses: @@ -79,6 +79,16 @@ In order of precedence Errbit uses:
79 <dt>GITHUB_SITE_TITLE</dt> 79 <dt>GITHUB_SITE_TITLE</dt>
80 <dd>The title to use for GitHub. This value is whatever you want displayed in the Errbit UI when referring to GitHub.</dd> 80 <dd>The title to use for GitHub. This value is whatever you want displayed in the Errbit UI when referring to GitHub.</dd>
81 <dd>defaults to GitHub</dd> 81 <dd>defaults to GitHub</dd>
  82 +<dt>GOOGLE_AUTHENTICATION
  83 +<dd>Allow google sign-in via OAuth
  84 +<dd>defaults to true
  85 +<dt>GOOGLE_CLIENT_ID
  86 +<dd>Client id of your google application
  87 +<dt>GOOGLE_SECRET
  88 +<dd>Secret key for your google application
  89 +<dt>GOOGLE_SITE_TITLE</dt>
  90 +<dd>The title to use for Google. This value is whatever you want displayed in the Errbit UI when referring to Google.</dd>
  91 +<dd>defaults to Google</dd>
82 <dt>EMAIL_DELIVERY_METHOD 92 <dt>EMAIL_DELIVERY_METHOD
83 <dd>:smtp or :sendmail, depending on how you want Errbit to send email 93 <dd>:smtp or :sendmail, depending on how you want Errbit to send email
84 <dt>SMTP_SERVER 94 <dt>SMTP_SERVER
spec/acceptance/acceptance_helper.rb
@@ -18,6 +18,14 @@ def mock_auth(user = &quot;test_user&quot;, token = &quot;abcdef&quot;) @@ -18,6 +18,14 @@ def mock_auth(user = &quot;test_user&quot;, token = &quot;abcdef&quot;)
18 'token' => token 18 'token' => token
19 } 19 }
20 ) 20 )
  21 +
  22 + OmniAuth.config.mock_auth[:google_oauth2] = Hashie::Mash.new(
  23 + provider: 'google',
  24 + uid: user,
  25 + info: {
  26 + email: 'errbit@errbit.example.com'
  27 + }
  28 + )
21 end 29 end
22 30
23 def log_in(user) 31 def log_in(user)
spec/acceptance/sign_in_with_google_spec.rb 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +require 'acceptance/acceptance_helper'
  2 +
  3 +feature 'Sign in with Google' do
  4 + background do
  5 + allow(Errbit::Config).to receive(:google_authentication).and_return(true)
  6 + Fabricate(:user, google_uid: 'nashby')
  7 + visit root_path
  8 + end
  9 +
  10 + scenario 'log in via Google with recognized user' do
  11 + mock_auth('nashby')
  12 +
  13 + click_link 'Sign in with Google'
  14 + expect(page).to have_content I18n.t('devise.omniauth_callbacks.success', kind: 'Google')
  15 + end
  16 +
  17 + scenario 'reject unrecognized user if authenticating via Google' do
  18 + mock_auth('unknown_user')
  19 +
  20 + click_link 'Sign in with Google'
  21 + expect(page).to have_content 'There are no authorized users with Google login'
  22 + end
  23 +end