/** * User authentication by token * * @param string $tokentype token type (EXTERNAL_TOKEN_EMBEDDED or EXTERNAL_TOKEN_PERMANENT) * @return stdClass the authenticated user * @throws webservice_access_exception */ protected function authenticate_by_token($tokentype) { global $DB; $loginfaileddefaultparams = array('context' => context_system::instance(), 'other' => array('method' => $this->authmethod, 'reason' => null)); if (!($token = $DB->get_record('external_tokens', array('token' => $this->token, 'tokentype' => $tokentype)))) { // Log failed login attempts. $params = $loginfaileddefaultparams; $params['other']['reason'] = 'invalid_token'; $event = \core\event\webservice_login_failed::create($params); $event->set_legacy_logdata(array(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '', get_string('failedtolog', 'webservice') . ": " . $this->token . " - " . getremoteaddr(), 0)); $event->trigger(); throw new moodle_exception('invalidtoken', 'webservice'); } if ($token->validuntil and $token->validuntil < time()) { $DB->delete_records('external_tokens', array('token' => $this->token, 'tokentype' => $tokentype)); throw new webservice_access_exception('Invalid token - token expired - check validuntil time for the token'); } if ($token->sid) { //assumes that if sid is set then there must be a valid associated session no matter the token type if (!\core\session\manager::session_exists($token->sid)) { $DB->delete_records('external_tokens', array('sid' => $token->sid)); throw new webservice_access_exception('Invalid session based token - session not found or expired'); } } if ($token->iprestriction and !address_in_subnet(getremoteaddr(), $token->iprestriction)) { $params = $loginfaileddefaultparams; $params['other']['reason'] = 'ip_restricted'; $params['other']['tokenid'] = $token->id; $event = \core\event\webservice_login_failed::create($params); $event->add_record_snapshot('external_tokens', $token); $event->set_legacy_logdata(array(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '', get_string('failedtolog', 'webservice') . ": " . getremoteaddr(), 0)); $event->trigger(); throw new webservice_access_exception('Invalid service - IP:' . getremoteaddr() . ' is not supported - check this allowed user'); } $this->restricted_context = context::instance_by_id($token->contextid); $this->restricted_serviceid = $token->externalserviceid; $user = $DB->get_record('user', array('id' => $token->userid), '*', MUST_EXIST); // log token access $DB->set_field('external_tokens', 'lastaccess', time(), array('id' => $token->id)); return $user; }
if (!empty($authoriseduser->iprestriction) and !address_in_subnet(getremoteaddr(), $authoriseduser->iprestriction)) { throw new moodle_exception('invalidiptoken', 'webservice'); } } //Check if a token has already been created for this user and this service //Note: this could be an admin created or an user created token. // It does not really matter we take the first one that is valid. $tokenssql = "SELECT t.id, t.sid, t.token, t.validuntil, t.iprestriction\n FROM {external_tokens} t\n WHERE t.userid = ? AND t.externalserviceid = ? AND t.tokentype = ?\n ORDER BY t.timecreated ASC"; $tokens = $DB->get_records_sql($tokenssql, array($user->id, $service->id, EXTERNAL_TOKEN_PERMANENT)); //A bit of sanity checks foreach ($tokens as $key => $token) { /// Checks related to a specific token. (script execution continue) $unsettoken = false; //if sid is set then there must be a valid associated session no matter the token type if (!empty($token->sid)) { if (!\core\session\manager::session_exists($token->sid)) { //this token will never be valid anymore, delete it $DB->delete_records('external_tokens', array('sid' => $token->sid)); $unsettoken = true; } } //remove token if no valid anymore //Also delete this wrong token (similar logic to the web service servers // /webservice/lib.php/webservice_server::authenticate_by_token()) if (!empty($token->validuntil) and $token->validuntil < time()) { $DB->delete_records('external_tokens', array('token' => $token->token, 'tokentype' => EXTERNAL_TOKEN_PERMANENT)); $unsettoken = true; } // remove token if its ip not in whitelist if (isset($token->iprestriction) and !address_in_subnet(getremoteaddr(), $token->iprestriction)) { $unsettoken = true;
public function test_session_exists() { global $CFG, $DB; $this->resetAfterTest(); $this->assertFalse(\core\session\manager::session_exists('abc')); $user = $this->getDataGenerator()->create_user(); $guest = guest_user(); // The file handler is used by default, so let's fake the data somehow. $sid = md5('hokus'); mkdir("{$CFG->dataroot}/sessions/", $CFG->directorypermissions, true); touch("{$CFG->dataroot}/sessions/sess_{$sid}"); $this->assertFalse(\core\session\manager::session_exists($sid)); $record = new stdClass(); $record->userid = 0; $record->sid = $sid; $record->timecreated = time(); $record->timemodified = $record->timecreated; $record->id = $DB->insert_record('sessions', $record); $this->assertTrue(\core\session\manager::session_exists($sid)); $record->timecreated = time() - $CFG->sessiontimeout - 100; $record->timemodified = $record->timecreated + 10; $DB->update_record('sessions', $record); $this->assertTrue(\core\session\manager::session_exists($sid)); $record->userid = $guest->id; $DB->update_record('sessions', $record); $this->assertTrue(\core\session\manager::session_exists($sid)); $record->userid = $user->id; $DB->update_record('sessions', $record); $this->assertFalse(\core\session\manager::session_exists($sid)); $CFG->sessiontimeout = $CFG->sessiontimeout + 3000; $this->assertTrue(\core\session\manager::session_exists($sid)); }
public function test_session_exists() { global $CFG; $this->resetAfterTest(); // The file handler is used by default, so let's fake the data somehow. $sid = md5('hokus'); mkdir("{$CFG->dataroot}/sessions/", $CFG->directorypermissions, true); touch("{$CFG->dataroot}/sessions/sess_{$sid}"); $this->assertTrue(\core\session\manager::session_exists($sid)); }
/** * Generate or return an existing token for the current authenticated user. * This function is used for creating a valid token for users authenticathing via login/token.php or admin/tool/mobile/launch.php. * * @param stdClass $service external service object * @return stdClass token object * @since Moodle 3.2 * @throws moodle_exception */ function external_generate_token_for_current_user($service) { global $DB, $USER; core_user::require_active_user($USER, true, true); // Check if there is any required system capability. if ($service->requiredcapability and !has_capability($service->requiredcapability, context_system::instance())) { throw new moodle_exception('missingrequiredcapability', 'webservice', '', $service->requiredcapability); } // Specific checks related to user restricted service. if ($service->restrictedusers) { $authoriseduser = $DB->get_record('external_services_users', array('externalserviceid' => $service->id, 'userid' => $USER->id)); if (empty($authoriseduser)) { throw new moodle_exception('usernotallowed', 'webservice', '', $service->shortname); } if (!empty($authoriseduser->validuntil) and $authoriseduser->validuntil < time()) { throw new moodle_exception('invalidtimedtoken', 'webservice'); } if (!empty($authoriseduser->iprestriction) and !address_in_subnet(getremoteaddr(), $authoriseduser->iprestriction)) { throw new moodle_exception('invalidiptoken', 'webservice'); } } // Check if a token has already been created for this user and this service. $conditions = array('userid' => $USER->id, 'externalserviceid' => $service->id, 'tokentype' => EXTERNAL_TOKEN_PERMANENT); $tokens = $DB->get_records('external_tokens', $conditions, 'timecreated ASC'); // A bit of sanity checks. foreach ($tokens as $key => $token) { // Checks related to a specific token. (script execution continue). $unsettoken = false; // If sid is set then there must be a valid associated session no matter the token type. if (!empty($token->sid)) { if (!\core\session\manager::session_exists($token->sid)) { // This token will never be valid anymore, delete it. $DB->delete_records('external_tokens', array('sid' => $token->sid)); $unsettoken = true; } } // Remove token is not valid anymore. if (!empty($token->validuntil) and $token->validuntil < time()) { $DB->delete_records('external_tokens', array('token' => $token->token, 'tokentype' => EXTERNAL_TOKEN_PERMANENT)); $unsettoken = true; } // Remove token if its ip not in whitelist. if (isset($token->iprestriction) and !address_in_subnet(getremoteaddr(), $token->iprestriction)) { $unsettoken = true; } if ($unsettoken) { unset($tokens[$key]); } } // If some valid tokens exist then use the most recent. if (count($tokens) > 0) { $token = array_pop($tokens); } else { $context = context_system::instance(); $isofficialservice = $service->shortname == MOODLE_OFFICIAL_MOBILE_SERVICE; if ($isofficialservice and has_capability('moodle/webservice:createmobiletoken', $context) or !is_siteadmin($USER) && has_capability('moodle/webservice:createtoken', $context)) { // Create a new token. $token = new stdClass(); $token->token = md5(uniqid(rand(), 1)); $token->userid = $USER->id; $token->tokentype = EXTERNAL_TOKEN_PERMANENT; $token->contextid = context_system::instance()->id; $token->creatorid = $USER->id; $token->timecreated = time(); $token->externalserviceid = $service->id; // MDL-43119 Token valid for 3 months (12 weeks). $token->validuntil = $token->timecreated + 12 * WEEKSECS; $token->iprestriction = null; $token->sid = null; $token->lastaccess = null; // Generate the private token, it must be transmitted only via https. $token->privatetoken = random_string(64); $token->id = $DB->insert_record('external_tokens', $token); $eventtoken = clone $token; $eventtoken->privatetoken = null; $params = array('objectid' => $eventtoken->id, 'relateduserid' => $USER->id, 'other' => array('auto' => true)); $event = \core\event\webservice_token_created::create($params); $event->add_record_snapshot('external_tokens', $eventtoken); $event->trigger(); } else { throw new moodle_exception('cannotcreatetoken', 'webservice', '', $service->shortname); } } return $token; }