/** * Called from set/unset_user_preferences, so that the prefs can be correctly reloaded in different sessions. * * NOTE: internal function, do not call from other code. * * @package core * @access private * @param integer $userid the user whose prefs were changed. */ function mark_user_preferences_changed($userid) { global $CFG; if (empty($userid) or isguestuser($userid)) { // No cache flags for guest and not-logged-in users. return; } set_cache_flag('userpreferenceschanged', $userid, 1, time() + $CFG->sessiontimeout); }
public function test_set_user_preference() { global $DB, $USER; $this->resetAfterTest(); $this->setAdminUser(); $otheruser = $this->getDataGenerator()->create_user(); $otheruserid = $otheruser->id; $DB->delete_records('user_preferences', array('userid' => $otheruserid)); set_cache_flag('userpreferenceschanged', $otheruserid, null); $user = new stdClass(); $user->id = $otheruserid; set_user_preference('aaa', 'bbb', $otheruserid); $this->assertSame('bbb', $DB->get_field('user_preferences', 'value', array('userid' => $otheruserid, 'name' => 'aaa'))); $this->assertSame('bbb', get_user_preferences('aaa', null, $otheruserid)); set_user_preference('xxx', 'yyy', $user); $this->assertSame('yyy', $DB->get_field('user_preferences', 'value', array('userid' => $otheruserid, 'name' => 'xxx'))); $this->assertSame('yyy', get_user_preferences('xxx', null, $otheruserid)); $this->assertTrue(is_array($user->preference)); $this->assertSame('bbb', $user->preference['aaa']); $this->assertSame('yyy', $user->preference['xxx']); set_user_preference('xxx', null, $user); $this->assertFalse($DB->get_field('user_preferences', 'value', array('userid' => $otheruserid, 'name' => 'xxx'))); $this->assertNull(get_user_preferences('xxx', null, $otheruserid)); set_user_preference('ooo', true, $user); $prefs = get_user_preferences(null, null, $otheruserid); $this->assertSame($user->preference['aaa'], $prefs['aaa']); $this->assertSame($user->preference['ooo'], $prefs['ooo']); $this->assertSame('1', $prefs['ooo']); set_user_preference('null', 0, $user); $this->assertSame('0', get_user_preferences('null', null, $otheruserid)); $this->assertSame('lala', get_user_preferences('undefined', 'lala', $otheruserid)); $DB->delete_records('user_preferences', array('userid' => $otheruserid)); set_cache_flag('userpreferenceschanged', $otheruserid, null); // Test $USER default. set_user_preference('_test_user_preferences_pref', 'ok'); $this->assertSame('ok', $USER->preference['_test_user_preferences_pref']); unset_user_preference('_test_user_preferences_pref'); $this->assertTrue(!isset($USER->preference['_test_user_preferences_pref'])); // Test 1333 char values (no need for unicode, there are already tests for that in DB tests). $longvalue = str_repeat('a', 1333); set_user_preference('_test_long_user_preference', $longvalue); $this->assertEquals($longvalue, get_user_preferences('_test_long_user_preference')); $this->assertEquals($longvalue, $DB->get_field('user_preferences', 'value', array('userid' => $USER->id, 'name' => '_test_long_user_preference'))); // Test > 1333 char values, coding_exception expected. $longvalue = str_repeat('a', 1334); try { set_user_preference('_test_long_user_preference', $longvalue); $this->fail('Exception expected - longer than 1333 chars not allowed as preference value'); } catch (moodle_exception $ex) { $this->assertInstanceOf('coding_exception', $ex); } // Test invalid params. try { set_user_preference('_test_user_preferences_pref', array()); $this->fail('Exception expected - array not valid preference value'); } catch (moodle_exception $ex) { $this->assertInstanceOf('coding_exception', $ex); } try { set_user_preference('_test_user_preferences_pref', new stdClass()); $this->fail('Exception expected - class not valid preference value'); } catch (moodle_exception $ex) { $this->assertInstanceOf('coding_exception', $ex); } try { set_user_preference('_test_user_preferences_pref', 1, array('xx' => 1)); $this->fail('Exception expected - user instance expected'); } catch (moodle_exception $ex) { $this->assertInstanceOf('coding_exception', $ex); } try { set_user_preference('_test_user_preferences_pref', 1, 'abc'); $this->fail('Exception expected - user instance expected'); } catch (moodle_exception $ex) { $this->assertInstanceOf('coding_exception', $ex); } try { set_user_preference('', 1); $this->fail('Exception expected - invalid name accepted'); } catch (moodle_exception $ex) { $this->assertInstanceOf('coding_exception', $ex); } try { set_user_preference('1', 1); $this->fail('Exception expected - invalid name accepted'); } catch (moodle_exception $ex) { $this->assertInstanceOf('coding_exception', $ex); } }
/** * Mark a context as dirty (with timestamp) so as to force reloading of the context. * * @deprecated since 2.2, use $context->mark_dirty() instead * @see context::mark_dirty() * @param string $path context path */ function mark_context_dirty($path) { global $CFG, $USER, $ACCESSLIB_PRIVATE; debugging('mark_context_dirty() is deprecated, please use $context->mark_dirty() instead.', DEBUG_DEVELOPER); if (during_initial_install()) { return; } // only if it is a non-empty string if (is_string($path) && $path !== '') { set_cache_flag('accesslib/dirtycontexts', $path, 1, time() + $CFG->sessiontimeout); if (isset($ACCESSLIB_PRIVATE->dirtycontexts)) { $ACCESSLIB_PRIVATE->dirtycontexts[$path] = 1; } else { if (CLI_SCRIPT) { $ACCESSLIB_PRIVATE->dirtycontexts = array($path => 1); } else { if (isset($USER->access['time'])) { $ACCESSLIB_PRIVATE->dirtycontexts = get_cache_flags('accesslib/dirtycontexts', $USER->access['time'] - 2); } else { $ACCESSLIB_PRIVATE->dirtycontexts = array($path => 1); } // flags not loaded yet, it will be done later in $context->reload_if_dirty() } } } }
/** * To be called from a page running under NTLM's * "Integrated Windows Authentication". * * If successful, it will set a special "cookie" (not an HTTP cookie!) * in cache_flags under the $this->pluginconfig/ntlmsess "plugin" and return true. * The "cookie" will be picked up by ntlmsso_finish() to complete the * process. * * On failure it will return false for the caller to display an appropriate * error message (probably saying that Integrated Windows Auth isn't enabled!) * * NOTE that this code will execute under the OS user credentials, * so we MUST avoid dealing with files -- such as session files. * (The caller should define('NO_MOODLE_COOKIES', true) before including config.php) * */ function ntlmsso_magic($sesskey) { if (isset($_SERVER['REMOTE_USER']) && !empty($_SERVER['REMOTE_USER'])) { // HTTP __headers__ seem to be sent in ISO-8859-1 encoding // (according to my reading of RFC-1945, RFC-2616 and RFC-2617 and // my local tests), so we need to convert the REMOTE_USER value // (i.e., what we got from the HTTP WWW-Authenticate header) into UTF-8 $username = core_text::convert($_SERVER['REMOTE_USER'], 'iso-8859-1', 'utf-8'); switch ($this->config->ntlmsso_type) { case 'ntlm': // The format is now configurable, so try to extract the username $username = $this->get_ntlm_remote_user($username); if (empty($username)) { return false; } break; case 'kerberos': // Format is username@DOMAIN $username = substr($username, 0, strpos($username, '@')); break; default: error_log($this->errorlogtag . get_string('ntlmsso_unknowntype', 'auth_ldap')); return false; // Should never happen! } $username = core_text::strtolower($username); // Compatibility hack set_cache_flag($this->pluginconfig . '/ntlmsess', $sesskey, $username, AUTH_NTLMTIMEOUT); return true; } return false; }
/** * Mark a context as dirty (with timestamp) * so as to force reloading of the context. * @param string $path context path */ function mark_context_dirty($path) { global $CFG, $ACCESSLIB_PRIVATE; if (empty($CFG->rolesactive)) { return; } // only if it is a non-empty string if (is_string($path) && $path !== '') { set_cache_flag('accesslib/dirtycontexts', $path, 1, time() + $CFG->sessiontimeout); if (isset($ACCESSLIB_PRIVATE->dirtycontexts)) { $ACCESSLIB_PRIVATE->dirtycontexts[$path] = 1; } } }
/** * Notify admin users or admin user of any failed logins (since last notification). * * Note that this function must be only executed from the cron script * It uses the cache_flags system to store temporary records, deleting them * by name before finishing * * @uses $CFG * @uses $db * @uses HOURSECS */ function notify_login_failures() { global $CFG, $db; switch ($CFG->notifyloginfailures) { case 'mainadmin': $recip = array(get_admin()); break; case 'alladmins': $recip = get_admins(); break; } if (empty($CFG->lastnotifyfailure)) { $CFG->lastnotifyfailure = 0; } // we need to deal with the threshold stuff first. if (empty($CFG->notifyloginthreshold)) { $CFG->notifyloginthreshold = 10; // default to something sensible. } /// Get all the IPs with more than notifyloginthreshold failures since lastnotifyfailure /// and insert them into the cache_flags temp table $iprs = get_recordset_sql("SELECT ip, count(*)\n FROM {$CFG->prefix}log\n WHERE module = 'login'\n AND action = 'error'\n AND time > {$CFG->lastnotifyfailure}\n GROUP BY ip\n HAVING count(*) >= {$CFG->notifyloginthreshold}"); while ($iprec = rs_fetch_next_record($iprs)) { if (!empty($iprec->ip)) { set_cache_flag('login_failure_by_ip', $iprec->ip, '1', 0); } } rs_close($iprs); /// Get all the INFOs with more than notifyloginthreshold failures since lastnotifyfailure /// and insert them into the cache_flags temp table $infors = get_recordset_sql("SELECT info, count(*)\n FROM {$CFG->prefix}log\n WHERE module = 'login'\n AND action = 'error'\n AND time > {$CFG->lastnotifyfailure}\n GROUP BY info\n HAVING count(*) >= {$CFG->notifyloginthreshold}"); while ($inforec = rs_fetch_next_record($infors)) { if (!empty($inforec->info)) { set_cache_flag('login_failure_by_info', $inforec->info, '1', 0); } } rs_close($infors); /// Now, select all the login error logged records belonging to the ips and infos /// since lastnotifyfailure, that we have stored in the cache_flags table $logsrs = get_recordset_sql("SELECT l.*, u.firstname, u.lastname\n FROM {$CFG->prefix}log l\n JOIN {$CFG->prefix}cache_flags cf ON (l.ip = cf.name)\n LEFT JOIN {$CFG->prefix}user u ON (l.userid = u.id)\n WHERE l.module = 'login'\n AND l.action = 'error'\n AND l.time > {$CFG->lastnotifyfailure}\n AND cf.flagtype = 'login_failure_by_ip'\n UNION ALL\n SELECT l.*, u.firstname, u.lastname\n FROM {$CFG->prefix}log l\n JOIN {$CFG->prefix}cache_flags cf ON (l.info = cf.name)\n LEFT JOIN {$CFG->prefix}user u ON (l.userid = u.id)\n WHERE l.module = 'login'\n AND l.action = 'error'\n AND l.time > {$CFG->lastnotifyfailure}\n AND cf.flagtype = 'login_failure_by_info'\n ORDER BY time DESC"); /// Init some variables $count = 0; $messages = ''; /// Iterate over the logs recordset while ($log = rs_fetch_next_record($logsrs)) { $log->time = userdate($log->time); $messages .= get_string('notifyloginfailuresmessage', '', $log) . "\n"; $count++; } rs_close($logsrs); /// If we haven't run in the last hour and /// we have something useful to report and we /// are actually supposed to be reporting to somebody if (time() - HOURSECS > $CFG->lastnotifyfailure && $count > 0 && is_array($recip) && count($recip) > 0) { $site = get_site(); $subject = get_string('notifyloginfailuressubject', '', format_string($site->fullname)); /// Calculate the complete body of notification (start + messages + end) $body = get_string('notifyloginfailuresmessagestart', '', $CFG->wwwroot) . ($CFG->lastnotifyfailure != 0 ? '(' . userdate($CFG->lastnotifyfailure) . ')' : '') . "\n\n" . $messages . "\n\n" . get_string('notifyloginfailuresmessageend', '', $CFG->wwwroot) . "\n\n"; /// For each destination, send mail mtrace('Emailing admins about ' . $count . ' failed login attempts'); foreach ($recip as $admin) { email_to_user($admin, get_admin(), $subject, $body); } /// Update lastnotifyfailure with current time set_config('lastnotifyfailure', time()); } /// Finally, delete all the temp records we have created in cache_flags delete_records_select('cache_flags', "flagtype IN ('login_failure_by_ip', 'login_failure_by_info')"); }
public function test_set_user_preference() { global $DB, $USER; if (!($otheruserid = $this->get_fake_preference_test_userid())) { $this->fail('Can not find unused user id for the preferences test'); return; } $DB->delete_records('user_preferences', array('userid' => $otheruserid)); set_cache_flag('userpreferenceschanged', $otheruserid, null); $user = new stdClass(); $user->id = $otheruserid; set_user_preference('aaa', 'bbb', $otheruserid); $this->assertEqual('bbb', $DB->get_field('user_preferences', 'value', array('userid' => $otheruserid, 'name' => 'aaa'))); $this->assertEqual('bbb', get_user_preferences('aaa', null, $otheruserid)); set_user_preference('xxx', 'yyy', $user); $this->assertEqual('yyy', $DB->get_field('user_preferences', 'value', array('userid' => $otheruserid, 'name' => 'xxx'))); $this->assertEqual('yyy', get_user_preferences('xxx', null, $otheruserid)); $this->assertTrue(is_array($user->preference)); $this->assertEqual($user->preference['aaa'], 'bbb'); $this->assertEqual($user->preference['xxx'], 'yyy'); set_user_preference('xxx', NULL, $user); $this->assertIdentical(false, $DB->get_field('user_preferences', 'value', array('userid' => $otheruserid, 'name' => 'xxx'))); $this->assertIdentical(null, get_user_preferences('xxx', null, $otheruserid)); set_user_preference('ooo', true, $user); $prefs = get_user_preferences(null, null, $otheruserid); $this->assertIdentical($prefs['aaa'], $user->preference['aaa']); $this->assertIdentical($prefs['ooo'], $user->preference['ooo']); $this->assertIdentical($prefs['ooo'], '1'); set_user_preference('null', 0, $user); $this->assertIdentical('0', get_user_preferences('null', null, $otheruserid)); $this->assertIdentical('lala', get_user_preferences('undefined', 'lala', $otheruserid)); $DB->delete_records('user_preferences', array('userid' => $otheruserid)); set_cache_flag('userpreferenceschanged', $otheruserid, null); // test $USER default set_user_preference('_test_user_preferences_pref', 'ok'); $this->assertIdentical('ok', $USER->preference['_test_user_preferences_pref']); unset_user_preference('_test_user_preferences_pref'); $this->assertTrue(!isset($USER->preference['_test_user_preferences_pref'])); //test invalid params try { set_user_preference('_test_user_preferences_pref', array()); $this->assertFail('Exception expected - array not valid preference value'); } catch (Exception $ex) { $this->assertTrue(true); } try { set_user_preference('_test_user_preferences_pref', new stdClass()); $this->assertFail('Exception expected - class not valid preference value'); } catch (Exception $ex) { $this->assertTrue(true); } try { set_user_preference('_test_user_preferences_pref', 1, array('xx' => 1)); $this->assertFail('Exception expected - user instance expected'); } catch (Exception $ex) { $this->assertTrue(true); } try { set_user_preference('_test_user_preferences_pref', 1, 'abc'); $this->assertFail('Exception expected - user instance expected'); } catch (Exception $ex) { $this->assertTrue(true); } try { set_user_preference('', 1); $this->assertFail('Exception expected - invalid name accepted'); } catch (Exception $ex) { $this->assertTrue(true); } try { set_user_preference('1', 1); $this->assertFail('Exception expected - invalid name accepted'); } catch (Exception $ex) { $this->assertTrue(true); } }
/** * To be called from a page running under NTLM's * "Integrated Windows Authentication". * * If successful, it will set a special "cookie" (not an HTTP cookie!) * in cache_flags under the "auth/ldap/ntlmsess" "plugin" and return true. * The "cookie" will be picked up by ntlmsso_finish() to complete the * process. * * On failure it will return false for the caller to display an appropriate * error message (probably saying that Integrated Windows Auth isn't enabled!) * * NOTE that this code will execute under the OS user credentials, * so we MUST avoid dealing with files -- such as session files. * (The caller should set $nomoodlecookie before including config.php) * */ function ntlmsso_magic($sesskey) { if (isset($_SERVER['REMOTE_USER']) && !empty($_SERVER['REMOTE_USER'])) { $username = $_SERVER['REMOTE_USER']; $username = substr(strrchr($username, '\\'), 1); //strip domain info $username = moodle_strtolower($username); //compatibility hack set_cache_flag('auth/ldap/ntlmsess', $sesskey, $username, AUTH_NTLMTIMEOUT); return true; } return false; }
public function test_set_user_preference() { global $DB, $USER; $this->resetAfterTest(true); $olduser = $USER; $USER = $DB->get_record('user', array('id'=>2)); //admin if (!$otheruserid = $this->get_fake_preference_test_userid()) { $this->fail('Can not find unused user id for the preferences test'); return; } $DB->delete_records('user_preferences', array('userid'=>$otheruserid)); set_cache_flag('userpreferenceschanged', $otheruserid, null); $user = new stdClass(); $user->id = $otheruserid; set_user_preference('aaa', 'bbb', $otheruserid); $this->assertEquals('bbb', $DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'aaa'))); $this->assertEquals('bbb', get_user_preferences('aaa', null, $otheruserid)); set_user_preference('xxx', 'yyy', $user); $this->assertEquals('yyy', $DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'xxx'))); $this->assertEquals('yyy', get_user_preferences('xxx', null, $otheruserid)); $this->assertTrue(is_array($user->preference)); $this->assertEquals($user->preference['aaa'], 'bbb'); $this->assertEquals($user->preference['xxx'], 'yyy'); set_user_preference('xxx', NULL, $user); $this->assertSame(false, $DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'xxx'))); $this->assertSame(null, get_user_preferences('xxx', null, $otheruserid)); set_user_preference('ooo', true, $user); $prefs = get_user_preferences(null, null, $otheruserid); $this->assertSame($prefs['aaa'], $user->preference['aaa']); $this->assertSame($prefs['ooo'], $user->preference['ooo']); $this->assertSame($prefs['ooo'], '1'); set_user_preference('null', 0, $user); $this->assertSame('0', get_user_preferences('null', null, $otheruserid)); $this->assertSame('lala', get_user_preferences('undefined', 'lala', $otheruserid)); $DB->delete_records('user_preferences', array('userid'=>$otheruserid)); set_cache_flag('userpreferenceschanged', $otheruserid, null); // test $USER default set_user_preference('_test_user_preferences_pref', 'ok'); $this->assertSame('ok', $USER->preference['_test_user_preferences_pref']); unset_user_preference('_test_user_preferences_pref'); $this->assertTrue(!isset($USER->preference['_test_user_preferences_pref'])); // Test 1333 char values (no need for unicode, there are already tests for that in DB tests) $longvalue = str_repeat('a', 1333); set_user_preference('_test_long_user_preference', $longvalue); $this->assertEquals($longvalue, get_user_preferences('_test_long_user_preference')); $this->assertEquals($longvalue, $DB->get_field('user_preferences', 'value', array('userid' => $USER->id, 'name' => '_test_long_user_preference'))); // Test > 1333 char values, coding_exception expected $longvalue = str_repeat('a', 1334); try { set_user_preference('_test_long_user_preference', $longvalue); $this->assertFail('Exception expected - longer than 1333 chars not allowed as preference value'); } catch (Exception $e) { $this->assertTrue($e instanceof coding_exception); } //test invalid params try { set_user_preference('_test_user_preferences_pref', array()); $this->assertFail('Exception expected - array not valid preference value'); } catch (Exception $ex) { $this->assertTrue(true); } try { set_user_preference('_test_user_preferences_pref', new stdClass); $this->assertFail('Exception expected - class not valid preference value'); } catch (Exception $ex) { $this->assertTrue(true); } try { set_user_preference('_test_user_preferences_pref', 1, array('xx'=>1)); $this->assertFail('Exception expected - user instance expected'); } catch (Exception $ex) { $this->assertTrue(true); } try { set_user_preference('_test_user_preferences_pref', 1, 'abc'); $this->assertFail('Exception expected - user instance expected'); } catch (Exception $ex) { $this->assertTrue(true); } try { set_user_preference('', 1); $this->assertFail('Exception expected - invalid name accepted'); } catch (Exception $ex) { $this->assertTrue(true); } try { set_user_preference('1', 1); $this->assertFail('Exception expected - invalid name accepted'); } catch (Exception $ex) { $this->assertTrue(true); } $USER = $olduser; }
/** * Mark a context as dirty (with timestamp) * so as to force reloading of the context. * @param string $path context path */ function mark_context_dirty($path) { global $CFG, $DIRTYCONTEXTS; // only if it is a non-empty string if (is_string($path) && $path !== '') { set_cache_flag('accesslib/dirtycontexts', $path, 1, time() + $CFG->sessiontimeout); if (isset($DIRTYCONTEXTS)) { $DIRTYCONTEXTS[$path] = 1; } } }
/** * Do the job. * Throw exceptions on errors (the job will be retried). */ public function execute() { global $CFG, $DB; if (empty($CFG->notifyloginfailures)) { return; } $recip = get_users_from_config($CFG->notifyloginfailures, 'moodle/site:config'); if (empty($CFG->lastnotifyfailure)) { $CFG->lastnotifyfailure = 0; } // If it has been less than an hour, or if there are no recipients, don't execute. if (time() - HOURSECS < $CFG->lastnotifyfailure || !is_array($recip) || count($recip) <= 0) { return; } // We need to deal with the threshold stuff first. if (empty($CFG->notifyloginthreshold)) { $CFG->notifyloginthreshold = 10; // Default to something sensible. } // Get all the IPs with more than notifyloginthreshold failures since lastnotifyfailure // and insert them into the cache_flags temp table. $logmang = get_log_manager(); $readers = $logmang->get_readers('\\core\\log\\sql_internal_reader'); $reader = reset($readers); $readername = key($readers); if (empty($reader) || empty($readername)) { // No readers, no processing. return true; } $logtable = $reader->get_internal_log_table_name(); $sql = "SELECT ip, COUNT(*)\n FROM {" . $logtable . "}\n WHERE eventname = ?\n AND timecreated > ?\n GROUP BY ip\n HAVING COUNT(*) >= ?"; $params = array('\\core\\event\\user_login_failed', $CFG->lastnotifyfailure, $CFG->notifyloginthreshold); $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $iprec) { if (!empty($iprec->ip)) { set_cache_flag('login_failure_by_ip', $iprec->ip, '1', 0); } } $rs->close(); // Get all the INFOs with more than notifyloginthreshold failures since lastnotifyfailure // and insert them into the cache_flags temp table. $sql = "SELECT userid, count(*)\n FROM {" . $logtable . "}\n WHERE eventname = ?\n AND timecreated > ?\n GROUP BY userid\n HAVING count(*) >= ?"; $params = array('\\core\\event\\user_login_failed', $CFG->lastnotifyfailure, $CFG->notifyloginthreshold); $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $inforec) { if (!empty($inforec->info)) { set_cache_flag('login_failure_by_id', $inforec->userid, '1', 0); } } $rs->close(); // Now, select all the login error logged records belonging to the ips and infos // since lastnotifyfailure, that we have stored in the cache_flags table. $sql = "SELECT * FROM (\n SELECT l.*, u.username\n FROM {" . $logtable . "} l\n JOIN {cache_flags} cf ON l.ip = cf.name\n LEFT JOIN {user} u ON l.userid = u.id\n WHERE l.eventname = ?\n AND l.timecreated > ?\n AND cf.flagtype = 'login_failure_by_ip'\n UNION ALL\n SELECT l.*, u.username\n FROM {" . $logtable . "} l\n JOIN {cache_flags} cf ON l.userid = " . $DB->sql_cast_char2int('cf.name') . "\n LEFT JOIN {user} u ON l.userid = u.id\n WHERE l.eventname = ?\n AND l.timecreated > ?\n AND cf.flagtype = 'login_failure_by_info') t\n ORDER BY t.timecreated DESC"; $params = array('\\core\\event\\user_login_failed', $CFG->lastnotifyfailure, '\\core\\event\\user_login_failed', $CFG->lastnotifyfailure); // Init some variables. $count = 0; $messages = ''; // Iterate over the logs recordset. $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $log) { $a = new \stdClass(); $a->time = userdate($log->timecreated); if (empty($log->username)) { // Entries with no valid username. We get attempted username from the event's other field. $other = unserialize($log->other); $a->info = empty($other['username']) ? '' : $other['username']; } else { $a->info = $log->username; } $a->ip = $log->ip; $messages .= get_string('notifyloginfailuresmessage', '', $a) . "\n"; $count++; } $rs->close(); // If we have something useful to report. if ($count > 0) { $site = get_site(); $subject = get_string('notifyloginfailuressubject', '', format_string($site->fullname)); // Calculate the complete body of notification (start + messages + end). $params = array('id' => 0, 'modid' => 'site_errors', 'chooselog' => '1', 'logreader' => $readername); $url = new \moodle_url('/report/log/index.php', $params); $body = get_string('notifyloginfailuresmessagestart', '', $CFG->wwwroot) . ($CFG->lastnotifyfailure != 0 ? '(' . userdate($CFG->lastnotifyfailure) . ')' : '') . "\n\n" . $messages . "\n\n" . get_string('notifyloginfailuresmessageend', '', $url->out(false) . ' ') . "\n\n"; // For each destination, send mail. mtrace('Emailing admins about ' . $count . ' failed login attempts'); foreach ($recip as $admin) { // Emailing the admins directly rather than putting these through the messaging system. email_to_user($admin, \core_user::get_support_user(), $subject, $body); } } // Update lastnotifyfailure with current time. set_config('lastnotifyfailure', time()); // Finally, delete all the temp records we have created in cache_flags. $DB->delete_records_select('cache_flags', "flagtype IN ('login_failure_by_ip', 'login_failure_by_info')"); }
/** * To be called from a page running under NTLM's * "Integrated Windows Authentication". * * If successful, it will set a special "cookie" (not an HTTP cookie!) * in cache_flags under the "auth/ldap/ntlmsess" "plugin" and return true. * The "cookie" will be picked up by ntlmsso_finish() to complete the * process. * * On failure it will return false for the caller to display an appropriate * error message (probably saying that Integrated Windows Auth isn't enabled!) * * NOTE that this code will execute under the OS user credentials, * so we MUST avoid dealing with files -- such as session files. * (The caller should set $nomoodlecookie before including config.php) * */ function ntlmsso_magic($sesskey) { if (isset($_SERVER['REMOTE_USER']) && !empty($_SERVER['REMOTE_USER'])) { // HTTP __headers__ seem to be sent in ISO-8859-1 encoding // (according to my reading of RFC-1945, RFC-2616 and RFC-2617 and // my local tests), so we need to convert the REMOTE_USER value // (i.e., what we got from the HTTP WWW-Authenticate header) into UTF-8 $textlib = textlib_get_instance(); $username = $textlib->convert($_SERVER['REMOTE_USER'], 'iso-8859-1', 'utf-8'); $username = substr(strrchr($username, '\\'), 1); //strip domain info $username = moodle_strtolower($username); //compatibility hack set_cache_flag('auth/ldap/ntlmsess', $sesskey, $username, AUTH_NTLMTIMEOUT); return true; } return false; }
function mark_context_dirty($path) { global $CFG; // only if it is a non-empty string if (is_string($path) && $path !== '') { set_cache_flag('accesslib/dirtycontexts', $path, 1, time() + $CFG->sessiontimeout); } }
/** * Notify admin users or admin user of any failed logins (since last notification). * * Note that this function must be only executed from the cron script * It uses the cache_flags system to store temporary records, deleting them * by name before finishing * * @return bool True if executed, false if not */ function notify_login_failures() { global $CFG, $DB, $OUTPUT; if (empty($CFG->notifyloginfailures)) { return false; } $recip = get_users_from_config($CFG->notifyloginfailures, 'moodle/site:config'); if (empty($CFG->lastnotifyfailure)) { $CFG->lastnotifyfailure = 0; } // If it has been less than an hour, or if there are no recipients, don't execute. if (time() - HOURSECS < $CFG->lastnotifyfailure || !is_array($recip) || count($recip) <= 0) { return false; } // we need to deal with the threshold stuff first. if (empty($CFG->notifyloginthreshold)) { $CFG->notifyloginthreshold = 10; // default to something sensible. } // Get all the IPs with more than notifyloginthreshold failures since lastnotifyfailure // and insert them into the cache_flags temp table $sql = "SELECT ip, COUNT(*)\n FROM {log}\n WHERE module = 'login' AND action = 'error'\n AND time > ?\n GROUP BY ip\n HAVING COUNT(*) >= ?"; $params = array($CFG->lastnotifyfailure, $CFG->notifyloginthreshold); $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $iprec) { if (!empty($iprec->ip)) { set_cache_flag('login_failure_by_ip', $iprec->ip, '1', 0); } } $rs->close(); // Get all the INFOs with more than notifyloginthreshold failures since lastnotifyfailure // and insert them into the cache_flags temp table $sql = "SELECT info, count(*)\n FROM {log}\n WHERE module = 'login' AND action = 'error'\n AND time > ?\n GROUP BY info\n HAVING count(*) >= ?"; $params = array($CFG->lastnotifyfailure, $CFG->notifyloginthreshold); $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $inforec) { if (!empty($inforec->info)) { set_cache_flag('login_failure_by_info', $inforec->info, '1', 0); } } $rs->close(); // Now, select all the login error logged records belonging to the ips and infos // since lastnotifyfailure, that we have stored in the cache_flags table $sql = "SELECT * FROM (\n SELECT l.*, u.firstname, u.lastname\n FROM {log} l\n JOIN {cache_flags} cf ON l.ip = cf.name\n LEFT JOIN {user} u ON l.userid = u.id\n WHERE l.module = 'login' AND l.action = 'error'\n AND l.time > ?\n AND cf.flagtype = 'login_failure_by_ip'\n UNION ALL\n SELECT l.*, u.firstname, u.lastname\n FROM {log} l\n JOIN {cache_flags} cf ON l.info = cf.name\n LEFT JOIN {user} u ON l.userid = u.id\n WHERE l.module = 'login' AND l.action = 'error'\n AND l.time > ?\n AND cf.flagtype = 'login_failure_by_info') t\n ORDER BY t.time DESC"; $params = array($CFG->lastnotifyfailure, $CFG->lastnotifyfailure); // Init some variables $count = 0; $messages = ''; // Iterate over the logs recordset $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $log) { $log->time = userdate($log->time); $messages .= get_string('notifyloginfailuresmessage', '', $log) . "\n"; $count++; } $rs->close(); // If we have something useful to report. if ($count > 0) { $site = get_site(); $subject = get_string('notifyloginfailuressubject', '', format_string($site->fullname)); // Calculate the complete body of notification (start + messages + end) $body = get_string('notifyloginfailuresmessagestart', '', $CFG->wwwroot) . ($CFG->lastnotifyfailure != 0 ? '(' . userdate($CFG->lastnotifyfailure) . ')' : '') . "\n\n" . $messages . "\n\n" . get_string('notifyloginfailuresmessageend', '', $CFG->wwwroot) . "\n\n"; // For each destination, send mail mtrace('Emailing admins about ' . $count . ' failed login attempts'); foreach ($recip as $admin) { //emailing the admins directly rather than putting these through the messaging system email_to_user($admin, core_user::get_support_user(), $subject, $body); } } // Update lastnotifyfailure with current time set_config('lastnotifyfailure', time()); // Finally, delete all the temp records we have created in cache_flags $DB->delete_records_select('cache_flags', "flagtype IN ('login_failure_by_ip', 'login_failure_by_info')"); return true; }
/** * Test logging in via LDAP calls a user_loggedin event. */ public function test_ldap_user_loggedin_event() { global $CFG, $DB, $USER; require_once $CFG->dirroot . '/auth/ldap/auth.php'; $this->resetAfterTest(); $this->assertFalse(isloggedin()); $user = $DB->get_record('user', array('username' => 'admin')); // Note: we are just going to trigger the function that calls the event, // not actually perform a LDAP login, for the sake of sanity. $ldap = new auth_plugin_ldap(); // Set the key for the cache flag we want to set which is used by LDAP. set_cache_flag($ldap->pluginconfig . '/ntlmsess', sesskey(), $user->username, AUTH_NTLMTIMEOUT); // We are going to need to set the sesskey as the user's password in order for the LDAP log in to work. update_internal_user_password($user, sesskey()); // The function ntlmsso_finish is responsible for triggering the event, so call it directly and catch the event. $sink = $this->redirectEvents(); // We need to supress this function call, or else we will get the message "session_regenerate_id(): Cannot // regenerate session id - headers already sent" as the ntlmsso_finish function calls complete_user_login @$ldap->ntlmsso_finish(); $events = $sink->get_events(); $sink->close(); // Check that the event is valid. $this->assertCount(1, $events); $event = reset($events); $this->assertInstanceOf('\\core\\event\\user_loggedin', $event); $this->assertEquals('user', $event->objecttable); $this->assertEquals('2', $event->objectid); $this->assertEquals(context_system::instance()->id, $event->contextid); $expectedlog = array(SITEID, 'user', 'login', 'view.php?id=' . $USER->id . '&course=' . SITEID, $user->id, 0, $user->id); $this->assertEventLegacyLogData($expectedlog, $event); }
/** * Mark a context as dirty (with timestamp) so as to force reloading of the context. */ public function mark_dirty() { global $CFG, $USER, $ACCESSLIB_PRIVATE; if (during_initial_install()) { return; } // only if it is a non-empty string if (is_string($this->_path) && $this->_path !== '') { set_cache_flag('accesslib/dirtycontexts', $this->_path, 1, time() + $CFG->sessiontimeout); if (isset($ACCESSLIB_PRIVATE->dirtycontexts)) { $ACCESSLIB_PRIVATE->dirtycontexts[$this->_path] = 1; } else { if (CLI_SCRIPT) { $ACCESSLIB_PRIVATE->dirtycontexts = array($this->_path => 1); } else { if (isset($USER->access['time'])) { $ACCESSLIB_PRIVATE->dirtycontexts = get_cache_flags('accesslib/dirtycontexts', $USER->access['time'] - 2); } else { $ACCESSLIB_PRIVATE->dirtycontexts = array($this->_path => 1); } // flags not loaded yet, it will be done later in $context->reload_if_dirty() } } } }
/** * Add the trainer info */ function add_trainer_info(&$sessions) { global $CFG, $DB; $moduleid = $DB->get_field('modules', 'id', array('name' => 'facetoface')); $alltrainers = array(); // all possible trainers for filter dropdown // find role id for trainer $trainerroleid = $DB->get_field('role', 'id', array('shortname' => 'facilitator')); foreach ($sessions as $session) { // individual session trainers $sessiontrainers = array(); // get trainers for this session from session_roles table // set to null if trainer role id not found $sess_trainers = (isset($trainerroleid)) ? $DB->get_records_select('facetoface_session_roles', "sessionid = ? AND roleid = ?", array($session->sessionid, $trainerroleid)) : null; // check if the module instance has already had trainer info added if (!array_key_exists($session->cmid, $alltrainers)) { $context = context_module::instance($session->cmid); if ($sess_trainers && is_array($sess_trainers)) { foreach ($sess_trainers as $sess_trainer) { $user = $DB->get_record('user', array('id' => $sess_trainer->userid)); $fullname = fullname($user); if (!array_key_exists($fullname, $sessiontrainers)) { $sessiontrainers[$fullname] = $fullname; } } if (!empty($sessiontrainers)) { asort($sessiontrainers); $session->trainers = $sessiontrainers; $alltrainers[$session->cmid] = $sessiontrainers; } else { $session->trainers = ''; $alltrainers[$session->cmid] = ''; } } } else { if (!empty($alltrainers[$session->cmid])) { $session->trainers = $alltrainers[$session->cmid]; } else { $session->trainers = ''; } } } // cache the trainerlist with an expiry of 15 minutes to help speed up the db load $cachevalue = serialize($alltrainers); $expiry = time() + TRAINER_CACHE_TIMEOUT * 60; set_cache_flag('blocks/facetoface', 'trainers', $cachevalue, $expiry); }