diff --git a/backup/upgrade.txt b/backup/upgrade.txt index d57f2465a5f..6fda6cb208a 100644 --- a/backup/upgrade.txt +++ b/backup/upgrade.txt @@ -5,6 +5,8 @@ information provided here is intended especially for developers. * The function get_async_backup_links_backup has a new param of $backupid and is part of a fix to async backups (See MDL-69983). +* During restore the function create_included_users has been updated to convert backups containing + legacy MD5 hashed passwords to the new password hashing scheme (See MDL-79134). === 4.1 === diff --git a/backup/util/dbops/restore_dbops.class.php b/backup/util/dbops/restore_dbops.class.php index 07856b57562..0633fd8567c 100644 --- a/backup/util/dbops/restore_dbops.class.php +++ b/backup/util/dbops/restore_dbops.class.php @@ -1253,6 +1253,10 @@ abstract class restore_dbops { } else if ($userauth->isinternal and $userauth->canresetpwd) { $user->password = 'restored'; } + } else if (self::password_should_be_discarded($user->password)) { + // Password is not empty and it is MD5 hashed. Generate a new random password for the user. + // We don't want MD5 hashes in the database and users won't be able to log in with the associated password anyway. + $user->password = hash_internal_user_password(base64_encode(random_bytes(24))); } // Creating new user, we must reset the policyagreed always @@ -1904,6 +1908,17 @@ abstract class restore_dbops { public static function delete_course_content($courseid, array $options = null) { return remove_course_contents($courseid, false, $options); } + + /** + * Checks if password stored in backup is a MD5 hash. + * Returns true if it is, false otherwise. + * + * @param string $password The password to check. + * @return bool + */ + private static function password_should_be_discarded(#[\SensitiveParameter] string $password): bool { + return (bool) preg_match('/^[0-9a-f]{32}$/', $password); + } } /*