diff --git a/app/controllers/devise/two_factor_authentication_controller.rb b/app/controllers/devise/two_factor_authentication_controller.rb index 0e7aed84..46c86299 100644 --- a/app/controllers/devise/two_factor_authentication_controller.rb +++ b/app/controllers/devise/two_factor_authentication_controller.rb @@ -46,7 +46,11 @@ def set_remember_two_factor_cookie(resource) if expires_seconds && expires_seconds > 0 cookies.signed[TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME] = { - value: "#{resource.class}-#{resource.public_send(Devise.second_factor_resource_id)}", + value: { + user_class: resource.class.to_s, + user_id: resource.public_send(Devise.second_factor_resource_id).to_s, + created_at: Time.current + }, expires: expires_seconds.seconds.from_now } end diff --git a/lib/two_factor_authentication/hooks/two_factor_authenticatable.rb b/lib/two_factor_authentication/hooks/two_factor_authenticatable.rb index 3ff03415..87ed6b44 100644 --- a/lib/two_factor_authentication/hooks/two_factor_authenticatable.rb +++ b/lib/two_factor_authentication/hooks/two_factor_authenticatable.rb @@ -1,8 +1,10 @@ Warden::Manager.after_authentication do |user, auth, options| if auth.env["action_dispatch.cookies"] - expected_cookie_value = "#{user.class}-#{user.public_send(Devise.second_factor_resource_id)}" - actual_cookie_value = auth.env["action_dispatch.cookies"].signed[TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME] - bypass_by_cookie = actual_cookie_value == expected_cookie_value + cookie = auth.env["action_dispatch.cookies"].signed[TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME] + bypass_by_cookie = cookie.present? + bypass_by_cookie &&= cookie["user_class"] == user.class.to_s + bypass_by_cookie &&= cookie["user_id"] == user.id.to_s + bypass_by_cookie &&= Time.current <= cookie["created_at"].to_datetime + user.class.remember_otp_session_for_seconds end if user.respond_to?(:need_two_factor_authentication?) && !bypass_by_cookie diff --git a/spec/features/two_factor_authenticatable_spec.rb b/spec/features/two_factor_authenticatable_spec.rb index d433d636..9a743bb7 100644 --- a/spec/features/two_factor_authenticatable_spec.rb +++ b/spec/features/two_factor_authenticatable_spec.rb @@ -136,6 +136,19 @@ expect(page).to have_content("Enter the code that was sent to you") end + scenario "requires TFA code again after if expiry date changes" do + sms_sign_in + + logout + + User.remember_otp_session_for_seconds = 1.day + Timecop.travel(1.day.from_now) + login_as user + visit dashboard_path + expect(page).to have_content("You are signed in as Marissa") + expect(page).to have_content("Enter the code that was sent to you") + end + scenario 'TFA should be different for different users' do sms_sign_in