1
0
Fork 0
mirror of https://github.com/omniauth/omniauth.git synced 2022-11-09 12:31:49 -05:00
omniauth--omniauth/spec/omniauth/strategy_spec.rb

442 lines
16 KiB
Ruby

require File.expand_path('../../spec_helper', __FILE__)
class ExampleStrategy
include OmniAuth::Strategy
option :name, 'test'
def call(env); self.call!(env) end
attr_reader :last_env
def request_phase
@fail = fail!(options[:failure]) if options[:failure]
@last_env = env
return @fail if @fail
raise "Request Phase"
end
def callback_phase
@fail = fail!(options[:failure]) if options[:failure]
@last_env = env
return @fail if @fail
raise "Callback Phase"
end
end
def make_env(path = '/auth/test', props = {})
{
'REQUEST_METHOD' => 'GET',
'PATH_INFO' => path,
'rack.session' => {},
'rack.input' => StringIO.new('test=true')
}.merge(props)
end
describe OmniAuth::Strategy do
let(:app){ lambda{|env| [404, {}, ['Awesome']]}}
describe '.default_options' do
it 'should be inherited from a parent class' do
superklass = Class.new
superklass.send :include, OmniAuth::Strategy
superklass.configure do |c|
c.foo = 'bar'
end
klass = Class.new(superklass)
klass.default_options.foo.should == 'bar'
end
end
describe '.configure' do
subject { klass = Class.new; klass.send :include, OmniAuth::Strategy; klass }
it 'should take a block and allow for default options setting' do
subject.configure do |c|
c.wakka = 'doo'
end
subject.default_options.should == {"wakka" => "doo"}
end
it 'should take a hash and deep merge it' do
subject.configure :abc => {:def => 123}
subject.configure :abc => {:hgi => 456}
subject.default_options.should == {'abc' => {'def' => 123, 'hgi' => 456}}
end
end
describe '.option' do
subject { klass = Class.new; klass.send :include, OmniAuth::Strategy; klass }
it 'should set a default value' do
subject.option :abc, 123
subject.default_options.abc.should == 123
end
it 'should set the default value to nil if none is provided' do
subject.option :abc
subject.default_options.abc.should be_nil
end
end
describe '#initialize' do
context 'options extraction' do
it 'should be the last argument if the last argument is a Hash' do
ExampleStrategy.new(app, :abc => 123).options[:abc].should == 123
end
it 'should be the default options if any are provided' do
ExampleStrategy.stub!(:default_options).and_return(OmniAuth::Strategy::Options.new(:abc => 123))
ExampleStrategy.new(app).options.abc.should == 123
end
end
end
describe '#full_host' do
let(:strategy){ ExampleStrategy.new(app, {}) }
it 'should not freak out if there is a pipe in the URL' do
strategy.call!(make_env('/whatever', 'rack.url_scheme' => 'http', 'SERVER_NAME' => 'facebook.lame', 'QUERY_STRING' => 'code=asofibasf|asoidnasd', 'SCRIPT_NAME' => '', 'SERVER_PORT' => 80))
lambda{ strategy.full_host }.should_not raise_error
end
end
describe '#call' do
let(:strategy){ ExampleStrategy.new(app, @options || {}) }
context 'omniauth.origin' do
it 'should be set on the request phase' do
lambda{ strategy.call(make_env('/auth/test', 'HTTP_REFERER' => 'http://example.com/origin')) }.should raise_error("Request Phase")
strategy.last_env['rack.session']['omniauth.origin'].should == 'http://example.com/origin'
end
it 'should be turned into an env variable on the callback phase' do
lambda{ strategy.call(make_env('/auth/test/callback', 'rack.session' => {'omniauth.origin' => 'http://example.com/origin'})) }.should raise_error("Callback Phase")
strategy.last_env['omniauth.origin'].should == 'http://example.com/origin'
end
it 'should set from the params if provided' do
lambda{ strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'origin=/foo')) }.should raise_error('Request Phase')
strategy.last_env['rack.session']['omniauth.origin'].should == '/foo'
end
it 'should be set on the failure env' do
OmniAuth.config.should_receive(:on_failure).and_return(lambda{|env| env})
@options = {:failure => :forced_fail}
strategy.call(make_env('/auth/test/callback', 'rack.session' => {'omniauth.origin' => '/awesome'}))
end
context "with script_name" do
it 'should be set on the request phase, containing full path' do
env = {'HTTP_REFERER' => 'http://example.com/sub_uri/origin', 'SCRIPT_NAME' => '/sub_uri' }
lambda{ strategy.call(make_env('/auth/test', env)) }.should raise_error("Request Phase")
strategy.last_env['rack.session']['omniauth.origin'].should == 'http://example.com/sub_uri/origin'
end
it 'should be turned into an env variable on the callback phase, containing full path' do
env = {
'rack.session' => {'omniauth.origin' => 'http://example.com/sub_uri/origin'},
'SCRIPT_NAME' => '/sub_uri'
}
lambda{ strategy.call(make_env('/auth/test/callback', env)) }.should raise_error("Callback Phase")
strategy.last_env['omniauth.origin'].should == 'http://example.com/sub_uri/origin'
end
end
end
context 'default paths' do
it 'should use the default request path' do
lambda{ strategy.call(make_env) }.should raise_error("Request Phase")
end
it 'should be case insensitive on request path' do
lambda{ strategy.call(make_env('/AUTH/Test'))}.should raise_error("Request Phase")
end
it 'should be case insensitive on callback path' do
lambda{ strategy.call(make_env('/AUTH/TeSt/CaLlBAck'))}.should raise_error("Callback Phase")
end
it 'should use the default callback path' do
lambda{ strategy.call(make_env('/auth/test/callback')) }.should raise_error("Callback Phase")
end
it 'should strip trailing spaces on request' do
lambda{ strategy.call(make_env('/auth/test/')) }.should raise_error("Request Phase")
end
it 'should strip trailing spaces on callback' do
lambda{ strategy.call(make_env('/auth/test/callback/')) }.should raise_error("Callback Phase")
end
context 'callback_url' do
it 'uses the default callback_path' do
strategy.should_receive(:full_host).and_return('http://example.com')
lambda{ strategy.call(make_env) }.should raise_error("Request Phase")
strategy.callback_url.should == 'http://example.com/auth/test/callback'
end
it 'preserves the query parameters' do
strategy.stub(:full_host).and_return('http://example.com')
begin
strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'id=5'))
rescue RuntimeError; end
strategy.callback_url.should == 'http://example.com/auth/test/callback?id=5'
end
it 'consider script name' do
strategy.stub(:full_host).and_return('http://example.com')
begin
strategy.call(make_env('/auth/test', 'SCRIPT_NAME' => '/sub_uri'))
rescue RuntimeError; end
strategy.callback_url.should == 'http://example.com/sub_uri/auth/test/callback'
end
end
end
context 'pre-request call through' do
subject { ExampleStrategy.new(app) }
let(:app){ lambda{|env| env['omniauth.boom'] = true; [env['test.status'] || 404, {}, ['Whatev']] } }
it 'should be able to modify the env on the fly before the request_phase' do
lambda{ subject.call(make_env) }.should raise_error("Request Phase")
subject.response.status.should == 404
subject.last_env.should be_key('omniauth.boom')
end
it 'should call through to the app instead if a non-404 response is received' do
lambda{ subject.call(make_env('/auth/test', 'test.status' => 200)) }.should_not raise_error
subject.response.body.should == ['Whatev']
end
end
context 'custom paths' do
it 'should use a custom request_path if one is provided' do
@options = {:request_path => '/awesome'}
lambda{ strategy.call(make_env('/awesome')) }.should raise_error("Request Phase")
end
it 'should use a custom callback_path if one is provided' do
@options = {:callback_path => '/radical'}
lambda{ strategy.call(make_env('/radical')) }.should raise_error("Callback Phase")
end
context 'callback_url' do
it 'uses a custom callback_path if one is provided' do
@options = {:callback_path => '/radical'}
strategy.should_receive(:full_host).and_return('http://example.com')
lambda{ strategy.call(make_env('/radical')) }.should raise_error("Callback Phase")
strategy.callback_url.should == 'http://example.com/radical'
end
it 'preserves the query parameters' do
@options = {:callback_path => '/radical'}
strategy.stub(:full_host).and_return('http://example.com')
begin
strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'id=5'))
rescue RuntimeError; end
strategy.callback_url.should == 'http://example.com/radical?id=5'
end
end
end
context 'custom prefix' do
before do
@options = {:path_prefix => '/wowzers'}
end
it 'should use a custom prefix for request' do
lambda{ strategy.call(make_env('/wowzers/test')) }.should raise_error("Request Phase")
end
it 'should use a custom prefix for callback' do
lambda{ strategy.call(make_env('/wowzers/test/callback')) }.should raise_error("Callback Phase")
end
context 'callback_url' do
it 'uses a custom prefix' do
strategy.should_receive(:full_host).and_return('http://example.com')
lambda{ strategy.call(make_env('/wowzers/test')) }.should raise_error("Request Phase")
strategy.callback_url.should == 'http://example.com/wowzers/test/callback'
end
it 'preserves the query parameters' do
strategy.stub(:full_host).and_return('http://example.com')
begin
strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'id=5'))
rescue RuntimeError; end
strategy.callback_url.should == 'http://example.com/wowzers/test/callback?id=5'
end
end
end
context 'request method restriction' do
before do
OmniAuth.config.allowed_request_methods = [:post]
end
it 'should not allow a request method of the wrong type' do
lambda{ strategy.call(make_env)}.should_not raise_error
end
it 'should allow a request method of the correct type' do
lambda{ strategy.call(make_env('/auth/test', 'REQUEST_METHOD' => 'POST'))}.should raise_error("Request Phase")
end
after do
OmniAuth.config.allowed_request_methods = [:get, :post]
end
end
context 'receiving an OPTIONS request' do
shared_examples_for "an OPTIONS request" do
it 'should respond with 200' do
response[0].should == 200
end
it 'should set the Allow header properly' do
response[1]['Allow'].should == "GET, POST"
end
end
context 'to the request path' do
let(:response) { strategy.call(make_env('/auth/test', 'REQUEST_METHOD' => 'OPTIONS')) }
it_should_behave_like 'an OPTIONS request'
end
context 'to the request path' do
let(:response) { strategy.call(make_env('/auth/test/callback', 'REQUEST_METHOD' => 'OPTIONS')) }
it_should_behave_like 'an OPTIONS request'
end
context 'to some other path' do
it 'should not short-circuit the request' do
env = make_env('/other', 'REQUEST_METHOD' => 'OPTIONS')
strategy.call(env).should == app.call(env)
end
end
end
context 'test mode' do
before do
OmniAuth.config.test_mode = true
end
it 'should short circuit the request phase entirely' do
response = strategy.call(make_env)
response[0].should == 302
response[1]['Location'].should == '/auth/test/callback'
end
it 'should be case insensitive on request path' do
strategy.call(make_env('/AUTH/Test'))[0].should == 302
end
it 'should respect SCRIPT_NAME (a.k.a. BaseURI)' do
response = strategy.call(make_env('/auth/test', 'SCRIPT_NAME' => '/sub_uri'))
response[1]['Location'].should == '/sub_uri/auth/test/callback'
end
it 'should be case insensitive on callback path' do
strategy.call(make_env('/AUTH/TeSt/CaLlBAck')).should == strategy.call(make_env('/auth/test/callback'))
end
it 'should maintain query string parameters' do
response = strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'cheese=stilton'))
response[1]['Location'].should == '/auth/test/callback?cheese=stilton'
end
it 'should not short circuit requests outside of authentication' do
strategy.call(make_env('/')).should == app.call(make_env('/'))
end
it 'should respond with the default hash if none is set' do
strategy.call make_env('/auth/test/callback')
strategy.env['omniauth.auth']['uid'].should == '1234'
end
it 'should respond with a provider-specific hash if one is set' do
OmniAuth.config.mock_auth[:test] = {
'uid' => 'abc'
}
strategy.call make_env('/auth/test/callback')
strategy.env['omniauth.auth']['uid'].should == 'abc'
end
it 'should simulate login failure if mocked data is set as a symbol' do
OmniAuth.config.mock_auth[:test] = :invalid_credentials
strategy.call make_env('/auth/test/callback')
strategy.env['omniauth.error.type'].should == :invalid_credentials
end
it 'should set omniauth.origin on the request phase' do
strategy.call(make_env('/auth/test', 'HTTP_REFERER' => 'http://example.com/origin'))
strategy.env['rack.session']['omniauth.origin'].should == 'http://example.com/origin'
end
it 'should set omniauth.origin from the params if provided' do
strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'origin=/foo'))
strategy.env['rack.session']['omniauth.origin'].should == '/foo'
end
it 'should turn omniauth.origin into an env variable on the callback phase' do
OmniAuth.config.mock_auth[:test] = {}
strategy.call(make_env('/auth/test/callback', 'rack.session' => {'omniauth.origin' => 'http://example.com/origin'}))
strategy.env['omniauth.origin'].should == 'http://example.com/origin'
end
end
context 'custom full_host' do
it 'should be the string when a string is there' do
OmniAuth.config.full_host = 'my.host.com'
strategy.full_host.should == 'my.host.com'
end
it 'should run the proc with the env when it is a proc' do
OmniAuth.config.full_host = Proc.new{|env| env['HOST']}
strategy.call(make_env('/auth/test', 'HOST' => 'my.host.net'))
strategy.full_host.should == 'my.host.net'
end
end
end
context 'setup phase' do
context 'when options[:setup] = true' do
let(:strategy){ ExampleStrategy.new(app, :setup => true) }
let(:app){lambda{|env| env['omniauth.strategy'].options[:awesome] = 'sauce' if env['PATH_INFO'] == '/auth/test/setup'; [404, {}, 'Awesome'] }}
it 'should call through to /auth/:provider/setup' do
strategy.call(make_env('/auth/test'))
strategy.options[:awesome].should == 'sauce'
end
it 'should not call through on a non-omniauth endpoint' do
strategy.call(make_env('/somewhere/else'))
strategy.options[:awesome].should_not == 'sauce'
end
end
context 'when options[:setup] is an app' do
let(:setup_proc) do
Proc.new do |env|
env['omniauth.strategy'].options[:awesome] = 'sauce'
end
end
let(:strategy){ ExampleStrategy.new(app, :setup => setup_proc) }
it 'should not call the app on a non-omniauth endpoint' do
strategy.call(make_env('/somehwere/else'))
strategy.options[:awesome].should_not == 'sauce'
end
it 'should call the rack app' do
strategy.call(make_env('/auth/test'))
strategy.options[:awesome].should == 'sauce'
end
end
end
end