Skip to content

Commit 7bc147d

Browse files
feat: intercept DatabaseAuthenticatable and PasswordsController for 2FA
Modify DatabaseAuthenticatable strategy to detect 2FA-enabled users after password validation and redirect to the default 2FA method's challenge page instead of signing in. Update PasswordsController to require 2FA verification after password reset when sign_in_after_reset_password is enabled.
1 parent de55046 commit 7bc147d

2 files changed

Lines changed: 29 additions & 3 deletions

File tree

app/controllers/devise/passwords_controller.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ def update
3737
if resource.errors.empty?
3838
resource.unlock_access! if unlockable?(resource)
3939
if sign_in_after_reset_password?
40+
if resource.respond_to?(:two_factor_enabled?) && resource.two_factor_enabled?
41+
session[:devise_two_factor_resource_id] = resource.id
42+
default_method = resource.enabled_two_factors.first
43+
set_flash_message!(:notice, :updated_two_factor_required)
44+
respond_with resource, location: new_two_factor_challenge_path(resource_name, default_method)
45+
return
46+
end
47+
4048
flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
4149
set_flash_message!(:notice, flash_message)
4250
resource.after_database_authentication

lib/devise/strategies/database_authenticatable.rb

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ def authenticate!
1111
hashed = false
1212

1313
if validate(resource){ hashed = true; resource.valid_password?(password) }
14-
remember_me(resource)
15-
resource.after_database_authentication
16-
success!(resource)
14+
if resource.respond_to?(:two_factor_enabled?) && resource.two_factor_enabled?
15+
initiate_two_factor_authentication!(resource)
16+
else
17+
remember_me(resource)
18+
resource.after_database_authentication
19+
success!(resource)
20+
end
1721
end
1822

1923
# In paranoid mode, hash the password even when a resource doesn't exist for the given authentication key.
@@ -24,6 +28,20 @@ def authenticate!
2428
Devise.paranoid ? fail(:invalid) : fail(:not_found_in_database)
2529
end
2630
end
31+
32+
private
33+
34+
def initiate_two_factor_authentication!(resource)
35+
session[:devise_two_factor_resource_id] = resource.id
36+
session[:devise_two_factor_remember_me] = remember_me?
37+
default_method = resource.enabled_two_factors.first
38+
redirect!(new_two_factor_challenge_path(scope, default_method))
39+
end
40+
41+
def new_two_factor_challenge_path(scope, method)
42+
Rails.application.routes.url_helpers
43+
.send(:"#{scope}_new_two_factor_#{method}_path")
44+
end
2745
end
2846
end
2947
end

0 commit comments

Comments
 (0)