module OmniAuth::Strategy

def self.included(base)

rubocop:disable ModuleLength
necessary to be compatible with the OmniAuth library.
OmniAuth includes this mixin to gain the default functionality
wrangle multiple providers. Each strategy provided by
The Strategy is the base unit of OmniAuth's ability to
def self.included(base)
  OmniAuth.strategies << base
  base.extend ClassMethods
  base.class_eval do
    option :setup, false
    option :skip_info, false
    option :origin_param, 'origin'
  end
end

def auth_hash

def auth_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

def call(env)

Parameters:
  • The (Hash) -- Rack environment.
def call(env)
  dup.call!(env)
end

def call!(env) # rubocop:disable CyclomaticComplexity, PerceivedComplexity

Parameters:
  • env (Hash) -- The Rack environment.
def call!(env) # rubocop:disable CyclomaticComplexity, PerceivedComplexity
  unless env['rack.session']
    error = OmniAuth::NoSessionError.new('You must provide a session to use OmniAuth.')
    raise(error)
  end
  @env = env
  warn_if_using_get_on_request_path
  @env['omniauth.strategy'] = self if on_auth_path?
  return mock_call!(env) if OmniAuth.config.test_mode
  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
    raise e if env.delete('omniauth.error.app')
    return fail!(e.message, e)
  end
  @app.call(env)
end

def call_app!(env = @env)

def call_app!(env = @env)
  @app.call(env)
rescue StandardError => e
  env['omniauth.error.app'] = true
  raise e
end

def callback_call

Performs the steps necessary to run the callback phase of a strategy.
def callback_call
  setup_phase
  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') || {}
  OmniAuth.config.before_callback_phase.call(@env) if OmniAuth.config.before_callback_phase
  callback_phase
end

def callback_path

def callback_path
  @callback_path ||= begin
    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 ||= "#{script_name}#{path_prefix}/#{name}/callback"
    path
  end
end

def callback_phase

def callback_phase
  env['omniauth.auth'] = auth_hash
  call_app!
end

def callback_url

def callback_url
  full_host + callback_path + query_string
end

def credentials

def credentials
  merge_stack(self.class.credentials_stack(self))
end

def current_path

def current_path
  @current_path ||= request.path.downcase.sub(CURRENT_PATH_REGEX, EMPTY_STRING)
end

def custom_path(kind)

def custom_path(kind)
  if options[kind].respond_to?(:call)
    result = options[kind].call(env)
    return nil unless result.is_a?(String)
    result
  else
    options[kind]
  end
end

def extra

def extra
  merge_stack(self.class.extra_stack(self))
end

def fail!(message_key, exception = nil)

def fail!(message_key, exception = nil)
  env['omniauth.error'] = exception
  env['omniauth.error.type'] = message_key.to_sym
  env['omniauth.error.strategy'] = self
  if exception
    log :error, "Authentication failure! #{message_key}: #{exception.class}, #{exception.message}"
  else
    log :error, "Authentication failure! #{message_key} encountered."
  end
  OmniAuth.config.on_failure.call(env)
end

def full_host

def full_host
  case OmniAuth.config.full_host
  when String
    OmniAuth.config.full_host
  when Proc
    OmniAuth.config.full_host.call(env)
  else
    # in Rack 1.3.x, request.url explodes if scheme is nil
    if request.scheme && request.url.match(URI::ABS_URI)
      uri = URI.parse(request.url.gsub(/\?.*$/, ''))
      uri.path = ''
      # sometimes the url is actually showing http inside rails because the
      # other layers (like nginx) have handled the ssl termination.
      uri.scheme = 'https' if ssl? # rubocop:disable BlockNesting
      uri.to_s
    else ''
    end
  end
end

def info

def info
  merge_stack(self.class.info_stack(self))
end

def initialize(app, *args, &block) # rubocop:disable UnusedMethodArgument

Other tags:
    Yield: - Yields options to block for further configuration.

Overloads:
  • new(app, *args, options = {})
  • new(app, options = {})

Parameters:
  • app (Rack application) -- The application on which this middleware is applied.
def initialize(app, *args, &block) # rubocop:disable UnusedMethodArgument
  @app = app
  @env = nil
  @options = self.class.default_options.dup
  options.deep_merge!(args.pop) if args.last.is_a?(Hash)
  options[:name] ||= self.class.to_s.split('::').last.downcase
  self.class.args.each do |arg|
    break if args.empty?
    options[arg] = args.shift
  end
  # Make sure that all of the args have been dealt with, otherwise error out.
  raise(ArgumentError.new("Received wrong number of arguments. #{args.inspect}")) unless args.empty?
  yield options if block_given?
end

def initialize_copy(*args)

def initialize_copy(*args)
  super
  @options = @options.dup
end

def inspect

def inspect
  "#<#{self.class}>"
end

def log(level, message)

log :warn, "This is a warning."
@example

with this strategy's name.
Direct access to the OmniAuth logger, automatically prefixed
def log(level, message)
  OmniAuth.logger.send(level, "(#{name}) #{message}")
end

def merge_stack(stack)

def merge_stack(stack)
  stack.inject({}) do |a, e|
    a.merge!(e)
    a
  end
end

def mock_call!(*)

in test mode.
in the event that OmniAuth has been configured to be
This is called in lieu of the normal request process
def mock_call!(*)
  begin
    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
    raise e if env.delete('omniauth.error.app')
    return fail!(e.message, e)
  end
  call_app!
end

def mock_callback_call

def mock_callback_call
  setup_phase
  @env['omniauth.origin'] = session.delete('omniauth.origin')
  @env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
  @env['omniauth.params'] = session.delete('omniauth.params') || {}
  mocked_auth = OmniAuth.mock_auth_for(name.to_s)
  if mocked_auth.is_a?(Symbol)
    fail!(mocked_auth)
  else
    @env['omniauth.auth'] = mocked_auth
    OmniAuth.config.before_callback_phase.call(@env) if OmniAuth.config.before_callback_phase
    call_app!
  end
end

def mock_request_call

def mock_request_call
  setup_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.origin_param
    if request.params[options.origin_param]
      session['omniauth.origin'] = request.params[options.origin_param]
    elsif env['HTTP_REFERER'] && !env['HTTP_REFERER'].match(/#{request_path}$/)
      session['omniauth.origin'] = env['HTTP_REFERER']
    end
  end
  redirect(callback_url)
end

def name

def name
  options[:name]
end

def on_auth_path?

request or callback path.
Returns true if the environment recognizes either the
def on_auth_path?
  on_request_path? || on_callback_path?
end

def on_callback_path?

def on_callback_path?
  on_path?(callback_path)
end

def on_path?(path)

def on_path?(path)
  current_path.casecmp(path).zero?
end

def on_request_path?

def on_request_path?
  if options[:request_path].respond_to?(:call)
    options[:request_path].call(env)
  else
    on_path?(request_path)
  end
end

def options_call

Responds to an OPTIONS request.
def options_call
  OmniAuth.config.before_options_phase.call(env) if OmniAuth.config.before_options_phase
  verbs = OmniAuth.config.allowed_request_methods.collect(&:to_s).collect(&:upcase).join(', ')
  [200, {'Allow' => verbs}, []]
end

def options_request?

def options_request?
  request.request_method == 'OPTIONS'
end

def path_prefix

def path_prefix
  options[:path_prefix] || OmniAuth.config.path_prefix
end

def query_string

def query_string
  request.query_string.empty? ? '' : "?#{request.query_string}"
end

def redirect(uri)

def redirect(uri)
  r = Rack::Response.new
  if options[:iframe]
    r.write("<script type='text/javascript' charset='utf-8'>top.location.href = '#{uri}';</script>")
  else
    r.write("Redirecting to #{uri}...")
    r.redirect(uri)
  end
  r.finish
end

def request

def request
  @request ||= Rack::Request.new(@env)
end

def request_call # rubocop:disable CyclomaticComplexity, MethodLength, PerceivedComplexity

rubocop:disable CyclomaticComplexity, MethodLength, PerceivedComplexity
Performs the steps necessary to run the request phase of a strategy.
def request_call # rubocop:disable CyclomaticComplexity, MethodLength, PerceivedComplexity
  setup_phase
  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 :debug, 'Rendering form from supplied Rack endpoint.'
    options.form.call(env)
  elsif options.form
    log :debug, 'Rendering form from underlying application.'
    call_app!
  elsif !options.origin_param
    request_phase
  else
    if request.params[options.origin_param]
      env['rack.session']['omniauth.origin'] = request.params[options.origin_param]
    elsif env['HTTP_REFERER'] && !env['HTTP_REFERER'].match(/#{request_path}$/)
      env['rack.session']['omniauth.origin'] = env['HTTP_REFERER']
    end
    request_phase
  end
rescue OmniAuth::AuthenticityError => e
  fail!(:authenticity_error, e)
end

def request_path

def request_path
  @request_path ||=
    if options[:request_path].is_a?(String)
      options[:request_path]
    else
      "#{script_name}#{path_prefix}/#{name}"
    end
end

def request_phase

Other tags:
    Abstract: - This method is called when the user is on the request path. You should
def request_phase
  raise(NotImplementedError)
end

def script_name

def script_name
  return '' if @env.nil?
  @env['SCRIPT_NAME'] || ''
end

def session

def session
  @env['rack.session']
end

def setup_path

def setup_path
  options[:setup_path] || "#{path_prefix}/#{name}/setup"
end

def setup_phase

underlying application. This will default to `/auth/:provider/setup`.
`:setup` option or it will call out to the setup path of the
if it is, will call either the Rack endpoint supplied to the
The setup phase looks for the `:setup` option to exist and,
def setup_phase
  if options[:setup].respond_to?(:call)
    log :debug, 'Setup endpoint detected, running now.'
    options[:setup].call(env)
  elsif options[: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
end

def skip_info?

use MyStrategy, :skip_info => lambda{|uid| User.find_by_uid(uid)}

@example

evaluates to true when you would like to skip info.
to true or by setting `:skip_info` to a Proc that takes a uid and
for existing users. You can use it either by setting the `:skip_info`
allows some strategies to save a call to an external API service
Determines whether or not user info should be retrieved. This
def skip_info?
  return false unless options.skip_info?
  return true unless options.skip_info.respond_to?(:call)
  options.skip_info.call(uid)
end

def ssl?

def ssl?
  request.env['HTTPS'] == 'on' ||
    request.env['HTTP_X_FORWARDED_SSL'] == 'on' ||
    request.env['HTTP_X_FORWARDED_SCHEME'] == 'https' ||
    (request.env['HTTP_X_FORWARDED_PROTO'] && request.env['HTTP_X_FORWARDED_PROTO'].split(',')[0] == 'https') ||
    request.env['rack.url_scheme'] == 'https'
end

def uid

def uid
  self.class.uid_stack(self).last
end

def user_info

def user_info
  {}
end

def warn_if_using_get_on_request_path

def warn_if_using_get_on_request_path
  return unless on_request_path?
  return unless OmniAuth.config.allowed_request_methods.include?(:get)
  return if OmniAuth.config.silence_get_warning
  log :warn, <<-WARN
u are using GET as an allowed request method for OmniAuth. This may leave
u open to CSRF attacks. As of v2.0.0, OmniAuth by default allows only POST
 its own routes. You should review the following resources to guide your
tigation:
tps://github.com/omniauth/omniauth/wiki/Resolving-CVE-2015-9284
tps://github.com/omniauth/omniauth/issues/960
tps://nvd.nist.gov/vuln/detail/CVE-2015-9284
tps://github.com/omniauth/omniauth/pull/809
u can ignore this warning by setting:
niAuth.config.silence_get_warning = true
  WARN
end