/** * Marks user deleted in internal user database and notifies the auth plugin. * Also unenrols user from all roles and does other cleanup. * * Any plugin that needs to purge user data should register the 'user_deleted' event. * * @param stdClass $user full user object before delete * @return boolean success * @throws coding_exception if invalid $user parameter detected */ function delete_user(stdClass $user) { global $CFG, $DB; require_once $CFG->libdir . '/grouplib.php'; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/message/lib.php'; require_once $CFG->dirroot . '/user/lib.php'; // Make sure nobody sends bogus record type as parameter. if (!property_exists($user, 'id') or !property_exists($user, 'username')) { throw new coding_exception('Invalid $user parameter in delete_user() detected'); } // Better not trust the parameter and fetch the latest info this will be very expensive anyway. if (!($user = $DB->get_record('user', array('id' => $user->id)))) { debugging('Attempt to delete unknown user account.'); return false; } // There must be always exactly one guest record, originally the guest account was identified by username only, // now we use $CFG->siteguest for performance reasons. if ($user->username === 'guest' or isguestuser($user)) { debugging('Guest user account can not be deleted.'); return false; } // Admin can be theoretically from different auth plugin, but we want to prevent deletion of internal accoutns only, // if anything goes wrong ppl may force somebody to be admin via config.php setting $CFG->siteadmins. if ($user->auth === 'manual' and is_siteadmin($user)) { debugging('Local administrator accounts can not be deleted.'); return false; } // Allow plugins to use this user object before we completely delete it. if ($pluginsfunction = get_plugins_with_function('pre_user_delete')) { foreach ($pluginsfunction as $plugintype => $plugins) { foreach ($plugins as $pluginfunction) { $pluginfunction($user); } } } // Keep user record before updating it, as we have to pass this to user_deleted event. $olduser = clone $user; // Keep a copy of user context, we need it for event. $usercontext = context_user::instance($user->id); // Delete all grades - backup is kept in grade_grades_history table. grade_user_delete($user->id); // Move unread messages from this user to read. message_move_userfrom_unread2read($user->id); // TODO: remove from cohorts using standard API here. // Remove user tags. core_tag_tag::remove_all_item_tags('core', 'user', $user->id); // Unconditionally unenrol from all courses. enrol_user_delete($user); // Unenrol from all roles in all contexts. // This might be slow but it is really needed - modules might do some extra cleanup! role_unassign_all(array('userid' => $user->id)); // Now do a brute force cleanup. // Remove from all cohorts. $DB->delete_records('cohort_members', array('userid' => $user->id)); // Remove from all groups. $DB->delete_records('groups_members', array('userid' => $user->id)); // Brute force unenrol from all courses. $DB->delete_records('user_enrolments', array('userid' => $user->id)); // Purge user preferences. $DB->delete_records('user_preferences', array('userid' => $user->id)); // Purge user extra profile info. $DB->delete_records('user_info_data', array('userid' => $user->id)); // Purge log of previous password hashes. $DB->delete_records('user_password_history', array('userid' => $user->id)); // Last course access not necessary either. $DB->delete_records('user_lastaccess', array('userid' => $user->id)); // Remove all user tokens. $DB->delete_records('external_tokens', array('userid' => $user->id)); // Unauthorise the user for all services. $DB->delete_records('external_services_users', array('userid' => $user->id)); // Remove users private keys. $DB->delete_records('user_private_key', array('userid' => $user->id)); // Remove users customised pages. $DB->delete_records('my_pages', array('userid' => $user->id, 'private' => 1)); // Force logout - may fail if file based sessions used, sorry. \core\session\manager::kill_user_sessions($user->id); // Generate username from email address, or a fake email. $delemail = !empty($user->email) ? $user->email : $user->username . '.' . $user->id . '@unknownemail.invalid'; $delname = clean_param($delemail . "." . time(), PARAM_USERNAME); // Workaround for bulk deletes of users with the same email address. while ($DB->record_exists('user', array('username' => $delname))) { // No need to use mnethostid here. $delname++; } // Mark internal user record as "deleted". $updateuser = new stdClass(); $updateuser->id = $user->id; $updateuser->deleted = 1; $updateuser->username = $delname; // Remember it just in case. $updateuser->email = md5($user->username); // Store hash of username, useful importing/restoring users. $updateuser->idnumber = ''; // Clear this field to free it up. $updateuser->picture = 0; $updateuser->timemodified = time(); // Don't trigger update event, as user is being deleted. user_update_user($updateuser, false, false); // Now do a final accesslib cleanup - removes all role assignments in user context and context itself. context_helper::delete_instance(CONTEXT_USER, $user->id); // Any plugin that needs to cleanup should register this event. // Trigger event. $event = \core\event\user_deleted::create(array('objectid' => $user->id, 'relateduserid' => $user->id, 'context' => $usercontext, 'other' => array('username' => $user->username, 'email' => $user->email, 'idnumber' => $user->idnumber, 'picture' => $user->picture, 'mnethostid' => $user->mnethostid))); $event->add_record_snapshot('user', $olduser); $event->trigger(); // We will update the user's timemodified, as it will be passed to the user_deleted event, which // should know about this updated property persisted to the user's table. $user->timemodified = $updateuser->timemodified; // Notify auth plugin - do not block the delete even when plugin fails. $authplugin = get_auth_plugin($user->auth); $authplugin->user_delete($user); return true; }
if ($authplugin->can_change_password()) { if (!$authplugin->user_update_password($usernew, $usernew->newpassword)) { print_error('cannotupdatepasswordonextauth', '', '', $usernew->auth); } unset_user_preference('create_password', $usernew); // Prevent cron from generating the password. if (!empty($CFG->passwordchangelogout)) { // We can use SID of other user safely here because they are unique, // the problem here is we do not want to logout admin here when changing own password. \core\session\manager::kill_user_sessions($usernew->id, session_id()); } } } // Force logout if user just suspended. if (isset($usernew->suspended) and $usernew->suspended and !$user->suspended) { \core\session\manager::kill_user_sessions($user->id); } } $usercontext = context_user::instance($usernew->id); // Update preferences. useredit_update_user_preference($usernew); // Update tags. if (!empty($CFG->usetags) and empty($USER->newadminuser)) { useredit_update_interests($usernew, $usernew->interests); } // Update user picture. if (empty($USER->newadminuser)) { useredit_update_picture($usernew, $userform, $filemanageroptions); } // Update mail bounces. useredit_update_bounces($user, $usernew);
/** * Syncronizes user fron external LDAP server to moodle user table * * Sync is now using username attribute. * * Syncing users removes or suspends users that dont exists anymore in external LDAP. * Creates new users and updates coursecreator status of users. * * @param bool $do_updates will do pull in data updates from LDAP if relevant */ function sync_users($do_updates = true) { global $CFG, $DB; print_string('connectingldap', 'auth_ldap'); $ldapconnection = $this->ldap_connect(); $dbman = $DB->get_manager(); /// Define table user to be created $table = new xmldb_table('tmp_extuser'); $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); $table->add_field('username', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null); $table->add_field('mnethostid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); $table->add_index('username', XMLDB_INDEX_UNIQUE, array('mnethostid', 'username')); print_string('creatingtemptable', 'auth_ldap', 'tmp_extuser'); $dbman->create_temp_table($table); //// //// get user's list from ldap to sql in a scalable fashion //// // prepare some data we'll need $filter = '(&(' . $this->config->user_attribute . '=*)' . $this->config->objectclass . ')'; $contexts = explode(';', $this->config->contexts); if (!empty($this->config->create_context)) { array_push($contexts, $this->config->create_context); } $ldap_pagedresults = ldap_paged_results_supported($this->config->ldap_version); $ldap_cookie = ''; foreach ($contexts as $context) { $context = trim($context); if (empty($context)) { continue; } do { if ($ldap_pagedresults) { ldap_control_paged_result($ldapconnection, $this->config->pagesize, true, $ldap_cookie); } if ($this->config->search_sub) { // Use ldap_search to find first user from subtree. $ldap_result = ldap_search($ldapconnection, $context, $filter, array($this->config->user_attribute)); } else { // Search only in this context. $ldap_result = ldap_list($ldapconnection, $context, $filter, array($this->config->user_attribute)); } if (!$ldap_result) { continue; } if ($ldap_pagedresults) { ldap_control_paged_result_response($ldapconnection, $ldap_result, $ldap_cookie); } if ($entry = @ldap_first_entry($ldapconnection, $ldap_result)) { do { $value = ldap_get_values_len($ldapconnection, $entry, $this->config->user_attribute); $value = core_text::convert($value[0], $this->config->ldapencoding, 'utf-8'); $value = trim($value); $this->ldap_bulk_insert($value); } while ($entry = ldap_next_entry($ldapconnection, $entry)); } unset($ldap_result); // Free mem. } while ($ldap_pagedresults && $ldap_cookie !== null && $ldap_cookie != ''); } // If LDAP paged results were used, the current connection must be completely // closed and a new one created, to work without paged results from here on. if ($ldap_pagedresults) { $this->ldap_close(true); $ldapconnection = $this->ldap_connect(); } /// preserve our user database /// if the temp table is empty, it probably means that something went wrong, exit /// so as to avoid mass deletion of users; which is hard to undo $count = $DB->count_records_sql('SELECT COUNT(username) AS count, 1 FROM {tmp_extuser}'); if ($count < 1) { print_string('didntgetusersfromldap', 'auth_ldap'); exit; } else { print_string('gotcountrecordsfromldap', 'auth_ldap', $count); } /// User removal // Find users in DB that aren't in ldap -- to be removed! // this is still not as scalable (but how often do we mass delete?) if ($this->config->removeuser == AUTH_REMOVEUSER_FULLDELETE) { $sql = "SELECT u.*\n FROM {user} u\n LEFT JOIN {tmp_extuser} e ON (u.username = e.username AND u.mnethostid = e.mnethostid)\n WHERE u.auth = :auth\n AND u.deleted = 0\n AND e.username IS NULL"; $remove_users = $DB->get_records_sql($sql, array('auth' => $this->authtype)); if (!empty($remove_users)) { print_string('userentriestoremove', 'auth_ldap', count($remove_users)); foreach ($remove_users as $user) { if (delete_user($user)) { echo "\t"; print_string('auth_dbdeleteuser', 'auth_db', array('name' => $user->username, 'id' => $user->id)); echo "\n"; } else { echo "\t"; print_string('auth_dbdeleteusererror', 'auth_db', $user->username); echo "\n"; } } } else { print_string('nouserentriestoremove', 'auth_ldap'); } unset($remove_users); // Free mem! } else { if ($this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) { $sql = "SELECT u.*\n FROM {user} u\n LEFT JOIN {tmp_extuser} e ON (u.username = e.username AND u.mnethostid = e.mnethostid)\n WHERE u.auth = :auth\n AND u.deleted = 0\n AND u.suspended = 0\n AND e.username IS NULL"; $remove_users = $DB->get_records_sql($sql, array('auth' => $this->authtype)); if (!empty($remove_users)) { print_string('userentriestoremove', 'auth_ldap', count($remove_users)); foreach ($remove_users as $user) { $updateuser = new stdClass(); $updateuser->id = $user->id; $updateuser->suspended = 1; user_update_user($updateuser, false); echo "\t"; print_string('auth_dbsuspenduser', 'auth_db', array('name' => $user->username, 'id' => $user->id)); echo "\n"; \core\session\manager::kill_user_sessions($user->id); } } else { print_string('nouserentriestoremove', 'auth_ldap'); } unset($remove_users); // Free mem! } } /// Revive suspended users if (!empty($this->config->removeuser) and $this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) { $sql = "SELECT u.id, u.username\n FROM {user} u\n JOIN {tmp_extuser} e ON (u.username = e.username AND u.mnethostid = e.mnethostid)\n WHERE (u.auth = 'nologin' OR (u.auth = ? AND u.suspended = 1)) AND u.deleted = 0"; // Note: 'nologin' is there for backwards compatibility. $revive_users = $DB->get_records_sql($sql, array($this->authtype)); if (!empty($revive_users)) { print_string('userentriestorevive', 'auth_ldap', count($revive_users)); foreach ($revive_users as $user) { $updateuser = new stdClass(); $updateuser->id = $user->id; $updateuser->auth = $this->authtype; $updateuser->suspended = 0; user_update_user($updateuser, false); echo "\t"; print_string('auth_dbreviveduser', 'auth_db', array('name' => $user->username, 'id' => $user->id)); echo "\n"; } } else { print_string('nouserentriestorevive', 'auth_ldap'); } unset($revive_users); } /// User Updates - time-consuming (optional) if ($do_updates) { // Narrow down what fields we need to update $all_keys = array_keys(get_object_vars($this->config)); $updatekeys = array(); foreach ($all_keys as $key) { if (preg_match('/^field_updatelocal_(.+)$/', $key, $match)) { // If we have a field to update it from // and it must be updated 'onlogin' we // update it on cron if (!empty($this->config->{'field_map_' . $match[1]}) and $this->config->{$match[0]} === 'onlogin') { array_push($updatekeys, $match[1]); // the actual key name } } } unset($all_keys); unset($key); } else { print_string('noupdatestobedone', 'auth_ldap'); } if ($do_updates and !empty($updatekeys)) { // run updates only if relevant $users = $DB->get_records_sql('SELECT u.username, u.id FROM {user} u WHERE u.deleted = 0 AND u.auth = ? AND u.mnethostid = ?', array($this->authtype, $CFG->mnet_localhost_id)); if (!empty($users)) { print_string('userentriestoupdate', 'auth_ldap', count($users)); $sitecontext = context_system::instance(); if (!empty($this->config->creators) and !empty($this->config->memberattribute) and $roles = get_archetype_roles('coursecreator')) { $creatorrole = array_shift($roles); // We can only use one, let's use the first one } else { $creatorrole = false; } $transaction = $DB->start_delegated_transaction(); $xcount = 0; $maxxcount = 100; foreach ($users as $user) { echo "\t"; print_string('auth_dbupdatinguser', 'auth_db', array('name' => $user->username, 'id' => $user->id)); if (!$this->update_user_record($user->username, $updatekeys, true)) { echo ' - ' . get_string('skipped'); } echo "\n"; $xcount++; // Update course creators if needed if ($creatorrole !== false) { if ($this->iscreator($user->username)) { role_assign($creatorrole->id, $user->id, $sitecontext->id, $this->roleauth); } else { role_unassign($creatorrole->id, $user->id, $sitecontext->id, $this->roleauth); } } } $transaction->allow_commit(); unset($users); // free mem } } else { // end do updates print_string('noupdatestobedone', 'auth_ldap'); } /// User Additions // Find users missing in DB that are in LDAP // and gives me a nifty object I don't want. // note: we do not care about deleted accounts anymore, this feature was replaced by suspending to nologin auth plugin $sql = 'SELECT e.id, e.username FROM {tmp_extuser} e LEFT JOIN {user} u ON (e.username = u.username AND e.mnethostid = u.mnethostid) WHERE u.id IS NULL'; $add_users = $DB->get_records_sql($sql); if (!empty($add_users)) { print_string('userentriestoadd', 'auth_ldap', count($add_users)); $sitecontext = context_system::instance(); if (!empty($this->config->creators) and !empty($this->config->memberattribute) and $roles = get_archetype_roles('coursecreator')) { $creatorrole = array_shift($roles); // We can only use one, let's use the first one } else { $creatorrole = false; } $transaction = $DB->start_delegated_transaction(); foreach ($add_users as $user) { $user = $this->get_userinfo_asobj($user->username); // Prep a few params $user->modified = time(); $user->confirmed = 1; $user->auth = $this->authtype; $user->mnethostid = $CFG->mnet_localhost_id; // get_userinfo_asobj() might have replaced $user->username with the value // from the LDAP server (which can be mixed-case). Make sure it's lowercase $user->username = trim(core_text::strtolower($user->username)); if (empty($user->lang)) { $user->lang = $CFG->lang; } if (empty($user->calendartype)) { $user->calendartype = $CFG->calendartype; } $id = user_create_user($user, false); echo "\t"; print_string('auth_dbinsertuser', 'auth_db', array('name' => $user->username, 'id' => $id)); echo "\n"; $euser = $DB->get_record('user', array('id' => $id)); if (!empty($this->config->forcechangepassword)) { set_user_preference('auth_forcepasswordchange', 1, $id); } // Add course creators if needed if ($creatorrole !== false and $this->iscreator($user->username)) { role_assign($creatorrole->id, $id, $sitecontext->id, $this->roleauth); } } $transaction->allow_commit(); unset($add_users); // free mem } else { print_string('nouserstobeadded', 'auth_ldap'); } $dbman->drop_table($table); $this->ldap_close(); return true; }
} } // Trigger event. \core\event\user_updated::create_from_userid($existinguser->id)->trigger(); } else { // no user information changed $upt->track('status', $struseruptodate); $usersuptodate++; if ($bulk == UU_BULK_ALL) { if (!in_array($user->id, $SESSION->bulk_users)) { $SESSION->bulk_users[] = $user->id; } } } if ($dologout) { \core\session\manager::kill_user_sessions($existinguser->id); } } else { // save the new user to the database $user->confirmed = 1; $user->timemodified = time(); $user->timecreated = time(); $user->mnethostid = $CFG->mnet_localhost_id; // we support ONLY local accounts here, sorry if (!isset($user->suspended) or $user->suspended === '') { $user->suspended = 0; } else { $user->suspended = $user->suspended ? 1 : 0; } $upt->track('suspended', $stryesnooptions[$user->suspended], 'normal', false); if (empty($user->auth)) {
/** * Suspends or Unsuspends a company and all of their users. * * Parameters - * $theme = string; * * */ public function suspend($suspend) { global $DB; // Get the company users. $users = $this->get_all_user_ids(); // Update their theme. foreach ($users as $userid) { if ($user = $DB->get_record('user', array('id' => $userid))) { if (!$DB->get_record('company_users', array('userid' => $user->id, 'companyid' => $this->id, 'suspended' => 1))) { $user->suspended = $suspend; $DB->update_record('user', $user); } if (!empty($suspend)) { \core\session\manager::kill_user_sessions($user->id); } } } // Set the suspend field for the company. $DB->set_field('company', 'suspended', $suspend, array('id' => $this->id)); }
/** * Terminates all sessions of one user, auth hooks are not executed. * NOTE: This can not work for file based sessions! * * @deprecated since 2.6 * @param int $userid user id */ function session_kill_user($userid) { debugging('session_kill_user() is deprecated, use \\core\\session\\manager::kill_user_sessions() instead', DEBUG_DEVELOPER); \core\session\manager::kill_user_sessions($userid); }
public function test_kill_user_sessions() { global $DB, $USER; $this->resetAfterTest(); $this->setAdminUser(); $userid = $USER->id; $sid = md5('hokus'); $record = new \stdClass(); $record->state = 0; $record->sid = $sid; $record->sessdata = null; $record->userid = $userid; $record->timecreated = time() - 60 * 60; $record->timemodified = time() - 30; $record->firstip = $record->lastip = '10.0.0.1'; $DB->insert_record('sessions', $record); $record->sid = md5('hokus2'); $DB->insert_record('sessions', $record); $record->userid = 0; $record->sid = md5('pokus'); $DB->insert_record('sessions', $record); $this->assertEquals(3, $DB->count_records('sessions')); \core\session\manager::kill_user_sessions($userid); $this->assertEquals(1, $DB->count_records('sessions')); $this->assertFalse($DB->record_exists('sessions', array('userid' => $userid))); }
/** * The IdP uses this function to kill child sessions on other hosts * * @param string $username Username for session to kill * @param string $useragent SHA1 hash of user agent to look for * @return string A plaintext report of what has happened */ function kill_children($username, $useragent) { global $CFG, $USER, $DB; $remoteclient = null; if (defined('MNET_SERVER')) { $remoteclient = get_mnet_remote_client(); } require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; $userid = $DB->get_field('user', 'id', array('mnethostid' => $CFG->mnet_localhost_id, 'username' => $username)); $returnstring = ''; $mnetsessions = $DB->get_records('mnet_session', array('userid' => $userid, 'useragent' => $useragent)); if (false == $mnetsessions) { $returnstring .= "Could find no remote sessions\n"; $mnetsessions = array(); } foreach ($mnetsessions as $mnetsession) { // If this script is being executed by a remote peer, that means the user has clicked // logout on that peer, and the session on that peer can be deleted natively. // Skip over it. if (isset($remoteclient->id) && $mnetsession->mnethostid == $remoteclient->id) { continue; } $returnstring .= "Deleting session\n"; $mnet_peer = new mnet_peer(); $mnet_peer->set_id($mnetsession->mnethostid); $mnet_request = new mnet_xmlrpc_client(); $mnet_request->set_method('auth/mnet/auth.php/kill_child'); // set $token and $useragent parameters $mnet_request->add_param($username); $mnet_request->add_param($useragent); if ($mnet_request->send($mnet_peer) === false) { debugging("Server side error has occured on host {$mnetsession->mnethostid}: " . join("\n", $mnet_request->error)); } } $ignore = $DB->delete_records('mnet_session', array('useragent' => $useragent, 'userid' => $userid)); if (isset($remoteclient) && isset($remoteclient->id)) { \core\session\manager::kill_user_sessions($userid); } return $returnstring; }
/** * Proceed with the import of the user. * * @return void */ public function proceed() { if (!$this->prepared) { throw new coding_exception('The course has not been prepared.'); } else { if ($this->has_errors()) { throw new moodle_exception('Cannot proceed, errors were detected.'); } else { if ($this->processstarted) { throw new coding_exception('The process has already been started.'); } } } $this->processstarted = true; if ($this->do === self::DO_DELETE) { $this->finaldata = $this->existing; try { $success = delete_user($this->existing); } catch (moodle_exception $e) { $success = false; } if (!$success) { $this->error('usernotdeletederror', new lang_string('usernotdeletederror', 'tool_uploadusercli')); return false; } $this->set_status('userdeleted', new lang_string('userdeleted', 'tool_uploaduser')); return true; } else { if ($this->do === self::DO_CREATE) { try { $this->finaldata->id = user_create_user($this->finaldata, false, false); } catch (Exception $e) { $this->error('errorcreatinguser', new lang_string('errorcreatinguser', 'tool_uploadusercli')); return false; } if ($this->needpasswordchange) { set_user_preference('auth_forcepasswordchange', 1, $this->finaldata); $this->set_status('forcepasswordchange', new lang_string('forcepasswordchange', 'tool_uploadusercli')); } if ($this->finaldata->password === 'to be generated') { set_user_preference('create_password', 1, $this->finaldata); } $this->set_status('useradded', new lang_string('newuser')); } else { if ($this->do === self::DO_UPDATE) { try { user_update_user($this->finaldata, false, false); } catch (Exception $e) { $this->error('usernotupdatederror', new lang_string('usernotupdatederror', 'error')); return false; } if ($this->dologout) { \core\session\manager::kill_user_sessions($this->finaldata->id); } $this->set_status('useraccountupdated', new lang_string('useraccountupdated', 'tool_uploaduser')); } } } if ($this->do === self::DO_UPDATE || $this->do === self::DO_CREATE) { if (!$this->isremote) { $this->finaldata = uu_pre_process_custom_profile_data($this->finaldata); profile_save_data($this->finaldata); } $success = $this->add_to_cohort(); $success = $success && $this->add_to_egr(); if (!$success) { return false; } } return true; }
/** * Suspends a user and keeps the company details as was. * @param int userid * @return boolean */ public static function suspend($userid) { global $DB; // Get the company details for the user. $company = company::get_company_byuserid($userid); $context = context_system::instance(); // Get the users company record. $DB->set_field('company_users', 'suspended', 1, array('userid' => $userid, 'companyid' => $company->id)); // Mark user as suspended. $DB->set_field('user', 'suspended', 1, array('id' => $userid)); // Log the user out. \core\session\manager::kill_user_sessions($userid); }
/** * This function processes a user's submitted token to validate the request to set a new password. * If the user's token is validated, they are prompted to set a new password. * @param string $token the one-use identifier which should verify the password reset request as being valid. * @return void */ function core_login_process_password_set($token) { global $DB, $CFG, $OUTPUT, $PAGE, $SESSION; require_once $CFG->dirroot . '/user/lib.php'; $pwresettime = isset($CFG->pwresettime) ? $CFG->pwresettime : 1800; $sql = "SELECT u.*, upr.token, upr.timerequested, upr.id as tokenid\n FROM {user} u\n JOIN {user_password_resets} upr ON upr.userid = u.id\n WHERE upr.token = ?"; $user = $DB->get_record_sql($sql, array($token)); $forgotpasswordurl = "{$CFG->httpswwwroot}/login/forgot_password.php"; if (empty($user) or $user->timerequested < time() - $pwresettime - DAYSECS) { // There is no valid reset request record - not even a recently expired one. // (suspicious) // Direct the user to the forgot password page to request a password reset. echo $OUTPUT->header(); notice(get_string('noresetrecord'), $forgotpasswordurl); die; // Never reached. } if ($user->timerequested < time() - $pwresettime) { // There is a reset record, but it's expired. // Direct the user to the forgot password page to request a password reset. $pwresetmins = floor($pwresettime / MINSECS); echo $OUTPUT->header(); notice(get_string('resetrecordexpired', '', $pwresetmins), $forgotpasswordurl); die; // Never reached. } if ($user->auth === 'nologin' or !is_enabled_auth($user->auth)) { // Bad luck - user is not able to login, do not let them set password. echo $OUTPUT->header(); print_error('forgotteninvalidurl'); die; // Never reached. } // Check this isn't guest user. if (isguestuser($user)) { print_error('cannotresetguestpwd'); } // Token is correct, and unexpired. $mform = new login_set_password_form(null, $user, 'post', '', 'autocomplete="yes"'); $data = $mform->get_data(); if (empty($data)) { // User hasn't submitted form, they got here directly from email link. // Next, display the form. $setdata = new stdClass(); $setdata->username = $user->username; $setdata->username2 = $user->username; $setdata->token = $user->token; $mform->set_data($setdata); $PAGE->verify_https_required(); echo $OUTPUT->header(); echo $OUTPUT->box(get_string('setpasswordinstructions'), 'generalbox boxwidthnormal boxaligncenter'); $mform->display(); echo $OUTPUT->footer(); return; } else { // User has submitted form. // Delete this token so it can't be used again. $DB->delete_records('user_password_resets', array('id' => $user->tokenid)); $userauth = get_auth_plugin($user->auth); if (!$userauth->user_update_password($user, $data->password)) { print_error('errorpasswordupdate', 'auth'); } user_add_password_history($user->id, $data->password); if (!empty($CFG->passwordchangelogout)) { \core\session\manager::kill_user_sessions($user->id, session_id()); } // Reset login lockout (if present) before a new password is set. login_unlock_account($user); // Clear any requirement to change passwords. unset_user_preference('auth_forcepasswordchange', $user); unset_user_preference('create_password', $user); if (!empty($user->lang)) { // Unset previous session language - use user preference instead. unset($SESSION->lang); } complete_user_login($user); // Triggers the login event. \core\session\manager::apply_concurrent_login_limit($user->id, session_id()); $urltogo = core_login_get_return_url(); unset($SESSION->wantsurl); redirect($urltogo, get_string('passwordset'), 1); } }
$navlinks = array(); $navlinks[] = array('name' => $strparticipants, 'link' => "$CFG->wwwroot/user/index.php?id=$course->id", 'type' => 'misc'); if ($mform->is_cancelled()) { redirect($CFG->wwwroot.'/user/preferences.php?userid='.$USER->id.'&course='.$course->id); } else if ($data = $mform->get_data()) { if (!$userauth->user_update_password($USER, $data->newpassword1)) { print_error('errorpasswordupdate', 'auth'); } user_add_password_history($USER->id, $data->newpassword1); if (!empty($CFG->passwordchangelogout)) { \core\session\manager::kill_user_sessions($USER->id, session_id()); } // Reset login lockout - we want to prevent any accidental confusion here. login_unlock_account($USER); // register success changing password unset_user_preference('auth_forcepasswordchange', $USER); unset_user_preference('create_password', $USER); $strpasswordchanged = get_string('passwordchanged'); $fullname = fullname($USER, true); $PAGE->set_title($strpasswordchanged); $PAGE->set_heading(fullname($USER));
/** * Update users * * @param array $users * @return null * @since Moodle 2.2 */ public static function update_users($users) { global $CFG, $DB, $USER; require_once($CFG->dirroot."/user/lib.php"); require_once($CFG->dirroot."/user/profile/lib.php"); // Required for customfields related function. // Ensure the current user is allowed to run this function. $context = context_system::instance(); require_capability('moodle/user:update', $context); self::validate_context($context); $params = self::validate_parameters(self::update_users_parameters(), array('users' => $users)); $filemanageroptions = array('maxbytes' => $CFG->maxbytes, 'subdirs' => 0, 'maxfiles' => 1, 'accepted_types' => 'web_image'); $transaction = $DB->start_delegated_transaction(); foreach ($params['users'] as $user) { // First check the user exists. if (!$existinguser = core_user::get_user($user['id'])) { continue; } // Check if we are trying to update an admin. if ($existinguser->id != $USER->id and is_siteadmin($existinguser) and !is_siteadmin($USER)) { continue; } // Other checks (deleted, remote or guest users). if ($existinguser->deleted or is_mnet_remote_user($existinguser) or isguestuser($existinguser->id)) { continue; } user_update_user($user, true, false); // Update user picture if it was specified for this user. if (empty($CFG->disableuserimages) && isset($user['userpicture'])) { $userobject = (object)$user; $userobject->deletepicture = null; if ($user['userpicture'] == 0) { $userobject->deletepicture = true; } else { $userobject->imagefile = $user['userpicture']; } core_user::update_picture($userobject, $filemanageroptions); } // Update user custom fields. if (!empty($user['customfields'])) { foreach ($user['customfields'] as $customfield) { // Profile_save_data() saves profile file it's expecting a user with the correct id, // and custom field to be named profile_field_"shortname". $user["profile_field_".$customfield['type']] = $customfield['value']; } profile_save_data((object) $user); } // Trigger event. \core\event\user_updated::create_from_userid($user['id'])->trigger(); // Preferences. if (!empty($user['preferences'])) { foreach ($user['preferences'] as $preference) { set_user_preference($preference['type'], $preference['value'], $user['id']); } } if (isset($user['suspended']) and $user['suspended']) { \core\session\manager::kill_user_sessions($user['id']); } } $transaction->allow_commit(); return null; }