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:
parent
6c5be8dfd5
commit
bd8294aecf
17 changed files with 207 additions and 57 deletions
1
Gemfile
1
Gemfile
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
class Devise::OauthCallbacksController < ApplicationController
|
||||
include Devise::Controllers::InternalHelpers
|
||||
|
||||
def twitter
|
||||
end
|
||||
|
||||
def github
|
||||
end
|
||||
include Devise::Oauth::Helpers
|
||||
end
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
14
lib/devise/oauth.rb
Normal 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
|
12
lib/devise/oauth/config.rb
Normal file
12
lib/devise/oauth/config.rb
Normal 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
|
69
lib/devise/oauth/helpers.rb
Normal file
69
lib/devise/oauth/helpers.rb
Normal 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
|
7
lib/devise/oauth/url_helpers.rb
Normal file
7
lib/devise/oauth/url_helpers.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
module Devise
|
||||
module Oauth
|
||||
module UrlHelpers
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
Loading…
Reference in a new issue