1
0
Fork 0
mirror of https://github.com/heartcombo/devise.git synced 2022-11-09 12:18:31 -05:00

More OAuth setup.

This commit is contained in:
José Valim 2010-07-13 10:09:55 +02:00
parent 6c5be8dfd5
commit bd8294aecf
17 changed files with 207 additions and 57 deletions

View file

@ -11,6 +11,7 @@ gem "sqlite3-ruby"
gem "webrat", "0.7.0"
gem "mocha", :require => false
gem "bcrypt-ruby", :require => "bcrypt"
gem "oauth2"
if RUBY_VERSION < '1.9'
gem "ruby-debug", ">= 0.10.3"

View file

@ -56,6 +56,7 @@ GEM
remote: http://rubygems.org/
specs:
abstract (1.0.0)
addressable (2.1.2)
arel (0.4.0)
activesupport (>= 3.0.0.beta)
bcrypt-ruby (2.1.2)
@ -65,6 +66,9 @@ GEM
columnize (0.3.1)
erubis (2.6.6)
abstract (>= 1.0.0)
faraday (0.4.6)
addressable (>= 2.1.1)
rack (>= 1.0.1)
i18n (0.4.1)
linecache (0.43)
mail (2.2.5)
@ -77,6 +81,9 @@ GEM
mongo (1.0.5)
bson (>= 1.0.4)
nokogiri (1.4.2)
oauth2 (0.0.10)
faraday (~> 0.4.1)
multi_json (>= 0.0.4)
polyglot (0.3.1)
rack (1.2.1)
rack-mount (0.6.9)
@ -111,6 +118,7 @@ DEPENDENCIES
mocha
mongo
mongoid!
oauth2
rails!
ruby-debug (>= 0.10.3)
sqlite3-ruby

View file

@ -1,9 +1,4 @@
class Devise::OauthCallbacksController < ApplicationController
include Devise::Controllers::InternalHelpers
def twitter
end
def github
end
include Devise::Oauth::Helpers
end

View file

@ -3,6 +3,7 @@ require 'active_support/dependencies'
module Devise
autoload :FailureApp, 'devise/failure_app'
autoload :Oauth, 'devise/oauth'
autoload :PathChecker, 'devise/path_checker'
autoload :Schema, 'devise/schema'
autoload :TestHelpers, 'devise/test_helpers'
@ -35,6 +36,7 @@ module Devise
CONTROLLERS = ActiveSupport::OrderedHash.new
ROUTES = ActiveSupport::OrderedHash.new
STRATEGIES = ActiveSupport::OrderedHash.new
URL_HELPERS = ActiveSupport::OrderedHash.new
# True values used to check params
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
@ -191,7 +193,9 @@ module Devise
def self.oauth(provider, *args)
@@oauth_providers << provider
@@oauth_providers.uniq!
@@oauth_configs[provider] = Devise::OAuth::Config.new(*args)
Devise::Oauth::Helpers.create_action(provider)
@@oauth_configs[provider] = Devise::Oauth::Config.new(*args)
end
def self.use_default_scope=(*)
@ -226,7 +230,7 @@ module Devise
mapping
end
# Make Devise aware of an 3rd party Devise-module. For convenience.
# Make Devise aware of an 3rd party Devise-module (like invitable). For convenience.
#
# == Options:
#
@ -248,21 +252,31 @@ module Devise
ALL << module_name
options.assert_valid_keys(:strategy, :model, :controller, :route)
config = {
:strategy => STRATEGIES,
:route => ROUTES,
:controller => CONTROLLERS
}
if strategy = options[:strategy]
STRATEGIES[module_name] = (strategy == true ? module_name : strategy)
end
config.each do |key, value|
next unless options[key]
name = (options[key] == true ? module_name : options[key])
if controller = options[:controller]
CONTROLLERS[module_name] = (controller == true ? module_name : controller)
end
if value.is_a?(Hash)
value[module_name] = name
if route = options[:route]
case route
when TrueClass
key, value = module_name, []
when Symbol
key, value = route, []
when Hash
key, value = route.keys.first, route.values.flatten
else
value << name unless value.include?(name)
raise ArgumentError, ":route should be true, a Symbol or a Hash"
end
URL_HELPERS[key] ||= []
URL_HELPERS[key].concat(value)
URL_HELPERS[key].uniq!
ROUTES[module_name] = key
end
if options[:model]

View file

@ -40,13 +40,15 @@ module Devise
#
# Examples:
#
# sign_in :user, @user # sign_in(scope, resource)
# sign_in @user # sign_in(resource)
# sign_in :user, @user # sign_in(scope, resource)
# sign_in @user # sign_in(resource)
# sign_in @user, :event => :authentication # sign_in(resource, options)
#
def sign_in(resource_or_scope, resource=nil)
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource ||= resource_or_scope
warden.set_user(resource, :scope => scope)
def sign_in(resource_or_scope, *args)
options = args.extract_options!
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource = args.last || resource_or_scope
warden.set_user(resource, options.merge!(:scope => scope))
end
# Sign out a given user or scope. This helper is useful for signing out an user
@ -159,14 +161,17 @@ module Devise
end
# Sign in an user and tries to redirect first to the stored location and
# then to the url specified by after_sign_in_path_for.
#
# If just a symbol is given, consider that the user was already signed in
# through other means and just perform the redirection.
def sign_in_and_redirect(resource_or_scope, resource=nil)
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource ||= resource_or_scope
sign_in(scope, resource) unless warden.user(scope) == resource
# then to the url specified by after_sign_in_path_for. It accepts the same
# parameters as the sign_in method.
def sign_in_and_redirect(resource_or_scope, *args)
options = args.extract_options!
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource = args.last || resource_or_scope
sign_in(scope, resource, options) unless warden.user(scope) == resource
redirect_for_sign_in(scope, resource)
end
def redirect_for_sign_in(scope, resource) #:nodoc:
redirect_to stored_location_for(scope) || after_sign_in_path_for(resource)
end
@ -179,6 +184,10 @@ module Devise
else
sign_out(scope)
end
redirect_for_sign_out(scope)
end
def redirect_for_sign_out(scope) #:nodoc:
redirect_to after_sign_out_path_for(scope)
end

View file

@ -10,7 +10,7 @@ module Devise
included do
helper DeviseHelper
helpers = %w(resource scope_name resource_name
helpers = %w(resource scope_name resource_name signed_in_resource
resource_class devise_mapping devise_controller?)
hide_action *helpers
helper_method *helpers
@ -35,6 +35,11 @@ module Devise
devise_mapping.to
end
# Returns a signed in resource from session (if one exists)
def signed_in_resource
warden.authenticate(:scope => resource_name)
end
# Attempt to find the mapped route for devise based on request path
def devise_mapping
@devise_mapping ||= request.env["devise.mapping"]

View file

@ -17,17 +17,15 @@ module Devise
# Render a view for the specified scope. Turned off by default.
# Accepts just :controller as option.
def render_with_scope(action, options={})
controller_name = options.delete(:controller) || self.controller_name
def render_with_scope(action, path=self.controller_path)
if self.class.scoped_views?
begin
render :template => "#{devise_mapping.plural}/#{controller_name}/#{action}"
render :template => "#{devise_mapping.plural}/#{path.split("/").last}/#{action}"
rescue ActionView::MissingTemplate
render :template => "#{controller_path}/#{action}"
render :template => "#{path}/#{action}"
end
else
render :template => "#{controller_path}/#{action}"
render :template => "#{path}/#{action}"
end
end
end

View file

@ -19,13 +19,11 @@ module Devise
# Those helpers are added to your ApplicationController.
module UrlHelpers
Devise::ROUTES.values.uniq.each do |module_name|
Devise::URL_HELPERS.each do |module_name, actions|
[:path, :url].each do |path_or_url|
actions = [ nil, :new_ ]
actions << :edit_ if [:password, :registration].include?(module_name)
actions << :destroy_ if [:session].include?(module_name)
actions.each do |action|
action = action ? "#{action}_" : ""
class_eval <<-URL_HELPERS, __FILE__, __LINE__ + 1
def #{action}#{module_name}_#{path_or_url}(resource_or_scope, *args)
scope = Devise::Mapping.find_scope!(resource_or_scope)

View file

@ -4,6 +4,10 @@ module Devise
extend ActiveSupport::Concern
module ClassMethods
def oauth_configs
Devise.oauth_configs.slice(*oauth_providers)
end
Devise::Models.config(self, :oauth_providers)
end
end

View file

@ -2,23 +2,26 @@ require 'active_support/core_ext/object/with_options'
Devise.with_options :model => true do |d|
# Strategies first
d.with_options :strategy => true do |s|
s.add_module :database_authenticatable, :controller => :sessions, :route => :session
s.add_module :token_authenticatable, :controller => :sessions, :route => :session
d.with_options :strategy => true do |s|
routes = [nil, :new, :destroy]
s.add_module :database_authenticatable, :controller => :sessions, :route => { :session => routes }
s.add_module :token_authenticatable, :controller => :sessions, :route => { :session => routes }
s.add_module :rememberable
end
# Other authentications
d.add_module :oauthable, :controller => :oauth_callbacks, :route => :oauth_callback
d.add_module :oauthable, :controller => :oauth_callbacks, :route => :oauth_callback
# Misc after
d.add_module :recoverable, :controller => :passwords, :route => :password
d.add_module :registerable, :controller => :registrations, :route => :registration
routes = [nil, :new, :edit]
d.add_module :recoverable, :controller => :passwords, :route => { :password => routes }
d.add_module :registerable, :controller => :registrations, :route => { :registration => routes }
d.add_module :validatable
# The ones which can sign out after
d.add_module :confirmable, :controller => :confirmations, :route => :confirmation
d.add_module :lockable, :controller => :unlocks, :route => :unlock
routes = [nil, :new]
d.add_module :confirmable, :controller => :confirmations, :route => { :confirmation => routes }
d.add_module :lockable, :controller => :unlocks, :route => { :unlock => routes }
d.add_module :timeoutable
# Stats for last, so we make sure the user is really signed in

14
lib/devise/oauth.rb Normal file
View file

@ -0,0 +1,14 @@
begin
require "oauth2"
rescue LoadError => e
warn "Could not load 'oauth2'. Please ensure you have the gem installed and listed in your Gemfile."
raise
end
module Devise
module Oauth
autoload :Config, "devise/oauth/config"
autoload :Helpers, "devise/oauth/helpers"
autoload :UrlHelpers, "devise/oauth/url_helpers"
end
end

View file

@ -0,0 +1,12 @@
module Devise
module Oauth
class Config
attr_reader :scope, :client
def initialize(app_id, app_secret, options)
@scope = Array.wrap(options.delete(:scope)).join(",")
@client = OAuth2::Client.new(app_id, app_secret, options)
end
end
end
end

View file

@ -0,0 +1,69 @@
module Devise
module Oauth
module Helpers
extend ActiveSupport::Concern
def self.create_action(name)
alias_method(name, :callback_action)
public name
end
included do
helpers = %w(oauth_callback oauth_config oauth_client)
hide_action *helpers
helper_method *helpers
before_filter :is_oauth_callback?
end
def oauth_callback
@oauth_callback ||= action_name.to_sym
end
def oauth_config
@oauth_client ||= resource_class.oauth_configs[oauth_callback]
end
def oauth_client
@oauth_client ||= oauth_config.client
end
protected
def is_oauth_callback?
raise ActionController::UnknownAction unless oauth_config
raise ActionController::UnknownAction unless params[:code]
end
def oauth_model_callback
"authentication_for_#{oauth_callback}_oauth"
end
def callback_action
access_token = oauth_client.web_server.get_access_token(params[:code])
self.resource = User.send(oauth_model_callback, access_token, signed_in_resource)
if resource.persisted?
sign_in_and_redirect resource_name, resource, :event => :authentication
else
render_for_oauth
end
end
def render_for_oauth
render_with_scope oauth_callback
rescue ActionView::MissingTemplate
render_with_scope :new, devise_mapping.controllers[:registrations]
end
# The default hook used by oauth to specify the redirect url.
def after_oauth_sign_in_path_for(resource_or_scope)
after_sign_in_path_for(resource_or_scope)
end
# Overwrite redirect_for_sign_in so it takes uses after_oauth_sign_in_path_for.
def redirect_for_sign_in(scope, resource) #:nodoc:
redirect_to stored_location_for(scope) || after_oauth_sign_in_path_for(resource)
end
end
end
end

View file

@ -0,0 +1,7 @@
module Devise
module Oauth
module UrlHelpers
end
end
end

View file

@ -1,10 +1,6 @@
require 'devise/rails/routes'
require 'devise/rails/warden_compat'
# Include UrlHelpers in ActionController and ActionView as soon as they are loaded.
ActiveSupport.on_load(:action_controller) { include Devise::Controllers::UrlHelpers }
ActiveSupport.on_load(:action_view) { include Devise::Controllers::UrlHelpers }
module Devise
class Engine < ::Rails::Engine
config.devise = Devise
@ -30,6 +26,11 @@ module Devise
app.config.filter_parameters.uniq
end
initializer "devise.url_helpers" do
ActiveSupport.on_load(:action_controller) { include Devise::Controllers::UrlHelpers }
ActiveSupport.on_load(:action_view) { include Devise::Controllers::UrlHelpers }
end
unless Rails.env.production?
config.after_initialize do
actions = [:confirmation_instructions, :reset_password_instructions, :unlock_instructions]

View file

@ -123,6 +123,16 @@ Devise.setup do |config|
# should add them to the navigational formats lists. Default is [:html]
# config.navigational_formats = [:html, :iphone]
# ==> OAuth
config.oauth :github, 'APP_ID', 'APP_SECRET',
:site => 'https://github.com/',
:authorize_path => '/login/oauth/authorize',
:access_token_path => '/login/oauth/access_token',
:scope => 'user,public_repo'
config.oauth :twitter, 'APP_ID', 'APP_SECRET',
:site => 'http://twitter.com/'
# ==> Warden configuration
# If you want to use other strategies, that are not (yet) supported by Devise,
# you can configure them inside the config.warden block. The example below

View file

@ -16,6 +16,8 @@ Webrat.configure do |config|
config.open_error_files = false
end
Faraday.default_adapter = :test
# Add support to load paths so we can overwrite broken webrat setup
$:.unshift File.expand_path('../support', __FILE__)
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }