dev:proposal:self_serve_password_reset
Table of Contents
Self-serve password reset implementation
New requirements
- UUID::Tiny (trunk already requires this)
Schema
CREATE TABLE actor.usr_password_reset ( uuid TEXT NOT NULL, usr BIGINT NOT NULL REFERENCES actor.usr(id) DEFERRABLE INITIALLY DEFERRED, request_time TIMESTAMP NOT NULL DEFAULT NOW(), has_been_reset BOOLEAN NOT NULL DEFAULT FALSE );
Fieldmapper
<class id="aupr" controller="open-ils.cstore" oils_obj:fieldmapper="actor::usr_password_reset" oils_persist:tablename="actor.usr_password_reset" reporter:label="User password reset requests"> <fields oils_persist:primary="uuid"> <field reporter:label="UUID" name="uuid" reporter:datatype="text"/> <field reporter:label="User" name="usr" reporter:datatype="link"/> <field reporter:label="Request Time" name="request_time" reporter:datatype="timestamp"/> <field reporter:label="Was Reset?" name="has_been_reset" reporter:datatype="bool"/> </fields> <links> <link field="usr" reltype="has_a" key="id" class="au"/> </links> </class>
</code>
OU settings, with defaults
- Password reset time-to-live: 24 hours?
- Number of concurrent active password reset requests for all users: 1000?
- Number of concurrent active password reset requests for one user: 3?
Overview
- User forgets password when prompted to log in; clicks "Forgot my password" link.
- Form prompts user for one of three types of identification:
- User name (unique)
- Barcode (unique)
- Email address? Not unique. Problem if multiple people share the same email address - whose password is getting reset?
- Upon submission, page responds that if there is a match for the provided identification and an email address on file for the corresponding user, an email will be sent with further instructions for recovering your password. Otherwise, [ local customization here - might be "Visit your local library" or whatever ]
- Assuming there is a match:
- Check how many currently active entries in the actor.usr_password_reset table exist (currently active = current password_reset_TTL (WHERE request_time > NOW() - password_reset_TTL) AND has_been_reset IS FALSE)
- Log a warning if > 75% global_threshold
- Log an error and throttle reset requests to 1 per minute if > global_threshold
- Check how many currently active entries in the actor.usr_password_reset table match usr
- Log an error if > usr_threshold and do not generate a reset
- Generate a random UUID: create_uuid_as_string(UUID_V4) - don't want to base this on the identifiers, as those are entirely predictable; rand() is not strong but good enough?
- Create an entry in actor.usr_password_reset
- Send an email to the email address on file: actor.usr.email
- "Someone has requested to have the password for your account at actor.usr.home_ou.name reset. If this was not you, please disregard this email message. If this was you, please open the following link in a Web browser to continue the password reset process: https://foobar/forgot-password/$uuid
- Listen for the magic URL on HTTPS (because we want the new password encrypted when it goes over the wire)
- We should monitor how many requests are being fired towards the magic URL root to prevent rainbow attacks, but kind of need that globally
- If we get a hit on an active entry in actor.usr_password_reset, display a Web form that gives the user the chance to set their password
- Password must be entered twice and must match
- Password should be subject to aou setting's password complexity rules
dev/proposal/self_serve_password_reset.txt · Last modified: 2022/02/10 13:34 by 127.0.0.1