mirror of
https://github.com/omniauth/omniauth.git
synced 2022-11-09 12:31:49 -05:00
commit
29c8216e0d
20 changed files with 484 additions and 110 deletions
21
.github/workflows/main.yml
vendored
21
.github/workflows/main.yml
vendored
|
@ -9,9 +9,9 @@ name: Ruby
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
branches: [ master, 2_0-indev ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
branches: [ master, 2_0-indev ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
@ -54,6 +54,21 @@ jobs:
|
|||
env:
|
||||
JRUBY_OPTS: --debug
|
||||
run: bundle exec rake
|
||||
frozen-string-compat:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.6
|
||||
bundler-cache: true
|
||||
- name: Install dependencies
|
||||
run: bundle install
|
||||
- name: Run tests
|
||||
env:
|
||||
RUBYOPT: "--enable-frozen-string-literal"
|
||||
run: bundle exec rake
|
||||
coveralls:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
|
@ -61,7 +76,7 @@ jobs:
|
|||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.5
|
||||
ruby-version: 2.6
|
||||
bundler-cache: true
|
||||
- name: Install dependencies
|
||||
run: bundle install
|
||||
|
|
3
Gemfile
3
Gemfile
|
@ -19,7 +19,8 @@ group :test do
|
|||
gem 'rack', '>= 2.0.6', :platforms => %i[jruby_18 jruby_19 ruby_19 ruby_20 ruby_21]
|
||||
gem 'rack-test'
|
||||
gem 'rest-client', '~> 2.0.0', :platforms => [:jruby_18]
|
||||
gem 'rspec', '~> 3.5.0'
|
||||
gem 'rspec', '~> 3.5'
|
||||
gem 'rack-freeze'
|
||||
gem 'rubocop', '>= 0.58.2', '< 0.69.0', :platforms => %i[ruby_20 ruby_21 ruby_22 ruby_23 ruby_24]
|
||||
gem 'simplecov-lcov'
|
||||
gem 'tins', '~> 1.13', :platforms => %i[jruby_18 jruby_19 ruby_19]
|
||||
|
|
19
README.md
19
README.md
|
@ -2,9 +2,8 @@
|
|||
|
||||
[![Gem Version](http://img.shields.io/gem/v/omniauth.svg)][gem]
|
||||
[![Build Status](http://img.shields.io/travis/omniauth/omniauth.svg)][travis]
|
||||
[![Code Climate](http://img.shields.io/codeclimate/github/omniauth/omniauth.svg)][codeclimate]
|
||||
[![Code Climate](https://api.codeclimate.com/v1/badges/ffd33970723587806744/maintainability)][codeclimate]
|
||||
[![Coverage Status](http://img.shields.io/coveralls/omniauth/omniauth.svg)][coveralls]
|
||||
[![Security](https://hakiri.io/github/omniauth/omniauth/master.svg)](https://hakiri.io/github/omniauth/omniauth/master)
|
||||
|
||||
[gem]: https://rubygems.org/gems/omniauth
|
||||
[travis]: http://travis-ci.org/omniauth/omniauth
|
||||
|
@ -33,8 +32,8 @@ development and easily swap in other strategies later.
|
|||
## Getting Started
|
||||
Each OmniAuth strategy is a Rack Middleware. That means that you can use
|
||||
it the same way that you use any other Rack middleware. For example, to
|
||||
use the built-in Developer strategy in a Sinatra application I might do
|
||||
this:
|
||||
use the built-in Developer strategy in a Sinatra application you might
|
||||
do this:
|
||||
|
||||
```ruby
|
||||
require 'sinatra'
|
||||
|
@ -46,7 +45,7 @@ class MyApplication < Sinatra::Base
|
|||
end
|
||||
```
|
||||
|
||||
Because OmniAuth is built for *multi-provider* authentication, I may
|
||||
Because OmniAuth is built for *multi-provider* authentication, you may
|
||||
want to leave room to run multiple strategies. For this, the built-in
|
||||
`OmniAuth::Builder` class gives you an easy way to specify multiple
|
||||
strategies. Note that there is **no difference** between the following
|
||||
|
@ -83,14 +82,14 @@ environment of a request to `/auth/:provider/callback`. This hash
|
|||
contains as much information about the user as OmniAuth was able to
|
||||
glean from the utilized strategy. You should set up an endpoint in your
|
||||
application that matches to the callback URL and then performs whatever
|
||||
steps are necessary for your application. For example, in a Rails app I
|
||||
would add a line in my `routes.rb` file like this:
|
||||
steps are necessary for your application. For example, in a Rails app
|
||||
you would add a line in your `routes.rb` file like this:
|
||||
|
||||
```ruby
|
||||
post '/auth/:provider/callback', to: 'sessions#create'
|
||||
```
|
||||
|
||||
And I might then have a `SessionsController` with code that looks
|
||||
And you might then have a `SessionsController` with code that looks
|
||||
something like this:
|
||||
|
||||
```ruby
|
||||
|
@ -112,7 +111,7 @@ class SessionsController < ApplicationController
|
|||
end
|
||||
```
|
||||
|
||||
The `omniauth.auth` key in the environment hash gives me my
|
||||
The `omniauth.auth` key in the environment hash provides an
|
||||
Authentication Hash which will contain information about the just
|
||||
authenticated user including a unique id, the strategy they just used
|
||||
for authentication, and personal details such as name and email address
|
||||
|
@ -167,7 +166,7 @@ a `session_store.rb` initializer, add `use ActionDispatch::Session::CookieStore`
|
|||
and have sessions functioning as normal.
|
||||
|
||||
To be clear: sessions may work, but your session options will be ignored
|
||||
(i.e the session key will default to `_session_id`). Instead of the
|
||||
(i.e. the session key will default to `_session_id`). Instead of the
|
||||
initializer, you'll have to set the relevant options somewhere
|
||||
before your middleware is built (like `application.rb`) and pass them to your
|
||||
preferred middleware, like this:
|
||||
|
|
|
@ -15,6 +15,7 @@ module OmniAuth
|
|||
autoload :Form, 'omniauth/form'
|
||||
autoload :AuthHash, 'omniauth/auth_hash'
|
||||
autoload :FailureEndpoint, 'omniauth/failure_endpoint'
|
||||
autoload :AuthenticityTokenProtection, 'omniauth/authenticity_token_protection'
|
||||
|
||||
def self.strategies
|
||||
@strategies ||= []
|
||||
|
@ -29,20 +30,22 @@ module OmniAuth
|
|||
logger
|
||||
end
|
||||
|
||||
def self.defaults
|
||||
def self.defaults # rubocop:disable MethodLength
|
||||
@defaults ||= {
|
||||
:camelizations => {},
|
||||
:path_prefix => '/auth',
|
||||
:on_failure => OmniAuth::FailureEndpoint,
|
||||
:failure_raise_out_environments => ['development'],
|
||||
:request_validation_phase => OmniAuth::AuthenticityTokenProtection,
|
||||
:before_request_phase => nil,
|
||||
:before_callback_phase => nil,
|
||||
:before_options_phase => nil,
|
||||
:form_css => Form::DEFAULT_CSS,
|
||||
:test_mode => false,
|
||||
:logger => default_logger,
|
||||
:allowed_request_methods => %i[get post],
|
||||
:mock_auth => {:default => AuthHash.new('provider' => 'default', 'uid' => '1234', 'info' => {'name' => 'Example User'})}
|
||||
:allowed_request_methods => %i[post],
|
||||
:mock_auth => {:default => AuthHash.new('provider' => 'default', 'uid' => '1234', 'info' => {'name' => 'Example User'})},
|
||||
:silence_get_warning => false
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -74,6 +77,14 @@ module OmniAuth
|
|||
end
|
||||
end
|
||||
|
||||
def request_validation_phase(&block)
|
||||
if block_given?
|
||||
@request_validation_phase = block
|
||||
else
|
||||
@request_validation_phase
|
||||
end
|
||||
end
|
||||
|
||||
def before_request_phase(&block)
|
||||
if block_given?
|
||||
@before_request_phase = block
|
||||
|
@ -111,8 +122,9 @@ module OmniAuth
|
|||
camelizations[name.to_s] = camelized.to_s
|
||||
end
|
||||
|
||||
attr_writer :on_failure, :before_callback_phase, :before_options_phase, :before_request_phase
|
||||
attr_accessor :failure_raise_out_environments, :path_prefix, :allowed_request_methods, :form_css, :test_mode, :mock_auth, :full_host, :camelizations, :logger
|
||||
attr_writer :on_failure, :before_callback_phase, :before_options_phase, :before_request_phase, :request_validation_phase
|
||||
attr_accessor :failure_raise_out_environments, :path_prefix, :allowed_request_methods, :form_css,
|
||||
:test_mode, :mock_auth, :full_host, :camelizations, :logger, :silence_get_warning
|
||||
end
|
||||
|
||||
def self.config
|
||||
|
@ -159,7 +171,7 @@ module OmniAuth
|
|||
if first_letter_in_uppercase
|
||||
word.to_s.gsub(%r{/(.?)}) { '::' + Regexp.last_match[1].upcase }.gsub(/(^|_)(.)/) { Regexp.last_match[2].upcase }
|
||||
else
|
||||
word.first + camelize(word)[1..-1]
|
||||
camelize(word).tap { |w| w[0] = w[0].downcase }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
30
lib/omniauth/authenticity_token_protection.rb
Normal file
30
lib/omniauth/authenticity_token_protection.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
require 'rack-protection'
|
||||
|
||||
module OmniAuth
|
||||
class AuthenticityError < StandardError; end
|
||||
class AuthenticityTokenProtection < Rack::Protection::AuthenticityToken
|
||||
def initialize(options = {})
|
||||
@options = default_options.merge(options)
|
||||
end
|
||||
|
||||
def self.call(env)
|
||||
new.call!(env)
|
||||
end
|
||||
|
||||
def call!(env)
|
||||
return if accepts?(env)
|
||||
|
||||
instrument env
|
||||
react env
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def deny(_env)
|
||||
OmniAuth.logger.send(:warn, "Attack prevented by #{self.class}")
|
||||
raise AuthenticityError.new(options[:message])
|
||||
end
|
||||
|
||||
alias default_reaction deny
|
||||
end
|
||||
end
|
|
@ -31,7 +31,7 @@ module OmniAuth
|
|||
middleware = klass
|
||||
else
|
||||
begin
|
||||
middleware = OmniAuth::Strategies.const_get(OmniAuth::Utils.camelize(klass.to_s).to_s)
|
||||
middleware = OmniAuth::Strategies.const_get(OmniAuth::Utils.camelize(klass.to_s).to_s, false)
|
||||
rescue NameError
|
||||
raise(LoadError.new("Could not find matching strategy for #{klass.inspect}. You may need to install an additional gem (such as omniauth-#{klass})."))
|
||||
end
|
||||
|
|
|
@ -27,10 +27,19 @@ module OmniAuth
|
|||
|
||||
def redirect_to_failure
|
||||
message_key = env['omniauth.error.type']
|
||||
new_path = "#{env['SCRIPT_NAME']}#{OmniAuth.config.path_prefix}/failure?message=#{message_key}#{origin_query_param}#{strategy_name_query_param}"
|
||||
|
||||
new_path = "#{env['SCRIPT_NAME']}#{strategy_path_prefix}/failure?message=#{Rack::Utils.escape(message_key)}#{origin_query_param}#{strategy_name_query_param}"
|
||||
Rack::Response.new(['302 Moved'], 302, 'Location' => new_path).finish
|
||||
end
|
||||
|
||||
def strategy_path_prefix
|
||||
if env['omniauth.error.strategy']
|
||||
env['omniauth.error.strategy'].path_prefix
|
||||
else
|
||||
OmniAuth.config.path_prefix
|
||||
end
|
||||
end
|
||||
|
||||
def strategy_name_query_param
|
||||
return '' unless env['omniauth.error.strategy']
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ module OmniAuth
|
|||
options[:header_info] ||= ''
|
||||
self.options = options
|
||||
|
||||
@html = ''
|
||||
@html = +'' # unary + string allows it to be mutable if strings are frozen
|
||||
@with_custom_button = false
|
||||
@footer = nil
|
||||
header(options[:title], options[:header_info])
|
||||
|
|
|
@ -180,18 +180,44 @@ module OmniAuth
|
|||
raise(error)
|
||||
end
|
||||
|
||||
warn_if_using_get
|
||||
|
||||
@env = env
|
||||
@env['omniauth.strategy'] = self if on_auth_path?
|
||||
|
||||
return mock_call!(env) if OmniAuth.config.test_mode
|
||||
return options_call if on_auth_path? && options_request?
|
||||
return request_call if on_request_path? && OmniAuth.config.allowed_request_methods.include?(request.request_method.downcase.to_sym)
|
||||
return callback_call if on_callback_path?
|
||||
return other_phase if respond_to?(:other_phase)
|
||||
|
||||
begin
|
||||
return options_call if on_auth_path? && options_request?
|
||||
return request_call if on_request_path? && OmniAuth.config.allowed_request_methods.include?(request.request_method.downcase.to_sym)
|
||||
return callback_call if on_callback_path?
|
||||
return other_phase if respond_to?(:other_phase)
|
||||
rescue StandardError => e
|
||||
return fail!(e.message, e)
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
def warn_if_using_get
|
||||
return unless OmniAuth.config.allowed_request_methods.include?(:get)
|
||||
return if OmniAuth.config.silence_get_warning
|
||||
|
||||
log :warn, <<-WARN
|
||||
You are using GET as an allowed request method for OmniAuth. This may leave
|
||||
you open to CSRF attacks. As of v2.0.0, OmniAuth by default allows only POST
|
||||
to its own routes. You should review the following resources to guide your
|
||||
mitigation:
|
||||
https://github.com/omniauth/omniauth/wiki/Resolving-CVE-2015-9284
|
||||
https://github.com/omniauth/omniauth/issues/960
|
||||
https://nvd.nist.gov/vuln/detail/CVE-2015-9284
|
||||
https://github.com/omniauth/omniauth/pull/809
|
||||
|
||||
You can ignore this warning by setting:
|
||||
OmniAuth.config.silence_get_warning = true
|
||||
WARN
|
||||
end
|
||||
|
||||
# Responds to an OPTIONS request.
|
||||
def options_call
|
||||
OmniAuth.config.before_options_phase.call(env) if OmniAuth.config.before_options_phase
|
||||
|
@ -202,17 +228,19 @@ module OmniAuth
|
|||
# Performs the steps necessary to run the request phase of a strategy.
|
||||
def request_call # rubocop:disable CyclomaticComplexity, MethodLength, PerceivedComplexity
|
||||
setup_phase
|
||||
log :info, 'Request phase initiated.'
|
||||
log :debug, 'Request phase initiated.'
|
||||
|
||||
# store query params from the request url, extracted in the callback_phase
|
||||
session['omniauth.params'] = request.GET
|
||||
|
||||
OmniAuth.config.request_validation_phase.call(env) if OmniAuth.config.request_validation_phase
|
||||
OmniAuth.config.before_request_phase.call(env) if OmniAuth.config.before_request_phase
|
||||
|
||||
if options.form.respond_to?(:call)
|
||||
log :info, 'Rendering form from supplied Rack endpoint.'
|
||||
log :debug, 'Rendering form from supplied Rack endpoint.'
|
||||
options.form.call(env)
|
||||
elsif options.form
|
||||
log :info, 'Rendering form from underlying application.'
|
||||
log :debug, 'Rendering form from underlying application.'
|
||||
call_app!
|
||||
elsif !options.origin_param
|
||||
request_phase
|
||||
|
@ -225,12 +253,14 @@ module OmniAuth
|
|||
|
||||
request_phase
|
||||
end
|
||||
rescue OmniAuth::AuthenticityError => e
|
||||
fail!(:authenticity_error, e)
|
||||
end
|
||||
|
||||
# Performs the steps necessary to run the callback phase of a strategy.
|
||||
def callback_call
|
||||
setup_phase
|
||||
log :info, 'Callback phase initiated.'
|
||||
log :debug, 'Callback phase initiated.'
|
||||
@env['omniauth.origin'] = session.delete('omniauth.origin')
|
||||
@env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
|
||||
@env['omniauth.params'] = session.delete('omniauth.params') || {}
|
||||
|
@ -268,8 +298,13 @@ module OmniAuth
|
|||
# in the event that OmniAuth has been configured to be
|
||||
# in test mode.
|
||||
def mock_call!(*)
|
||||
return mock_request_call if on_request_path? && OmniAuth.config.allowed_request_methods.include?(request.request_method.downcase.to_sym)
|
||||
return mock_callback_call if on_callback_path?
|
||||
begin
|
||||
OmniAuth.config.request_validation_phase.call(env) if OmniAuth.config.request_validation_phase
|
||||
return mock_request_call if on_request_path? && OmniAuth.config.allowed_request_methods.include?(request.request_method.downcase.to_sym)
|
||||
return mock_callback_call if on_callback_path?
|
||||
rescue StandardError => e
|
||||
return fail!(e.message, e)
|
||||
end
|
||||
|
||||
call_app!
|
||||
end
|
||||
|
@ -312,10 +347,10 @@ module OmniAuth
|
|||
# underlying application. This will default to `/auth/:provider/setup`.
|
||||
def setup_phase
|
||||
if options[:setup].respond_to?(:call)
|
||||
log :info, 'Setup endpoint detected, running now.'
|
||||
log :debug, 'Setup endpoint detected, running now.'
|
||||
options[:setup].call(env)
|
||||
elsif options[:setup]
|
||||
log :info, 'Calling through to underlying application for setup.'
|
||||
log :debug, 'Calling through to underlying application for setup.'
|
||||
setup_env = env.merge('PATH_INFO' => setup_path, 'REQUEST_METHOD' => 'GET')
|
||||
call_app!(setup_env)
|
||||
end
|
||||
|
@ -345,11 +380,13 @@ module OmniAuth
|
|||
end
|
||||
|
||||
def auth_hash
|
||||
hash = AuthHash.new(:provider => name, :uid => uid)
|
||||
hash.info = info unless skip_info?
|
||||
hash.credentials = credentials if credentials
|
||||
hash.extra = extra if extra
|
||||
hash
|
||||
credentials_data = credentials
|
||||
extra_data = extra
|
||||
AuthHash.new(:provider => name, :uid => uid).tap do |auth|
|
||||
auth.info = info unless skip_info?
|
||||
auth.credentials = credentials_data if credentials_data
|
||||
auth.extra = extra_data if extra_data
|
||||
end
|
||||
end
|
||||
|
||||
# Determines whether or not user info should be retrieved. This
|
||||
|
@ -389,7 +426,12 @@ module OmniAuth
|
|||
end
|
||||
|
||||
def request_path
|
||||
@request_path ||= options[:request_path].is_a?(String) ? options[:request_path] : "#{path_prefix}/#{name}"
|
||||
@request_path ||=
|
||||
if options[:request_path].is_a?(String)
|
||||
options[:request_path]
|
||||
else
|
||||
"#{script_name}#{path_prefix}/#{name}"
|
||||
end
|
||||
end
|
||||
|
||||
def callback_path
|
||||
|
@ -397,7 +439,7 @@ module OmniAuth
|
|||
path = options[:callback_path] if options[:callback_path].is_a?(String)
|
||||
path ||= current_path if options[:callback_path].respond_to?(:call) && options[:callback_path].call(env)
|
||||
path ||= custom_path(:request_path)
|
||||
path ||= "#{path_prefix}/#{name}/callback"
|
||||
path ||= "#{script_name}#{path_prefix}/#{name}/callback"
|
||||
path
|
||||
end
|
||||
end
|
||||
|
@ -409,7 +451,7 @@ module OmniAuth
|
|||
CURRENT_PATH_REGEX = %r{/$}.freeze
|
||||
EMPTY_STRING = ''.freeze
|
||||
def current_path
|
||||
@current_path ||= request.path_info.downcase.sub(CURRENT_PATH_REGEX, EMPTY_STRING)
|
||||
@current_path ||= request.path.downcase.sub(CURRENT_PATH_REGEX, EMPTY_STRING)
|
||||
end
|
||||
|
||||
def query_string
|
||||
|
@ -441,7 +483,7 @@ module OmniAuth
|
|||
end
|
||||
|
||||
def callback_url
|
||||
full_host + script_name + callback_path + query_string
|
||||
full_host + callback_path + query_string
|
||||
end
|
||||
|
||||
def script_name
|
||||
|
@ -491,16 +533,15 @@ module OmniAuth
|
|||
OmniAuth.config.on_failure.call(env)
|
||||
end
|
||||
|
||||
def dup
|
||||
super.tap do
|
||||
@options = @options.dup
|
||||
end
|
||||
end
|
||||
|
||||
class Options < OmniAuth::KeyStore; end
|
||||
|
||||
protected
|
||||
|
||||
def initialize_copy(*args)
|
||||
super
|
||||
@options = @options.dup
|
||||
end
|
||||
|
||||
def merge_stack(stack)
|
||||
stack.inject({}) do |a, e|
|
||||
a.merge!(e)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module OmniAuth
|
||||
VERSION = '1.9.1'.freeze
|
||||
VERSION = '2.0.0'.freeze
|
||||
end
|
||||
|
|
|
@ -8,6 +8,7 @@ Gem::Specification.new do |spec|
|
|||
spec.add_dependency 'hashie', ['>= 3.4.6']
|
||||
spec.add_dependency 'rack', ['>= 1.6.2', '< 3']
|
||||
spec.add_development_dependency 'bundler', '~> 2.0'
|
||||
spec.add_dependency 'rack-protection'
|
||||
spec.add_development_dependency 'rake', '~> 12.0'
|
||||
spec.authors = ['Michael Bleigh', 'Erik Michaels-Ober', 'Tom Milewski']
|
||||
spec.description = 'A generalized Rack framework for multiple-provider authentication.'
|
||||
|
|
|
@ -20,10 +20,12 @@ end
|
|||
|
||||
require 'rspec'
|
||||
require 'rack/test'
|
||||
require 'rack/freeze'
|
||||
require 'omniauth'
|
||||
require 'omniauth/test'
|
||||
|
||||
OmniAuth.config.logger = Logger.new('/dev/null')
|
||||
OmniAuth.config.request_validation_phase = nil
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.include Rack::Test::Methods
|
||||
|
@ -49,7 +51,7 @@ class ExampleStrategy
|
|||
|
||||
def request_phase
|
||||
options[:mutate_on_request].call(options) if options[:mutate_on_request]
|
||||
@fail = fail!(options[:failure]) if options[:failure]
|
||||
@fail = fail!(options[:failure], options[:failure_exception]) if options[:failure]
|
||||
@last_env = env
|
||||
return @fail if @fail
|
||||
|
||||
|
@ -58,7 +60,7 @@ class ExampleStrategy
|
|||
|
||||
def callback_phase
|
||||
options[:mutate_on_callback].call(options) if options[:mutate_on_callback]
|
||||
@fail = fail!(options[:failure]) if options[:failure]
|
||||
@fail = fail!(options[:failure], options[:failure_exception]) if options[:failure]
|
||||
@last_env = env
|
||||
return @fail if @fail
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@ describe OmniAuth::AuthHash do
|
|||
expect(subject.weird_field.info).to eq 'string'
|
||||
end
|
||||
|
||||
it 'has a subkey_class' do
|
||||
expect(OmniAuth::AuthHash.subkey_class).to eq Hashie::Mash
|
||||
end
|
||||
|
||||
describe '#valid?' do
|
||||
subject { OmniAuth::AuthHash.new(:uid => '123', :provider => 'example', :info => {:name => 'Steven'}) }
|
||||
|
||||
|
@ -111,6 +115,10 @@ describe OmniAuth::AuthHash do
|
|||
end
|
||||
end
|
||||
|
||||
it 'has a subkey_class' do
|
||||
expect(OmniAuth::AuthHash::InfoHash.subkey_class).to eq Hashie::Mash
|
||||
end
|
||||
|
||||
require 'hashie/version'
|
||||
if Gem::Version.new(Hashie::VERSION) >= Gem::Version.new('3.5.1')
|
||||
context 'with Hashie 3.5.1+' do
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'helper'
|
|||
describe OmniAuth::Builder do
|
||||
describe '#provider' do
|
||||
it 'translates a symbol to a constant' do
|
||||
expect(OmniAuth::Strategies).to receive(:const_get).with('MyStrategy').and_return(Class.new)
|
||||
expect(OmniAuth::Strategies).to receive(:const_get).with('MyStrategy', false).and_return(Class.new)
|
||||
OmniAuth::Builder.new(nil) do
|
||||
provider :my_strategy
|
||||
end
|
||||
|
@ -26,6 +26,16 @@ describe OmniAuth::Builder do
|
|||
end
|
||||
end.to raise_error(LoadError, 'Could not find matching strategy for :lorax. You may need to install an additional gem (such as omniauth-lorax).')
|
||||
end
|
||||
|
||||
it "doesn't translate a symbol to a top-level constant" do
|
||||
class MyStrategy; end
|
||||
|
||||
expect do
|
||||
OmniAuth::Builder.new(nil) do
|
||||
provider :my_strategy
|
||||
end
|
||||
end.to raise_error(LoadError, 'Could not find matching strategy for :my_strategy. You may need to install an additional gem (such as omniauth-my_strategy).')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#options' do
|
||||
|
@ -111,14 +121,11 @@ describe OmniAuth::Builder do
|
|||
|
||||
describe '#call' do
|
||||
it 'passes env to to_app.call' do
|
||||
app = lambda { |_env| [200, {}, []] }
|
||||
app = lambda { |env| [200, {}, env['CUSTOM_ENV_VALUE']] }
|
||||
builder = OmniAuth::Builder.new(app)
|
||||
env = {'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/some/path'}
|
||||
allow(app).to receive(:call).and_call_original
|
||||
env = {'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/some/path', 'CUSTOM_ENV_VALUE' => 'VALUE'}
|
||||
|
||||
builder.call(env)
|
||||
|
||||
expect(app).to have_received(:call).with(env)
|
||||
expect(builder.call(env)).to eq([200, {}, 'VALUE'])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -43,16 +43,27 @@ describe OmniAuth::FailureEndpoint do
|
|||
expect(head['Location']).to eq('/random/auth/failure?message=invalid_request&strategy=test')
|
||||
end
|
||||
|
||||
it 'respects the configured path prefix' do
|
||||
it 'respects the globally configured path prefix' do
|
||||
allow(OmniAuth.config).to receive(:path_prefix).and_return('/boo')
|
||||
_, head, = *subject.call(env)
|
||||
expect(head['Location']).to eq('/boo/failure?message=invalid_request&strategy=test')
|
||||
end
|
||||
|
||||
it 'respects the custom path prefix configured on the strategy' do
|
||||
env['omniauth.error.strategy'] = ExampleStrategy.new({}, path_prefix: "/some/custom/path")
|
||||
_, head, = *subject.call(env)
|
||||
expect(head['Location']).to eq('/some/custom/path/failure?message=invalid_request&strategy=test')
|
||||
end
|
||||
|
||||
it 'includes the origin (escaped) if one is provided' do
|
||||
env['omniauth.origin'] = '/origin-example'
|
||||
_, head, = *subject.call(env)
|
||||
expect(head['Location']).to be_include('&origin=%2Forigin-example')
|
||||
end
|
||||
|
||||
it 'escapes the message key' do
|
||||
_, head = *subject.call(env.merge('omniauth.error.type' => 'Connection refused!'))
|
||||
expect(head['Location']).to be_include('message=Connection+refused%21')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,7 +7,8 @@ describe OmniAuth::Form do
|
|||
end
|
||||
|
||||
it 'evaluates in the instance when called with a block and no argument' do
|
||||
OmniAuth::Form.build { |f| expect(f.class).to eq(OmniAuth::Form) }
|
||||
f = OmniAuth::Form.build { @html = '<h1>OmniAuth</h1>' }
|
||||
expect(f.instance_variable_get(:@html)).to eq('<h1>OmniAuth</h1>')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -20,4 +21,34 @@ describe OmniAuth::Form do
|
|||
expect(OmniAuth::Form.new(:title => 'Something Cool').to_html).to be_include('<h1>Something Cool</h1>')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#password_field' do
|
||||
it 'adds a labeled input field' do
|
||||
form = OmniAuth::Form.new.password_field('pass', 'password')
|
||||
form_html = form.to_html
|
||||
expect(form_html).to include('<label for=\'password\'>pass:</label>')
|
||||
expect(form_html).to include('<input type=\'password\' id=\'password\' name=\'password\'/>')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#html' do
|
||||
it 'appends to the html body' do
|
||||
form = OmniAuth::Form.build { @html = +'<p></p>' }
|
||||
form.html('<h1></h1>')
|
||||
|
||||
expect(form.instance_variable_get(:@html)).to eq '<p></p><h1></h1>'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'fieldset' do
|
||||
it 'creates a fieldset with options' do
|
||||
form = OmniAuth::Form.new
|
||||
options = {:style => 'color: red', :id => 'fieldSetId'}
|
||||
expected = "<fieldset style='color: red' id='fieldSetId'>\n <legend>legendary</legend>\n\n</fieldset>"
|
||||
|
||||
form.fieldset('legendary', options) {}
|
||||
|
||||
expect(form.to_html).to include expected
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,6 +25,7 @@ RSpec.describe OmniAuth::KeyStore do
|
|||
|
||||
it 'does not log anything to the console' do
|
||||
stub_const('Hashie::VERSION', version)
|
||||
allow(OmniAuth::KeyStore).to receive(:respond_to?).with(:disable_warnings).and_return(false)
|
||||
OmniAuth::KeyStore.override_logging
|
||||
expect(logger).not_to receive(:info)
|
||||
OmniAuth::KeyStore.new(:id => 1234)
|
||||
|
|
|
@ -10,7 +10,7 @@ describe OmniAuth::Strategies::Developer do
|
|||
end
|
||||
|
||||
context 'request phase' do
|
||||
before(:each) { get '/auth/developer' }
|
||||
before(:each) { post '/auth/developer' }
|
||||
|
||||
it 'displays a form' do
|
||||
expect(last_response.status).to eq(200)
|
||||
|
|
|
@ -2,7 +2,7 @@ require 'helper'
|
|||
|
||||
def make_env(path = '/auth/test', props = {})
|
||||
{
|
||||
'REQUEST_METHOD' => 'GET',
|
||||
'REQUEST_METHOD' => 'POST',
|
||||
'PATH_INFO' => path,
|
||||
'rack.session' => {},
|
||||
'rack.input' => StringIO.new('test=true')
|
||||
|
@ -32,6 +32,12 @@ describe OmniAuth::Strategy do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'user_info' do
|
||||
it 'should default to an empty hash' do
|
||||
expect(fresh_strategy.new(app, :skip_info => true).user_info).to eq({})
|
||||
end
|
||||
end
|
||||
|
||||
describe '.configure' do
|
||||
subject do
|
||||
c = Class.new
|
||||
|
@ -63,6 +69,29 @@ describe OmniAuth::Strategy do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#fail!' do
|
||||
it 'provides exception information when one is provided' do
|
||||
env = make_env
|
||||
exception = RuntimeError.new('No session!')
|
||||
|
||||
expect(OmniAuth.logger).to receive(:error).with(
|
||||
"(test) Authentication failure! failed: #{exception.class}, #{exception.message}"
|
||||
)
|
||||
|
||||
ExampleStrategy.new(app, :failure => :failed, :failure_exception => exception).call(env)
|
||||
end
|
||||
|
||||
it 'provides a generic message when not provided an exception' do
|
||||
env = make_env
|
||||
|
||||
expect(OmniAuth.logger).to receive(:error).with(
|
||||
'(test) Authentication failure! Some Issue encountered.'
|
||||
)
|
||||
|
||||
ExampleStrategy.new(app, :failure => 'Some Issue').call(env)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#skip_info?' do
|
||||
it 'is true if options.skip_info is true' do
|
||||
expect(ExampleStrategy.new(app, :skip_info => true)).to be_skip_info
|
||||
|
@ -173,19 +202,25 @@ describe OmniAuth::Strategy do
|
|||
end
|
||||
let(:instance) { subject.new(app) }
|
||||
|
||||
it 'calls through to uid and info' do
|
||||
it 'calls through to uid, info, credentials, and extra' do
|
||||
expect(instance).to receive(:uid)
|
||||
expect(instance).to receive(:info)
|
||||
expect(instance).to receive(:credentials).and_return(expires: true).once
|
||||
expect(instance).to receive(:extra).and_return(something: 'else').once
|
||||
instance.auth_hash
|
||||
end
|
||||
|
||||
it 'returns an AuthHash' do
|
||||
allow(instance).to receive(:uid).and_return('123')
|
||||
allow(instance).to receive(:info).and_return(:name => 'Hal Awesome')
|
||||
allow(instance).to receive(:credentials).and_return(expires: true)
|
||||
allow(instance).to receive(:extra).and_return(something: 'else')
|
||||
hash = instance.auth_hash
|
||||
expect(hash).to be_kind_of(OmniAuth::AuthHash)
|
||||
expect(hash.uid).to eq('123')
|
||||
expect(hash.info.name).to eq('Hal Awesome')
|
||||
expect(hash.credentials.expires).to eq(true)
|
||||
expect(hash.extra.something).to eq('else')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -312,7 +347,9 @@ describe OmniAuth::Strategy do
|
|||
context 'disabled' do
|
||||
it 'does not set omniauth.origin' do
|
||||
@options = {:origin_param => false}
|
||||
expect { strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'return=/foo')) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
|
||||
strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'return=/foo'))
|
||||
expect(strategy.last_env['rack.session']['omniauth.origin']).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
@ -320,24 +357,31 @@ describe OmniAuth::Strategy do
|
|||
context 'custom' do
|
||||
it 'sets from a custom param' do
|
||||
@options = {:origin_param => 'return'}
|
||||
expect { strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'return=/foo')) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
|
||||
strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'return=/foo'))
|
||||
expect(strategy.last_env['rack.session']['omniauth.origin']).to eq('/foo')
|
||||
end
|
||||
end
|
||||
|
||||
context 'default flow' do
|
||||
it 'is set on the request phase' do
|
||||
expect { strategy.call(make_env('/auth/test', 'HTTP_REFERER' => 'http://example.com/origin')) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with("Request Phase", kind_of(StandardError))
|
||||
strategy.call(make_env('/auth/test', 'HTTP_REFERER' => 'http://example.com/origin'))
|
||||
|
||||
expect(strategy.last_env['rack.session']['omniauth.origin']).to eq('http://example.com/origin')
|
||||
end
|
||||
|
||||
it 'is turned into an env variable on the callback phase' do
|
||||
expect { strategy.call(make_env('/auth/test/callback', 'rack.session' => {'omniauth.origin' => 'http://example.com/origin'})) }.to raise_error('Callback Phase')
|
||||
expect(strategy).to receive(:fail!).with("Callback Phase", kind_of(StandardError))
|
||||
strategy.call(make_env('/auth/test/callback', 'rack.session' => {'omniauth.origin' => 'http://example.com/origin'}))
|
||||
|
||||
expect(strategy.last_env['omniauth.origin']).to eq('http://example.com/origin')
|
||||
end
|
||||
|
||||
it 'sets from the params if provided' do
|
||||
expect { strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'origin=/foo')) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'origin=/foo'))
|
||||
expect(strategy.last_env['rack.session']['omniauth.origin']).to eq('/foo')
|
||||
end
|
||||
|
||||
|
@ -350,7 +394,9 @@ describe OmniAuth::Strategy do
|
|||
context 'with script_name' do
|
||||
it 'is set on the request phase, containing full path' do
|
||||
env = {'HTTP_REFERER' => 'http://example.com/sub_uri/origin', 'SCRIPT_NAME' => '/sub_uri'}
|
||||
expect { strategy.call(make_env('/auth/test', env)) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
|
||||
strategy.call(make_env('/auth/test', env))
|
||||
expect(strategy.last_env['rack.session']['omniauth.origin']).to eq('http://example.com/sub_uri/origin')
|
||||
end
|
||||
|
||||
|
@ -359,8 +405,9 @@ describe OmniAuth::Strategy do
|
|||
'rack.session' => {'omniauth.origin' => 'http://example.com/sub_uri/origin'},
|
||||
'SCRIPT_NAME' => '/sub_uri'
|
||||
}
|
||||
expect(strategy).to receive(:fail!).with('Callback Phase', kind_of(StandardError))
|
||||
|
||||
expect { strategy.call(make_env('/auth/test/callback', env)) }.to raise_error('Callback Phase')
|
||||
strategy.call(make_env('/auth/test/callback', env))
|
||||
expect(strategy.last_env['omniauth.origin']).to eq('http://example.com/sub_uri/origin')
|
||||
end
|
||||
end
|
||||
|
@ -369,34 +416,41 @@ describe OmniAuth::Strategy do
|
|||
|
||||
context 'default paths' do
|
||||
it 'uses the default request path' do
|
||||
expect { strategy.call(make_env) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
strategy.call(make_env)
|
||||
end
|
||||
|
||||
it 'is case insensitive on request path' do
|
||||
expect { strategy.call(make_env('/AUTH/Test')) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
strategy.call(make_env('/AUTH/Test'))
|
||||
end
|
||||
|
||||
it 'is case insensitive on callback path' do
|
||||
expect { strategy.call(make_env('/AUTH/TeSt/CaLlBAck')) }.to raise_error('Callback Phase')
|
||||
expect(strategy).to receive(:fail!).with('Callback Phase', kind_of(StandardError))
|
||||
strategy.call(make_env('/AUTH/TeSt/CaLlBAck'))
|
||||
end
|
||||
|
||||
it 'uses the default callback path' do
|
||||
expect { strategy.call(make_env('/auth/test/callback')) }.to raise_error('Callback Phase')
|
||||
expect(strategy).to receive(:fail!).with('Callback Phase', kind_of(StandardError))
|
||||
strategy.call(make_env('/auth/test/callback'))
|
||||
end
|
||||
|
||||
it 'strips trailing spaces on request' do
|
||||
expect { strategy.call(make_env('/auth/test/')) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
strategy.call(make_env('/auth/test/'))
|
||||
end
|
||||
|
||||
it 'strips trailing spaces on callback' do
|
||||
expect { strategy.call(make_env('/auth/test/callback/')) }.to raise_error('Callback Phase')
|
||||
expect(strategy).to receive(:fail!).with('Callback Phase', kind_of(StandardError))
|
||||
strategy.call(make_env('/auth/test/callback/'))
|
||||
end
|
||||
|
||||
context 'callback_url' do
|
||||
it 'uses the default callback_path' do
|
||||
expect(strategy).to receive(:full_host).and_return('http://example.com')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
|
||||
expect { strategy.call(make_env) }.to raise_error('Request Phase')
|
||||
strategy.call(make_env)
|
||||
|
||||
expect(strategy.callback_url).to eq('http://example.com/auth/test/callback')
|
||||
end
|
||||
|
@ -436,12 +490,15 @@ describe OmniAuth::Strategy do
|
|||
context 'dynamic paths' do
|
||||
it 'runs the request phase if the custom request path evaluator is truthy' do
|
||||
@options = {:request_path => lambda { |_env| true }}
|
||||
expect { strategy.call(make_env('/asoufibasfi')) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
strategy.call(make_env('/asoufibasfi'))
|
||||
end
|
||||
|
||||
it 'runs the callback phase if the custom callback path evaluator is truthy' do
|
||||
@options = {:callback_path => lambda { |_env| true }}
|
||||
expect { strategy.call(make_env('/asoufiasod')) }.to raise_error('Callback Phase')
|
||||
expect(strategy).to receive(:fail!).with('Callback Phase', kind_of(StandardError))
|
||||
|
||||
strategy.call(make_env('/asoufiasod'))
|
||||
end
|
||||
|
||||
it 'provides a custom callback path if request_path evals to a string' do
|
||||
|
@ -451,8 +508,9 @@ describe OmniAuth::Strategy do
|
|||
|
||||
it 'correctly reports the callback path when the custom callback path evaluator is truthy' do
|
||||
strategy_instance = ExampleStrategy.new(app, :callback_path => lambda { |env| env['PATH_INFO'] == '/auth/bish/bosh/callback' })
|
||||
expect(strategy_instance).to receive(:fail!).with('Callback Phase', kind_of(StandardError))
|
||||
|
||||
expect { strategy_instance.call(make_env('/auth/bish/bosh/callback')) }.to raise_error('Callback Phase')
|
||||
strategy_instance.call(make_env('/auth/bish/bosh/callback'))
|
||||
expect(strategy_instance.callback_path).to eq('/auth/bish/bosh/callback')
|
||||
end
|
||||
end
|
||||
|
@ -460,20 +518,25 @@ describe OmniAuth::Strategy do
|
|||
context 'custom paths' do
|
||||
it 'uses a custom request_path if one is provided' do
|
||||
@options = {:request_path => '/awesome'}
|
||||
expect { strategy.call(make_env('/awesome')) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
|
||||
strategy.call(make_env('/awesome'))
|
||||
end
|
||||
|
||||
it 'uses a custom callback_path if one is provided' do
|
||||
@options = {:callback_path => '/radical'}
|
||||
expect { strategy.call(make_env('/radical')) }.to raise_error('Callback Phase')
|
||||
expect(strategy).to receive(:fail!).with('Callback Phase', kind_of(StandardError))
|
||||
|
||||
strategy.call(make_env('/radical'))
|
||||
end
|
||||
|
||||
context 'callback_url' do
|
||||
it 'uses a custom callback_path if one is provided' do
|
||||
@options = {:callback_path => '/radical'}
|
||||
expect(strategy).to receive(:full_host).and_return('http://example.com')
|
||||
expect(strategy).to receive(:fail!).with('Callback Phase', kind_of(StandardError))
|
||||
|
||||
expect { strategy.call(make_env('/radical')) }.to raise_error('Callback Phase')
|
||||
strategy.call(make_env('/radical'))
|
||||
|
||||
expect(strategy.callback_url).to eq('http://example.com/radical')
|
||||
end
|
||||
|
@ -496,18 +559,20 @@ describe OmniAuth::Strategy do
|
|||
end
|
||||
|
||||
it 'uses a custom prefix for request' do
|
||||
expect { strategy.call(make_env('/wowzers/test')) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
strategy.call(make_env('/wowzers/test'))
|
||||
end
|
||||
|
||||
it 'uses a custom prefix for callback' do
|
||||
expect { strategy.call(make_env('/wowzers/test/callback')) }.to raise_error('Callback Phase')
|
||||
expect(strategy).to receive(:fail!).with('Callback Phase', kind_of(StandardError))
|
||||
strategy.call(make_env('/wowzers/test/callback'))
|
||||
end
|
||||
|
||||
context 'callback_url' do
|
||||
it 'uses a custom prefix' do
|
||||
expect(strategy).to receive(:full_host).and_return('http://example.com')
|
||||
|
||||
expect { strategy.call(make_env('/wowzers/test')) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
strategy.call(make_env('/wowzers/test'))
|
||||
|
||||
expect(strategy.callback_url).to eq('http://example.com/wowzers/test/callback')
|
||||
end
|
||||
|
@ -523,21 +588,66 @@ describe OmniAuth::Strategy do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with relative url root' do
|
||||
let(:props) { {'SCRIPT_NAME' => '/myapp'} }
|
||||
it 'accepts the request' do
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
|
||||
strategy.call(make_env('/auth/test', props))
|
||||
expect(strategy.request_path).to eq('/myapp/auth/test')
|
||||
end
|
||||
|
||||
it 'accepts the callback' do
|
||||
expect(strategy).to receive(:fail!).with('Callback Phase', kind_of(StandardError))
|
||||
|
||||
strategy.call(make_env('/auth/test/callback', props))
|
||||
end
|
||||
|
||||
context 'callback_url' do
|
||||
it 'redirects to the correctly prefixed callback' do
|
||||
expect(strategy).to receive(:full_host).and_return('http://example.com')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
|
||||
strategy.call(make_env('/auth/test', props))
|
||||
|
||||
expect(strategy.callback_url).to eq('http://example.com/myapp/auth/test/callback')
|
||||
end
|
||||
end
|
||||
|
||||
context 'custom request' do
|
||||
before do
|
||||
@options = {:request_path => '/myapp/override', :callback_path => '/myapp/override/callback'}
|
||||
end
|
||||
it 'does not prefix a custom request path' do
|
||||
expect(strategy).to receive(:full_host).and_return('http://example.com')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
|
||||
expect(strategy.request_path).to eq('/myapp/override')
|
||||
|
||||
strategy.call(make_env('/override', props))
|
||||
|
||||
expect(strategy.callback_url).to eq('http://example.com/myapp/override/callback')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context 'request method restriction' do
|
||||
before do
|
||||
OmniAuth.config.allowed_request_methods = [:post]
|
||||
before(:context) do
|
||||
OmniAuth.config.allowed_request_methods = %i[put post]
|
||||
end
|
||||
|
||||
it 'does not allow a request method of the wrong type' do
|
||||
expect { strategy.call(make_env) }.not_to raise_error
|
||||
expect { strategy.call(make_env('/auth/test', 'REQUEST_METHOD' => 'GET')) }.not_to raise_error
|
||||
end
|
||||
|
||||
it 'allows a request method of the correct type' do
|
||||
expect { strategy.call(make_env('/auth/test', 'REQUEST_METHOD' => 'POST')) }.to raise_error('Request Phase')
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
strategy.call(make_env('/auth/test'))
|
||||
end
|
||||
|
||||
after do
|
||||
OmniAuth.config.allowed_request_methods = %i[get post]
|
||||
after(:context) do
|
||||
OmniAuth.config.allowed_request_methods = %i[post]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -548,7 +658,7 @@ describe OmniAuth::Strategy do
|
|||
end
|
||||
|
||||
it 'sets the Allow header properly' do
|
||||
expect(response[1]['Allow']).to eq('GET, POST')
|
||||
expect(response[1]['Allow']).to eq('POST')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -579,14 +689,16 @@ describe OmniAuth::Strategy do
|
|||
it 'does not affect original options' do
|
||||
@options[:test_option] = true
|
||||
@options[:mutate_on_request] = proc { |options| options.delete(:test_option) }
|
||||
expect { strategy.call(make_env) }.to raise_error('Request Phase')
|
||||
|
||||
strategy.call(make_env)
|
||||
expect(strategy.options).to have_key(:test_option)
|
||||
end
|
||||
|
||||
it 'does not affect deep options' do
|
||||
@options[:deep_option] = {:test_option => true}
|
||||
@options[:mutate_on_request] = proc { |options| options[:deep_option].delete(:test_option) }
|
||||
expect { strategy.call(make_env) }.to raise_error('Request Phase')
|
||||
|
||||
strategy.call(make_env)
|
||||
expect(strategy.options[:deep_option]).to have_key(:test_option)
|
||||
end
|
||||
end
|
||||
|
@ -595,14 +707,16 @@ describe OmniAuth::Strategy do
|
|||
it 'does not affect original options' do
|
||||
@options[:test_option] = true
|
||||
@options[:mutate_on_callback] = proc { |options| options.delete(:test_option) }
|
||||
expect { strategy.call(make_env('/auth/test/callback', 'REQUEST_METHOD' => 'POST')) }.to raise_error('Callback Phase')
|
||||
|
||||
strategy.call(make_env('/auth/test/callback', 'REQUEST_METHOD' => 'POST'))
|
||||
expect(strategy.options).to have_key(:test_option)
|
||||
end
|
||||
|
||||
it 'does not affect deep options' do
|
||||
@options[:deep_option] = {:test_option => true}
|
||||
@options[:mutate_on_callback] = proc { |options| options[:deep_option].delete(:test_option) }
|
||||
expect { strategy.call(make_env('/auth/test/callback', 'REQUEST_METHOD' => 'POST')) }.to raise_error('Callback Phase')
|
||||
|
||||
strategy.call(make_env('/auth/test/callback', 'REQUEST_METHOD' => 'POST'))
|
||||
expect(strategy.options[:deep_option]).to have_key(:test_option)
|
||||
end
|
||||
end
|
||||
|
@ -771,6 +885,12 @@ describe OmniAuth::Strategy do
|
|||
expect(strategy.env['omniauth.params']).to eq('foo' => 'bar')
|
||||
end
|
||||
|
||||
it 'rescues errors in request_call' do
|
||||
allow(strategy).to receive(:mock_request_call).and_raise(StandardError.new('Oh no'))
|
||||
expect(strategy).to receive(:fail!).with('Oh no', kind_of(StandardError))
|
||||
strategy.call(make_env)
|
||||
end
|
||||
|
||||
after do
|
||||
OmniAuth.config.test_mode = false
|
||||
end
|
||||
|
@ -809,6 +929,65 @@ describe OmniAuth::Strategy do
|
|||
OmniAuth.config.test_mode = false
|
||||
end
|
||||
end
|
||||
|
||||
context 'authenticity validation' do
|
||||
let(:app) { lambda { |_env| [200, {}, ['reached our target']] } }
|
||||
let(:strategy) { ExampleStrategy.new(app, :request_path => '/auth/test') }
|
||||
before do
|
||||
OmniAuth.config.request_validation_phase = OmniAuth::AuthenticityTokenProtection
|
||||
end
|
||||
|
||||
context 'with default POST only request methods' do
|
||||
let!(:csrf_token) { SecureRandom.base64(32) }
|
||||
let(:escaped_token) { URI.encode_www_form_component(csrf_token, Encoding::UTF_8) }
|
||||
|
||||
it 'allows a request with matching authenticity_token' do
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
|
||||
post_env = make_env('/auth/test', 'rack.session' => {:csrf => csrf_token}, 'rack.input' => StringIO.new("authenticity_token=#{escaped_token}"))
|
||||
strategy.call(post_env)
|
||||
end
|
||||
|
||||
it 'does not allow a request without a matching authenticity token' do
|
||||
post_env = make_env('/auth/test', 'rack.input' => StringIO.new("authenticity_token=#{escaped_token}"))
|
||||
expect(strategy.call(post_env)[0]).to eq(302)
|
||||
expect(strategy.call(post_env)[2]).to eq(['302 Moved'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'with allowed GET' do
|
||||
before(:context) do
|
||||
@old_allowed_request_methods = OmniAuth.config.allowed_request_methods
|
||||
OmniAuth.config.allowed_request_methods = %i[post get]
|
||||
end
|
||||
|
||||
it 'allows a request without authenticity token' do
|
||||
expect(strategy).to receive(:fail!).with('Request Phase', kind_of(StandardError))
|
||||
|
||||
get_env = make_env('/auth/test', 'REQUEST_METHOD' => 'GET')
|
||||
strategy.call(get_env)
|
||||
end
|
||||
|
||||
after(:context) do
|
||||
OmniAuth.config.allowed_request_methods = @old_allowed_request_methods
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
OmniAuth.config.request_validation_phase = nil
|
||||
end
|
||||
end
|
||||
|
||||
it 'calls fail! when encountering an unhandled exception' do
|
||||
allow(strategy).to receive(:request_phase).and_raise(Errno::ECONNREFUSED)
|
||||
expect(strategy).to receive(:fail!).with('Connection refused', kind_of(Errno::ECONNREFUSED))
|
||||
strategy.call(make_env)
|
||||
end
|
||||
|
||||
it 'redirects to the fail! result when encountering an unhandled exception' do
|
||||
OmniAuth.config.test_mode = false
|
||||
expect(strategy.call(make_env).first).to eq 302
|
||||
end
|
||||
end
|
||||
|
||||
context 'setup phase' do
|
||||
|
|
|
@ -26,20 +26,22 @@ describe OmniAuth do
|
|||
end
|
||||
|
||||
before do
|
||||
@old_path_prefix = OmniAuth.config.path_prefix
|
||||
@old_on_failure = OmniAuth.config.on_failure
|
||||
@old_before_callback_phase = OmniAuth.config.before_callback_phase
|
||||
@old_before_options_phase = OmniAuth.config.before_options_phase
|
||||
@old_before_request_phase = OmniAuth.config.before_request_phase
|
||||
@old_path_prefix = OmniAuth.config.path_prefix
|
||||
@old_on_failure = OmniAuth.config.on_failure
|
||||
@old_before_callback_phase = OmniAuth.config.before_callback_phase
|
||||
@old_before_options_phase = OmniAuth.config.before_options_phase
|
||||
@old_before_request_phase = OmniAuth.config.before_request_phase
|
||||
@old_request_validation_phase = OmniAuth.config.request_validation_phase
|
||||
end
|
||||
|
||||
after do
|
||||
OmniAuth.configure do |config|
|
||||
config.path_prefix = @old_path_prefix
|
||||
config.on_failure = @old_on_failure
|
||||
config.before_callback_phase = @old_before_callback_phase
|
||||
config.before_options_phase = @old_before_options_phase
|
||||
config.before_request_phase = @old_before_request_phase
|
||||
config.path_prefix = @old_path_prefix
|
||||
config.on_failure = @old_on_failure
|
||||
config.before_callback_phase = @old_before_callback_phase
|
||||
config.before_options_phase = @old_before_options_phase
|
||||
config.before_request_phase = @old_before_request_phase
|
||||
config.request_validation_phase = @old_request_validation_phase
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -88,6 +90,15 @@ describe OmniAuth do
|
|||
expect(OmniAuth.config.before_callback_phase.call).to eq('heyhey')
|
||||
end
|
||||
|
||||
it 'is able to set request_validation_phase' do
|
||||
OmniAuth.configure do |config|
|
||||
config.request_validation_phase do
|
||||
'validated'
|
||||
end
|
||||
end
|
||||
expect(OmniAuth.config.request_validation_phase.call).to eq('validated')
|
||||
end
|
||||
|
||||
describe 'mock auth' do
|
||||
before do
|
||||
@auth_hash = {:uid => '12345', :info => {:name => 'Joe', :email => 'joe@example.com'}}
|
||||
|
@ -128,6 +139,13 @@ describe OmniAuth do
|
|||
end
|
||||
|
||||
describe '::Utils' do
|
||||
describe 'form_css' do
|
||||
it 'returns a style tag with the configured form_css' do
|
||||
allow(OmniAuth).to receive(:config).and_return(double(:form_css => 'css.css'))
|
||||
expect(OmniAuth::Utils.form_css).to eq "<style type='text/css'>css.css</style>"
|
||||
end
|
||||
end
|
||||
|
||||
describe '.deep_merge' do
|
||||
it 'combines hashes' do
|
||||
expect(OmniAuth::Utils.deep_merge({'abc' => {'def' => 123}}, 'abc' => {'foo' => 'bar'})).to eq('abc' => {'def' => 123, 'foo' => 'bar'})
|
||||
|
@ -148,6 +166,15 @@ describe OmniAuth do
|
|||
OmniAuth.config.add_camelization('oauth', 'OAuth')
|
||||
expect(OmniAuth::Utils.camelize(:oauth)).to eq('OAuth')
|
||||
end
|
||||
|
||||
it 'doesn\'t uppercase the first letter when passed false' do
|
||||
expect(OmniAuth::Utils.camelize('apple_jack', false)).to eq('appleJack')
|
||||
end
|
||||
|
||||
it 'replaces / with ::' do
|
||||
expect(OmniAuth::Utils.camelize('apple_jack/cereal')).to eq('AppleJack::Cereal')
|
||||
expect(OmniAuth::Utils.camelize('apple_jack/cereal', false)).to eq('appleJack::Cereal')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue