Skip to content
This repository has been archived by the owner on Jul 15, 2021. It is now read-only.

Commit

Permalink
Add authentication using Google OAuth
Browse files Browse the repository at this point in the history
- Add users table
- Whitelist user email domains
- Add environment variable configuration
  • Loading branch information
yassskitt committed Aug 20, 2015
1 parent 23077f2 commit 252250e
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 2 deletions.
16 changes: 16 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Orientation configuration
#
# set this to 'codeschool.com:pluralsight.com' to only authorize
# emails from these two domains to sign in to Orientation
APP_DOMAIN=compliments.dev
EMAIL_WHITELIST=

# Google OAuth 2
#
# Create a new project on Google's API console here: https://console.developers.google.com/
# Then enable the Google+ and Contacts APIs for this project.
#
# e.g. 831a244758x7.apps.googleusercontent.com
GOOGLE_KEY=
# e.g. 5Ac5Fcigyty0tRO6b4c4Zh4E
GOOGLE_SECRET=
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
/log/*
!/log/.keep
/tmp
.env
4 changes: 3 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0', group: :doc

gem 'omniauth-google-oauth2'
gem 'dotenv-rails'

# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

Expand All @@ -42,4 +45,3 @@ group :development, :test do
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
end

27 changes: 27 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,17 @@ GEM
execjs
coffee-script-source (1.9.1.1)
debug_inspector (0.0.2)
dotenv (2.0.2)
dotenv-rails (2.0.2)
dotenv (= 2.0.2)
railties (~> 4.0)
erubis (2.7.0)
execjs (2.6.0)
faraday (0.9.1)
multipart-post (>= 1.2, < 3)
globalid (0.3.6)
activesupport (>= 4.1.0)
hashie (3.4.2)
i18n (0.7.0)
jbuilder (2.3.1)
activesupport (>= 3.0.0, < 5)
Expand All @@ -62,6 +69,7 @@ GEM
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (1.8.3)
jwt (1.5.1)
loofah (2.0.3)
nokogiri (>= 1.5.9)
mail (2.6.3)
Expand All @@ -70,8 +78,25 @@ GEM
mini_portile (0.6.2)
minitest (5.8.0)
multi_json (1.11.2)
multi_xml (0.5.5)
multipart-post (2.0.0)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
oauth2 (1.0.0)
faraday (>= 0.8, < 0.10)
jwt (~> 1.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (~> 1.2)
omniauth (1.2.2)
hashie (>= 1.2, < 4)
rack (~> 1.0)
omniauth-google-oauth2 (0.2.6)
omniauth (> 1.0)
omniauth-oauth2 (~> 1.1)
omniauth-oauth2 (1.3.1)
oauth2 (~> 1.0)
omniauth (~> 1.2)
pg (0.18.2)
rack (1.6.4)
rack-test (0.6.3)
Expand Down Expand Up @@ -142,8 +167,10 @@ PLATFORMS
DEPENDENCIES
byebug
coffee-rails (~> 4.1.0)
dotenv-rails
jbuilder (~> 2.0)
jquery-rails
omniauth-google-oauth2
pg
rails (= 4.2.3)
sass-rails (~> 5.0)
Expand Down
31 changes: 31 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,35 @@ class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :authenticate_user!

private

def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id].present?
end
helper_method :current_user

def user_signed_in?
current_user.present?
end
helper_method :user_signed_in?

def authenticate_user!
if current_user
true
else
session["return_to"] ||= request.url
redirect_to login_path unless login_redirect? or oauth_callback?
end
end
helper_method :authenticate_user!

def login_redirect?
request.path == login_path
end

def oauth_callback?
request.path == oauth_callback_path("google_oauth2")
end
end
33 changes: 33 additions & 0 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
class SessionsController < ApplicationController
def new
origin = { origin: session.delete(:return_to) }.to_query
redirect_to("/auth/google_oauth2?#{origin}")
end

def create
user = User.find_or_create_from_omniauth(auth_hash)
if user.valid?
session[:user_id] = user.id
flash[:notice] = "Signed in!"
# OmniAuth automatically saves the HTTP_REFERER when you begin the auth process
redirect_to request.env['omniauth.origin'] || root_url
else
flash[:error] = "You need a #{ENV.fetch('APP_DOMAIN')} account to sign in."
redirect_to root_url
end
end

def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Signed out!"
end

protected

def auth_hash
# calling to_h because Strong Parameters don't allow direct access
# to request parameters, even when passed to a class outside the
# controller scope.
request.env['omniauth.auth'].to_h
end
end
37 changes: 37 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,46 @@
class User < ActiveRecord::Base

validates :email, presence: true
validate :whitelisted_email, if: -> { self.class.email_whitelist? }

def self.find_or_create_from_omniauth(auth)
find_and_update_from_omniauth(auth) or create_from_omniauth(auth)
end

def self.create_from_omniauth(auth)
create do |user|
user.provider = auth["provider"]
user.uid = auth["uid"]
user.name = auth["info"]["name"]
user.email = auth["info"]["email"]
user.image = auth["info"]["image"]
end
end

def self.find_and_update_from_omniauth(auth)
find_by(auth.slice("provider","uid")).tap do |user|
user && user.update_attribute(:image, auth["info"]["image"])
end
end

def to_s
self.name || self.email
end

private

def self.email_whitelist?
!!ENV['EMAIL_WHITELIST']
end

def email_whitelist
ENV["EMAIL_WHITELIST"].split(":")
end

def whitelisted_email
if email_whitelist.none? { |email| self.email.include?(email) }
errors.add(:email, "doesn't match the email domain whitelist: #{email_whitelist}")
end
end

end
3 changes: 3 additions & 0 deletions config/initializers/omniauth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, ENV["GOOGLE_KEY"], ENV["GOOGLE_SECRET"]
end
6 changes: 6 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
# You can have the root of your site routed with "root"
# root 'welcome#index'

resources :sessions, only: [:new, :create, :destroy]
get 'auth/:provider/callback', to: 'sessions#create', as: :oauth_callback
get 'auth/failure', to: redirect('/')
get 'login', to: 'sessions#new', as: :login
get 'logout', to: 'sessions#destroy', as: :logout

# Example of regular route:
# get 'products/:id' => 'catalog#view'

Expand Down
12 changes: 11 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,19 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 0) do
ActiveRecord::Schema.define(version: 20150819222233) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

create_table "users", force: :cascade do |t|
t.string "provider"
t.string "uid"
t.string "name"
t.string "email"
t.string "image"
t.datetime "created_at"
t.datetime "updated_at"
end

end

0 comments on commit 252250e

Please sign in to comment.