Beispiel #1
0
 /**
  * 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));
 }
Beispiel #5
0
/**
 * 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;
}