Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Update for Rails 3 plus README help #1

Closed
wants to merge 7 commits into from

1 participant

Commits on Mar 14, 2012
  1. @sodabrew
  2. @sodabrew
  3. @sodabrew
  4. @sodabrew

    Working routes for rails 3.

    sodabrew authored
Commits on Mar 15, 2012
  1. @sodabrew
  2. @sodabrew

    Bump version to 0.0.7.sodabrew. Change method names to google_apps_au…

    sodabrew authored
    …th_begin and _finish. Change to hash arguments with defaults. Allow non-Apps logins as well.
Commits on Mar 16, 2012
  1. @sodabrew

    Add logout endpoint, and use redirect_to :back because Google passes …

    sodabrew authored
    …HTTP Referer: unchanged through the auth process.
This page is out of date. Refresh to see the latest.
View
2  Gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
- googleapps-auth (0.0.6)
+ googleapps-auth (0.0.7.sodabrew)
actionpack (>= 2.3.5)
ruby-openid (= 2.1.8)
View
79 README.markdown
@@ -8,12 +8,7 @@ when dealing with authenticating against Google's Apps-For-Your-Domain accounts,
### Gem
- gem "googleapps-auth", "0.0.5", :git => "git://github.com/livingsocial/rails-googleapps-auth.git", :require => "googleapps_auth"
-
-### Plugin
-Then, checkout this repo into your vendors/plugins dir:
-
- script/rails plugin git://github.com/livingsocial/rails-googleapps-auth.git
+ gem "googleapps-auth", "0.0.7.sodabrew", :git => "git://github.com/sodabrew/rails-googleapps-auth.git", :require => "googleapps_auth"
## Configuration
The path to a certificate file _must_ be configured before you start making requests to Google Apps. Due to
@@ -27,19 +22,37 @@ The following line in a rails initializer will enable the plugin for use:
Otherwise the authetication methods will raise GoogleAppsAuth::CertificateAuthorityFileError errors.
+To set your Google Apps domain for all instances at initialization, rather than at call time, use:
+
+ GoogleAppsAuth.default_domain = "example.com"
+
+If you do not specify an Apps domain either via default_domain, or by the
+:domain argument to google_apps_auth_begin, you'll be prompted by Google to
+select which of your accounts to sign in with. This will allow users to log
+into your Rails app using either their Google account or ANY Google Apps domain
+account.
+
## Authenticating Users
Create a new controller.
class AuthController < ApplicationController
def login
- # user will immediately be redirected to google to log in.
- # args are 1) your domain, 2) your "finish" controller action, and
- # 3) any required ax params (email/firstname/lastname/language)
- google_apps_authenticate "hungrymachine.com", 'finish', [:email]
+ # User will immediately be redirected to Google to log in, and redirected back to the 'finish' action when done.
+
+ # Override defaults:
+ google_apps_auth_begin :domain => "example.com", :return_action => 'finish', :attrs => [:email]
+
+ # Or use no args at all (domain defaults to nil, return_action defaults to 'finish')
+ # google_apps_auth_begin
end
+ def logout
+ reset_session
+ redirect_to :back
+ end
+
def finish
- response = google_apps_handle_auth
+ response = google_apps_auth_finish
if response.failed? or response.canceled?
flash[:notice] = "Could not authenticate: #{response.error}"
else
@@ -47,14 +60,20 @@ Create a new controller.
session[:user] = response[:email].first
flash[:notice] = "Thanks for logging in, #{response[:email].first}"
end
- redirect_to :root_url
+ redirect_to :back
end
end
To log users in, just redirect them to your controller's **login** action. Additionally, you will need to
add routes for your two actions in your *config/routes.rb* file:
- map.resources :auth, :collection => { :login => :get, :finish => :get }
+ resources :auth do
+ collection do
+ get 'login'
+ get 'logout'
+ get 'finish'
+ end
+ end
Additionally, a memory store is used by default, but if you will have many users authenticating you should use a different
[OpenID::Store](https://github.com/openid/ruby-openid/tree/master/lib/openid/store/) by adding a *store* protected method to your controller:
@@ -72,6 +91,40 @@ Additionally, a memory store is used by default, but if you will have many users
end
end
+##Requiring Authentication in Controllers
+To require that a user is authentication in order to perform certain actions, add the following helpers to ApplicationController:
+
+ class ApplicationController < ActionController::Base
+
+ ...
+
+ def login_required
+ if session[:user]
+ return true
+ end
+ flash[:warning] = 'Login required.'
+ session[:return_to] = request.fullpath
+ redirect_to :controller => "auth", :action => "login"
+ return false
+ end
+
+ def current_user
+ session[:user]
+ end
+ end
+
+Then at the top of each controller, specify the actions you wish to protect -- pick just one of the following *before_filter* for each controller:
+
+ class YourController < ApplicationController
+ # Protect every action in this controller
+ before_filter :login_required
+
+ # Protect just these actions
+ before_filter :login_required, :only => [:monkeywith]
+
+ # Protect everything else, but allow these to be unauthenticated
+ before_filter :login_required, :except => [:justlooking]
+ end
# Further Reading
* [Google's docs on OpenID discovery for hosted domains](http://groups.google.com/group/google-federated-login-api/web/openid-discovery-for-hosted-domains)
View
61 lib/googleapps_auth.rb
@@ -5,14 +5,17 @@
require 'openid/extensions/ax'
module GoogleAppsAuth
- ID_PREFIX = "https://www.google.com/accounts/o8/site-xrds?hd="
- XRDS_PREFIX = "https://www.google.com/accounts/o8/user-xrds?uri="
+ ID_PREFIX = "https://www.google.com/accounts/o8/id"
+ DOMAIN_ID_PREFIX = "https://www.google.com/accounts/o8/site-xrds?hd="
+ DOMAIN_XRDS_PREFIX = "https://www.google.com/accounts/o8/user-xrds?uri="
AX_SCHEMAS = {
:email => "http://schema.openid.net/contact/email",
:firstname => "http://axschema.org/namePerson/first",
:lastname => "http://axschema.org/namePerson/last",
- :language => "http://axschema.org/pref/language"
+ :language => "http://axschema.org/pref/language",
+ :country => "http://axschema.org/contact/country/home",
}
+ @@default_domain = nil
def self.certificate_authority_file=(path)
OpenID.fetcher.ca_file = path
@@ -26,6 +29,14 @@ def self.certificate_authority_file
OpenID.fetcher.ca_file
end
+ def self.default_domain=(domain)
+ @@default_domain = domain
+ end
+
+ def self.default_domain
+ @@default_domain
+ end
+
class Result
attr_reader :error
def initialize(status, error=nil, attrs=nil)
@@ -54,16 +65,28 @@ def failed?
class CertificateAuthorityFileError < StandardError; end
protected
- def google_apps_authenticate(appname, return_action = 'finish', get_attrs = nil)
+
+ ##
+ # return_to::
+ # return_action::
+ # domain::
+ # attrs:: zero or more of [ :email, :firstname, :lastname, :language ]
+ def google_apps_auth_begin(opts={})
assert_certificate_authority_file_present!
- get_attrs ||= []
+ opts = {
+ :return_action => 'finish',
+ :return_to => nil,
+ :domain => GoogleAppsAuth.default_domain,
+ :attrs => []
+ }.merge(opts)
+
begin
- oidreq = consumer.begin GoogleAppsAuth::ID_PREFIX + appname
- return_to = url_for :action => return_action, :only_path => false
+ oidreq = consumer.begin opts[:domain] ? GoogleAppsAuth::DOMAIN_ID_PREFIX + opts[:domain] : GoogleAppsAuth::ID_PREFIX
+ return_to = opts[:return_to] || url_for(:action => opts[:return_action], :only_path => false)
realm = request.protocol + request.host_with_port
ax = OpenID::AX::FetchRequest.new
- get_attrs.each { |attr|
+ opts[:attrs].each { |attr|
ax.add OpenID::AX::AttrInfo.new(GoogleAppsAuth::AX_SCHEMAS[attr], attr.to_s, true)
}
oidreq.add_extension(ax)
@@ -80,8 +103,7 @@ def google_apps_authenticate(appname, return_action = 'finish', get_attrs = nil)
end
end
-
- def google_apps_handle_auth
+ def google_apps_auth_finish
assert_certificate_authority_file_present!
current_url = url_for(:action => request.symbolized_path_parameters[:action], :only_path => false)
@@ -127,13 +149,20 @@ def assert_certificate_authority_file_present!
end
## TemplateURI's are not followed by the openid gem - so we have to trick it
+## when we're in private domain mode.
class OpenID::Consumer::IdResHandler
- def verify_discovery_results
+ original_verify_discovery_results = instance_method(:verify_discovery_results)
+
+ define_method(:verify_discovery_results) do
oldid = @message.get_arg(OpenID::OPENID_NS, 'identity', nil)
- @message.set_arg(OpenID::OPENID_NS, 'identity', GoogleAppsAuth::XRDS_PREFIX + oldid)
- @message.set_arg(OpenID::OPENID_NS, 'claimed_id', GoogleAppsAuth::XRDS_PREFIX + oldid)
- verify_discovery_results_openid2
- @message.set_arg(OpenID::OPENID_NS, 'identity', oldid)
- @message.set_arg(OpenID::OPENID_NS, 'claimed_id', oldid)
+ if oldid =~ /google.com\/accounts/
+ original_verify_discovery_results.bind(self).call
+ else
+ @message.set_arg(OpenID::OPENID_NS, 'identity', GoogleAppsAuth::DOMAIN_XRDS_PREFIX + oldid)
+ @message.set_arg(OpenID::OPENID_NS, 'claimed_id', GoogleAppsAuth::DOMAIN_XRDS_PREFIX + oldid)
+ verify_discovery_results_openid2
+ @message.set_arg(OpenID::OPENID_NS, 'identity', oldid)
+ @message.set_arg(OpenID::OPENID_NS, 'claimed_id', oldid)
+ end
end
end
View
2  lib/googleapps_auth/version.rb
@@ -1,3 +1,3 @@
module GoogleAppsAuth
- VERSION = "0.0.6"
+ VERSION = "0.0.7.sodabrew"
end
View
2  rails-googleapps-auth.gemspec
@@ -1,4 +1,4 @@
-require "lib/googleapps_auth/version"
+require "./lib/googleapps_auth/version"
require "date"
Gem::Specification.new do |gem|
View
5 spec/resources/sessions_controller.rb
@@ -2,13 +2,14 @@ class SessionsController < ActionController::Base
protect_from_forgery
def start
- google_apps_authenticate "example.com", :conclude, [:email] do
+ ## google_apps_auth_begin :return_action => :conclude, :attrs => [:email] do
+ google_apps_auth_begin :domain => "example.com", :return_action => :conclude, :attrs => [:email] do
render :status => 500, :text => ""
end
end
def conclude
- if(the_google = google_apps_handle_auth) && the_google.succeeded?
+ if(the_google = google_apps_auth_finish) && the_google.succeeded?
render :status => 200, :text => ""
else
render :status => 500, :text => ""
Something went wrong with that request. Please try again.