2015-02-24 13:58:18 -05:00
|
|
|
require 'active_model/version'
|
2010-04-06 10:34:22 -04:00
|
|
|
require 'devise/hooks/activatable'
|
2013-08-02 17:13:15 -04:00
|
|
|
require 'devise/hooks/csrf_cleaner'
|
2010-04-06 10:34:22 -04:00
|
|
|
|
2010-03-29 14:52:34 -04:00
|
|
|
module Devise
|
|
|
|
module Models
|
2011-01-11 13:53:17 -05:00
|
|
|
# Authenticatable module. Holds common settings for authentication.
|
2010-03-29 14:52:34 -04:00
|
|
|
#
|
2010-07-15 07:01:31 -04:00
|
|
|
# == Options
|
2010-03-29 14:52:34 -04:00
|
|
|
#
|
2010-07-15 07:01:31 -04:00
|
|
|
# Authenticatable adds the following options to devise_for:
|
2010-03-29 14:52:34 -04:00
|
|
|
#
|
2010-07-15 07:01:31 -04:00
|
|
|
# * +authentication_keys+: parameters used for authentication. By default [:email].
|
2010-03-29 14:52:34 -04:00
|
|
|
#
|
2013-04-14 01:07:54 -04:00
|
|
|
# * +http_authentication_key+: map the username passed via HTTP Auth to this parameter. Defaults to
|
2013-03-04 12:18:20 -05:00
|
|
|
# the first element in +authentication_keys+.
|
|
|
|
#
|
2010-09-21 05:45:44 -04:00
|
|
|
# * +request_keys+: parameters from the request object used for authentication.
|
|
|
|
# By specifying a symbol (which should be a request method), it will automatically be
|
|
|
|
# passed to find_for_authentication method and considered in your model lookup.
|
|
|
|
#
|
|
|
|
# For instance, if you set :request_keys to [:subdomain], :subdomain will be considered
|
2013-04-18 00:54:38 -04:00
|
|
|
# as key on authentication. This can also be a hash where the value is a boolean specifying
|
2010-09-21 05:45:44 -04:00
|
|
|
# if the value is required or not.
|
|
|
|
#
|
2013-05-17 16:20:06 -04:00
|
|
|
# * +http_authenticatable+: if this model allows http authentication. By default false.
|
2010-07-15 07:01:31 -04:00
|
|
|
# It also accepts an array specifying the strategies that should allow http.
|
2010-04-01 13:09:33 -04:00
|
|
|
#
|
2010-07-15 07:01:31 -04:00
|
|
|
# * +params_authenticatable+: if this model allows authentication through request params. By default true.
|
|
|
|
# It also accepts an array specifying the strategies that should allow params authentication.
|
2010-03-29 14:52:34 -04:00
|
|
|
#
|
2011-12-11 14:39:41 -05:00
|
|
|
# * +skip_session_storage+: By default Devise will store the user in session.
|
2014-02-25 11:42:55 -05:00
|
|
|
# By default is set to skip_session_storage: [:http_auth].
|
2011-12-11 14:39:41 -05:00
|
|
|
#
|
2011-03-25 10:39:08 -04:00
|
|
|
# == active_for_authentication?
|
2010-04-06 10:34:22 -04:00
|
|
|
#
|
2011-11-05 17:54:40 -04:00
|
|
|
# After authenticating a user and in each request, Devise checks if your model is active by
|
2013-04-18 00:54:38 -04:00
|
|
|
# calling model.active_for_authentication?. This method is overwritten by other devise modules. For instance,
|
2011-03-25 10:39:08 -04:00
|
|
|
# :confirmable overwrites .active_for_authentication? to only return true if your model was confirmed.
|
2010-04-06 10:34:22 -04:00
|
|
|
#
|
2014-11-30 23:56:44 -05:00
|
|
|
# You can overwrite this method yourself, but if you do, don't forget to call super:
|
2010-04-06 10:34:22 -04:00
|
|
|
#
|
2011-03-25 10:39:08 -04:00
|
|
|
# def active_for_authentication?
|
2010-04-06 10:34:22 -04:00
|
|
|
# super && special_condition_is_valid?
|
|
|
|
# end
|
|
|
|
#
|
2011-03-25 10:39:08 -04:00
|
|
|
# Whenever active_for_authentication? returns false, Devise asks the reason why your model is inactive using
|
2010-04-06 10:34:22 -04:00
|
|
|
# the inactive_message method. You can overwrite it as well:
|
|
|
|
#
|
|
|
|
# def inactive_message
|
|
|
|
# special_condition_is_valid? ? super : :special_condition_is_not_valid
|
|
|
|
# end
|
|
|
|
#
|
2010-03-29 14:52:34 -04:00
|
|
|
module Authenticatable
|
|
|
|
extend ActiveSupport::Concern
|
|
|
|
|
2012-02-15 14:18:52 -05:00
|
|
|
BLACKLIST_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
|
|
|
|
:remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
|
|
|
|
:last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
|
2013-12-10 09:05:48 -05:00
|
|
|
:remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
|
2012-02-15 14:18:52 -05:00
|
|
|
|
2010-04-16 16:00:06 -04:00
|
|
|
included do
|
2014-02-25 11:42:55 -05:00
|
|
|
class_attribute :devise_modules, instance_writer: false
|
2010-04-16 16:00:06 -04:00
|
|
|
self.devise_modules ||= []
|
2011-12-04 17:58:19 -05:00
|
|
|
|
|
|
|
before_validation :downcase_keys
|
|
|
|
before_validation :strip_whitespace
|
2010-04-16 16:00:06 -04:00
|
|
|
end
|
|
|
|
|
2012-02-24 17:56:04 -05:00
|
|
|
def self.required_fields(klass)
|
|
|
|
[]
|
|
|
|
end
|
|
|
|
|
2010-05-16 08:13:43 -04:00
|
|
|
# Check if the current object is valid for authentication. This method and
|
|
|
|
# find_for_authentication are the methods used in a Warden::Strategy to check
|
|
|
|
# if a model should be signed in or not.
|
2010-04-06 10:34:22 -04:00
|
|
|
#
|
2011-03-25 10:39:08 -04:00
|
|
|
# However, you should not overwrite this method, you should overwrite active_for_authentication?
|
|
|
|
# and inactive_message instead.
|
2010-03-29 17:44:47 -04:00
|
|
|
def valid_for_authentication?
|
2011-11-05 17:54:40 -04:00
|
|
|
block_given? ? yield : true
|
2010-04-06 10:34:22 -04:00
|
|
|
end
|
|
|
|
|
2012-03-13 13:24:21 -04:00
|
|
|
def unauthenticated_message
|
|
|
|
:invalid
|
|
|
|
end
|
|
|
|
|
2011-03-25 10:39:08 -04:00
|
|
|
def active_for_authentication?
|
2011-03-28 15:26:53 -04:00
|
|
|
true
|
2010-04-06 10:34:22 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def inactive_message
|
|
|
|
:inactive
|
2010-03-29 17:44:47 -04:00
|
|
|
end
|
|
|
|
|
2010-09-25 11:24:42 -04:00
|
|
|
def authenticatable_salt
|
|
|
|
end
|
|
|
|
|
2015-03-31 13:09:34 -04:00
|
|
|
# Redefine serializable_hash in models for more secure defaults.
|
|
|
|
# By default, it removes from the serializable model all attributes that
|
|
|
|
# are *not* accessible. You can remove this default by using :force_except
|
|
|
|
# and passing a new list of attributes you want to exempt. All attributes
|
|
|
|
# given to :except will simply add names to exempt to Devise internal list.
|
|
|
|
def serializable_hash(options = nil)
|
|
|
|
options ||= {}
|
|
|
|
options[:except] = Array(options[:except])
|
|
|
|
|
|
|
|
if options[:force_except]
|
|
|
|
options[:except].concat Array(options[:force_except])
|
|
|
|
else
|
|
|
|
options[:except].concat BLACKLIST_FOR_SERIALIZATION
|
|
|
|
end
|
|
|
|
|
|
|
|
super(options)
|
2012-02-15 13:52:10 -05:00
|
|
|
end
|
|
|
|
|
2012-06-16 07:00:51 -04:00
|
|
|
protected
|
|
|
|
|
2012-06-16 07:06:52 -04:00
|
|
|
def devise_mailer
|
|
|
|
Devise.mailer
|
|
|
|
end
|
|
|
|
|
2012-06-16 07:00:51 -04:00
|
|
|
# This is an internal method called every time Devise needs
|
2014-01-09 11:00:27 -05:00
|
|
|
# to send a notification/mail. This can be overridden if you
|
2012-06-16 07:00:51 -04:00
|
|
|
# need to customize the e-mail delivery logic. For instance,
|
|
|
|
# if you are using a queue to deliver e-mails (delayed job,
|
|
|
|
# sidekiq, resque, etc), you must add the delivery to the queue
|
|
|
|
# just after the transaction was committed. To achieve this,
|
|
|
|
# you can override send_devise_notification to store the
|
|
|
|
# deliveries until the after_commit callback is triggered:
|
|
|
|
#
|
|
|
|
# class User
|
|
|
|
# devise :database_authenticatable, :confirmable
|
|
|
|
#
|
|
|
|
# after_commit :send_pending_notifications
|
|
|
|
#
|
|
|
|
# protected
|
|
|
|
#
|
2013-08-05 12:56:07 -04:00
|
|
|
# def send_devise_notification(notification, *args)
|
|
|
|
# # If the record is new or changed then delay the
|
2013-03-01 09:32:15 -05:00
|
|
|
# # delivery until the after_commit callback otherwise
|
|
|
|
# # send now because after_commit will not be called.
|
|
|
|
# if new_record? || changed?
|
2013-08-05 12:56:07 -04:00
|
|
|
# pending_notifications << [notification, args]
|
2013-03-01 09:32:15 -05:00
|
|
|
# else
|
2013-08-05 12:56:07 -04:00
|
|
|
# devise_mailer.send(notification, self, *args).deliver
|
2013-03-01 09:32:15 -05:00
|
|
|
# end
|
2012-06-16 07:00:51 -04:00
|
|
|
# end
|
|
|
|
#
|
|
|
|
# def send_pending_notifications
|
2013-08-05 12:56:07 -04:00
|
|
|
# pending_notifications.each do |notification, args|
|
|
|
|
# devise_mailer.send(notification, self, *args).deliver
|
2012-06-16 07:00:51 -04:00
|
|
|
# end
|
2013-03-01 09:32:15 -05:00
|
|
|
#
|
|
|
|
# # Empty the pending notifications array because the
|
|
|
|
# # after_commit hook can be called multiple times which
|
|
|
|
# # could cause multiple emails to be sent.
|
|
|
|
# pending_notifications.clear
|
2012-06-16 07:00:51 -04:00
|
|
|
# end
|
|
|
|
#
|
|
|
|
# def pending_notifications
|
|
|
|
# @pending_notifications ||= []
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
2013-08-05 12:56:07 -04:00
|
|
|
def send_devise_notification(notification, *args)
|
2014-09-02 13:50:57 -04:00
|
|
|
message = devise_mailer.send(notification, self, *args)
|
|
|
|
# Remove once we move to Rails 4.2+ only.
|
|
|
|
if message.respond_to?(:deliver_now)
|
|
|
|
message.deliver_now
|
|
|
|
else
|
|
|
|
message.deliver
|
|
|
|
end
|
2012-06-16 07:00:51 -04:00
|
|
|
end
|
|
|
|
|
2012-06-16 07:06:52 -04:00
|
|
|
def downcase_keys
|
2013-10-17 19:07:42 -04:00
|
|
|
self.class.case_insensitive_keys.each { |k| apply_to_attribute_or_variable(k, :downcase) }
|
2012-06-16 07:06:52 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def strip_whitespace
|
2013-10-17 19:07:42 -04:00
|
|
|
self.class.strip_whitespace_keys.each { |k| apply_to_attribute_or_variable(k, :strip) }
|
2012-12-01 22:01:13 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def apply_to_attribute_or_variable(attr, method)
|
2013-01-09 12:42:54 -05:00
|
|
|
if self[attr]
|
2013-10-17 19:07:42 -04:00
|
|
|
self[attr] = self[attr].try(method)
|
2013-01-09 12:42:54 -05:00
|
|
|
|
|
|
|
# Use respond_to? here to avoid a regression where globally
|
|
|
|
# configured strip_whitespace_keys or case_insensitive_keys were
|
2013-10-18 07:45:21 -04:00
|
|
|
# attempting to strip or downcase when a model didn't have the
|
2013-01-09 12:42:54 -05:00
|
|
|
# globally configured key.
|
2013-10-17 19:07:42 -04:00
|
|
|
elsif respond_to?(attr) && respond_to?("#{attr}=")
|
|
|
|
new_value = send(attr).try(method)
|
|
|
|
send("#{attr}=", new_value)
|
2013-01-09 12:42:54 -05:00
|
|
|
end
|
2012-06-16 07:06:52 -04:00
|
|
|
end
|
|
|
|
|
2010-03-29 14:52:34 -04:00
|
|
|
module ClassMethods
|
2011-12-04 17:58:19 -05:00
|
|
|
Devise::Models.config(self, :authentication_keys, :request_keys, :strip_whitespace_keys,
|
2013-03-04 12:18:20 -05:00
|
|
|
:case_insensitive_keys, :http_authenticatable, :params_authenticatable, :skip_session_storage,
|
2013-04-14 01:07:54 -04:00
|
|
|
:http_authentication_key)
|
2010-04-01 13:09:33 -04:00
|
|
|
|
2011-08-29 08:40:10 -04:00
|
|
|
def serialize_into_session(record)
|
2015-02-19 06:13:57 -05:00
|
|
|
[record.to_key, record.authenticatable_salt]
|
2011-08-29 08:40:10 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def serialize_from_session(key, salt)
|
|
|
|
record = to_adapter.get(key)
|
|
|
|
record if record && record.authenticatable_salt == salt
|
|
|
|
end
|
|
|
|
|
2010-04-01 13:09:33 -04:00
|
|
|
def params_authenticatable?(strategy)
|
|
|
|
params_authenticatable.is_a?(Array) ?
|
|
|
|
params_authenticatable.include?(strategy) : params_authenticatable
|
|
|
|
end
|
2010-03-29 14:52:34 -04:00
|
|
|
|
2010-04-01 13:09:33 -04:00
|
|
|
def http_authenticatable?(strategy)
|
|
|
|
http_authenticatable.is_a?(Array) ?
|
|
|
|
http_authenticatable.include?(strategy) : http_authenticatable
|
|
|
|
end
|
2010-03-29 14:52:34 -04:00
|
|
|
|
|
|
|
# Find first record based on conditions given (ie by the sign in form).
|
2012-03-30 03:00:03 -04:00
|
|
|
# This method is always called during an authentication process but
|
|
|
|
# it may be wrapped as well. For instance, database authenticatable
|
|
|
|
# provides a `find_for_database_authentication` that wraps a call to
|
|
|
|
# this method. This allows you to customize both database authenticatable
|
2012-12-04 14:37:12 -05:00
|
|
|
# or the whole authenticate stack by customize `find_for_authentication.`
|
2012-03-30 03:00:03 -04:00
|
|
|
#
|
2010-03-29 14:52:34 -04:00
|
|
|
# Overwrite to add customized conditions, create a join, or maybe use a
|
|
|
|
# namedscope to filter records while authenticating.
|
|
|
|
# Example:
|
|
|
|
#
|
2013-01-26 13:42:25 -05:00
|
|
|
# def self.find_for_authentication(tainted_conditions)
|
2014-02-25 11:42:55 -05:00
|
|
|
# find_first_by_auth_conditions(tainted_conditions, active: true)
|
2010-03-29 14:52:34 -04:00
|
|
|
# end
|
|
|
|
#
|
2012-03-30 03:00:03 -04:00
|
|
|
# Finally, notice that Devise also queries for users in other scenarios
|
|
|
|
# besides authentication, for example when retrieving an user to send
|
|
|
|
# an e-mail for password reset. In such cases, find_for_authentication
|
|
|
|
# is not called.
|
2013-01-26 13:42:25 -05:00
|
|
|
def find_for_authentication(tainted_conditions)
|
|
|
|
find_first_by_auth_conditions(tainted_conditions)
|
2011-11-10 07:14:02 -05:00
|
|
|
end
|
|
|
|
|
2013-01-26 13:42:25 -05:00
|
|
|
def find_first_by_auth_conditions(tainted_conditions, opts={})
|
2013-06-19 03:17:54 -04:00
|
|
|
to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
|
2010-03-29 14:52:34 -04:00
|
|
|
end
|
2010-04-16 16:00:06 -04:00
|
|
|
|
2014-12-11 22:55:25 -05:00
|
|
|
# Find or initialize a record setting an error if it can't be found.
|
2010-04-16 16:00:06 -04:00
|
|
|
def find_or_initialize_with_error_by(attribute, value, error=:invalid) #:nodoc:
|
2010-09-21 06:05:17 -04:00
|
|
|
find_or_initialize_with_errors([attribute], { attribute => value }, error)
|
2010-04-16 16:00:06 -04:00
|
|
|
end
|
2010-09-21 06:05:17 -04:00
|
|
|
|
2014-12-11 22:55:25 -05:00
|
|
|
# Find or initialize a record with group of attributes based on a list of required attributes.
|
2010-07-25 13:53:42 -04:00
|
|
|
def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
|
2015-12-15 14:26:19 -05:00
|
|
|
attributes = if attributes.respond_to? :permit
|
|
|
|
attributes.slice(*required_attributes).permit!.to_h.with_indifferent_access
|
|
|
|
else
|
|
|
|
attributes.with_indifferent_access.slice(*required_attributes)
|
|
|
|
end
|
2010-07-25 13:53:42 -04:00
|
|
|
attributes.delete_if { |key, value| value.blank? }
|
|
|
|
|
|
|
|
if attributes.size == required_attributes.size
|
2012-03-30 02:53:35 -04:00
|
|
|
record = find_first_by_auth_conditions(attributes)
|
2010-07-25 13:53:42 -04:00
|
|
|
end
|
2011-05-16 14:08:22 -04:00
|
|
|
|
2010-07-25 13:53:42 -04:00
|
|
|
unless record
|
|
|
|
record = new
|
|
|
|
|
2010-09-21 06:05:17 -04:00
|
|
|
required_attributes.each do |key|
|
2010-09-24 05:30:08 -04:00
|
|
|
value = attributes[key]
|
|
|
|
record.send("#{key}=", value)
|
|
|
|
record.errors.add(key, value.present? ? error : :blank)
|
2010-07-25 13:53:42 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
record
|
|
|
|
end
|
2010-07-18 17:32:56 -04:00
|
|
|
|
2011-03-11 14:46:08 -05:00
|
|
|
protected
|
|
|
|
|
2013-06-19 03:17:54 -04:00
|
|
|
def devise_parameter_filter
|
|
|
|
@devise_parameter_filter ||= Devise::ParameterFilter.new(case_insensitive_keys, strip_whitespace_keys)
|
2011-05-26 09:45:03 -04:00
|
|
|
end
|
2010-03-29 14:52:34 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2012-03-13 13:24:21 -04:00
|
|
|
end
|