From 5c510d69b4daa882c3a075c24a287573c93cd470 Mon Sep 17 00:00:00 2001 From: 839 <8398a7@gmail.com> Date: Thu, 7 Apr 2016 22:23:12 +0900 Subject: [PATCH] Add sign in with google omniauth --- .env.default | 2 ++ Gemfile | 2 ++ Gemfile.lock | 6 ++++++ app/assets/stylesheets/errbit.css.erb | 1 + app/controllers/users/omniauth_callbacks_controller.rb | 26 ++++++++++++++++++++++++++ app/controllers/users_controller.rb | 5 +++++ app/models/user.rb | 5 +++++ app/views/devise/sessions/new.html.haml | 1 + app/views/shared/_link_google_account.html.haml | 5 +++++ app/views/users/edit.html.haml | 1 + app/views/users/show.html.haml | 1 + config/initializers/devise.rb | 6 ++++++ config/load.rb | 5 +++++ config/routes.rb | 1 + spec/acceptance/acceptance_helper.rb | 8 ++++++++ spec/acceptance/sign_in_with_google_spec.rb | 23 +++++++++++++++++++++++ 16 files changed, 98 insertions(+), 0 deletions(-) create mode 100644 app/views/shared/_link_google_account.html.haml create mode 100644 spec/acceptance/sign_in_with_google_spec.rb diff --git a/.env.default b/.env.default index f55b14c..2c0cfce 100644 --- a/.env.default +++ b/.env.default @@ -23,3 +23,5 @@ GITHUB_API_URL=https://api.github.com GITHUB_ACCESS_SCOPE='[repo]' GITHUB_SITE_TITLE=GitHub DEVISE_MODULES='[database_authenticatable,recoverable,rememberable,trackable,validatable,omniauthable]' +GOOGLE_AUTHENTICATION=true +GOOGLE_SITE_TITLE=Google diff --git a/Gemfile b/Gemfile index f7a6d50..8b43f82 100644 --- a/Gemfile +++ b/Gemfile @@ -50,6 +50,8 @@ gem 'flowdock' # --------------------------------------- # GitHub OAuth gem 'omniauth-github' +# Google OAuth +gem 'omniauth-google-oauth2' gem 'ri_cal' gem 'yajl-ruby', platform: 'ruby' diff --git a/Gemfile.lock b/Gemfile.lock index ab339ff..1293e39 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -228,6 +228,11 @@ GEM omniauth-github (1.1.2) omniauth (~> 1.0) omniauth-oauth2 (~> 1.1) + omniauth-google-oauth2 (0.4.0) + jwt (~> 1.5.0) + multi_json (~> 1.3) + omniauth (>= 1.1.1) + omniauth-oauth2 (>= 1.3.1) omniauth-oauth2 (1.3.1) oauth2 (~> 1.0) omniauth (~> 1.2) @@ -460,6 +465,7 @@ DEPENDENCIES mongoid-rspec (~> 3.0.0) mongoid_rails_migrations omniauth-github + omniauth-google-oauth2 pjax_rails poltergeist pry-byebug diff --git a/app/assets/stylesheets/errbit.css.erb b/app/assets/stylesheets/errbit.css.erb index ce4b071..140d463 100644 --- a/app/assets/stylesheets/errbit.css.erb +++ b/app/assets/stylesheets/errbit.css.erb @@ -231,6 +231,7 @@ a.action { float: right; font-size: 0.9em;} } #action-bar span.github a:before { font-family: FontAwesome; content: "\f09b"; margin-right: 8px; position: relative; top: 4px; font-size: 26px; } +#action-bar span.google a:before { font-family: FontAwesome; content: "\f1a0"; margin-right: 8px; position: relative; top: 4px; font-size: 26px; } #action-bar span a.issue-tracker-button { padding-left: 5px; diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index d5d560e..5a537c9 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -39,6 +39,32 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController end end + def google_oauth2 + google_uid = env['omniauth.auth'].uid + google_email = env['omniauth.auth'].info.email + google_user = User.where(google_uid: google_uid).first + google_site_title = Errbit::Config.google_site_title + # If user is already signed in, link google details to their account + if current_user + # ... unless a user is already registered with same google login + if google_user && google_user != current_user + flash[:error] = "User already registered with #{google_site_title} login '#{google_email}'!" + else + # Add github details to current user + current_user.update(google_uid: google_uid) + flash[:success] = "Successfully linked #{google_email} account!" + end + # User must have clicked 'link account' from their user page, so redirect there. + redirect_to user_path(current_user) + elsif google_user + flash[:success] = I18n.t 'devise.omniauth_callbacks.success', kind: google_site_title + sign_in_and_redirect google_user, event: :authentication + else + flash[:error] = "There are no authorized users with #{google_site_title} login '#{google_email}'. Please ask an administrator to register your user account." + redirect_to new_user_session_path + end + end + private def update_user_with_github_attributes(user, login, token) user.update_attributes( github_login: login, diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 32c3dd8..1ac5144 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -51,6 +51,11 @@ class UsersController < ApplicationController redirect_to user_path(user) end + def unlink_google + user.update(google_uid: nil) + redirect_to user_path(user) + end + protected def require_user_edit_priviledges diff --git a/app/models/user.rb b/app/models/user.rb index e6a2a16..c936543 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -8,6 +8,7 @@ class User field :email field :github_login field :github_oauth_token + field :google_uid field :name field :admin, type: Boolean, default: false field :per_page, type: Fixnum, default: PER_PAGE @@ -71,6 +72,10 @@ class User self[:github_login] = login end + def google_account? + google_uid.present? + end + def ensure_authentication_token if authentication_token.blank? self.authentication_token = generate_authentication_token diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index aba4939..6531376 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -5,6 +5,7 @@ - content_for :action_bar do %div.action-bar %span.github= link_to "Sign in with #{Errbit::Config.github_site_title}", user_omniauth_authorize_path(:github) + %span.google= link_to "Sign in with #{Errbit::Config.google_site_title}", user_omniauth_authorize_path(:google_oauth2) = form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| .required diff --git a/app/views/shared/_link_google_account.html.haml b/app/views/shared/_link_google_account.html.haml new file mode 100644 index 0000000..24415a7 --- /dev/null +++ b/app/views/shared/_link_google_account.html.haml @@ -0,0 +1,5 @@ +- if Errbit::Config.google_authentication && user == current_user + - if user.google_account? + %span.google= link_to "Unlink #{Errbit::Config.google_site_title} account", unlink_google_user_path, method: :delete, data: { confirm: 'Are you sure?' } + - else + %span.google= link_to "Link #{Errbit::Config.google_site_title} account", user_omniauth_authorize_path(:google_oauth2) diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml index 0e015c3..54db567 100644 --- a/app/views/users/edit.html.haml +++ b/app/views/users/edit.html.haml @@ -1,6 +1,7 @@ - content_for :title, "Edit #{user.name}" - content_for :action_bar do = render 'shared/link_github_account', :user => user + = render 'shared/link_google_account' = link_to('cancel', user_path(user), :class => 'button') = form_for user, :html => {:autocomplete => "off"} do |f| diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 52e9040..51a619a 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -7,6 +7,7 @@ - content_for :action_bar do = render 'shared/link_github_account' + = render 'shared/link_google_account' = link_to 'edit', edit_user_path(user), :class => 'button' = link_to 'destroy', user_path(user), :method => :delete, :data => { :confirm => t('users.confirm_delete') }, :class => 'delete button' diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index a29d24f..b867741 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -252,6 +252,12 @@ Devise.setup do |config| github_options end + if Errbit::Config.google_authentication || Rails.env.test? + config.omniauth :google_oauth2, + Errbit::Config.google_client_id, + Errbit::Config.google_secret + end + # ==> Warden configuration # If you want to use other strategies, that are not supported by Devise, or # change the failure app, you can configure them inside the config.warden block. diff --git a/config/load.rb b/config/load.rb index 83f7a35..7418a04 100644 --- a/config/load.rb +++ b/config/load.rb @@ -39,6 +39,11 @@ Errbit::Config = Configurator.run( github_access_scope: ['GITHUB_ACCESS_SCOPE'], github_api_url: ['GITHUB_API_URL'], github_site_title: ['GITHUB_SITE_TITLE'], + # google + google_authentication: ['GOOGLE_AUTHENTICATION'], + google_site_title: ['GOOGLE_SITE_TITLE'], + google_client_id: ['GOOGLE_CLIENT_ID'], + google_secret: ['GOOGLE_SECRET'], email_delivery_method: ['EMAIL_DELIVERY_METHOD', lambda do |values| values[:email_delivery_method] && values[:email_delivery_method].to_sym diff --git a/config/routes.rb b/config/routes.rb index 77c0b20..87fce77 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,6 +9,7 @@ Rails.application.routes.draw do resources :users do member do delete :unlink_github + delete :unlink_google end end diff --git a/spec/acceptance/acceptance_helper.rb b/spec/acceptance/acceptance_helper.rb index 66417be..de2f468 100644 --- a/spec/acceptance/acceptance_helper.rb +++ b/spec/acceptance/acceptance_helper.rb @@ -18,6 +18,14 @@ def mock_auth(user = "test_user", token = "abcdef") 'token' => token } ) + + OmniAuth.config.mock_auth[:google_oauth2] = Hashie::Mash.new( + provider: 'google', + uid: user, + info: { + email: 'errbit@errbit.example.com' + } + ) end def log_in(user) diff --git a/spec/acceptance/sign_in_with_google_spec.rb b/spec/acceptance/sign_in_with_google_spec.rb new file mode 100644 index 0000000..827af26 --- /dev/null +++ b/spec/acceptance/sign_in_with_google_spec.rb @@ -0,0 +1,23 @@ +require 'acceptance/acceptance_helper' + +feature 'Sign in with Google' do + background do + allow(Errbit::Config).to receive(:google_authentication).and_return(true) + Fabricate(:user, google_uid: 'nashby') + visit root_path + end + + scenario 'log in via Google with recognized user' do + mock_auth('nashby') + + click_link 'Sign in with Google' + expect(page).to have_content I18n.t('devise.omniauth_callbacks.success', kind: 'Google') + end + + scenario 'reject unrecognized user if authenticating via Google' do + mock_auth('unknown_user') + + click_link 'Sign in with Google' + expect(page).to have_content 'There are no authorized users with Google login' + end +end -- libgit2 0.21.2