diff --git a/lib/db/install.xml b/lib/db/install.xml index fab9fd7ebda..af9e2dcd8b1 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -2577,6 +2577,7 @@ + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index cf1a331d1ac..a9b56166469 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2250,6 +2250,7 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2016101100.00); } + if ($oldversion < 2016101101.00) { // Define field component to be added to message_read. $table = new xmldb_table('message_read'); @@ -2272,5 +2273,18 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2016101101.00); } + if ($oldversion < 2016101400.01) { + $table = new xmldb_table('external_tokens'); + $field = new xmldb_field('privatetoken', XMLDB_TYPE_CHAR, '64', null, null, null, null); + + // Conditionally add privatetoken field to the external_tokens table. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Main savepoint reached. + upgrade_main_savepoint(true, 2016101400.01); + } + return true; } diff --git a/lib/externallib.php b/lib/externallib.php index fb7f5945c8b..a0c98959117 100644 --- a/lib/externallib.php +++ b/lib/externallib.php @@ -724,6 +724,7 @@ function external_generate_token($tokentype, $serviceorid, $userid, $contextorid if (!empty($iprestriction)) { $newtoken->iprestriction = $iprestriction; } + $newtoken->privatetoken = null; $DB->insert_record('external_tokens', $newtoken); return $newtoken->token; } @@ -1053,6 +1054,8 @@ function external_generate_token_for_current_user($service) { $token->externalserviceid = $service->id; // MDL-43119 Token valid for 3 months (12 weeks). $token->validuntil = $token->timecreated + 12 * WEEKSECS; + // Generate the private token, it must be transmitted only via https. + $token->privatetoken = random_string(64); $token->id = $DB->insert_record('external_tokens', $token); $params = array( diff --git a/login/token.php b/login/token.php index 13ea7fcd07f..244bda51319 100644 --- a/login/token.php +++ b/login/token.php @@ -44,11 +44,14 @@ $username = trim(core_text::strtolower($username)); if (is_restored_user($username)) { throw new moodle_exception('restoredaccountresetpassword', 'webservice'); } + +$systemcontext = context_system::instance(); + $user = authenticate_user_login($username, $password); if (!empty($user)) { // Cannot authenticate unless maintenance access is granted. - $hasmaintenanceaccess = has_capability('moodle/site:maintenanceaccess', context_system::instance(), $user); + $hasmaintenanceaccess = has_capability('moodle/site:maintenanceaccess', $systemcontext, $user); if (!empty($CFG->maintenance_enabled) and !$hasmaintenanceaccess) { throw new moodle_exception('sitemaintenance', 'admin'); } @@ -92,6 +95,8 @@ if (!empty($user)) { // Get an existing token or create a new one. $token = external_generate_token_for_current_user($service); + $privatetoken = $token->privatetoken; + $token->privatetoken = null; // log token access $DB->set_field('external_tokens', 'lastaccess', time(), array('id'=>$token->id)); @@ -103,8 +108,16 @@ if (!empty($user)) { $event->add_record_snapshot('external_tokens', $token); $event->trigger(); + $siteadmin = has_capability('moodle/site:config', $systemcontext, $USER->id) || is_siteadmin($USER->id); + $usertoken = new stdClass; $usertoken->token = $token->token; + // Private token, only transmitted to https sites and non-admin users. + if (is_https() and !$siteadmin) { + $usertoken->privatetoken = $privatetoken; + } else { + $usertoken->privatetoken = null; + } echo json_encode($usertoken); } else { throw new moodle_exception('invalidlogin'); diff --git a/version.php b/version.php index ae0d05d3d35..6bc440dbfce 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2016101400.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2016101400.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. diff --git a/webservice/lib.php b/webservice/lib.php index 8ddca420a8b..cee781bb7fb 100644 --- a/webservice/lib.php +++ b/webservice/lib.php @@ -340,6 +340,7 @@ class webservice { $newtoken->contextid = context_system::instance()->id; $newtoken->creatorid = $userid; $newtoken->timecreated = time(); + $newtoken->privatetoken = null; $DB->insert_record('external_tokens', $newtoken); } diff --git a/webservice/upgrade.txt b/webservice/upgrade.txt index 47e5d0f1395..895a5f90a57 100644 --- a/webservice/upgrade.txt +++ b/webservice/upgrade.txt @@ -12,6 +12,11 @@ This information is intended for authors of webservices, not people writing webs In some contexts those parameteres are not necessary because is not required to do a file rewrite via file_rewrite_pluginfile_urls. * External function get_site_info now returns the site course ID. This new field is marked as VALUE_OPTIONAL for backwards compatibility. +* A new field "privatetoken" has been added to the "external_tokens" table. + This private token must be safely stored (or not stored at all) by the client because it will be used in places where a request + must be double-checked. + This token should not be passed via GET paramaters and it must be transmitted only via https. + This token is generated only in login/token.php after the user credential has been confirmed. It can't be generated by admins. === 3.1 ===