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
50 changes: 34 additions & 16 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,48 @@ By using WardenOmniAuth, you can make use of any of the OmniAuth authentication
This is also usable in the [Devise](http://github.com/plataformatec/devise) Rails Engine
## Usage (Rack)

<pre><code>use OmniAuth::Builer do
```ruby
use OmniAuth::Builer do
# setup omniauth
end

OmniAuth.config.on_failure = Proc.new do |env|
OmniAuth::FailureEndpoint.new(env).redirect_to_failure
end

use Warden::Manager do |config|
# setup warden configuration
# setup warden configuration, e.g.:
config.failure_app = lambda do |env|
# This is also the failure app for any OmniAuth failures
Rack::Response.new({:errors => env['warden'].errors.full_messages}.to_json, 401).finish
end
e
end

use WardenOmniAuth do |config|
config.redirect\_after\_callback = "/redirect/path" # default "/"
config.redirect_after_callback { |env| env['omniauth.origin'] || "/redirect/path" }
# or: config.redirect_after_callback = "/redirect/path"
end

WardenOmniAuth.on_callback do |omni_user, strategy|
# return a user object, e.g.:
User.authenticate!(strategy, omni_user['uid'])
end

run MyApp
</code></pre>
```

## Usage (Devise)

<pre><code># config/initializer.rb
```ruby
# config/initializer.rb
Devise.setup do |config|
config.warden do |manager|
[:omni\_twitter, :omni\_facebook, :omni\_github].each do |strategy|
manager.default\_strategies(:scope => :user).unshift strategy
[:omni_twitter, :omni_facebook, :omni_github].each do |strategy|
manager.default_strategies(:scope => :user).unshift strategy
end
end
</code></pre>
```

This will add the stratgeies to the normal devise user login for github, then facebook, then twitter.

Expand All @@ -47,27 +64,28 @@ By default, it grabs just _user\\info_, _uid_, _credentials_, _provider_ as a ha

If you want to customise this you can do:

<pre><code>
WardenOmniAuth.on\_callback do |user|
# all callbacks will go here by default
```ruby
WardenOmniAuth.on_callback do |user,strategy|
# all callbacks will go here by default;
# strategy is something like 'twitter', 'facebook', etc
end
</code></pre>
```

Whatever you return from the block is the user that's made available in warden.

## Dealing with each kind of callback

<pre><code>
```ruby
use WardenOmniAuth do |config|
Warden::Strategies[:omni\_twitter].on_callback do |user|
Warden::Strategies[:omni_twitter].on_callback do |user,strategy|
# do stuff to get a user and return it from the block
end

Warden::Strategies[:omni\_facebook].on_callback do |user|
Warden::Strategies[:omni_facebook].on_callback do |user,strategy|
# do stuff to get a user for a facebook user
end
end
</code></pre>
```

This will use a specific callback to get the user, or fallback if nothing specific has been defined.

Expand Down
74 changes: 30 additions & 44 deletions lib/warden_omniauth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require 'omniauth'

class WardenOmniAuth
DEFAULT_CALLBACK = lambda do |user|
DEFAULT_CALLBACK = lambda do |user, strategy|
u = {}
u[:info] = user['info']
u[:uid] = user['uid']
Expand Down Expand Up @@ -30,7 +30,7 @@ def self.on_callback(&blk)
# @example
# WardenOmniAuth.setup_strategies(:twitter, :facebook)
def self.setup_strategies(*names)
names.map do |name|
names.each do |name|
full_name = :"omni_#{name}"
unless Warden::Strategies[full_name]
klass = Class.new(WardenOmniAuth::Strategy)
Expand All @@ -44,20 +44,15 @@ def self.setup_strategies(*names)
# The base omniauth warden strategy. This is inherited for each
# omniauth strategy
class Strategy < Warden::Strategies::Base
# make a specific callback for this strategy
def self.on_callback(&blk)
@on_callback = blk if blk
@on_callback || WardenOmniAuth.on_callback
end

# The name of the OmniAuth strategy to map to
def self.omni_name=(name)
@omni_name = name
end

# The name of the OmniAuth strategy to map to
def self.omni_name
@omni_name
class << self
# The name of the OmniAuth strategy to map to
attr_accessor :omni_name

# make a specific callback for this strategy
def on_callback(&blk)
@on_callback = blk if blk
@on_callback || WardenOmniAuth.on_callback
end
end

def authenticate!
Expand All @@ -66,51 +61,38 @@ def authenticate!

# set the user if one exists
# otherwise, redirect for authentication
if user = (env['omniauth.auth'] || env['rack.auth'] || request['auth']) # TODO: Fix.. Completely insecure... do not use this will look in params for the auth. Apparently fixed in the new gem

success! self.class.on_callback[user]
if user = env['omniauth.auth']
success! self.class.on_callback[user, self.class.omni_name]
else
path_prefix = OmniAuth::Configuration.instance.path_prefix
redirect! File.join(path_prefix, self.class.omni_name)
# Pass in the request URI as the 'origin' param, so that
# OmniAuth later provides it under env['omniauth.origin']
redirect! File.join(path_prefix, self.class.omni_name), { 'origin' => env['REQUEST_URI'] }
end
end
end

# Pulled from extlib
# Convert to snake case.
#
# "FooBar".snake_case #=> "foo_bar"
# "HeadlineCNNNews".snake_case #=> "headline_cnn_news"
# "CNN".snake_case #=> "cnn"
#
# @return [String] Receiver converted to snake case.
#
# @api public
def self.snake_case(string)
return string.downcase if string.match(/\A[A-Z]+\z/)
string.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
gsub(/([a-z])([A-Z])/, '\1_\2').
downcase
end

def initialize(app)
# setup the warden strategies to wrap the omniauth ones
names = OmniAuth::Strategies.constants.map do |konstant|
name = WardenOmniAuth.snake_case(konstant.to_s)
# Create a fake instance of the OmniAuth strategy to be able
# to use the #name method instead of guessing based on the
# class name.
s = OmniAuth::Strategies.const_get(konstant).new(nil)
s.name
end
WardenOmniAuth.setup_strategies(*names)
yield self if block_given?
@app = app
end

# redirect after a callback
def redirect_after_callback=(path)
@redirect_after_callback_path = path
@redirect_after_callback = lambda { |env| path }
end


def redirect_after_callback_path
@redirect_after_callback_path ||= "/"
# redirect after a callback
def redirect_after_callback(&block)
@redirect_after_callback = block
end

def call(env)
Expand All @@ -132,7 +114,7 @@ def call(env)
args << {:scope => scope.to_sym} if scope
response = Rack::Response.new
if env['warden'].authenticate? *args
response.redirect(redirect_after_callback_path)
response.redirect(@redirect_after_callback.call(env).to_s)
response.finish
else
auth_path = request.path.gsub(/\/callback$/, "")
Expand All @@ -143,6 +125,10 @@ def call(env)
Rack::Response.new("Bad Session", 400).finish
end
end
elsif request.path =~ /^#{prefix}\/failure$/i
# query params: message, strategy, origin
env['warden'].errors.add(:login, request.params['message'])
throw :warden
else
@app.call(env)
end
Expand Down
13 changes: 10 additions & 3 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@
user
end


module MyHelpers
def app
@app || create_app{|e| Rack::Response.new("OK").finish }
end

def create_app(&blk)
failure = lambda{|e| Rack::Response.new("Can't login", 401).finish }
failure = lambda do |env|
errors = env['warden'].errors.full_messages
if errors.count > 0
Rack::Response.new("Can't login: #{errors.join(',')}", 401).finish
else
Rack::Response.new("Can't login", 401).finish
end
end
builder = Rack::Builder.new do
use Warden::Manager do |config|
config.failure_app = failure
Expand All @@ -33,7 +39,8 @@ def create_app(&blk)

use WardenOmniAuth do |config|
$omni_auth = config
config.redirect_after_callback = "/redirect/path"
$expected_redirect = "/redirect/path"
config.redirect_after_callback = $expected_redirect
end
run blk
end.to_app
Expand Down
Loading