Skip to content

Commit

Permalink
Support hmac_secret rotation in email_base feature
Browse files Browse the repository at this point in the history
This supports the previous secret when validing email tokens.
In terms of rotation time, that depends on the longest validity
time you want to support for any feature using the email_base
feature (email_auth, lockout, reset_password, verify_account,
verify_login_change). The default validity for each of those
features except verify_account is 1 day. verify_account has
no deadline.  However, if the verify account link has expired,
the user can request that the email be resent, and the resent
email will have the link with the new hmac.
  • Loading branch information
jeremyevans committed Sep 29, 2023
1 parent a474d2d commit e404896
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
=== master

* Support hmac_secret rotation in email_base feature (jeremyevans) (#365)

* Support hmac_secret rotation in webauthn feature (jeremyevans) (#365)

* Support hmac_secret rotation in jwt_refresh feature (jeremyevans) (#365)
Expand Down
10 changes: 4 additions & 6 deletions lib/rodauth/features/email_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,10 @@ def account_from_key(token, status_id=nil)

return unless actual = yield(id)

unless timing_safe_eql?(key, convert_email_token_key(actual))
if hmac_secret && allow_raw_email_token?
return unless timing_safe_eql?(key, actual)
else
return
end
unless (hmac_secret && timing_safe_eql?(key, convert_email_token_key(actual))) ||
(hmac_secret_rotation? && timing_safe_eql?(key, compute_old_hmac(actual))) ||
((!hmac_secret || allow_raw_email_token?) && timing_safe_eql?(key, actual))
return
end
ds = account_ds(id)
ds = ds.where(account_status_column=>status_id) if status_id && !skip_status_checks?
Expand Down
19 changes: 18 additions & 1 deletion spec/verify_account_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
describe 'Rodauth verify_account feature' do
it "should support verifying accounts" do
last_sent_column = nil
secret = nil
secret = old_secret = nil
allow_raw_token = false
rodauth do
enable :login, :create_account, :verify_account
verify_account_autologin? false
verify_account_email_last_sent_column{last_sent_column}
hmac_secret{secret}
hmac_old_secret{old_secret}
allow_raw_email_token?{allow_raw_token}
verify_account_set_password? false
require_login_confirmation? true
Expand Down Expand Up @@ -89,6 +90,11 @@
visit link
page.find('#error_flash').text.must_equal "There was an error verifying your account: invalid verify account key"

secret = SecureRandom.random_bytes(32)
old_secret = SecureRandom.random_bytes(32)
visit link
page.find('#error_flash').text.must_equal "There was an error verifying your account: invalid verify account key"

allow_raw_token = true
visit link
click_button 'Verify Account'
Expand All @@ -103,11 +109,13 @@
[false, true].each do |ph|
it "should support setting passwords when verifying accounts #{'with account_password_hash_column' if ph}" do
initial_secret = secret = SecureRandom.random_bytes(32)
old_secret = nil
rodauth do
enable :login, :create_account, :verify_account
account_password_hash_column :ph if ph
verify_account_autologin? false
hmac_secret{secret}
hmac_old_secret{old_secret}
end
roda do |r|
r.rodauth
Expand All @@ -125,6 +133,15 @@
visit link
page.find('#error_flash').text.must_equal "There was an error verifying your account: invalid verify account key"

secret = SecureRandom.random_bytes(32)
old_secret = SecureRandom.random_bytes(32)
visit link
page.find('#error_flash').text.must_equal "There was an error verifying your account: invalid verify account key"

old_secret = initial_secret
visit link
page.find_by_id('password')[:autocomplete].must_equal 'new-password'

secret = initial_secret
visit link
page.find_by_id('password')[:autocomplete].must_equal 'new-password'
Expand Down

0 comments on commit e404896

Please sign in to comment.