FEATURE: Allow site admin to mark a user's password as expired (#27314)

This commit adds the ability for site administrators to mark users'
passwords as expired. Note that this commit does not add any client side
interface to mark a user's password as expired.

The following changes are introduced in this commit:

1. Adds a `user_passwords` table and `UserPassword` model. While the
   `user_passwords` table is currently used to only store expired
   passwords, it will be used in the future to store a user's current
   password as well.

2. Adds a `UserPasswordExpirer.expire_user_password` method which can
   be used from the Rails console to mark a user's password as expired.

3. Updates `SessionsController#create` to check that the user's current
   password has not been marked as expired after confirming the
   password. If the password is determined to be expired based on the
   existence of a `UserPassword` record with the `password_expired_at`
   column set, we will not log the user in and will display a password
   expired notice. A forgot password email is automatically send out to
   the user as well.
This commit is contained in:
Alan Guo Xiang Tan
2024-06-04 15:42:53 +08:00
committed by GitHub
parent 30f55cd64b
commit e97ef7e9af
14 changed files with 370 additions and 15 deletions

View File

@ -141,6 +141,29 @@ RSpec.describe PasswordValidator do
expect(record.errors[:password]).to include(password_error_message(:same_as_current))
end
it "adds an error when new password is same as a previous password" do
@password = "thisisaoldpassword"
record.save!
record.reload
new_password = "thisisanewpassword"
_expired_user_password =
Fabricate(
:expired_user_password,
password: new_password,
password_algorithm: record.password_algorithm,
password_salt: record.salt,
user: record,
)
record.password = new_password
@password = new_password
validate
expect(record.errors[:password]).to include(password_error_message(:same_as_previous))
end
it "validation required if password is required" do
expect(record.password_validation_required?).to eq(true)
end