Store the salt in session and expire the session if the user changes his password
This commit is contained in:
parent
6613653df0
commit
617e142e34
|
@ -11,6 +11,7 @@
|
|||
* Ensure the friendly token does not include "_" or "-" since some e-mails may not autolink it properly (by github.com/rymai)
|
||||
* Extracted encryptors into :encryptable for better bcrypt support
|
||||
* :rememberable is now able to use salt as token if no remember_token is provided
|
||||
* Store the salt in session and expire the session if the user changes his password
|
||||
|
||||
* bugfix
|
||||
* after_sign_in_path_for always receives a resource
|
||||
|
|
|
@ -31,6 +31,7 @@ class Devise::RegistrationsController < ApplicationController
|
|||
def update
|
||||
if resource.update_with_password(params[resource_name])
|
||||
set_flash_message :notice, :updated
|
||||
sign_in resource_name, resource, :bypass => true
|
||||
redirect_to after_update_path_for(resource)
|
||||
else
|
||||
clean_up_passwords(resource)
|
||||
|
|
|
@ -87,18 +87,29 @@ module Devise
|
|||
# Sign in an user that already was authenticated. This helper is useful for logging
|
||||
# users in after sign up.
|
||||
#
|
||||
# All options given to sign_in is passed forward to the set_user method in warden.
|
||||
# The only exception is the :bypass option, which bypass warden callbacks and stores
|
||||
# the user straight in session. This option is useful in cases the user is already
|
||||
# signed in, but we want to refresh the credentials in session.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# sign_in :user, @user # sign_in(scope, resource)
|
||||
# sign_in @user # sign_in(resource)
|
||||
# sign_in @user, :event => :authentication # sign_in(resource, options)
|
||||
#
|
||||
# sign_in @user, :bypass => true # sign_in(resource, options)
|
||||
#
|
||||
def sign_in(resource_or_scope, *args)
|
||||
options = args.extract_options!
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
resource = args.last || resource_or_scope
|
||||
expire_session_data_after_sign_in!
|
||||
warden.set_user(resource, options.merge!(:scope => scope))
|
||||
|
||||
if options[:bypass]
|
||||
warden.session_serializer.store(resource, scope)
|
||||
else
|
||||
expire_session_data_after_sign_in!
|
||||
warden.set_user(resource, options.merge!(:scope => scope))
|
||||
end
|
||||
end
|
||||
|
||||
# Sign out a given user or scope. This helper is useful for signing out an user
|
||||
|
|
|
@ -73,6 +73,9 @@ module Devise
|
|||
:inactive
|
||||
end
|
||||
|
||||
def authenticatable_salt
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
Devise::Models.config(self, :authentication_keys, :request_keys, :http_authenticatable, :params_authenticatable)
|
||||
|
||||
|
|
|
@ -15,18 +15,28 @@ end
|
|||
|
||||
class Warden::SessionSerializer
|
||||
def serialize(record)
|
||||
[record.class.name, record.id]
|
||||
[record.class.name, record.id, record.authenticatable_salt]
|
||||
end
|
||||
|
||||
def deserialize(keys)
|
||||
klass, id = keys
|
||||
klass.constantize.find(:first, :conditions => { :id => id })
|
||||
rescue NameError => e
|
||||
if e.message =~ /uninitialized constant/
|
||||
Rails.logger.debug "Trying to deserialize invalid class #{klass}"
|
||||
nil
|
||||
else
|
||||
raise
|
||||
if keys.size == 2
|
||||
raise "Devise changed how it stores objects in session. If you are seeing this message, " <<
|
||||
"you can fix it by changing one character in your cookie secret, forcing all previous " <<
|
||||
"cookies to expire, or cleaning up your database sessions if you are using a db store."
|
||||
end
|
||||
|
||||
klass, id, salt = keys
|
||||
|
||||
begin
|
||||
record = klass.constantize.find(:first, :conditions => { :id => id })
|
||||
record if record && record.authenticatable_salt == salt
|
||||
rescue NameError => e
|
||||
if e.message =~ /uninitialized constant/
|
||||
Rails.logger.debug "Trying to deserialize invalid class #{klass}"
|
||||
nil
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -100,6 +100,13 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
|||
@controller.sign_in(user)
|
||||
end
|
||||
|
||||
test 'sign in accepts bypass as option' do
|
||||
user = User.new
|
||||
@mock_warden.expects(:session_serializer).returns(serializer = mock())
|
||||
serializer.expects(:store).with(user, :user)
|
||||
@controller.sign_in(user, :bypass => true)
|
||||
end
|
||||
|
||||
test 'sign out proxy to logout on warden' do
|
||||
@mock_warden.expects(:user).with(:user).returns(true)
|
||||
@mock_warden.expects(:logout).with(:user).returns(true)
|
||||
|
|
|
@ -98,6 +98,20 @@ class RegistrationTest < ActionController::IntegrationTest
|
|||
assert_equal "user.new@email.com", User.first.email
|
||||
end
|
||||
|
||||
test 'a signed in user should still be able to use the website after changing his password' do
|
||||
sign_in_as_user
|
||||
get edit_user_registration_path
|
||||
|
||||
fill_in 'password', :with => '12345678'
|
||||
fill_in 'password confirmation', :with => '12345678'
|
||||
fill_in 'current password', :with => '123456'
|
||||
click_button 'Update'
|
||||
|
||||
assert_contain 'You updated your account successfully.'
|
||||
get users_path
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'a signed in user should not change his current user with invalid password' do
|
||||
sign_in_as_user
|
||||
get edit_user_registration_path
|
||||
|
|
Loading…
Reference in New Issue