diff --git a/lang/en/error.php b/lang/en/error.php index 2fc15787bde..f3568de260a 100644 --- a/lang/en/error.php +++ b/lang/en/error.php @@ -501,6 +501,7 @@ $string['opensslsignerror'] = 'OpenSSL unable to sign data'; $string['opensslsealerror'] = 'OpenSSL unable to seal data'; $string['pagenotexisttitle'] = '404 Error: File not found'; $string['pagenotexist'] = '

An unusual error occurred trying to view a page that does not exist:

{$a}'; +$string['passwordexceeded'] = 'Password cannot be more than {$a} characters!'; $string['pathdoesnotstartslash'] = 'No valid arguments supplied, path does not start with slash!'; $string['pleasereport'] = 'If you have time, please let us know what you were trying to do when the error occurred:'; $string['pluginrequirementsnotmet'] = 'Plugin "{$a->pluginname}" ({$a->pluginversion}) could not be installed. It requires a newer version of Moodle (currently you are using {$a->currentmoodle}, you need {$a->requiremoodle}).'; diff --git a/lib/moodlelib.php b/lib/moodlelib.php index ad60fb291e5..2de6b34aa09 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -583,6 +583,11 @@ define('CONTACT_SUPPORT_AUTHENTICATED', 1); */ define('CONTACT_SUPPORT_ANYONE', 2); +/** + * Maximum number of characters for password. + */ +define('MAX_PASSWORD_CHARACTERS', 128); + // PARAMETER HANDLING. /** @@ -4740,6 +4745,11 @@ function get_password_peppers(): array { */ function validate_internal_user_password(stdClass $user, #[\SensitiveParameter] string $password): bool { + if (exceeds_password_length($password)) { + // Password cannot be more than MAX_PASSWORD_CHARACTERS characters. + return false; + } + if ($user->password === AUTH_PASSWORD_NOT_CACHED) { // Internal password is not used at all, it can not validate. return false; @@ -4782,11 +4792,17 @@ function validate_internal_user_password(stdClass $user, #[\SensitiveParameter] * @param bool $fasthash If true, use a low number of rounds when generating the hash * This is faster to generate but makes the hash less secure. * It is used when lots of hashes need to be generated quickly. + * @param int $pepperlength Lenght of the peppers * @return string The hashed password. * * @throws moodle_exception If a problem occurs while generating the hash. */ -function hash_internal_user_password(#[\SensitiveParameter] string $password, $fasthash = false): string { +function hash_internal_user_password(#[\SensitiveParameter] string $password, $fasthash = false, $pepperlength = 0): string { + if (exceeds_password_length($password, $pepperlength)) { + // Password cannot be more than MAX_PASSWORD_CHARACTERS. + throw new \moodle_exception(get_string("passwordexceeded", 'error', MAX_PASSWORD_CHARACTERS)); + } + // Set the cost factor to 5000 for fast hashing, otherwise use default cost. $rounds = $fasthash ? 5000 : 10000; @@ -11012,3 +11028,14 @@ function site_is_public() { return $ispublic; } + +/** + * Validates user's password length. + * + * @param string $password + * @param int $pepperlength The length of the used peppers + * @return bool + */ +function exceeds_password_length(string $password, int $pepperlength = 0): bool { + return (strlen($password) > (MAX_PASSWORD_CHARACTERS + $pepperlength)); +} diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php index 8c53a5c220e..21c4e56b1c9 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -2739,6 +2739,25 @@ EOF; get_password_peppers(); } + /** + * Test function to validate password length. + * + * @covers ::exceeds_password_length + * @return void + */ + public function test_exceeds_password_length() { + $this->resetAfterTest(true); + + // With password less than equals to MAX_PASSWORD_CHARACTERS. + $this->assertFalse(exceeds_password_length('test')); + + // With password more than MAX_PASSWORD_CHARACTERS. + $password = 'thisisapasswordthatcontainscharactersthatcan'; + $password .= 'exeedthepasswordlengthof128thisispasswordthatcont'; + $password .= 'ainscharactersthatcanexeedthelength-----'; + $this->assertTrue(exceeds_password_length($password)); + } + /** * Test function validate_internal_user_password. * @covers ::validate_internal_user_password diff --git a/lib/upgrade.txt b/lib/upgrade.txt index 6a149b58cb0..1f51d0c0a44 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -163,6 +163,8 @@ being forced open in all behat tests. but a subset can be specified instead. * core/form-autocomplete now supports disabled options in the source select list. These will be displayed in the autocomplete options with the aria-disabled attribute, and will not be selectable. +* Added a new constant called MAX_PASSWORD_CHARACTERS in moodlelib.php to hold a length of accepted password. +* Added a new method called exceeds_password_length in moodlelib.php to validate the password length. === 4.2 === diff --git a/login/change_password_form.php b/login/change_password_form.php index 63933875d74..8c73ed20ce7 100644 --- a/login/change_password_form.php +++ b/login/change_password_form.php @@ -59,13 +59,14 @@ class login_change_password_form extends moodleform { $mform->setType('password', PARAM_RAW); $mform->addElement('password', 'newpassword1', get_string('newpassword'), - ['autocomplete' => 'new-password']); + ['autocomplete' => 'new-password', 'maxlength' => MAX_PASSWORD_CHARACTERS]); $mform->addRule('newpassword1', get_string('required'), 'required', null, 'client'); + $mform->addRule('password', get_string('maximumchars', '', MAX_PASSWORD_CHARACTERS), + 'maxlength', MAX_PASSWORD_CHARACTERS, 'client'); $mform->setType('newpassword1', PARAM_RAW); - $mform->addElement('password', 'newpassword2', - get_string('newpassword').' ('.get_String('again').')', - ['autocomplete' => 'new-password']); + $mform->addElement('password', 'newpassword2', get_string('newpassword').' ('.get_String('again').')', + ['autocomplete' => 'new-password', 'maxlength' => MAX_PASSWORD_CHARACTERS]); $mform->addRule('newpassword2', get_string('required'), 'required', null, 'client'); $mform->setType('newpassword2', PARAM_RAW); diff --git a/login/set_password_form.php b/login/set_password_form.php index 1b29fb554fa..89221e70c5b 100644 --- a/login/set_password_form.php +++ b/login/set_password_form.php @@ -70,12 +70,16 @@ class login_set_password_form extends moodleform { if ($policies) { $mform->addElement('static', 'passwordpolicyinfo', '', implode('
', $policies)); } - $mform->addElement('password', 'password', get_string('newpassword')); + $mform->addElement('password', 'password', get_string('newpassword'), + ['maxlength' => MAX_PASSWORD_CHARACTERS]); $mform->addRule('password', get_string('required'), 'required', null, 'client'); + $mform->addRule('password', get_string('maximumchars', '', MAX_PASSWORD_CHARACTERS), + 'maxlength', MAX_PASSWORD_CHARACTERS, 'client'); $mform->setType('password', PARAM_RAW); $strpasswordagain = get_string('newpassword') . ' (' . get_string('again') . ')'; - $mform->addElement('password', 'password2', $strpasswordagain); + $mform->addElement('password', 'password2', $strpasswordagain, + ['maxlength' => MAX_PASSWORD_CHARACTERS]); $mform->addRule('password2', get_string('required'), 'required', null, 'client'); $mform->setType('password2', PARAM_RAW); diff --git a/login/signup_form.php b/login/signup_form.php index 356ab0823ab..2609b2810dd 100644 --- a/login/signup_form.php +++ b/login/signup_form.php @@ -44,12 +44,14 @@ class login_signup_form extends moodleform implements renderable, templatable { $mform->addElement('static', 'passwordpolicyinfo', '', print_password_policy()); } $mform->addElement('password', 'password', get_string('password'), [ - 'maxlength' => 32, + 'maxlength' => MAX_PASSWORD_CHARACTERS, 'size' => 12, 'autocomplete' => 'new-password' ]); $mform->setType('password', core_user::get_property_type('password')); $mform->addRule('password', get_string('missingpassword'), 'required', null, 'client'); + $mform->addRule('password', get_string('maximumchars', '', MAX_PASSWORD_CHARACTERS), + 'maxlength', MAX_PASSWORD_CHARACTERS, 'client'); $mform->addElement('text', 'email', get_string('email'), 'maxlength="100" size="25"'); $mform->setType('email', core_user::get_property_type('email')); diff --git a/user/editadvanced_form.php b/user/editadvanced_form.php index 2622dc89179..82af2a8451a 100644 --- a/user/editadvanced_form.php +++ b/user/editadvanced_form.php @@ -120,7 +120,10 @@ class user_editadvanced_form extends moodleform { } $purpose = user_edit_map_field_purpose($userid, 'password'); - $mform->addElement('passwordunmask', 'newpassword', get_string('newpassword'), 'size="20"' . $purpose); + $mform->addElement('passwordunmask', 'newpassword', get_string('newpassword'), + 'maxlength="'.MAX_PASSWORD_CHARACTERS.'" size="20"' . $purpose); + $mform->addRule('newpassword', get_string('maximumchars', '', MAX_PASSWORD_CHARACTERS), + 'maxlength', MAX_PASSWORD_CHARACTERS, 'client'); $mform->addHelpButton('newpassword', 'newpassword'); $mform->setType('newpassword', core_user::get_property_type('password')); $mform->disabledIf('newpassword', 'createpassword', 'checked');