Skip to content

Instantly share code, notes, and snippets.

@TildeWill
Forked from anonymous/Gemfile
Last active March 23, 2017 17:41
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save TildeWill/5078443 to your computer and use it in GitHub Desktop.
SSO for an installed Google App
#app/models/user.rb
class User < ActiveRecord::Base
attr_accessible :email, :first_name, :last_name,
:full_name, :image_url, :uid
def domain
email.split("@").last
end
def self.create_with_omniauth(auth)
create! do |user|
user.uid = auth["uid"]
user.first_name = auth["info"]["first_name"]
user.last_name = auth["info"]["last_name"]
user.full_name = auth["info"]["name"]
user.email = auth["info"]["email"]
user.image_url = auth['info']['image']
end
end
end
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_filter :authenticate_user!
helper_method :current_user, :user_signed_in?, :current_users
def authenticate_user!
redirect_to '/auth/google_apps' unless user_signed_in?
end
private
def current_user
@current_user ||= User.find_by_id(session[:user_id]) if user_signed_in?
end
def user_signed_in?
session[:user_id] && User.find_by_id(session[:user_id])
end
end
#lib/google/client.rb
require 'oauth'
require 'rexml/document'
module Google
class Client
attr_accessor :version
def self.get(base, query_parameters, version = '2.0')
make_request(:get, url(base, query_parameters), version)
end
private
def self.make_request(method, url, version)
oauth_consumer = OAuth::Consumer.new(GOOGLE_APP_ID, GOOGLE_APP_SECRET)
access_token = OAuth::AccessToken.new(oauth_consumer)
response = access_token.request(method, url, {'GData-Version' => version})
if response.is_a?(Net::HTTPFound)
return make_request(method, response['Location'], version)
end
return unless response.is_a?(Net::HTTPSuccess)
feed = REXML::Document.new(response.body)
throw :halt, [500, "Unable to query feed"] if feed.nil?
feed
end
def self.url(base, query_parameters={})
url = base
unless query_parameters.empty?
url += '?'
query_parameters.each { |key, value| url += "#{CGI::escape(key)}=#{CGI::escape(value)}&" }
url.chop!
end
url
end
end
end
#lib/google/contact.rb
module Google
class Contact
attr_accessor :full_name, :first_name, :last_name, :email, :company, :title, :notes
def self.all(email)
feed = Google::Client.get("https://www.google.com/m8/feeds/contacts/default/full", {
'xoauth_requestor_id' => email
}, '3.0')
feed.elements.collect('//entry') do |entry|
new(
:full_name => entry.elements["gd:name"].elements["gd:fullName"].text,
:first_name => entry.elements["gd:name"].elements["gd:givenName"].text,
:last_name => entry.elements["gd:name"].elements["gd:familyName"].text,
:email => entry.elements["gd:email"].attribute("address").value,
:company => entry.elements["gd:organization"].elements["gd:orgName"].text,
:title => entry.elements["gd:organization"].elements["gd:orgTitle"].text,
:notes => entry.elements["content"].text
)
end
end
def initialize(options = {})
@full_name = options[:full_name]
@first_name = options[:first_name]
@last_name = options[:last_name]
@email = options[:email]
@company = options[:company]
@title = options[:title]
@notes = options[:notes]
end
end
end
#Gemfile
source 'https://rubygems.org'
...
gem 'oauth'
gem 'omniauth-google-apps'
...
#config/initializers/omniauth.rb
require 'openid/store/filesystem'
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_apps, :store => OpenID::Store::Filesystem.new('./tmp')
end
#config/routes.rb
...
match "/auth/:provider/callback" => "sessions#create"
match "/signout" => "sessions#destroy", :as => :signout
...
#app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
skip_before_filter :authenticate_user!, only: :create
def create
auth = request.env["omniauth.auth"]
user = User.find_by_uid(auth["uid"]) || User.create_with_omniauth(auth)
session[:user_id] = user.id
redirect_to root_url, :notice => "Signed in!"
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Signed out!"
end
end
#lib/google/user.rb
module Google
class User
attr_accessor :login, :first_name, :last_name
def self.all(domain)
feed = Google::Client.get("https://apps-apis.google.com/a/feeds/#{domain}/user/2.0", {
'get' => 'all'
})
feed.elements.collect('//entry') { |e| new_from_entry(e) }
end
def self.find(domain, login)
feed = Google::Client.get("https://apps-apis.google.com/a/feeds/#{domain}/user/2.0/#{login}", {})
feed.elements.collect('//entry') { |e| new_from_entry(e) }
end
def initialize(options ={})
@login = options[:login]
@first_name = options[:first_name]
@last_name = options[:last_name]
end
private
def self.new_from_entry(entry)
new(
:login => entry.elements["apps:login"].attribute("userName").value,
:first_name => entry.elements["apps:name"].attribute("givenName").value,
:last_name => entry.elements["apps:name"].attribute("familyName").value,
)
end
end
end
@mcansky
Copy link

mcansky commented Jan 12, 2014

any update since then ?

what is the route the google app market will use to redirect the user to arrive and be logged in ?

Google app market docs describe that domain name will be passed with but, using the omniauth-google-apps gem I cannot find the entry point that is supposed to receive such information. (users keep being presented with the "enter domain name" form before being redirected to google for auth, then back to the app, logged in).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment