Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] GitHub Authentication #1595

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ gem 'cloudinary', '~> 1.11.1'
gem 'figaro', '1.1.1'
gem 'google-api-client', '~> 0.30.2'
gem 'kaminari', '1.1.1'
gem 'omniauth-github'
gem 'omniauth-google-oauth2', '~> 0.7.0'
gem 'omniauth-rails_csrf_protection', '~> 0.1.2'
gem 'premailer-rails'
Expand Down Expand Up @@ -84,6 +85,7 @@ group :development, :test do

gem 'bullet'

gem 'awesome_print'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this gem necessary? What's it being used for?

gem 'webdrivers'
end

Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ GEM
rake (>= 10.4, < 13.0)
arel (9.0.0)
ast (2.4.0)
awesome_print (1.8.0)
aws_cf_signer (0.1.3)
bcrypt (3.1.13)
better_errors (2.6.0)
Expand Down Expand Up @@ -225,6 +226,9 @@ GEM
omniauth (1.9.1)
hashie (>= 3.4.6)
rack (>= 1.6.2, < 3)
omniauth-github (1.3.0)
omniauth (~> 1.5)
omniauth-oauth2 (>= 1.4.0, < 2.0)
omniauth-google-oauth2 (0.7.0)
jwt (>= 2.0)
omniauth (>= 1.1.1)
Expand Down Expand Up @@ -495,6 +499,7 @@ PLATFORMS
DEPENDENCIES
activerecord-import
annotate (~> 2.7)
awesome_print
bcrypt (= 3.1.13)
better_errors (~> 2.5)
bullet
Expand Down Expand Up @@ -522,6 +527,7 @@ DEPENDENCIES
jquery-rails (= 4.3.5)
kaminari (= 1.1.1)
letter_opener
omniauth-github
omniauth-google-oauth2 (~> 0.7.0)
omniauth-rails_csrf_protection (~> 0.1.2)
pg (= 1.1.4)
Expand Down
15 changes: 14 additions & 1 deletion app/controllers/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,20 @@ def google_oauth2
kind: t('omniauth.google'))
sign_in_and_redirect @user, event: :authentication
else
redirect_to new_user_session_path, notice: t('omniauth.access_denied')
redirect_to new_user_session_path, alert: t('omniauth.access_denied')
end
end

def github
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am just curious why we have github auth, are our users mostly from github?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is something that @julianguyen can answer, but if I may try. since this is a platform that encourages collaboration, maybe a target audience of tech people are in mind?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah GitHub authentication isn't a priority like Facebook would be for instance. This was requested by a contributor 🙃

But we could use this functionality to show links for filing GitHub issues just for folks signed in it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also test this new method!

@user = User.from_omniauth request.env['omniauth.auth']

if @user.valid?
flash[:notice] = I18n.t('devise.omniauth_callbacks.success',
kind: t('omniauth.github'))

sign_in_and_redirect @user, event: :authentication
else
redirect_to new_user_session_path, alert: t('omniauth.access_denied')
end
end

Expand Down
31 changes: 25 additions & 6 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class User < ApplicationRecord
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :invitable, :database_authenticatable, :registerable, :uid,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable,
omniauth_providers: [:google_oauth2]
omniauth_providers: %i[google_oauth2 github]

mount_uploader :avatar, AvatarUploader

Expand All @@ -81,24 +81,38 @@ class User < ApplicationRecord
validates :locale, inclusion: {
in: Rails.application.config.i18n.available_locales.map(&:to_s).push(nil)
}
validate :password_complexity

# add unless statement here instead of the concern for readability
# TODO: refactor the Password validator concern
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this be done in another PR? :) Feel free to create an issue for this as well just to document.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one of the setbacks on making this PR short. I agree on having this as another ticket.

validate :password_complexity, unless: :oauth_provided?

def active_for_authentication?
super && !banned
end

def self.find_for_google_oauth2(access_token)
user = find_or_initialize_by(email: access_token.info.email)
user.name ||= access_token.info.name
# TODO: to refactor and to move to builder pattern
# UserBuilder::GoogleOauth2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comment as above.

def self.find_for_google_oauth2(auth)
user = find_or_initialize_by(email: auth.info.email)
user.name ||= auth.info.name
user.password ||= Devise.friendly_token[0, 20]
update_access_token_fields(user: user, access_token: access_token)
update_access_token_fields(user: user, access_token: auth)
user
end

# to refactor, could be single oauth method to begin with
def self.from_omniauth(auth)
where(provider: auth.provider,
uid: auth.provider + auth.uid).first_or_create do |user|
UserBuilder::Builder.build(user: user, auth: auth)
end
end

def google_access_token
google_access_token_expired? ? update_access_token : token
end

# TODO: refactor this and use one checker
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call!

def google_oauth2_enabled?
token.present?
end
Expand Down Expand Up @@ -140,6 +154,11 @@ def update_access_token

private

# checks if user is created from oauth
def oauth_provided?
provider.present? || token.present?
end

def google_access_token_expired?
!access_expires_at || Time.zone.now > access_expires_at
end
Expand Down
31 changes: 31 additions & 0 deletions app/services/user_builder/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true
module UserBuilder
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

class Base
attr_reader :user

def self.call(user:, auth:)
new(user: user, auth: auth)
end

def initialize(user:, auth:)
@user = user
@user.tap do
user.provider = auth.provider
user.name = auth.info.name
user.uid = provider_uid(auth)
user.email = auth.info.email
user.password = default_password
end
end

private

def default_password
Devise.friendly_token[0, 20]
end

def provider_uid(auth)
auth.provider + auth.uid
end
end
end
15 changes: 15 additions & 0 deletions app/services/user_builder/builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true
module UserBuilder
class Builder
# Adds new omni auth providers here
SERVICE = {
# 'google_oauth' => GoogleOauth2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be uncommented?

}.freeze

# UserBuilder::Builder.build(user: user, provider: provider, auth: auth)
def self.build(user:, auth:)
service = SERVICE.fetch(auth.provider, UserBuilder::Base)
service.call(user: user, auth: auth)
end
end
end
17 changes: 11 additions & 6 deletions app/views/devise/shared/_links.erb
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
<div class="smallMarginTop">
<%- if devise_mapping.omniauthable? and request.base_url != 'http://0.0.0.0:3000' %>
<%- resource_class.omniauth_providers.each do |provider| %>
<% if provider.to_s == "google_oauth2" && (current_page?(new_user_session_path) || current_page?(new_user_password_path)) %>
<%= button_to t('devise.shared.sign_in_google'), omniauth_authorize_path(resource_name, provider), method: :post, class: 'buttonGhostM' %>
<% elsif provider.to_s == "google_oauth2" %>
<%= button_to t('devise.shared.sign_up_google'), omniauth_authorize_path(resource_name, provider), method: :post, class: 'buttonGhostM' %>
<% end -%>
<%- resource_class.omniauth_providers.each do |provider| %>

<% if provider.to_s == "google_oauth2" && (current_page?(new_user_session_path) || current_page?(new_user_password_path)) %>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO:
add a helper that handles showing of button links

show_signup_page? provider

show_register_page? provider

<%= button_to t('devise.shared.sign_in_google'), omniauth_authorize_path(resource_name, provider), method: :post, class: 'buttonGhostM smallMarginBottom' %>
<% elsif provider.to_s == "github" && (current_page?(new_user_session_path) || current_page?(new_user_password_path)) %>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this part is a bit dirty, needs some refactoring

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be great!

<%= button_to t('devise.shared.sign_in_github'), omniauth_authorize_path(resource_name, provider), method: :post, class: 'buttonGhostM smallMarginBottom' %>
<% elsif provider.to_s == "google_oauth2" %>
<%= button_to t('devise.shared.sign_up_google'), omniauth_authorize_path(resource_name, provider), method: :post, class: 'buttonGhostM smallMarginBottom' %>
<% elsif provider.to_s == 'github' %>
<%= button_to t('devise.shared.sign_up_github'), omniauth_authorize_path(resource_name, provider), method: :post, class: 'buttonGhostM smallMarginBottom' %>
<% end -%>
<% end -%>
<% end -%>
</div>
Expand Down
2 changes: 2 additions & 0 deletions config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -317,4 +317,6 @@
approval_prompt: 'select_account consent force',
scope: 'userinfo.email,userinfo.profile,calendar'
)

config.omniauth :github, ENV['GITHUB_CLIENT_ID'], ENV['GITHUB_CLIENT_SECRET'], scope: 'user:email'
end
3 changes: 3 additions & 0 deletions config/locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ de:
mehr blockiert.
omniauth:
google: Google
github: Github
access_denied: 'Zutritt verweigert'
pages:
about:
Expand Down Expand Up @@ -1183,6 +1184,8 @@ de:
shared:
sign_in_google: 'Mit Google einloggen'
sign_up_google: 'Mit Google anmelden'
sign_in_github: 'Sign in with Github'
sign_up_github: 'Sign up with Github'
confirmation: 'Keine Anweisungen zur Bestätigung erhalten?'
unlock: 'Keine Anweisungen zur Freischaltung erhalten?'
unlock:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ en:
%{code_of_conduct_link}. You are no longer banned.
omniauth:
google: Google
github: Github
access_denied: 'Access Denied'
pages:
about:
Expand Down Expand Up @@ -1107,6 +1108,8 @@ en:
shared:
sign_in_google: 'Sign in with Google'
sign_up_google: 'Sign up with Google'
sign_in_github: 'Sign in with Github'
sign_up_github: 'Sign up with Github'
confirmation: 'Didn''t receive confirmation instructions?'
unlock: 'Didn''t receive unlock instructions?'
unlock:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ es:
%{code_of_conduct_link}. Ya no estás baneado/a.'
omniauth:
google: Google
github: Github
access_denied: 'Acceso Denegado'
pages:
about:
Expand Down Expand Up @@ -972,6 +973,8 @@ es:
shared:
sign_in_google: 'Registrarse con Google'
sign_up_google: 'Ingresar con Google'
sign_in_github: 'Sign in with Github'
sign_up_github: 'Sign up with Github'
confirmation: '¿No recibiste instrucciones de confirmación?'
unlock: '¿No recibiste instrucciones para desbloquear?'
unlock:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ fr:
%{code_of_conduct_link}.
omniauth:
google: Google
github: Github
access_denied: 'Accès refusé'
pages:
about:
Expand Down Expand Up @@ -1160,6 +1161,8 @@ fr:
shared:
sign_in_google: "S'identifier avec Google"
sign_up_google: "S'enregistrer avec Google"
sign_in_github: 'Sign in with Github'
sign_up_github: 'Sign up with Github'
confirmation: "Vous n'avez pas reçu vous informations de confirmation ?"
unlock: >-
Vous n'avez pas reçu vos informations pour débloquer votre compte ?
Expand Down
3 changes: 3 additions & 0 deletions config/locales/hi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ hi:
किया गया था। अब आप प्रतिबंधित नहीं हैं'
omniauth:
google: 'गूगल'
github: 'Github'
access_denied: 'पहुंच अस्वीकृत'
pages:
about:
Expand Down Expand Up @@ -888,6 +889,8 @@ hi:
shared:
sign_in_google: 'Google के साथ साइन इन करें'
sign_up_google: 'Google के साथ साइन अप करें'
sign_in_github: 'Sign in with Github'
sign_up_github: 'Sign up with Github'
confirmation: 'पुष्टि निर्देश प्राप्त नहीं हुआ?'
unlock: 'क्या अनलॉक निर्देश प्राप्त नहीं होंगे?'
unlock:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/it.yml
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ it:
nostra %{code_of_conduct_link}. Non sei più bannato.'
omniauth:
google: Google
github: Github
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I don't think we need to add another GitHub translation since we already have one at navigation.github. In general, we don't want to introduce duplication in our translation files.

access_denied: 'Accesso Negato'
pages:
about:
Expand Down Expand Up @@ -965,6 +966,8 @@ it:
shared:
sign_in_google: 'Effettua il login con Google'
sign_up_google: 'Registrati con Google'
sign_in_github: 'Sign in with Github'
sign_up_github: 'Sign up with Github'
confirmation: 'Non hai ricevuto le istruzioni per confermare la tua EMail?'
unlock: 'Non hai ricevuto le istruzioni per sbloccare il tuo account?'
unlock:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/nb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ nb:
%{code_of_conduct_link}. Du er ikke lenger utestengt.'
omniauth:
google: Google
github: Github
access_denied: 'Adgang avvist'
pages:
about:
Expand Down Expand Up @@ -957,6 +958,8 @@ nb:
shared:
sign_in_google: 'Logg inn med Google'
sign_up_google: 'Registrer deg med Google'
sign_in_github: 'Sign in with Github'
sign_up_github: 'Sign up with Github'
confirmation: 'Mottok ikke bekreftelsesinstruksjoner?'
unlock: 'Mottok ikke opplåsningsinstruksjoner?'
unlock:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/nl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ nl:
%{code_of_conduct_link} schond. Je bent niet langer verbannen.'
omniauth:
google: Google
github: Github
access_denied: 'Toegang geweigerd'
pages:
about:
Expand Down Expand Up @@ -976,6 +977,8 @@ nl:
shared:
sign_in_google: 'Log in met Google'
sign_up_google: 'Registreren met Google'
sign_in_github: 'Sign in with Github'
sign_up_github: 'Sign up with Github'
confirmation: 'Bevestiginginstructies niet ontvangen?'
unlock: 'Ontgrendelingsinstructies niet ontvangen?'
unlock:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/pt-BR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ pt-BR:
%{code_of_conduct_link}. Você não está mais banido.'
omniauth:
google: Google
github: Github
access_denied: 'Acesso negado'
pages:
about:
Expand Down Expand Up @@ -1000,6 +1001,8 @@ pt-BR:
shared:
sign_in_google: 'Entrar com sua conta Google'
sign_up_google: 'Cadastre-se com sua conta Google'
sign_in_github: 'Sign in with Github'
sign_up_github: 'Sign up with Github'
confirmation: 'Não recebeu as instruções de confirmação?'
unlock: 'Não recebeu as instruções de desbloqueio?'
unlock:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/sv.yml
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ sv:
%{code_of_conduct_link}. Du är inte längre förbjuden.'
omniauth:
google: Google
github: Github
access_denied: 'Åtkomst nekad'
pages:
about:
Expand Down Expand Up @@ -952,6 +953,8 @@ sv:
shared:
sign_in_google: 'Logga in med Google'
sign_up_google: 'Registrera dig hos Google'
sign_in_github: 'Logga in med Github'
sign_up_github: 'Registrera dig hos Github'
confirmation: 'Fick du inte bekräftelsesinstruktioner?'
unlock: 'Fick du inte upplåsningsinstruktioner?'
unlock:
Expand Down
Loading