2010-03-29 14:13:19 +00:00
|
|
|
require 'devise/strategies/database_authenticatable'
|
2010-09-25 14:08:46 +00:00
|
|
|
require 'bcrypt'
|
2009-10-12 11:37:28 +00:00
|
|
|
|
2009-09-17 12:24:33 +00:00
|
|
|
module Devise
|
2009-10-09 11:30:25 +00:00
|
|
|
module Models
|
2011-01-11 18:53:17 +00:00
|
|
|
# Authenticatable Module, responsible for encrypting password and validating
|
2009-10-09 12:27:44 +00:00
|
|
|
# authenticity of a user while signing in.
|
|
|
|
#
|
2010-07-15 11:01:31 +00:00
|
|
|
# == Options
|
2009-10-20 13:55:57 +00:00
|
|
|
#
|
2010-07-15 11:01:31 +00:00
|
|
|
# DatabaseAuthenticable adds the following options to devise_for:
|
2009-10-20 13:55:57 +00:00
|
|
|
#
|
2011-08-05 10:07:54 +00:00
|
|
|
# * +pepper+: a random string used to provide a more secure hash. Use
|
|
|
|
# `rake secret` to generate new keys.
|
|
|
|
#
|
2010-09-25 14:08:46 +00:00
|
|
|
# * +stretches+: the cost given to bcrypt.
|
2009-11-15 05:31:13 +00:00
|
|
|
#
|
2010-07-15 11:01:31 +00:00
|
|
|
# == Examples
|
2009-10-09 12:27:44 +00:00
|
|
|
#
|
|
|
|
# User.find(1).valid_password?('password123') # returns true/false
|
2009-10-20 13:55:57 +00:00
|
|
|
#
|
2010-03-29 14:13:19 +00:00
|
|
|
module DatabaseAuthenticatable
|
2010-04-06 14:34:22 +00:00
|
|
|
extend ActiveSupport::Concern
|
2009-09-17 14:06:46 +00:00
|
|
|
|
2010-02-17 11:35:38 +00:00
|
|
|
included do
|
|
|
|
attr_reader :password, :current_password
|
|
|
|
attr_accessor :password_confirmation
|
2009-09-17 12:24:33 +00:00
|
|
|
end
|
|
|
|
|
2012-02-17 16:37:44 +00:00
|
|
|
module ModuleMethods
|
|
|
|
extend self
|
|
|
|
|
|
|
|
def required_fields
|
2012-02-17 16:52:42 +00:00
|
|
|
[:encrypted_password] + Devise.authentication_keys
|
2012-02-17 16:37:44 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-09-26 14:47:56 +00:00
|
|
|
# Generates password encryption based on the given value.
|
2009-10-15 18:52:25 +00:00
|
|
|
def password=(new_password)
|
|
|
|
@password = new_password
|
2010-09-25 14:08:46 +00:00
|
|
|
self.encrypted_password = password_digest(@password) if @password.present?
|
2009-10-15 18:52:25 +00:00
|
|
|
end
|
|
|
|
|
2011-02-15 10:33:54 +00:00
|
|
|
# Verifies whether an password (ie from sign in) is the user password.
|
2010-09-28 15:45:06 +00:00
|
|
|
def valid_password?(password)
|
2011-04-16 10:43:43 +00:00
|
|
|
return false if encrypted_password.blank?
|
|
|
|
bcrypt = ::BCrypt::Password.new(self.encrypted_password)
|
|
|
|
password = ::BCrypt::Engine.hash_secret("#{password}#{self.class.pepper}", bcrypt.salt)
|
|
|
|
Devise.secure_compare(password, self.encrypted_password)
|
2010-01-24 02:38:52 +00:00
|
|
|
end
|
|
|
|
|
2010-02-08 22:14:03 +00:00
|
|
|
# Set password and password confirmation to nil
|
|
|
|
def clean_up_passwords
|
2011-09-02 17:14:15 +00:00
|
|
|
self.password = self.password_confirmation = nil
|
2010-02-08 22:14:03 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# Update record attributes when :current_password matches, otherwise returns
|
|
|
|
# error on :current_password. It also automatically rejects :password and
|
|
|
|
# :password_confirmation if they are blank.
|
2011-11-24 08:51:03 +00:00
|
|
|
def update_with_password(params, *options)
|
2010-02-16 13:31:49 +00:00
|
|
|
current_password = params.delete(:current_password)
|
2010-02-08 19:38:47 +00:00
|
|
|
|
2010-04-25 07:38:56 +00:00
|
|
|
if params[:password].blank?
|
|
|
|
params.delete(:password)
|
|
|
|
params.delete(:password_confirmation) if params[:password_confirmation].blank?
|
|
|
|
end
|
2010-02-08 22:14:03 +00:00
|
|
|
|
2010-02-15 13:15:24 +00:00
|
|
|
result = if valid_password?(current_password)
|
2011-11-24 09:24:06 +00:00
|
|
|
update_attributes(params, *options)
|
2009-12-15 00:55:55 +00:00
|
|
|
else
|
2010-04-01 12:00:21 +00:00
|
|
|
self.attributes = params
|
2011-06-21 21:23:07 +00:00
|
|
|
self.valid?
|
|
|
|
self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
2009-12-15 00:55:55 +00:00
|
|
|
false
|
|
|
|
end
|
2010-02-08 22:14:03 +00:00
|
|
|
|
2010-04-01 12:00:21 +00:00
|
|
|
clean_up_passwords
|
2010-02-08 22:14:03 +00:00
|
|
|
result
|
2009-12-15 00:55:55 +00:00
|
|
|
end
|
|
|
|
|
2011-06-22 16:01:49 +00:00
|
|
|
# Updates record attributes without asking for the current password.
|
2011-10-25 16:37:53 +00:00
|
|
|
# Never allows to change the current password. If you are using this
|
|
|
|
# method, you should probably override this method to protect other
|
|
|
|
# attributes you would not like to be updated without a password.
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
#
|
|
|
|
# def update_without_password(params={})
|
|
|
|
# params.delete(:email)
|
|
|
|
# super(params)
|
|
|
|
# end
|
|
|
|
#
|
2011-11-24 08:51:03 +00:00
|
|
|
def update_without_password(params, *options)
|
2011-05-05 07:24:21 +00:00
|
|
|
params.delete(:password)
|
|
|
|
params.delete(:password_confirmation)
|
|
|
|
|
2011-11-24 09:24:06 +00:00
|
|
|
result = update_attributes(params, *options)
|
2011-05-05 07:24:21 +00:00
|
|
|
clean_up_passwords
|
|
|
|
result
|
|
|
|
end
|
2011-11-24 09:24:06 +00:00
|
|
|
|
2010-04-06 11:26:56 +00:00
|
|
|
def after_database_authentication
|
|
|
|
end
|
|
|
|
|
2010-09-25 14:08:46 +00:00
|
|
|
# A reliable way to expose the salt regardless of the implementation.
|
|
|
|
def authenticatable_salt
|
2010-11-11 21:51:19 +00:00
|
|
|
self.encrypted_password[0,29] if self.encrypted_password
|
2010-09-25 14:08:46 +00:00
|
|
|
end
|
|
|
|
|
2010-03-29 21:44:47 +00:00
|
|
|
protected
|
2009-11-18 11:26:47 +00:00
|
|
|
|
2010-09-25 14:08:46 +00:00
|
|
|
# Digests the password using bcrypt.
|
2010-03-29 21:44:47 +00:00
|
|
|
def password_digest(password)
|
2010-09-28 15:45:06 +00:00
|
|
|
::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
|
2010-03-29 21:44:47 +00:00
|
|
|
end
|
2009-10-09 11:30:25 +00:00
|
|
|
|
|
|
|
module ClassMethods
|
2010-11-20 20:19:12 +00:00
|
|
|
Devise::Models.config(self, :pepper, :stretches)
|
2010-07-12 04:59:49 +00:00
|
|
|
|
2010-07-05 17:11:37 +00:00
|
|
|
# We assume this method already gets the sanitized values from the
|
|
|
|
# DatabaseAuthenticatable strategy. If you are using this method on
|
|
|
|
# your own, be sure to sanitize the conditions hash to only include
|
|
|
|
# the proper fields.
|
2010-04-06 11:26:56 +00:00
|
|
|
def find_for_database_authentication(conditions)
|
|
|
|
find_for_authentication(conditions)
|
2009-11-19 15:53:57 +00:00
|
|
|
end
|
2009-11-23 00:32:54 +00:00
|
|
|
end
|
2009-09-17 12:46:40 +00:00
|
|
|
end
|
2009-09-17 12:24:33 +00:00
|
|
|
end
|
|
|
|
end
|