public
Last active — forked from /Gemfile

SSO for an installed Google App

  • Download Gist
Google App Auth.rb
Ruby
1 2 3 4 5 6 7
#Gemfile
source 'https://rubygems.org'
 
...
gem 'oauth'
gem 'omniauth-google-apps'
...
active_record_user.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#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
application_controller.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#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
client.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
#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
contact.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
#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
omniauth.rb
Ruby
1 2 3 4 5 6
#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
routes.rb
Ruby
1 2 3 4 5
#config/routes.rb
...
match "/auth/:provider/callback" => "sessions#create"
match "/signout" => "sessions#destroy", :as => :signout
...
sessions_controller.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#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
user.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
#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

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).

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.