Beispiel #1
0
/**
 * Compare password against hash stored in user object to determine if it is valid.
 *
 * If necessary it also updates the stored hash to the current format.
 *
 * @param stdClass $user (Password property may be updated).
 * @param string $password Plain text password.
 * @return bool True if password is valid.
 */
function validate_internal_user_password($user, $password)
{
    global $CFG;
    if ($user->password === AUTH_PASSWORD_NOT_CACHED) {
        // Internal password is not used at all, it can not validate.
        return false;
    }
    // If hash isn't a legacy (md5) hash, validate using the library function.
    if (!password_is_legacy_hash($user->password)) {
        return password_verify($password, $user->password);
    }
    // Otherwise we need to check for a legacy (md5) hash instead. If the hash
    // is valid we can then update it to the new algorithm.
    $sitesalt = isset($CFG->passwordsaltmain) ? $CFG->passwordsaltmain : '';
    $validated = false;
    if ($user->password === md5($password . $sitesalt) or $user->password === md5($password) or $user->password === md5(addslashes($password) . $sitesalt) or $user->password === md5(addslashes($password))) {
        // Note: we are intentionally using the addslashes() here because we
        //       need to accept old password hashes of passwords with magic quotes.
        $validated = true;
    } else {
        for ($i = 1; $i <= 20; $i++) {
            // 20 alternative salts should be enough, right?
            $alt = 'passwordsaltalt' . $i;
            if (!empty($CFG->{$alt})) {
                if ($user->password === md5($password . $CFG->{$alt}) or $user->password === md5(addslashes($password) . $CFG->{$alt})) {
                    $validated = true;
                    break;
                }
            }
        }
    }
    if ($validated) {
        // If the password matches the existing md5 hash, update to the
        // current hash algorithm while we have access to the user's password.
        update_internal_user_password($user, $password);
    }
    return $validated;
}
 /**
  * Test function update_internal_user_password().
  */
 public function test_update_internal_user_password()
 {
     global $DB;
     $this->resetAfterTest();
     $passwords = array('password', '1234', 'changeme', '****');
     foreach ($passwords as $password) {
         $user = $this->getDataGenerator()->create_user(array('auth' => 'manual'));
         update_internal_user_password($user, $password);
         // The user object should have been updated.
         $this->assertTrue(validate_internal_user_password($user, $password));
         // The database field for the user should also have been updated to the
         // same value.
         $this->assertSame($user->password, $DB->get_field('user', 'password', array('id' => $user->id)));
     }
     $user = $this->getDataGenerator()->create_user(array('auth' => 'manual'));
     // Manually set the user's password to the md5 of the string 'password'.
     $DB->set_field('user', 'password', '5f4dcc3b5aa765d61d8327deb882cf99', array('id' => $user->id));
     // Update the password.
     update_internal_user_password($user, 'password');
     if (password_compat_not_supported()) {
         // If bcrypt not properly supported the password should remain as an md5 hash.
         $expected_hash = hash_internal_user_password('password', true);
         $this->assertSame($user->password, $expected_hash);
         $this->assertTrue(password_is_legacy_hash($user->password));
     } else {
         // Otherwise password should have been updated to a bcrypt hash.
         $this->assertFalse(password_is_legacy_hash($user->password));
     }
 }
Beispiel #3
0
 /**
  * Test function update_internal_user_password().
  */
 public function test_update_internal_user_password()
 {
     global $DB;
     $this->resetAfterTest();
     $passwords = array('password', '1234', 'changeme', '****');
     foreach ($passwords as $password) {
         $user = $this->getDataGenerator()->create_user(array('auth' => 'manual'));
         update_internal_user_password($user, $password);
         // The user object should have been updated.
         $this->assertTrue(validate_internal_user_password($user, $password));
         // The database field for the user should also have been updated to the
         // same value.
         $this->assertSame($user->password, $DB->get_field('user', 'password', array('id' => $user->id)));
     }
     $user = $this->getDataGenerator()->create_user(array('auth' => 'manual'));
     // Manually set the user's password to the md5 of the string 'password'.
     $DB->set_field('user', 'password', '5f4dcc3b5aa765d61d8327deb882cf99', array('id' => $user->id));
     $sink = $this->redirectEvents();
     // Update the password.
     update_internal_user_password($user, 'password');
     $events = $sink->get_events();
     $sink->close();
     $event = array_pop($events);
     // Password should have been updated to a bcrypt hash.
     $this->assertFalse(password_is_legacy_hash($user->password));
     // Verify event information.
     $this->assertInstanceOf('\\core\\event\\user_password_updated', $event);
     $this->assertSame($user->id, $event->relateduserid);
     $this->assertEquals(context_user::instance($user->id), $event->get_context());
     $this->assertEventContextNotUsed($event);
     // Verify recovery of property 'auth'.
     unset($user->auth);
     update_internal_user_password($user, 'newpassword');
     $this->assertDebuggingCalled('User record in update_internal_user_password() must include field auth', DEBUG_DEVELOPER);
     $this->assertEquals('manual', $user->auth);
 }