Basic omniauth support.

This commit is contained in:
José Valim 2010-10-14 20:04:02 +02:00
parent bca72ddf59
commit 21d5e50054
11 changed files with 215 additions and 18 deletions

View File

@ -6,6 +6,7 @@ require 'set'
module Devise
autoload :FailureApp, 'devise/failure_app'
autoload :Oauth, 'devise/oauth'
autoload :OmniAuth, 'devise/omniauth'
autoload :PathChecker, 'devise/path_checker'
autoload :Schema, 'devise/schema'
autoload :TestHelpers, 'devise/test_helpers'
@ -180,10 +181,6 @@ module Devise
mattr_accessor :sign_out_via
@@sign_out_via = :get
# Oauth providers
mattr_accessor :oauth_providers
@@oauth_providers = []
# PRIVATE CONFIGURATION
# Store scopes mappings.
@ -194,15 +191,15 @@ module Devise
mattr_reader :oauth_configs
@@oauth_configs = ActiveSupport::OrderedHash.new
# Omniauth configurations.
mattr_reader :omniauth_configs
@@omniauth_configs = ActiveSupport::OrderedHash.new
# Define a set of modules that are called when a mapping is added.
mattr_reader :helpers
@@helpers = Set.new
@@helpers << Devise::Controllers::Helpers
# Define a set of modules that are called when a provider is added.
mattr_reader :oauth_helpers
@@oauth_helpers = Set.new
# Private methods to interface with Warden.
mattr_accessor :warden_config
@@warden_config = nil
@ -214,6 +211,14 @@ module Devise
yield self
end
def self.oauth_providers
oauth_configs.keys
end
def self.omniauth_providers
omniauth_configs.keys
end
def self.cookie_domain=(value)
ActiveSupport::Deprecation.warn "Devise.cookie_domain=(value) is deprecated. "
"Please use Devise.cookie_options = { :domain => value } instead."
@ -322,19 +327,23 @@ module Devise
#
def self.oauth(provider, *args)
@@helpers << Devise::Oauth::UrlHelpers
@@oauth_helpers << Devise::Oauth::InternalHelpers
@@oauth_providers << provider
@@oauth_providers.uniq!
@@oauth_helpers.each { |h| h.define_oauth_helpers(provider) }
Devise::Oauth::InternalHelpers.define_oauth_helpers(provider)
@@oauth_configs[provider] = Devise::Oauth::Config.new(*args)
end
# Specify an omniauth provider.
#
# config.omniauth :github, APP_ID, APP_SECRET
#
def self.omniauth(provider, *args)
@@helpers << Devise::OmniAuth::UrlHelpers
@@omniauth_configs[provider] = Devise::OmniAuth::Config.new(provider, args)
end
# Include helpers in the given scope to AC and AV.
def self.include_helpers(scope)
ActiveSupport.on_load(:action_controller) do
include scope::Helpers
include scope::Helpers if defined?(scope::Helpers)
include scope::UrlHelpers
end

View File

@ -222,6 +222,7 @@ module Devise
# A hook called to expire session data after sign up/in. This is used
# by a few extensions, like oauth, to expire tokens stored in session.
def expire_session_data_after_sign_in!
session.keys.grep(/^devise\./).each { |k| session.delete(k) }
end
end
end

View File

@ -84,7 +84,7 @@ module Devise
end
def fullpath
"#{@path_prefix}/#{@path}".squeeze("/")
"/#{@path_prefix}/#{@path}".squeeze("/")
end
# Create magic predicates for verifying what module is activated by this map.

View File

@ -0,0 +1,26 @@
require 'devise/omniauth'
module Devise
module Models
# Adds OAuth support to your model. The whole workflow is deeply discussed in the
# README. This module adds just a class +oauth_access_token+ helper to your model
# which assists you on creating an access token. All the other OAuth hooks in
# Devise must be implemented by yourself in your application.
#
# == Options
#
# Oauthable adds the following options to devise_for:
#
# * +oauth_providers+: Which providers are avaialble to this model. It expects an array:
#
# devise_for :database_authenticatable, :oauthable, :oauth_providers => [:twitter]
#
module Omniauthable
extend ActiveSupport::Concern
module ClassMethods
Devise::Models.config(self, :omniauth_providers)
end
end
end
end

View File

@ -11,7 +11,8 @@ Devise.with_options :model => true do |d|
# Other authentications
d.add_module :encryptable
d.add_module :oauthable, :controller => :oauth_callbacks, :route => :oauth_callback
d.add_module :oauthable, :controller => :oauth_callbacks, :route => :oauth_callback
d.add_module :omniauthable, :controller => :omniauth_callbacks, :route => :omniauth_callback
# Misc after
routes = [nil, :new, :edit]

55
lib/devise/omniauth.rb Normal file
View File

@ -0,0 +1,55 @@
begin
require "omniauth/core"
rescue LoadError => e
warn "Could not load 'omniauth/core'. Please ensure you have the oa-core gem installed and listed in your Gemfile."
raise
end
module OmniAuth
module Strategy
# TODO HAX Backport to OmniAuth
def initialize(app, name, *args)
@app = app
@name = name.to_sym
yield self if block_given?
end
end
end
module Devise
module OmniAuth
autoload :Config, "devise/omniauth/config"
autoload :UrlHelpers, "devise/omniauth/url_helpers"
autoload :TestHelpers, "devise/omniauth/test_helpers"
class << self
delegate :short_circuit_authorizers!, :unshort_circuit_authorizers!, :to => "Devise::OmniAuth::TestHelpers"
def test_mode!
Faraday.default_adapter = :test if defined?(Faraday)
ActiveSupport.on_load(:action_controller) { include Devise::OmniAuth::TestHelpers }
ActiveSupport.on_load(:action_view) { include Devise::OmniAuth::TestHelpers }
end
def stub!(provider, stubs=nil, &block)
raise "You either need to pass stubs as a block or as a parameter" unless block_given? || stubs
config = Devise.omniauth_configs[provider]
config.check_if_allow_stubs!
stubs ||= Faraday::Adapter::Test::Stubs.new(&block)
config.build_connection do |b|
b.adapter :test, stubs
end
end
def reset_stubs!(*providers)
target = providers.any? ? Devise.omniauth_configs.slice(*providers) : Devise.omniauth_configs
target.each_value do |config|
next unless config.allow_stubs?
config.build_connection { |b| b.adapter Faraday.default_adapter }
end
end
end
end
end

View File

@ -0,0 +1,30 @@
module Devise
module OmniAuth
class Config
attr_accessor :strategy
attr_reader :args
def initialize(provider, args)
@provider = provider
@args = args
@strategy = nil
end
def strategy_class
::OmniAuth::Strategies.const_get("#{::OmniAuth::Utils.camelize(@provider.to_s)}")
end
def check_if_allow_stubs!
raise "#{@provider} OmniAuth strategy does not allow stubs, only OAuth2 ones." unless allow_stubs?
end
def allow_stubs?
!(defined?(OmniAuth::Strategies::OAuth2) && strategy.is_a?(OmniAuth::Strategies::OAuth2))
end
def build_connection(&block)
strategy.client.connection.build(&block)
end
end
end
end

View File

@ -0,0 +1,29 @@
module Devise
module OmniAuth
module TestHelpers #:nodoc:
def self.short_circuit_authorizers!
module_eval <<-ALIASES, __FILE__, __LINE__ + 1
def omniauth_authorize_path(*args)
omniauth_callback_path(*args)
end
ALIASES
Devise.mappings.each_value do |m|
next unless m.omniauthable?
module_eval <<-ALIASES, __FILE__, __LINE__ + 1
def #{m.name}_omniauth_authorize_path(provider)
#{m.name}_omniauth_callback_path(provider)
end
ALIASES
end
end
def self.unshort_circuit_authorizers!
module_eval do
instance_methods.each { |m| remove_method(m) }
end
end
end
end
end

View File

@ -0,0 +1,29 @@
module Devise
module OmniAuth
module UrlHelpers
def self.define_helpers(mapping)
return unless mapping.omniauthable?
class_eval <<-URL_HELPERS, __FILE__, __LINE__ + 1
def #{mapping.name}_omniauth_authorize_path(provider)
if Devise.omniauth_configs[provider.to_sym]
"#{mapping.fullpath}/auth/\#{provider}"
else
raise ArgumentError, "Could not find omniauth provider \#{provider.inspect}"
end
end
URL_HELPERS
end
def omniauth_authorize_path(resource_or_scope, *args)
scope = Devise::Mapping.find_scope!(resource_or_scope)
send("#{scope}_omniauth_authorize_path", *args)
end
def omniauth_callback_url(resource_or_scope, *args)
scope = Devise::Mapping.find_scope!(resource_or_scope)
send("#{scope}_omniauth_callback_path", *args)
end
end
end
end

View File

@ -29,11 +29,23 @@ module Devise
end
initializer "devise.oauth_url_helpers" do
if Devise.oauth_providers.any?
if Devise.oauth_configs.any?
Devise.include_helpers(Devise::Oauth)
end
end
initializer "devise.omniauth" do |app|
Devise.omniauth_configs.each do |provider, config|
app.middleware.use config.strategy_class, *config.args do |strategy|
config.strategy = strategy
end
end
if Devise.omniauth_configs.any?
Devise.include_helpers(Devise::OmniAuth)
end
end
initializer "devise.encryptor_check" do
case Devise.encryptor
when :bcrypt

View File

@ -243,6 +243,11 @@ module ActionDispatch::Routing
:to => controllers[:oauth_callbacks], :as => :oauth_callback
end
def devise_omniauth_callback(mapping, controllers) #:nodoc:
get "/auth/:action/callback", :action => Regexp.union(mapping.to.omniauth_providers.map(&:to_s)),
:to => controllers[:omniauth_callbacks], :as => :omniauth_callback
end
def with_devise_exclusive_scope(new_path, new_as) #:nodoc:
old_as, old_path, old_module = @scope[:as], @scope[:path], @scope[:module]
@scope[:as], @scope[:path], @scope[:module] = new_as, new_path, nil