$temp->add(new admin_setting_configcheckbox('loginpageautofocus', new lang_string('loginpageautofocus', 'admin'), new lang_string('loginpageautofocus_help', 'admin'), 0));
$temp->add(new admin_setting_configselect('guestloginbutton', new lang_string('guestloginbutton', 'auth'),
new lang_string('showguestlogin', 'auth'), '1', array('0'=>new lang_string('hide'), '1'=>new lang_string('show'))));
+ $options = array(0 => get_string('no'), 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 10 => 10, 20 => 20, 50 => 50);
+ $temp->add(new admin_setting_configselect('limitconcurrentlogins',
+ new lang_string('limitconcurrentlogins', 'core_auth'),
+ new lang_string('limitconcurrentlogins_desc', 'core_auth'), 0, $options));
$temp->add(new admin_setting_configtext('alternateloginurl', new lang_string('alternateloginurl', 'auth'),
new lang_string('alternatelogin', 'auth', htmlspecialchars(get_login_url())), ''));
$temp->add(new admin_setting_configtext('forgottenpasswordurl', new lang_string('forgottenpasswordurl', 'auth'),
}
}
+ /**
+ * Terminate other sessions of current user depending
+ * on $CFG->limitconcurrentlogins restriction.
+ *
+ * This is expected to be called right after complete_user_login().
+ *
+ * NOTE:
+ * * Do not use from SSO auth plugins, this would not work.
+ * * Do not use from web services because they do not have sessions.
+ *
+ * @param int $userid
+ * @param string $sid session id to be always keep, usually the current one
+ * @return void
+ */
+ public static function apply_concurrent_login_limit($userid, $sid = null) {
+ global $CFG, $DB;
+
+ // NOTE: the $sid parameter is here mainly to allow testing,
+ // in most cases it should be current session id.
+
+ if (isguestuser($userid) or empty($userid)) {
+ // This applies to real users only!
+ return;
+ }
+
+ if (empty($CFG->limitconcurrentlogins) or $CFG->limitconcurrentlogins < 0) {
+ return;
+ }
+
+ $count = $DB->count_records('sessions', array('userid' => $userid));
+
+ if ($count <= $CFG->limitconcurrentlogins) {
+ return;
+ }
+
+ $i = 0;
+ $select = "userid = :userid";
+ $params = array('userid' => $userid);
+ if ($sid) {
+ if ($DB->record_exists('sessions', array('sid' => $sid, 'userid' => $userid))) {
+ $select .= " AND sid <> :sid";
+ $params['sid'] = $sid;
+ $i = 1;
+ }
+ }
+
+ $sessions = $DB->get_records_select('sessions', $select, $params, 'timecreated DESC', 'id, sid');
+ foreach ($sessions as $session) {
+ $i++;
+ if ($i <= $CFG->limitconcurrentlogins) {
+ continue;
+ }
+ self::kill_session($session->sid);
+ }
+ }
+
/**
* Set current user.
*
$this->assertEquals(1, $DB->count_records('sessions', array('userid' => $userid, 'sid' => md5('pokus5'))));
}
+ public function test_apply_concurrent_login_limit() {
+ global $DB;
+ $this->resetAfterTest();
+
+ $user1 = $this->getDataGenerator()->create_user();
+ $user2 = $this->getDataGenerator()->create_user();
+ $guest = guest_user();
+
+ $record = new \stdClass();
+ $record->state = 0;
+ $record->sessdata = null;
+ $record->userid = $user1->id;
+ $record->timemodified = time();
+ $record->firstip = $record->lastip = '10.0.0.1';
+
+ $record->sid = md5('hokus1');
+ $record->timecreated = 20;
+ $DB->insert_record('sessions', $record);
+ $record->sid = md5('hokus2');
+ $record->timecreated = 10;
+ $DB->insert_record('sessions', $record);
+ $record->sid = md5('hokus3');
+ $record->timecreated = 30;
+ $DB->insert_record('sessions', $record);
+
+ $record->userid = $user2->id;
+ $record->sid = md5('pokus1');
+ $record->timecreated = 20;
+ $DB->insert_record('sessions', $record);
+ $record->sid = md5('pokus2');
+ $record->timecreated = 10;
+ $DB->insert_record('sessions', $record);
+ $record->sid = md5('pokus3');
+ $record->timecreated = 30;
+ $DB->insert_record('sessions', $record);
+
+ $record->timecreated = 10;
+ $record->userid = $guest->id;
+ $record->sid = md5('g1');
+ $DB->insert_record('sessions', $record);
+ $record->sid = md5('g2');
+ $DB->insert_record('sessions', $record);
+ $record->sid = md5('g3');
+ $DB->insert_record('sessions', $record);
+
+ $record->userid = 0;
+ $record->sid = md5('nl1');
+ $DB->insert_record('sessions', $record);
+ $record->sid = md5('nl2');
+ $DB->insert_record('sessions', $record);
+ $record->sid = md5('nl3');
+ $DB->insert_record('sessions', $record);
+
+ set_config('limitconcurrentlogins', 0);
+ $this->assertCount(12, $DB->get_records('sessions'));
+
+ \core\session\manager::apply_concurrent_login_limit($user1->id);
+ \core\session\manager::apply_concurrent_login_limit($user2->id);
+ \core\session\manager::apply_concurrent_login_limit($guest->id);
+ \core\session\manager::apply_concurrent_login_limit(0);
+ $this->assertCount(12, $DB->get_records('sessions'));
+
+ set_config('limitconcurrentlogins', -1);
+
+ \core\session\manager::apply_concurrent_login_limit($user1->id);
+ \core\session\manager::apply_concurrent_login_limit($user2->id);
+ \core\session\manager::apply_concurrent_login_limit($guest->id);
+ \core\session\manager::apply_concurrent_login_limit(0);
+ $this->assertCount(12, $DB->get_records('sessions'));
+
+ set_config('limitconcurrentlogins', 2);
+
+ \core\session\manager::apply_concurrent_login_limit($user1->id);
+ $this->assertCount(11, $DB->get_records('sessions'));
+ $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 20)));
+ $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 30)));
+ $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 10)));
+
+ $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
+ $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
+ $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
+ set_config('limitconcurrentlogins', 2);
+ \core\session\manager::apply_concurrent_login_limit($user2->id, md5('pokus2'));
+ $this->assertCount(10, $DB->get_records('sessions'));
+ $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
+ $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
+ $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
+
+ \core\session\manager::apply_concurrent_login_limit($guest->id);
+ \core\session\manager::apply_concurrent_login_limit(0);
+ $this->assertCount(10, $DB->get_records('sessions'));
+
+ set_config('limitconcurrentlogins', 1);
+
+ \core\session\manager::apply_concurrent_login_limit($user1->id, md5('grrr'));
+ $this->assertCount(9, $DB->get_records('sessions'));
+ $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 20)));
+ $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 30)));
+ $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 10)));
+
+ \core\session\manager::apply_concurrent_login_limit($user1->id);
+ $this->assertCount(9, $DB->get_records('sessions'));
+ $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 20)));
+ $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 30)));
+ $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 10)));
+
+ \core\session\manager::apply_concurrent_login_limit($user2->id, md5('pokus2'));
+ $this->assertCount(8, $DB->get_records('sessions'));
+ $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
+ $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
+ $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
+
+ \core\session\manager::apply_concurrent_login_limit($user2->id);
+ $this->assertCount(8, $DB->get_records('sessions'));
+ $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
+ $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
+ $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
+
+ \core\session\manager::apply_concurrent_login_limit($guest->id);
+ \core\session\manager::apply_concurrent_login_limit(0);
+ $this->assertCount(8, $DB->get_records('sessions'));
+ }
+
public function test_kill_all_sessions() {
global $DB, $USER;
$this->resetAfterTest();