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

Deprecate and disable old behavior accumulated with time.

This commit is contained in:
José Valim 2011-12-04 23:58:19 +01:00
parent 03d9ebb56e
commit bd27bf7677
20 changed files with 141 additions and 309 deletions

View file

@ -1,4 +1,4 @@
== 1.6.0 (unreleased)
== 2.0.0 (unreleased)
* enhancements
* Add support for e-mail reconfirmation on change (by github.com/Mandaryn and github.com/heimidal)

View file

@ -84,7 +84,7 @@ module Devise
# False by default for backwards compatibility.
mattr_accessor :case_insensitive_keys
@@case_insensitive_keys = false
# Keys that should have whitespace stripped.
# False by default for backwards compatibility.
mattr_accessor :strip_whitespace_keys
@ -120,27 +120,20 @@ module Devise
mattr_accessor :remember_for
@@remember_for = 2.weeks
# If true, a valid remember token can be re-used between multiple browsers.
mattr_accessor :remember_across_browsers
@@remember_across_browsers = true
# If true, extends the user's remember period when remembered via cookie.
mattr_accessor :extend_remember_period
@@extend_remember_period = false
# If true, uses salt as remember token and does not create it in the database.
# By default is false for backwards compatibility.
mattr_accessor :use_salt_as_remember_token
@@use_salt_as_remember_token = false
# Time interval you can access your account before confirming your account.
mattr_accessor :confirm_within
@@confirm_within = 0.days
# Defines which key will be used when confirming an account
# Defines which key will be used when confirming an account.
mattr_accessor :confirmation_keys
@@confirmation_keys = [ :email ]
# Defines if email should be reconfirmable.
# False by default for backwards compatibility.
mattr_accessor :reconfirmable
@@reconfirmable = false
@ -156,11 +149,6 @@ module Devise
mattr_accessor :encryptor
@@encryptor = nil
# Tells if devise should apply the schema in ORMs where devise declaration
# and schema belongs to the same class (as Datamapper and Mongoid).
mattr_accessor :apply_schema
@@apply_schema = true
# Scoped views. Since it relies on fallbacks to render default views, it's
# turned off by default.
mattr_accessor :scoped_views
@ -193,6 +181,7 @@ module Devise
@@reset_password_keys = [ :email ]
# Time interval you can reset your password with a reset password key
# Nil by default for backwards compatibility.
mattr_accessor :reset_password_within
@@reset_password_within = nil
@ -225,6 +214,22 @@ module Devise
mattr_accessor :sign_out_via
@@sign_out_via = :get
# DEPRECATED CONFIG
# If true, uses salt as remember token and does not create it in the database.
# By default is false for backwards compatibility.
mattr_accessor :use_salt_as_remember_token
@@use_salt_as_remember_token = false
# Tells if devise should apply the schema in ORMs where devise declaration
# and schema belongs to the same class (as Datamapper and Mongoid).
mattr_accessor :apply_schema
@@apply_schema = true
def self.remember_across_browsers=(value)
puts "\n[DEVISE] Devise.remember_across_browsers is deprecated and has no effect. Please remove it."
end
# PRIVATE CONFIGURATION
# Store scopes mappings.

View file

@ -93,8 +93,15 @@ MESSAGE
def require_no_authentication
return unless is_navigational_format?
no_input = devise_mapping.no_input_strategies
args = no_input.dup.push :scope => resource_name
if no_input.present? && warden.authenticate?(*args)
authenticated = if no_input.present?
args = no_input.dup.push :scope => resource_name
warden.authenticate?(*args)
else
warden.authenticated?(resource_name)
end
if authenticated
resource = warden.user(resource_name)
flash[:alert] = I18n.t("devise.failure.already_authenticated")
redirect_to after_sign_in_path_for(resource)

View file

@ -52,6 +52,9 @@ module Devise
included do
class_attribute :devise_modules, :instance_writer => false
self.devise_modules ||= []
before_validation :downcase_keys
before_validation :strip_whitespace
end
# Check if the current object is valid for authentication. This method and
@ -79,8 +82,21 @@ module Devise
Devise.mailer
end
def headers_for(name)
{}
end
def downcase_keys
(self.class.case_insensitive_keys || []).each { |k| self[k].try(:downcase!) }
end
def strip_whitespace
(self.class.strip_whitespace_keys || []).each { |k| self[k].try(:strip!) }
end
module ClassMethods
Devise::Models.config(self, :authentication_keys, :request_keys, :strip_whitespace_keys, :case_insensitive_keys, :http_authenticatable, :params_authenticatable)
Devise::Models.config(self, :authentication_keys, :request_keys, :strip_whitespace_keys,
:case_insensitive_keys, :http_authenticatable, :params_authenticatable)
def serialize_into_session(record)
[record.to_key, record.authenticatable_salt]

View file

@ -67,7 +67,7 @@ module Devise
# Send confirmation instructions by email
def send_confirmation_instructions
@reconfirmation_required = false
generate_confirmation_token! if self.confirmation_token.nil?
generate_confirmation_token! if self.confirmation_token.blank?
self.devise_mailer.confirmation_instructions(self).deliver
end
@ -96,11 +96,11 @@ module Devise
end
def headers_for(action)
if action == :confirmation_instructions && respond_to?(:unconfirmed_email)
{ :to => unconfirmed_email.present? ? unconfirmed_email : email }
else
{}
headers = super
if action == :confirmation_instructions && pending_reconfirmation?
headers[:to] = unconfirmed_email
end
headers
end
protected

View file

@ -25,8 +25,6 @@ module Devise
included do
attr_reader :password, :current_password
attr_accessor :password_confirmation
before_validation :downcase_keys
before_validation :strip_whitespace
end
# Generates password encryption based on the given value.
@ -103,15 +101,6 @@ module Devise
protected
# Downcase case-insensitive keys
def downcase_keys
(self.class.case_insensitive_keys || []).each { |k| self[k].try(:downcase!) }
end
def strip_whitespace
(self.class.strip_whitespace_keys || []).each { |k| self[k].try(:strip!) }
end
# Digests the password using bcrypt.
def password_digest(password)
::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s

View file

@ -29,6 +29,7 @@ module Devise
def reset_password!(new_password, new_password_confirmation)
self.password = new_password
self.password_confirmation = new_password_confirmation
if valid?
clear_reset_password_token
after_password_reset
@ -64,7 +65,6 @@ module Devise
# reset_password_period_valid? # will always return false
#
def reset_password_period_valid?
return true unless respond_to?(:reset_password_sent_at)
reset_password_sent_at && reset_password_sent_at.utc >= self.class.reset_password_within.ago
end
@ -77,7 +77,7 @@ module Devise
# Generates a new random token for reset password
def generate_reset_password_token
self.reset_password_token = self.class.reset_password_token
self.reset_password_sent_at = Time.now.utc if respond_to?(:reset_password_sent_at=)
self.reset_password_sent_at = Time.now.utc
self.reset_password_token
end
@ -90,7 +90,7 @@ module Devise
# Removes reset_password token
def clear_reset_password_token
self.reset_password_token = nil
self.reset_password_sent_at = nil if respond_to?(:reset_password_sent_at=)
self.reset_password_sent_at = nil
end
def after_password_reset

View file

@ -21,11 +21,6 @@ module Devise
# used to calculate the expires time for the cookie created to remember
# the user. By default remember_for is 2.weeks.
#
# * +remember_across_browsers+: if a valid remember token can be re-used
# between multiple browsers. By default remember_across_browsers is true
# and cannot be turned off if you are using password salt instead of remember
# token.
#
# * +extend_remember_period+: if true, extends the user's remember period
# when remembered via cookie. False by default.
#
@ -49,7 +44,6 @@ module Devise
# Generate a new remember token and save the record without validations
# unless remember_across_browsers is true and the user already has a valid token.
def remember_me!(extend_period=false)
self.remember_token = self.class.remember_token if respond_to?(:remember_token) && generate_remember_token?
self.remember_created_at = Time.now.utc if generate_remember_timestamp?(extend_period)
save(:validate => false)
end
@ -75,9 +69,7 @@ module Devise
end
def rememberable_value
if respond_to?(:remember_token)
remember_token
elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt)
if respond_to?(:authenticatable_salt) && (salt = authenticatable_salt)
salt
else
raise "The #{self.class.name} class does not respond to remember_token and " <<
@ -92,12 +84,6 @@ module Devise
protected
# Generate a token unless remember_across_browsers is true and there is
# an existing remember_token or the existing remember_token has expried.
def generate_remember_token? #:nodoc:
!(self.class.remember_across_browsers && remember_token) || remember_expired?
end
# Generate a timestamp if extend_remember_period is true, if no remember_token
# exists, or if an existing remember token has expired.
def generate_remember_timestamp?(extend_period) #:nodoc:
@ -121,8 +107,7 @@ module Devise
generate_token(:remember_token)
end
Devise::Models.config(self, :remember_for, :remember_across_browsers,
:extend_remember_period, :cookie_options)
Devise::Models.config(self, :remember_for, :extend_remember_period, :cookie_options)
end
end
end

View file

@ -33,7 +33,7 @@ module Devise
private
def remember_exists_and_not_expired?
return false unless respond_to?(:remember_expired?)
return false unless respond_to?(:remember_created_at)
remember_created_at && !remember_expired?
end

View file

@ -23,7 +23,7 @@ module Devise
base.class_eval do
validates_presence_of :email, :if => :email_required?
validates_uniqueness_of :email, :case_sensitive => (case_insensitive_keys != false), :allow_blank => true, :if => :email_changed?
validates_uniqueness_of :email, :allow_blank => true, :if => :email_changed?
validates_format_of :email, :with => email_regexp, :allow_blank => true, :if => :email_changed?
validates_presence_of :password, :if => :password_required?

View file

@ -41,5 +41,32 @@ module Devise
end
end
end
initializer "devise.deprecations" do
if Devise.case_insensitive_keys == false
puts "\n[DEVISE] Devise.case_insensitive_keys is false and is no longer " \
"supported. If you want to continue running on this mode, please ensure " \
"you are not using validatable in your models and set this value to an empty array."
end
if Devise.apply_schema && defined?(Mongoid)
puts "\n[DEVISE] Devise.apply_schema is true. This means Devise was " \
"automatically configuring your DB. This no longer happens. You should " \
"set this options to false and manually set the fields used by Devise."
end
# TODO: Deprecate the true value of this option as well
if Devise.use_salt_as_remember_token == false
puts "\n[DEVISE] Devise.use_salt_as_remember_token is false and is no longer " \
"supported. Devise will use part of salt as remember token and the remember " \
"token column can be removed from your models."
end
if Devise.reset_password_within.nil?
puts "\n[DEVISE] Devise.reset_password_within is nil. Please set this value to " \
"an interval (for example, 6.hours) and add a reset_password_sent_at field to " \
"your Devise models (if they don't have one already)."
end
end
end
end

View file

@ -92,9 +92,6 @@ Devise.setup do |config|
# The time the user will be remembered without asking for credentials again.
# config.remember_for = 2.weeks
# If true, a valid remember token can be re-used between multiple browsers.
# config.remember_across_browsers = true
# If true, extends the user's remember period when remembered via cookie.
# config.extend_remember_period = false
@ -151,7 +148,7 @@ Devise.setup do |config|
# Time interval you can reset your password with a reset password key.
# Don't put a too small interval or your users won't have the time to
# change their passwords.
config.reset_password_within = 2.hours
config.reset_password_within = 6.hours
# ==> Configuration for :encryptable
# Allow you to use another encryption algorithm besides bcrypt (default). You can use

View file

@ -45,10 +45,12 @@ class HelpersTest < ActionController::TestCase
@controller.send :require_no_authentication
end
test 'require no authentication skips if no inputs are available' do
test 'require no authentication only checks if already authenticated if no inputs strategies are available' do
Devise.mappings[:user].expects(:no_input_strategies).returns([])
@mock_warden.expects(:authenticate?).never
@controller.expects(:redirect_to).never
@mock_warden.expects(:authenticated?).with(:user).once.returns(true)
@mock_warden.expects(:user).with(:user).returns(User.new)
@controller.expects(:redirect_to).with(root_path)
@controller.send :require_no_authentication
end

View file

@ -9,14 +9,6 @@ class RememberMeTest < ActionController::IntegrationTest
user
end
def create_admin_and_remember
admin = create_admin
admin.remember_me!
raw_cookie = Admin.serialize_into_cookie(admin)
cookies['remember_admin_token'] = generate_signed_cookie(raw_cookie)
admin
end
def generate_signed_cookie(raw_cookie)
request = ActionDispatch::TestRequest.new
request.cookie_jar.signed['raw_cookie'] = raw_cookie
@ -117,34 +109,6 @@ class RememberMeTest < ActionController::IntegrationTest
end
end
test 'if both extend_remember_period and remember_across_browsers are true, sends the same token with a new expire date' do
swap Devise, :remember_across_browsers => true, :extend_remember_period => true, :remember_for => 1.year do
admin = create_admin_and_remember
token = admin.remember_token
admin.remember_created_at = old = 10.minutes.ago
admin.save!
get root_path
assert (cookie_expires("remember_admin_token") - 1.year) > (old + 5.minutes)
assert_equal token, signed_cookie("remember_admin_token").last
end
end
test 'if both extend_remember_period and remember_across_browsers are false, sends a new token with old expire date' do
swap Devise, :remember_across_browsers => false, :extend_remember_period => false, :remember_for => 1.year do
admin = create_admin_and_remember
token = admin.remember_token
admin.remember_created_at = old = 10.minutes.ago
admin.save!
get root_path
assert (cookie_expires("remember_admin_token") - 1.year) < (old + 5.minutes)
assert_not_equal token, signed_cookie("remember_admin_token").last
end
end
test 'do not remember other scopes' do
user = create_user_and_remember
get root_path
@ -182,20 +146,6 @@ class RememberMeTest < ActionController::IntegrationTest
assert_not warden.authenticated?(:user)
end
test 'do not remember the admin anymore after forget' do
admin = create_admin_and_remember
get root_path
assert warden.authenticated?(:admin)
get destroy_admin_session_path
assert_not warden.authenticated?(:admin)
assert_nil admin.reload.remember_token
assert_nil warden.cookies['remember_admin_token']
get root_path
assert_not warden.authenticated?(:admin)
end
test 'changing user password expires remember me token' do
user = create_user_and_remember
user.password = "another_password"

View file

@ -51,12 +51,12 @@ class MappingTest < ActiveSupport::TestCase
test 'has strategies depending on the model declaration' do
assert_equal [:rememberable, :token_authenticatable, :database_authenticatable], Devise.mappings[:user].strategies
assert_equal [:rememberable, :database_authenticatable], Devise.mappings[:admin].strategies
assert_equal [:database_authenticatable], Devise.mappings[:admin].strategies
end
test 'has no input strategies depending on the model declaration' do
assert_equal [:rememberable, :token_authenticatable], Devise.mappings[:user].no_input_strategies
assert_equal [:rememberable], Devise.mappings[:admin].no_input_strategies
assert_equal [], Devise.mappings[:admin].no_input_strategies
end
test 'find scope for a given object' do

View file

@ -195,31 +195,4 @@ class RecoverableTest < ActiveSupport::TestCase
assert_equal "has expired, please request a new one", reset_password_user.errors[:reset_password_token].join
end
end
test 'should save the model when the reset_password_sent_at doesnt exist' do
user = create_user
def user.respond_to?(meth, *)
if meth == :reset_password_sent_at=
false
else
super
end
end
user.send_reset_password_instructions
user.reload
assert_not_nil user.reset_password_token
end
test 'should have valid period if does not respond to reset_password_sent_at' do
user = create_user
def user.respond_to?(meth, *)
if meth == :reset_password_sent_at
false
else
super
end
end
assert user.reset_password_period_valid?
end
end

View file

@ -1,7 +1,46 @@
require 'test_helper'
module SharedRememberableTest
extend ActiveSupport::Testing::Declarative
class RememberableTest < ActiveSupport::TestCase
def resource_class
User
end
def create_resource
create_user
end
test 'remember_me should not generate a new token if using salt' do
user = create_user
user.expects(:valid?).never
user.remember_me!
end
test 'forget_me should not clear remember token if using salt' do
user = create_user
user.remember_me!
user.expects(:valid?).never
user.forget_me!
end
test 'serialize into cookie' do
user = create_user
user.remember_me!
assert_equal [user.to_key, user.authenticatable_salt], User.serialize_into_cookie(user)
end
test 'serialize from cookie' do
user = create_user
user.remember_me!
assert_equal user, User.serialize_from_cookie(user.to_key, user.authenticatable_salt)
end
test 'raises a RuntimeError if authenticatable_salt is nil' do
user = User.new
user.encrypted_password = nil
assert_raise RuntimeError do
user.rememberable_value
end
end
test 'should respond to remember_me attribute' do
assert resource_class.new.respond_to?(:remember_me)
@ -127,161 +166,3 @@ module SharedRememberableTest
end
end
end
class RememberableTest < ActiveSupport::TestCase
include SharedRememberableTest
def resource_class
Admin
end
def create_resource
create_admin
end
test 'remember_me should generate a new token and save the record without validating' do
admin = create_admin
admin.expects(:valid?).never
token = admin.remember_token
admin.remember_me!
assert_not_equal token, admin.remember_token
assert_not admin.changed?
end
test 'forget_me should clear remember token and save the record without validating' do
admin = create_admin
admin.remember_me!
assert_not admin.remember_token.nil?
admin.expects(:valid?).never
admin.forget_me!
assert admin.remember_token.nil?
assert_not admin.changed?
end
test 'serialize into cookie' do
admin = create_admin
admin.remember_me!
assert_equal [admin.to_key, admin.remember_token], Admin.serialize_into_cookie(admin)
end
test 'serialize from cookie' do
admin = create_admin
admin.remember_me!
assert_equal admin, Admin.serialize_from_cookie(admin.to_key, admin.remember_token)
end
test 'if remember_across_browsers is true, remember_me! should create a new token if no token exists' do
swap Devise, :remember_across_browsers => true, :remember_for => 1.year do
admin = create_admin
assert_equal nil, admin.remember_token
admin.remember_me!
assert_not_equal nil, admin.remember_token
end
end
test 'if remember_across_browsers is true, remember_me! should create a new token if a token exists but has expired' do
swap Devise, :remember_across_browsers => true, :remember_for => 1.day do
admin = create_admin
admin.remember_me!
admin.remember_created_at = 2.days.ago
admin.save
token = admin.remember_token
admin.remember_me!
assert_not_equal token, admin.remember_token
end
end
test 'if remember_across_browsers is true, remember_me! should not create a new token if a token exists and has not expired' do
swap Devise, :remember_across_browsers => true, :remember_for => 2.days do
admin = create_admin
admin.remember_me!
admin.remember_created_at = 1.day.ago
admin.save
token = admin.remember_token
admin.remember_me!
assert_equal token, admin.remember_token
end
end
test 'if remember_across_browsers is false, remember_me! should create a new token if no token exists' do
swap Devise, :remember_across_browsers => false do
admin = create_admin
assert_equal nil, admin.remember_token
admin.remember_me!
assert_not_equal nil, admin.remember_token
end
end
test 'if remember_across_browsers is false, remember_me! should create a new token if a token exists but has expired' do
swap Devise, :remember_across_browsers => false, :remember_for => 1.day do
admin = create_admin
admin.remember_me!
admin.remember_created_at = 2.days.ago
admin.save
token = admin.remember_token
admin.remember_me!
assert_not_equal token, admin.remember_token
end
end
test 'if remember_across_browsers is false, remember_me! should create a new token if a token exists and has not expired' do
swap Devise, :remember_across_browsers => false, :remember_for => 2.days do
admin = create_admin
admin.remember_me!
admin.remember_created_at = 1.day.ago
admin.save
token = admin.remember_token
admin.remember_me!
assert_not_equal token, admin.remember_token
end
end
end
class WithSaltRememberableTest < ActiveSupport::TestCase
include SharedRememberableTest
setup do
assert_not User.new.respond_to?(:remember_token)
end
def resource_class
User
end
def create_resource
create_user
end
test 'remember_me should not generate a new token if using salt' do
user = create_user
user.expects(:valid?).never
user.remember_me!
end
test 'forget_me should not clear remember token if using salt' do
user = create_user
user.remember_me!
user.expects(:valid?).never
user.forget_me!
end
test 'serialize into cookie' do
user = create_user
user.remember_me!
assert_equal [user.to_key, user.authenticatable_salt], User.serialize_into_cookie(user)
end
test 'serialize from cookie' do
user = create_user
user.remember_me!
assert_equal user, User.serialize_from_cookie(user.to_key, user.authenticatable_salt)
end
test 'raises a RuntimeError if authenticatable_salt is nil' do
user = User.new
user.encrypted_password = nil
assert_raise RuntimeError do
user.rememberable_value
end
end
end

View file

@ -39,7 +39,7 @@ class ActiveRecordTest < ActiveSupport::TestCase
end
test 'can cherry pick modules' do
assert_include_modules Admin, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :rememberable, :encryptable
assert_include_modules Admin, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :encryptable
end
test 'validations options are not applied too late' do
@ -55,12 +55,12 @@ class ActiveRecordTest < ActiveSupport::TestCase
end
test 'chosen modules are inheritable' do
assert_include_modules Inheritable, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :rememberable, :encryptable
assert_include_modules Inheritable, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :encryptable
end
test 'order of module inclusion' do
correct_module_order = [:database_authenticatable, :rememberable, :encryptable, :recoverable, :registerable, :lockable, :timeoutable]
incorrect_module_order = [:database_authenticatable, :timeoutable, :registerable, :recoverable, :lockable, :encryptable, :rememberable]
correct_module_order = [:database_authenticatable, :encryptable, :recoverable, :registerable, :lockable, :timeoutable]
incorrect_module_order = [:database_authenticatable, :timeoutable, :registerable, :recoverable, :lockable, :encryptable]
assert_include_modules Admin, *incorrect_module_order

View file

@ -60,7 +60,7 @@ Devise.setup do |config|
# ==> Configuration for :database_authenticatable
# For bcrypt, this is the cost for hashing the password and defaults to 10. If
# using other encryptors, it sets how many times you want the password re-encrypted.
config.stretches = 10
config.stretches = Rails.env.test? ? 1 : 10
# ==> Configuration for :confirmable
# The time you want to give your user to confirm his account. During this time

View file

@ -3,7 +3,7 @@ module SharedAdmin
included do
devise :database_authenticatable, :encryptable, :registerable,
:timeoutable, :recoverable, :rememberable, :lockable,
:timeoutable, :recoverable, :lockable,
:unlock_strategy => :time, :lock_strategy => :none
end