1
0
Fork 0
mirror of https://github.com/heartcombo/devise.git synced 2022-11-09 12:18:31 -05:00
heartcombo--devise/lib/devise/failure_app.rb

255 lines
7.2 KiB
Ruby
Raw Normal View History

2010-02-19 03:52:04 -05:00
require "action_controller/metal"
2009-10-22 18:12:00 -04:00
module Devise
# Failure application that will be called every time :warden is thrown from
# any strategy or hook. Responsible for redirect the user to the sign in
# page based on current scope and mapping. If no scope is given, redirect
# to the default_url.
2010-02-19 03:52:04 -05:00
class FailureApp < ActionController::Metal
include ActionController::UrlFor
include ActionController::Redirecting
include Rails.application.routes.url_helpers
include Rails.application.routes.mounted_helpers
include Devise::Controllers::StoreLocation
2014-02-25 11:42:55 -05:00
delegate :flash, to: :request
2009-10-22 18:12:00 -04:00
def self.call(env)
@respond ||= action(:respond)
@respond.call(env)
end
2009-11-16 11:31:09 -05:00
# Try retrieving the URL options from the parent controller (usually
# ApplicationController). Instance methods are not supported at the moment,
# so only the class-level attribute is used.
2010-02-19 03:52:04 -05:00
def self.default_url_options(*args)
if defined?(Devise.parent_controller.constantize)
Devise.parent_controller.constantize.try(:default_url_options) || {}
else
{}
end
end
2010-02-19 03:52:04 -05:00
def respond
if http_auth?
http_auth
elsif warden_options[:recall]
recall
else
redirect
end
2009-10-22 18:12:00 -04:00
end
def http_auth
self.status = 401
self.headers["WWW-Authenticate"] = %(Basic realm=#{Devise.http_authentication_realm.inspect}) if http_auth_header?
self.content_type = request.format.to_s
self.response_body = http_auth_body
end
def recall
config = Rails.application.config
header_info = if config.try(:relative_url_root)
base_path = Pathname.new(config.relative_url_root)
full_path = Pathname.new(attempted_path)
{ "SCRIPT_NAME" => config.relative_url_root,
"PATH_INFO" => '/' + full_path.relative_path_from(base_path).to_s }
else
{ "PATH_INFO" => attempted_path }
end
header_info.each do | var, value|
if request.respond_to?(:set_header)
request.set_header(var, value)
else
env[var] = value
end
end
flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
# self.response = recall_app(warden_options[:recall]).call(env)
self.response = recall_app(warden_options[:recall]).call(request.env)
end
def redirect
store_location!
if is_flashing_format?
if flash[:timedout] && flash[:alert]
flash.keep(:timedout)
flash.keep(:alert)
else
flash[:alert] = i18n_message
end
end
redirect_to redirect_url
end
protected
def i18n_options(options)
options
end
def i18n_message(default = nil)
message = warden_message || default || :unauthenticated
if message.is_a?(Symbol)
options = {}
options[:resource_name] = scope
options[:scope] = "devise.failure"
options[:default] = [message]
auth_keys = scope_class.authentication_keys
keys = auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys
options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
options = i18n_options(options)
I18n.t(:"#{scope}.#{message}", options)
else
message.to_s
end
end
def redirect_url
if warden_message == :timeout
flash[:timedout] = true if is_flashing_format?
path = if request.get?
attempted_path
else
request.referrer
end
2014-03-31 12:32:45 -04:00
path || scope_url
else
2014-03-31 12:32:45 -04:00
scope_url
end
end
def route(scope)
:"new_#{scope}_session_url"
end
2014-03-31 12:32:45 -04:00
def scope_url
opts = {}
route = route(scope)
opts[:format] = request_format unless skip_format?
2012-05-09 17:41:05 -04:00
config = Rails.application.config
if config.respond_to?(:relative_url_root)
# Rails 4.2 goes into an infinite loop if opts[:script_name] is unset
rails_4_2 = (Rails::VERSION::MAJOR >= 4) && (Rails::VERSION::MINOR >= 2)
if config.relative_url_root.present? || rails_4_2
opts[:script_name] = config.relative_url_root
end
end
router_name = Devise.mappings[scope].router_name || Devise.available_router_name
context = send(router_name)
if context.respond_to?(route)
context.send(route, opts)
2014-03-31 12:32:45 -04:00
elsif respond_to?(:root_url)
root_url(opts)
else
"/"
end
end
2011-04-29 08:11:47 -04:00
def skip_format?
%w(html */*).include? request_format.to_s
end
# Choose whether we should respond in a http authentication fashion,
# including 401 and optional headers.
#
# This method allows the user to explicitly disable http authentication
# on ajax requests in case they want to redirect on failures instead of
# handling the errors on their own. This is useful in case your ajax API
# is the same as your public API and uses a format like JSON (so you
# cannot mark JSON as a navigational format).
def http_auth?
if request.xhr?
Devise.http_authenticatable_on_xhr
else
!(request_format && is_navigational_format?)
end
end
# It does not make sense to send authenticate headers in ajax requests
# or if the user disabled them.
def http_auth_header?
2014-09-24 09:48:46 -04:00
scope_class.http_authenticatable && !request.xhr?
end
def http_auth_body
2011-02-15 04:26:28 -05:00
return i18n_message unless request_format
method = "to_#{request_format}"
if method == "to_xml"
2014-02-25 11:42:55 -05:00
{ error: i18n_message }.to_xml(root: "errors")
elsif {}.respond_to?(method)
2014-02-25 11:42:55 -05:00
{ error: i18n_message }.send(method)
else
i18n_message
end
2010-02-19 03:52:04 -05:00
end
def recall_app(app)
controller, action = app.split("#")
2011-04-16 07:30:15 -04:00
controller_name = ActiveSupport::Inflector.camelize(controller)
controller_klass = ActiveSupport::Inflector.constantize("#{controller_name}Controller")
controller_klass.action(action)
end
2010-02-19 03:52:04 -05:00
def warden
request.respond_to?(:get_header) ? request.get_header("warden") : env["warden"]
2010-02-19 03:52:04 -05:00
end
2010-02-19 03:52:04 -05:00
def warden_options
request.respond_to?(:get_header) ? request.get_header("warden.options") : env["warden.options"]
end
def warden_message
@message ||= warden.message || warden_options[:message]
end
def scope
@scope ||= warden_options[:scope] || Devise.default_scope
end
2014-09-24 09:48:46 -04:00
def scope_class
@scope_class ||= Devise.mappings[scope].to
end
2010-03-11 12:39:32 -05:00
def attempted_path
warden_options[:attempted_path]
end
# Stores requested uri to redirect the user after signing in. We cannot use
# scoped session provided by warden here, since the user is not authenticated
# yet, but we still need to store the uri based on scope, so different scopes
# would never use the same uri to redirect.
def store_location!
store_location_for(scope, attempted_path) if request.get? && !http_auth?
end
2012-01-02 15:00:55 -05:00
def is_navigational_format?
Devise.navigational_formats.include?(request_format)
end
# Check if flash messages should be emitted. Default is to do it on
# navigational formats
def is_flashing_format?
is_navigational_format?
end
2012-01-02 15:00:55 -05:00
def request_format
@request_format ||= request.format.try(:ref)
end
2009-10-22 18:12:00 -04:00
end
end