Skip to content

Instantly share code, notes, and snippets.

@petros
Forked from jonmagic/application_controller.rb
Created March 13, 2014 05:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save petros/9522426 to your computer and use it in GitHub Desktop.
Save petros/9522426 to your computer and use it in GitHub Desktop.
class ApplicationController < ActionController::Base
include SessionAuthentication
# ...
end
class AuthenticatedUser
# Raise if the user must be a member of the team on GitHub.
class TeamMembershipRequired < StandardError; end
# Public: Find or create User from the OmniAuth::AuthHash returned after
# OAuthing with GitHub.
#
# omniauth_authhash - OmniAuth::AuthHash instance.
#
# Returns a User.
def self.find(omniauth_authhash)
user = new(omniauth_authhash)
user.authenticate!
user.save!
end
def initialize(omniauth_authhash)
@omniauth_authhash = omniauth_authhash
end
# Public: OmniAuth::AuthHash passed in at initialization.
#
# Returns an OmniAuth::AuthHash.
attr_reader :omniauth_authhash
# Public: The GitHub id of the user.
#
# Returns an Integer.
def github_id
omniauth_authhash.uid
end
# Public: Users name on GitHub.
#
# Returns a String.
def name
omniauth_authhash.info.name
end
# Public: Users nickname on GitHub.
#
# Returns a String.
def username
omniauth_authhash.info.nickname
end
# Public: The access token of the user, needed for making API requests on
# behalf of the user.
#
# Returns a String.
def access_token
omniauth_authhash.credentials.token
end
# Public: Is this user on the team specified by ENV["GITHUB_TEAM_ID"]?
#
# Returns a TrueClass or FalseClass.
def team_member?
omniauth_authhash.credentials.team_member?
end
# Public: User instance, found or initialized by github_id.
#
# Returns a User.
def user
@user ||= begin
user = User.find_or_initialize_by(:github_id => github_id)
user.name = name
user.username = username
user.access_token = access_token
user
end
end
# Public: Raises an error if the user is not a team member or does not have
# a github.com email address.
def authenticate!
raise TeamMembershipRequired unless team_member?
end
# Public: Save authenticated user and the users email addresses.
#
# Returns a User.
def save!
user.save!
user
end
end
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.integer :github_id, :null => false
t.string :username
t.string :access_token
t.timestamps
end
add_index :users, :github_id, :unique => true
end
end
Rails.application.config.middleware.use OmniAuth::Builder do
provider :githubteammember, ENV["GITHUB_CLIENT_ID"], ENV["GITHUB_CLIENT_SECRET"], :scope => "user"
end
OmniAuth.config.on_failure = Proc.new { |env|
if env["omniauth.error"].kind_of? OmniAuth::Strategies::OAuth2::CallbackError
[302, {"Location" => "/", "Content-Type"=> "text/html"}, []]
end
}
Intercom::Application.routes.draw do
get "/auth/githubteammember/callback" => "sessions#create"
get "/signout" => "sessions#signout"
get "/auth/failure" => "sessions#failure"
end
require 'active_support/concern'
require 'active_support/core_ext'
# SessionAuthentication adds session authentication to a controller.
# It includes helper methods for views and a signin_required method to use
# in a before_filter to ensure a request is by a signed in user.
module SessionAuthentication
extend ActiveSupport::Concern
included do
helper_method :current_user, :signed_in?
before_filter :signin_required
end
# Public: Returns the current user or kicks off authentication.
#
# Returns a User or NilClass.
def current_user
return @current_user if defined?(@current_user)
self.current_user = user_from_session
end
# Internal: Set the current user and add to session.
#
# user - The user object you would like to make the current user.
def current_user=(user)
return unless user.present?
@current_user = user
session[:user_id] = user.id
end
# Public: Sign in the user and redirect to the saved url or root path.
#
# user - The user object you would like to make the current user.
def sign_in_and_redirect(user)
self.current_user = user
redirect_to session[:return_to] || root_path
end
# Public: Validates signed in state.
#
# Returns a TrueClass or FalseClass.
def signed_in?
!!current_user
end
# Public: Require that the the user making the request is signed in.
def signin_required
signed_in? || permission_denied
end
# Public: Treat the web request or api request as unauthorized.
def permission_denied
session[:return_to] = request.path if request.path
redirect_to "/auth/githubteammember"
end
# Internal: Attempt to find user from session if session[:user_id] is present.
#
# Returns a User or NilClass.
def user_from_session
session[:return_to] = request.path if request.path
user_finder.find_by_id(session[:user_id]) if session[:user_id].present?
end
# Internal: Accessing the user finder through this method
# allows us to test the interaction more easily
def user_finder
@user_finder ||= User
end
# Internal: Set user finder to an alternative source.
attr_writer(:user_finder)
end
class SessionsController < ApplicationController
skip_before_filter :signin_required, :only => [:create, :failure]
rescue_from AuthenticatedUser::TeamMembershipRequired do
render :text => "Authentication failure."
end
# Public: Create and log in a user from the Omniauth auth payload.
def create
user = AuthenticatedUser.find(request.env["omniauth.auth"])
sign_in_and_redirect user
end
# Public: Remove user's session and redirect.
def signout
reset_session
redirect_to "https://github.com"
end
end
# TokenAuthentication adds token authentication to a controller and provides
# an authentication_required method that can be used in a before_filter to
# ensure that requests are authenticated.
module TokenAuthentication
# Public: Require that the request has a valid authentication token.
def authentication_required
authenticated? || permission_denied
end
# Public: Does the request have an authenticated_user?
#
# Returns a TrueClass or FalseClass.
def authenticated?
!!authenticated_user
end
# Public: The authenticated_user if one is set.
#
# Returns a User or NilClass.
def authenticated_user
return @authenticated_user if defined?(@authenticated_user)
self.authenticated_user = user_from_token
end
# Internal: Set the authenticated_user.
#
# user - A User found by their token.
def authenticated_user=(user)
return unless user.present?
@authenticated_user = user
end
# Internal: Halts the request with an unauthorized response.
def permission_denied
head :unauthorized
end
# Internal: Attempt to find user from Authorization header or access_token
# parameter.
#
# Returns a User or NilClass.
def user_from_token
token = request.headers["Authorization"]
if token =~ /^token ([\w]+)$/i
token = $1
else
token = params.delete("access_token")
end
User.find_by_access_token(token) if token.present?
end
end
class User < ActiveRecord::Base
# Public: Full name.
# column :name
# Returns a String.
# Public: GitHub id.
# column :github_id
# Returns an Integer.
validates :github_id, :presence => true, :uniqueness => true
# Public: Username.
# column :username
# Returns a String.
# Public: Access token for making GitHub API requests.
# column :access_token
# Returns a String.
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment