mirror of
https://github.com/discourse/discourse.git
synced 2025-05-28 23:49:34 +08:00
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:

committed by
GitHub

parent
30f55cd64b
commit
e97ef7e9af
@ -1991,7 +1991,7 @@ RSpec.describe SessionController do
|
||||
end
|
||||
end
|
||||
|
||||
describe "success by username" do
|
||||
describe "success by username and password" do
|
||||
it "logs in correctly" do
|
||||
events =
|
||||
DiscourseEvent.track_events do
|
||||
@ -2030,6 +2030,70 @@ RSpec.describe SessionController do
|
||||
end
|
||||
end
|
||||
|
||||
describe "when user's password has been marked as expired" do
|
||||
let!(:expired_user_password) do
|
||||
Fabricate(
|
||||
:expired_user_password,
|
||||
user:,
|
||||
password: "myawesomepassword",
|
||||
password_salt: user.salt,
|
||||
password_algorithm: user.password_algorithm,
|
||||
)
|
||||
end
|
||||
|
||||
before { RateLimiter.enable }
|
||||
|
||||
use_redis_snapshotting
|
||||
|
||||
it "should return an error response code with the right error message and enqueues the password reset email" do
|
||||
expect_enqueued_with(
|
||||
job: :critical_user_email,
|
||||
args: {
|
||||
type: "forgot_password",
|
||||
user_id: user.id,
|
||||
},
|
||||
) do
|
||||
post "/session.json", params: { login: user.username, password: "myawesomepassword" }
|
||||
end
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["error"]).to eq(I18n.t("login.password_expired"))
|
||||
expect(session[:current_user_id]).to eq(nil)
|
||||
end
|
||||
|
||||
it "should limit the number of forgot password emails sent a day to the user when logging in with an expired password" do
|
||||
SiteSetting.max_logins_per_ip_per_minute =
|
||||
described_class::FORGOT_PASSWORD_EMAIL_LIMIT_PER_DAY + 1
|
||||
|
||||
SiteSetting.max_logins_per_ip_per_hour =
|
||||
described_class::FORGOT_PASSWORD_EMAIL_LIMIT_PER_DAY + 1
|
||||
|
||||
described_class::FORGOT_PASSWORD_EMAIL_LIMIT_PER_DAY.times do
|
||||
expect_enqueued_with(
|
||||
job: :critical_user_email,
|
||||
args: {
|
||||
type: "forgot_password",
|
||||
user_id: user.id,
|
||||
},
|
||||
) do
|
||||
post "/session.json", params: { login: user.username, password: "myawesomepassword" }
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
expect_not_enqueued_with(
|
||||
job: :critical_user_email,
|
||||
args: {
|
||||
type: "forgot_password",
|
||||
user_id: user.id,
|
||||
},
|
||||
) do
|
||||
post "/session.json", params: { login: user.username, password: "myawesomepassword" }
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when a user has security key-only 2FA login" do
|
||||
let!(:user_security_key) do
|
||||
Fabricate(
|
||||
|
Reference in New Issue
Block a user