Permalink
Browse files

MDL-23692 forgotpw: Simplify forgotpw process.

  • Loading branch information...
peterbulmer committed Sep 14, 2013
1 parent f4491c2 commit 92de749fc715108098df5f874d1cfb22af31bf38
Showing with 322 additions and 73 deletions.
  1. +16 −0 admin/settings/security.php
  2. +2 −0 lang/en/admin.php
  3. +25 −1 lang/en/moodle.php
  4. +9 −0 lib/cronlib.php
  5. +14 −1 lib/db/install.xml
  6. +21 −0 lib/db/upgrade.php
  7. +8 −4 lib/moodlelib.php
  8. +7 −7 login/forgot_password.php
  9. +133 −59 login/lib.php
  10. +86 −0 login/set_password_form.php
  11. +1 −1 version.php
@@ -70,6 +70,22 @@
$temp->add(new admin_setting_configtext('minpasswordupper', new lang_string('minpasswordupper', 'admin'), new lang_string('configminpasswordupper', 'admin'), 1, PARAM_INT));
$temp->add(new admin_setting_configtext('minpasswordnonalphanum', new lang_string('minpasswordnonalphanum', 'admin'), new lang_string('configminpasswordnonalphanum', 'admin'), 1, PARAM_INT));
$temp->add(new admin_setting_configtext('maxconsecutiveidentchars', new lang_string('maxconsecutiveidentchars', 'admin'), new lang_string('configmaxconsecutiveidentchars', 'admin'), 0, PARAM_INT));
+ $pwresetoptions = array(
+ 300 => new lang_string('numminutes', '', 5),
+ 900 => new lang_string('numminutes', '', 15),
+ 1800 => new lang_string('numminutes', '', 30),
+ 2700 => new lang_string('numminutes', '', 45),
+ 3600 => new lang_string('numminutes', '', 60),
+ 7200 => new lang_string('numminutes', '', 120),
+ 14400 => new lang_string('numminutes', '', 240)
+ );
+ $adminsetting = new admin_setting_configselect(
+ 'pwresettime',
+ new lang_string('passwordresettime','admin'),
+ new lang_string('configpasswordresettime','admin'),
+ 1800,
+ $pwresetoptions);
+ $temp->add($adminsetting);
$temp->add(new admin_setting_configcheckbox('groupenrolmentkeypolicy', new lang_string('groupenrolmentkeypolicy', 'admin'), new lang_string('groupenrolmentkeypolicy_desc', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('disableuserimages', new lang_string('disableuserimages', 'admin'), new lang_string('configdisableuserimages', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('emailchangeconfirmation', new lang_string('emailchangeconfirmation', 'admin'), new lang_string('configemailchangeconfirmation', 'admin'), 1));
View
@@ -277,6 +277,7 @@
$string['configopentogoogle'] = 'If you enable this setting, then Google will be allowed to enter your site as a Guest. In addition, people coming in to your site via a Google search will automatically be logged in as a Guest. Note that this only provides transparent access to courses that already allow guest access.';
$string['configoverride'] = 'Defined in config.php';
$string['configpasswordpolicy'] = 'Turning this on will make Moodle check user passwords against a valid password policy. Use the settings below to specify your policy (they will be ignored if you set this to \'No\').';
+$string['configpasswordresettime'] = 'This specifies the amount of time people have to validate a password reset request before it expires. Usually 30 minutes is a good value.';
$string['configpathtoclam'] = 'Path to clam AV. Probably something like /usr/bin/clamscan or /usr/bin/clamdscan. You need this in order for clam AV to run.';
$string['configpathtodu'] = 'Path to du. Probably something like /usr/bin/du. If you enter this, pages that display directory contents will run much faster for directories with a lot of files.';
$string['configperfdebug'] = 'If you turn this on, performance info will be printed in the footer of the standard theme';
@@ -778,6 +779,7 @@
$string['order3'] = 'Third';
$string['order4'] = 'Fourth';
$string['passwordpolicy'] = 'Password policy';
+$string['passwordresettime'] = 'Maximum time to validate password reset request';
$string['pathconvert'] = 'Path of <i>convert</i> binary';
$string['pathdvips'] = 'Path of <i>dvips</i> binary';
$string['pathlatex'] = 'Path of <i>latex</i> binary';
View
@@ -535,6 +535,7 @@
$string['editthiscategory'] = 'Edit this category';
$string['edituser'] = 'Edit user accounts';
$string['email'] = 'Email address';
+$string['emailalreadysent'] = 'A Password reset email has already been sent. Please check your email.';
$string['emailactive'] = 'Email activated';
$string['emailagain'] = 'Email (again)';
$string['emailconfirm'] = 'Confirm your account';
@@ -609,7 +610,7 @@
$string['emailpasswordconfirmnoemail'] = '<p>The user account you specified does not have a recorded email address.</p>
<p>Please contact the site administrator.</p>';
$string['emailpasswordconfirmnotsent'] = '<p>The user detail you supplied does not identify an existing user account.</p>
- <p>Please check the detail you entered, then try again.
+ <p>Please check the information you entered, then try again.
If you continue to have difficulty, please contact the site administrator.</p>';
$string['emailpasswordconfirmsent'] = 'An email should have been sent to your address at <b>{$a}</b>.
<br />It contains easy instructions to confirm and complete this password change.
@@ -651,6 +652,24 @@
An email containing your new password has been sent to your address at<br /><b>{$a->email}</b>.<br />
The new password was automatically generated - you might like to
<a href="{$a->link}">change your password</a> to something easier to remember.';
+$string['emailresetconfirmation'] = 'Hi {$a->firstname},
+
+A password reset was requested for your account \'{$a->username}\' at {$a->sitename}.
+
+To confirm this request, and set a new password for your account, please
+go to the following web address:
+
+{$a->link}
+(This link is valid for {$a->resetminutes} minutes from the time this reset was first requested)
+
+If this password reset was not requested by you, no action is needed.
+
+If you need help, please contact the site administrator,
+{$a->admin}';
+$string['emailresetconfirmationsubject'] = '{$a}: Password reset request';
+$string['emailresetconfirmsent'] = 'An email has been sent to your address at <b>{$a}</b>.
+<br />It contains easy instructions to confirm and complete this password change.
+If you continue to have difficulty, contact the site administrator.';
$string['emptydragdropregion'] = 'empty region';
$string['enable'] = 'Enable';
$string['encryptedcode'] = 'Encrypted code';
@@ -1226,6 +1245,7 @@
Following is the content of your email:';
$string['noreplybouncesubject'] = '{$a} - bounced email.';
$string['noreplyname'] = 'Do not reply to this email';
+$string['noresetrecord'] = 'There is no record of that reset request. Please initiate a new password reset request.';
$string['noresults'] = 'No results';
$string['normal'] = 'Normal';
$string['normalfilter'] = 'Normal search';
@@ -1304,6 +1324,7 @@
$string['passwordrecovery'] = 'Yes, help me log in';
$string['passwordsdiffer'] = 'These passwords do not match';
$string['passwordsent'] = 'Password has been sent';
+$string['passwordset'] = 'Your password has been set.';
$string['passwordsenttext'] = '<p>An email has been sent to your address at {$a->email}.</p>
<p><b>Please check your email for your new password</b></p>
<p>The new password was automatically generated, so you might like to
@@ -1418,6 +1439,7 @@
$string['resetcourse'] = 'Reset course';
$string['resetinfo'] = 'This page allows you to empty a course of user data, while retaining the activities and other settings. Please be warned that by choosing items below and submitting this page you will delete your chosen user data from this course forever!';
$string['resetnotimplemented'] = 'Reset not implemented';
+$string['resetrecordexpired'] = 'The password reset link you used is more than {$a} minutes old and has expired. Please initiate a new password reset.';
$string['resetstartdate'] = 'Reset start date';
$string['resetstatus'] = 'Status';
$string['resettask'] = 'Task';
@@ -1542,6 +1564,8 @@
$string['servererror'] = 'An error occurred whilst communicating with the server';
$string['serverlocaltime'] = 'Server\'s local time';
$string['setcategorytheme'] = 'Set category theme';
+$string['setpassword'] = 'Set Password';
+$string['setpasswordinstructions'] = 'Please enter and repeat your new password below, then click "Set Password". <br />Your new password will be saved, and you will be logged in.';
$string['settings'] = 'Settings';
$string['shortname'] = 'Short name'; // @deprecated MDL-34652 - use shortnamecourse or shortnameuser or some own context specific string
$string['shortnamecollisionwarning'] = '[*] = This shortname is already in use by a course and will need to be changed upon approval';
View
@@ -173,6 +173,15 @@ function cron_run() {
mtrace(' Deleting temporary files...');
cron_delete_from_temp();
+ // Cleanup user password reset records
+ // Delete any reset request records which are expired by more than a day.
+ // (We keep recently expired requests around so we can give a different error msg to users who
+ // are trying to user a recently expired reset attempt).
+ $pwresettime = isset($CFG->pwresettime) ? $CFG->pwresettime : 1800;
+ $earliestvalid = time() - $pwresettime - DAYSECS;
+ $DB->delete_records_select('user_password_resets', "timerequested < ?", array($earliestvalid));
+ mtrace(' Cleaned up old password reset records');
+
mtrace("...finished clean-up tasks");
} // End of occasional clean-up tasks
View
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="lib/db" VERSION="20130921" COMMENT="XMLDB file for core Moodle tables"
+<XMLDB PATH="lib/db" VERSION="20130927" COMMENT="XMLDB file for core Moodle tables"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
>
@@ -3050,5 +3050,18 @@
<KEY NAME="fk_backpackid" TYPE="foreign" FIELDS="backpackid" REFTABLE="badge_backpack" REFFIELDS="id"/>
</KEYS>
</TABLE>
+ <TABLE NAME="user_password_resets" COMMENT="table tracking password reset confirmation tokens">
+ <FIELDS>
+ <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
+ <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="id of the user account which requester claimed to be"/>
+ <FIELD NAME="timerequested" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The time that the user first requested this password reset"/>
+ <FIELD NAME="timererequested" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The time the user re-requested the password reset."/>
+ <FIELD NAME="token" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="secret set and emailed to user"/>
+ </FIELDS>
+ <KEYS>
+ <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+ <KEY NAME="userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id"/>
+ </KEYS>
+ </TABLE>
</TABLES>
</XMLDB>
View
@@ -2555,5 +2555,26 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2013092001.02);
}
+ if ($oldversion < 2013092700.02) {
+ // Create a new 'user_password_resets' table.
+ $table = new xmldb_table('user_password_resets');
+ $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
+ $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, null);
+ $table->add_field('timerequested', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, null);
+ $table->add_field('timererequested', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0, null);
+ $table->add_field('token', XMLDB_TYPE_CHAR, '32', null, XMLDB_NOTNULL, null, null, null);
+
+ // Adding keys to table.
+ $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+ $table->add_key('fk_userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
+
+ // Conditionally launch create table.
+ if (!$dbman->table_exists($table)) {
+ $dbman->create_table($table);
+ }
+ upgrade_main_savepoint(true, 2013092700.02);
+ }
+
+
return true;
}
View
@@ -5947,23 +5947,27 @@ function send_confirmation_email($user) {
* Sends a password change confirmation email.
*
* @param stdClass $user A {@link $USER} object
+ * @param stdClass $resetrecord An object tracking metadata regarding password reset request
* @return bool Returns true if mail was sent OK and false if there was an error.
*/
-function send_password_change_confirmation_email($user) {
+function send_password_change_confirmation_email($user, $resetrecord) {
global $CFG;
$site = get_site();
$supportuser = core_user::get_support_user();
+ $pwresetmins = isset($CFG->pwresettime) ? floor($CFG->pwresettime / MINSECS) : 30;
$data = new stdClass();
$data->firstname = $user->firstname;
$data->lastname = $user->lastname;
+ $data->username = $user->username;
$data->sitename = format_string($site->fullname);
- $data->link = $CFG->httpswwwroot .'/login/forgot_password.php?p='. $user->secret .'&s='. urlencode($user->username);
+ $data->link = $CFG->httpswwwroot .'/login/forgot_password.php?token='. $resetrecord->token;
$data->admin = generate_email_signoff();
+ $data->resetminutes = $pwresetmins;
- $message = get_string('emailpasswordconfirmation', '', $data);
- $subject = get_string('emailpasswordconfirmationsubject', '', format_string($site->fullname));
+ $message = get_string('emailresetconfirmation', '', $data);
+ $subject = get_string('emailresetconfirmationsubject', '', format_string($site->fullname));
// Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
return email_to_user($user, $supportuser, $subject, $message);
View
@@ -28,11 +28,11 @@
require('../config.php');
require_once($CFG->libdir.'/authlib.php');
-require_once('lib.php');
+require_once(__DIR__ . '/lib.php');
require_once('forgot_password_form.php');
+require_once('set_password_form.php');
-$p_secret = optional_param('p', false, PARAM_RAW);
-$p_username = optional_param('s', false, PARAM_RAW);
+$token = optional_param('token', false, PARAM_RAW);
//HTTPS is required in this page when $CFG->loginhttps enabled
$PAGE->https_required();
@@ -60,12 +60,12 @@
redirect($CFG->wwwroot.'/index.php', get_string('loginalready'), 5);
}
-if (empty($p_secret)) {
- // This is a new password reset request
- // identify the user & send confirmation email
+if (empty($token)) {
+ // This is a new password reset request.
+ // Process the request; identify the user & send confirmation email:
forgotpw_process_request();
} else {
// User clicked on confirmation link in email message
// validate the token & set new password
- forgotpw_process_pwset($p_secret, $p_username);
+ forgotpw_process_pwset($token);
}
Oops, something went wrong.

0 comments on commit 92de749

Please sign in to comment.