2010-04-06 10:34:22 -04:00
|
|
|
require 'devise/hooks/activatable'
|
|
|
|
|
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
|
|
|
#
|
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
|
|
|
|
# as key on authentication. This can also be a hash where the value is a boolean expliciting
|
|
|
|
# if the value is required or not.
|
|
|
|
#
|
2010-07-15 07:01:31 -04:00
|
|
|
# * +http_authenticatable+: if this model allows http authentication. By default true.
|
|
|
|
# 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.
|
|
|
|
# You can skip storage for http and token auth by appending values to array:
|
|
|
|
# :skip_session_storage => [:token_auth] or :skip_session_storage => [:http_auth, :token_auth],
|
|
|
|
# by default is set to :skip_session_storage => [:http_auth].
|
|
|
|
#
|
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
|
2011-03-25 10:39:08 -04:00
|
|
|
# calling model.active_for_authentication?. This method is overwriten by other devise modules. For instance,
|
|
|
|
# :confirmable overwrites .active_for_authentication? to only return true if your model was confirmed.
|
2010-04-06 10:34:22 -04:00
|
|
|
#
|
|
|
|
# You overwrite this method yourself, but if you do, don't forget to call super:
|
|
|
|
#
|
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,
|
2012-03-30 03:05:58 -04:00
|
|
|
:remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at, :authentication_token]
|
2012-02-15 14:18:52 -05:00
|
|
|
|
2010-04-16 16:00:06 -04:00
|
|
|
included do
|
|
|
|
class_attribute :devise_modules, :instance_writer => false
|
|
|
|
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
|
|
|
|
|
2011-11-05 11:53:27 -04:00
|
|
|
def devise_mailer
|
|
|
|
Devise.mailer
|
|
|
|
end
|
|
|
|
|
2011-12-04 17:58:19 -05:00
|
|
|
def headers_for(name)
|
|
|
|
{}
|
|
|
|
end
|
|
|
|
|
|
|
|
def downcase_keys
|
2012-05-06 07:13:53 -04:00
|
|
|
self.class.case_insensitive_keys.each { |k| self[k].try(:downcase!) }
|
2011-12-04 17:58:19 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def strip_whitespace
|
2012-05-06 07:13:53 -04:00
|
|
|
self.class.strip_whitespace_keys.each { |k| self[k].try(:strip!) }
|
2011-12-04 17:58:19 -05:00
|
|
|
end
|
|
|
|
|
2012-02-15 13:52:10 -05:00
|
|
|
array = %w(serializable_hash)
|
|
|
|
# to_xml does not call serializable_hash on 3.1
|
|
|
|
array << "to_xml" if Rails::VERSION::STRING[0,3] == "3.1"
|
|
|
|
|
|
|
|
array.each do |method|
|
|
|
|
class_eval <<-RUBY, __FILE__, __LINE__
|
2012-02-15 14:05:18 -05:00
|
|
|
# Redefine to_xml and serializable_hash in models for more secure defaults.
|
2012-02-15 13:52:10 -05:00
|
|
|
# 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 #{method}(options=nil)
|
|
|
|
options ||= {}
|
|
|
|
options[:except] = Array(options[:except])
|
|
|
|
|
|
|
|
if options[:force_except]
|
|
|
|
options[:except].concat Array(options[:force_except])
|
|
|
|
else
|
2012-02-15 14:18:52 -05:00
|
|
|
options[:except].concat BLACKLIST_FOR_SERIALIZATION
|
2012-02-15 13:52:10 -05:00
|
|
|
end
|
|
|
|
super(options)
|
|
|
|
end
|
|
|
|
RUBY
|
|
|
|
end
|
|
|
|
|
2012-06-16 07:00:51 -04:00
|
|
|
protected
|
|
|
|
|
|
|
|
# This is an internal method called every time Devise needs
|
|
|
|
# to send a notification/mail. This can be overriden if you
|
|
|
|
# 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
|
|
|
|
#
|
|
|
|
# def send_devise_notification(notification)
|
|
|
|
# pending_notifications << notification
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# def send_pending_notifications
|
|
|
|
# pending_notifications.each do |n|
|
|
|
|
# devise_mailer.send(n, self).deliver
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# def pending_notifications
|
|
|
|
# @pending_notifications ||= []
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
def send_devise_notification(notification)
|
|
|
|
devise_mailer.send(notification, self).deliver
|
|
|
|
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,
|
2011-12-11 14:39:41 -05:00
|
|
|
:case_insensitive_keys, :http_authenticatable, :params_authenticatable, :skip_session_storage)
|
2010-04-01 13:09:33 -04:00
|
|
|
|
2011-08-29 08:40:10 -04:00
|
|
|
def serialize_into_session(record)
|
|
|
|
[record.to_key, record.authenticatable_salt]
|
|
|
|
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
|
|
|
|
# or the whole authenticate stack by customize `find_for_authentication.`
|
|
|
|
#
|
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:
|
|
|
|
#
|
|
|
|
# def self.find_for_authentication(conditions={})
|
|
|
|
# conditions[:active] = true
|
|
|
|
# super
|
|
|
|
# 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.
|
2010-03-29 14:52:34 -04:00
|
|
|
def find_for_authentication(conditions)
|
2011-11-10 07:14:02 -05:00
|
|
|
find_first_by_auth_conditions(conditions)
|
|
|
|
end
|
|
|
|
|
|
|
|
def find_first_by_auth_conditions(conditions)
|
|
|
|
to_adapter.find_first devise_param_filter.filter(conditions)
|
2010-03-29 14:52:34 -04:00
|
|
|
end
|
2010-04-16 16:00:06 -04:00
|
|
|
|
|
|
|
# Find an initialize a record setting an error if it can't be found.
|
|
|
|
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
|
|
|
|
|
|
|
# Find an initialize a 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:
|
|
|
|
attributes = attributes.slice(*required_attributes)
|
|
|
|
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
|
|
|
|
|
2011-11-10 07:14:02 -05:00
|
|
|
def devise_param_filter
|
|
|
|
@devise_param_filter ||= Devise::ParamFilter.new(case_insensitive_keys, strip_whitespace_keys)
|
2011-05-26 09:45:03 -04:00
|
|
|
end
|
2011-03-11 14:46:08 -05:00
|
|
|
|
2010-07-18 17:32:56 -04:00
|
|
|
# Generate a token by looping and ensuring does not already exist.
|
|
|
|
def generate_token(column)
|
|
|
|
loop do
|
|
|
|
token = Devise.friendly_token
|
2010-10-16 15:49:05 -04:00
|
|
|
break token unless to_adapter.find_first({ column => token })
|
2010-07-18 17:32:56 -04:00
|
|
|
end
|
|
|
|
end
|
2010-03-29 14:52:34 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2012-03-13 13:24:21 -04:00
|
|
|
end
|