Do not timeout if remember me is enabled

This commit is contained in:
José Valim
2016-01-22 16:18:57 +01:00
parent eb0f0b662f
commit 14affc8a55
4 changed files with 41 additions and 12 deletions

View File

@@ -9,6 +9,13 @@ module Devise
Rails.configuration.session_options.slice(:path, :domain, :secure)
end
def remember_me_is_active?(resource)
return false unless resource.respond_to?(:remember_me)
scope = Devise::Mapping.find_scope!(resource)
cookie = cookies.signed[remember_key(resource, scope)]
resource.class.serialized_in_cookie?(resource, *cookie)
end
# Remembers the given resource by setting up a cookie
def remember_me(resource)
return if env["devise.skip_storage"]

View File

@@ -19,9 +19,10 @@ Warden::Manager.after_set_user do |record, warden, options|
proxy = Devise::Hooks::Proxy.new(warden)
if record.timedout?(last_request_at) && !env['devise.skip_timeout']
if record.timedout?(last_request_at) &&
!env['devise.skip_timeout'] &&
!proxy.remember_me_is_active?(record)
Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
throw :warden, scope: scope, message: :timeout
end

View File

@@ -101,7 +101,6 @@ module Devise
def after_remembered
end
protected
module ClassMethods
# Create the cookie key using the record id and remember_token
@@ -111,6 +110,25 @@ module Devise
# Recreate the user based on the stored cookie
def serialize_from_cookie(*args)
serialize_from_cookie_with_or_without_record(nil, args)
end
# Check if the given record is the one serialized in cookie
def serialized_in_cookie?(record, *args)
!!serialize_from_cookie_with_or_without_record(record, args)
end
# Generate a token checking if one does not already exist in the database.
def remember_token #:nodoc:
loop do
token = Devise.friendly_token
break token unless to_adapter.find_first({ remember_token: token })
end
end
private
def serialize_from_cookie_with_or_without_record(record, args)
id, token, generated_at = args
# The token is only valid if:
@@ -122,20 +140,13 @@ module Devise
# 6. the token matches
if generated_at &&
(self.remember_for.ago < generated_at) &&
(record = to_adapter.get(id)) &&
(record ||= to_adapter.get(id)) && (id == record.to_key) &&
(generated_at > (record.remember_created_at || Time.now).utc) &&
Devise.secure_compare(record.rememberable_value, token)
record
end
end
# Generate a token checking if one does not already exist in the database.
def remember_token #:nodoc:
loop do
token = Devise.friendly_token
break token unless to_adapter.find_first({ remember_token: token })
end
end
# TODO: extend_remember_period is no longer used
Devise::Models.config(self, :remember_for, :extend_remember_period, :rememberable_options, :expire_all_remember_me_on_sign_out)

View File

@@ -165,7 +165,17 @@ class SessionTimeoutTest < ActionDispatch::IntegrationTest
end
end
test 'does not crashes when the last_request_at is a String' do
test 'time out not triggered if remembered' do
user = sign_in_as_user remember_me: true
get expire_user_path(user)
assert_not_nil last_request_at
get users_path
assert_response :success
assert warden.authenticated?(:user)
end
test 'does not crash when the last_request_at is a String' do
user = sign_in_as_user
get edit_form_user_path(user, last_request_at: Time.now.utc.to_s)