Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,18 @@ oauth services you would like to have on the <tt>Warden::Manager</tt> middleware
config.oauth(:twitter) do |twitter|
twitter.consumer_secret = <YOUR CONSUMER SECRET>
twitter.consumer_key = <YOUR CONSUMER KEY>
twitter.options :site => 'http://twitter.com'
twitter.options({
:site => 'http://twitter.com',
:oauth_callback => (BASE_URL.end_with?('/') ? BASE_URL[0..-2] : BASE_URL) + '/users',
:oauth_callback_confirmed => 'true'
})
end
config.default_strategies(:twitter_oauth, :password, :other)
end

You then need to set the BASE_URL constant in your environment files so that the oauth_callback will work:

BASE_URL = "http://localhost"

== Giving an Access Token fetcher

Expand Down Expand Up @@ -61,7 +69,34 @@ Note:

In Rails, don't set the <tt>:warden_oauth_provider</tt> parameter as part of the login route, if you do this, rails will catch the parameter, but not the
warden rack middleware, ergo, it won't work as expected.
== Oauth 2.0

To use oauth 2.0 it is very similar to standard oauth. Here is my example for working with facebook


config.warden do |manager|
manager.oauth2(:facebook) do |fb|
fb.consumer_key = FACEBOOK_CONSUMER_KEY
fb.consumer_secret = FACEBOOK_CONSUMER_SECRET
fb.client_id = FACEBOOK_CLIENT_ID
fb.options({
:authorize_url => 'https://www.facebook.com/dialog/oauth',
:access_token_url => 'https://graph.facebook.com/oauth/access_token',
:site => 'https://graph.facebook.com',
:scope => 'email,offline_access',
:redirect_uri => (BASE_URL.end_with?('/') ? BASE_URL[0..-2] : BASE_URL) + '/users'
})
end
manager.default_strategies(:scope => :user).unshift :facebook_oauth
end

Note: You still need to give an Access Token fetcher

Warden::OAuth2.access_token_user_finder(:facebook) do |access_token|
end

Note: Instead of oauth the keyword oauth2 is used in both examples above

== Examples

If you want to know how to make a twitter authentication client, check examples/twitter/application.rb
Expand Down
20 changes: 20 additions & 0 deletions lib/warden_oauth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,23 @@ module OAuth

end
end

require "oauth2"

module Warden
module OAuth2

base_path = File.dirname(__FILE__) + "/warden_oauth2"

require base_path + "/base"
require base_path + "/errors"
autoload :Utils, base_path + '/utils'
autoload :StrategyBuilder, base_path + '/strategy_builder'
autoload :Strategy, base_path + '/strategy'
autoload :Config, base_path + "/config"
require base_path + "/config_extension"


end
end

5 changes: 2 additions & 3 deletions lib/warden_oauth/strategy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def valid?
def authenticate!
if params.include?('warden_oauth_provider')
store_request_token_on_session
redirect!(request_token.authorize_url)
redirect!(request_token.authorize_url(config.options))
throw(:warden)
elsif params.include?('oauth_token')
load_request_token_from_session
Expand Down Expand Up @@ -78,8 +78,7 @@ def consumer
end

def request_token
host_with_port = Warden::OAuth::Utils.host_with_port(request)
@request_token ||= consumer.get_request_token(:oauth_callback => host_with_port)
@request_token ||= consumer.get_request_token(:oauth_callback => config.options[:oauth_callback])
end

def access_token
Expand Down
13 changes: 13 additions & 0 deletions lib/warden_oauth2/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Warden
module OAuth2

def self.access_token_user_finder(key, &block)
Strategy.access_token_user_finders[key] = block
end

def self.clear_access_token_user_finders
Strategy.access_token_user_finders.clear
end

end
end
51 changes: 51 additions & 0 deletions lib/warden_oauth2/config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module Warden
module OAuth2

#
# Holds all the information of the OAuth service.
#
class Config
attr_accessor :provider_name

def consumer_key(key = nil)
unless key.nil?
@consumer_key = key
end
@consumer_key
end
alias_method :consumer_key=, :consumer_key

def consumer_secret(secret = nil)
unless secret.nil?
@consumer_secret = secret
end
@consumer_secret
end
alias_method :consumer_secret=, :consumer_secret

def client_id(client_id = nil)
unless client_id.nil?
@client_id = client_id
end
@client_id
end
alias_method :client_id=, :client_id

def options(options = nil)
unless options.nil?
@options = options
end
@options
end
alias_method :options=, :options

def check_requirements
if @consumer_key.nil? || @consumer_secret.nil? || @client_id.nil?
raise Warden::OAuth2::ConfigError.new("You need to specify the consumer key, consumer secret, and client id")
end
end

end

end
end
45 changes: 45 additions & 0 deletions lib/warden_oauth2/config_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
module Warden
module OAuth2

#
# Holds all the extensions made to Warden::Config in order to create OAuth
# consumers.
#
module ConfigExtension

#
# Helps to setup a new OAuth client authentication, to get started you need to define
# a service name, and then on the block assign the different values required in order
# to boot the OAuth process.
# @param [Symbol] service An identifier of the OAuth service
#
# @example
# use Warden::Manager do |config|
# config.oauth(:twitter) do
# consumer_key "<YOUR CONSUMER KEY>"
# consumer_secret "<YOUR CONSUMER SECRET>"
# options :site => 'http://twitter.com'
# end
# end
#
def oauth2(service, &block)
config = Warden::OAuth2::Config.new
if block_given?
if block.arity == 1
yield config
else
config.instance_eval(&block)
end
end
config.check_requirements
config.provider_name = service
Warden::OAuth2::Strategy.build(service, config)
end

end

end
end

Warden::Config.send(:include, Warden::OAuth2::ConfigExtension)

9 changes: 9 additions & 0 deletions lib/warden_oauth2/errors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Warden
module OAuth2

class ConfigError < ArgumentError; end
class ServiceAlreadyRegistered < StandardError; end
class AccessTokenFinderMissing < StandardError; end

end
end
144 changes: 144 additions & 0 deletions lib/warden_oauth2/strategy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
module Warden
module OAuth2

#
# Holds all the main logic of the OAuth authentication, all the generated
# OAuth classes will extend from this class
#
class Strategy < Warden::Strategies::Base
extend StrategyBuilder

######################
### Strategy Logic ###
######################


def self.access_token_user_finders
(@_user_token_finders ||= {})
end

#
# An OAuth strategy will be valid to execute if:
# * A 'warden_oauth_provider' parameter is given, with the name of the OAuth service
# * A 'oauth_token' is being receive on the request (response from an OAuth provider)
#
def valid?
(params.include?('warden_oauth2_provider') && params['warden_oauth2_provider'] == config.provider_name.to_s) ||
params.include?('code')
end


#
# Manages the OAuth authentication process, there can be 3 outcomes from this Strategy:
# 1. The OAuth credentials are invalid and the FailureApp is called
# 2. The OAuth credentials are valid, but there is no user associated to them. In this case
# the FailureApp is called, but the env['warden.options'][:oauth][:access_token] will be
# available.
# 3. The OAuth credentials are valid, and the user is authenticated successfuly
#
# @note
# If you want to signup users with the twitter credentials, you can manage the creation of a new
# user in the FailureApp with the given access_token
#
def authenticate!
puts "Inside OAUTH2 authenticate!****^^^^^^^^^^^^^^^^^^^"
if params.include?('warden_oauth2_provider')
#store_request_token_url_on_session
redirect!(consumer.authorize_url(:redirect_uri => config.options[:redirect_uri],:client_id => config.client_id,:scope => config.options[:scope]))
throw(:warden)
elsif params.include?('code')
#load_request_token_from_session
user = find_user_by_access_token(access_token)
if user.nil?
puts "got bad user"
fail!("User with access token not found")
throw_error_with_oauth_info
else
puts "Got success"
success!(user)
end
end
end

def fail!(msg) #:nodoc:
self.errors.add(service_param_name.to_sym, msg)
super
end

###################
### OAuth Logic ###
###################

def consumer
puts 'options - ' + config.options.inspect
@consumer ||= ::OAuth2::Client.new(config.client_id, config.consumer_secret, config.options)
end

# def request_token
# #@request_token_url ||= consumer.get_request_token(:redirect_uri => config.options[:redirect_uri],:scope => config.options[:scope])
# @request_token_url ||= consumer.authorize_url
# end
#
def access_token
puts 'access_token_url = ' + consumer.access_token_url.inspect
@access_token ||= consumer.web_server.get_access_token(params['code'],:redirect_uri => config.options[:redirect_uri])
end

protected

def find_user_by_access_token(access_token)
raise RuntimeError.new(<<-ERROR_MESSAGE) unless self.respond_to?(:_find_user_by_access_token)

You need to define a finder by access_token for this strategy.
Write on the warden initializer the following code:
Warden::OAuth2.access_token_user_finder(:#{config.provider_name}) do |access_token|
# Logic to get your user from an access_token
end

ERROR_MESSAGE
self._find_user_by_access_token(access_token)
end

def throw_error_with_oauth_info
throw(:warden, :oauth => {
self.config.provider_name => {
:provider => config.provider_name,
:access_token => access_token,
:consumer_key => config.consumer_key,
:consumer_secret => config.consumer_secret
}
})
end

# def store_request_token_on_session
# puts 'request_token - ' + request_token.inspect
# session[:request_token] = request_token.token
# session[:request_secret] = request_token.secret
# end
#
# def load_request_token_from_session
# token = session.delete(:request_token)
# secret = session.delete(:request_secret)
# @request_token = ::OAuth2::RequestToken.new(consumer, token, secret)
# end

# def missing_stored_token?
# !request_token
# end
#
# def stored_token_match_recieved_token?
# request_token.token == params['oauth_token']
# end

def service_param_name
'%s_oauth2' % config.provider_name
end

def config
self.class::CONFIG
end

end

end
end
Loading