/** * Return an XHTML string for the setting * @return string Returns an XHTML string */ public function output_html($data, $query = '') { $tokens = get_config('local_o365', 'systemtokens'); $setuser = ''; if (!empty($tokens)) { $tokens = unserialize($tokens); if (isset($tokens['idtoken'])) { try { $idtoken = \auth_oidc\jwt::instance_from_encoded($tokens['idtoken']); $setuser = $idtoken->claim('upn'); } catch (\Exception $e) { // There is a check below for an empty $setuser. } } } $settinghtml = '<input type="hidden" id="' . $this->get_id() . '" name="' . $this->get_full_name() . '" value="0" />'; $setuserurl = new \moodle_url('/local/o365/acp.php', ['mode' => 'setsystemuser']); if (!empty($setuser)) { $settinghtml .= get_string('settings_systemapiuser_userset', 'local_o365', $setuser) . ' '; $settinghtml .= \html_writer::link($setuserurl, get_string('settings_systemapiuser_change', 'local_o365')); } else { $settinghtml .= get_string('settings_systemapiuser_usernotset', 'local_o365') . ' '; $settinghtml .= \html_writer::link($setuserurl, get_string('settings_systemapiuser_setuser', 'local_o365')); } return format_admin_setting($this, $this->visiblename, $settinghtml, $this->description); }
/** * Return an XHTML string for the setting * @return string Returns an XHTML string */ public function output_html($data, $query = '') { global $OUTPUT; $tokens = get_config('local_o365', 'systemtokens'); $setuser = ''; if (!empty($tokens)) { $tokens = unserialize($tokens); if (isset($tokens['idtoken'])) { try { $idtoken = \auth_oidc\jwt::instance_from_encoded($tokens['idtoken']); $setuser = $idtoken->claim('upn'); } catch (\Exception $e) { // There is a check below for an empty $setuser. } } } $settinghtml = '<input type="hidden" id="' . $this->get_id() . '" name="' . $this->get_full_name() . '" value="0" />'; $setuserurl = new \moodle_url('/local/o365/acp.php', ['mode' => 'setsystemuser']); if (!empty($setuser)) { $message = \html_writer::tag('span', get_string('settings_systemapiuser_userset', 'local_o365', $setuser)) . ' '; $linkstr = get_string('settings_systemapiuser_change', 'local_o365'); $message .= \html_writer::link($setuserurl, $linkstr, ['class' => 'btn', 'style' => 'margin-left: 0.5rem']); $messageattrs = ['class' => 'local_o365_statusmessage alert-success']; $icon = $OUTPUT->pix_icon('t/check', 'success', 'moodle'); $settinghtml .= \html_writer::tag('div', $icon . $message, $messageattrs); } else { $message = \html_writer::tag('span', get_string('settings_systemapiuser_usernotset', 'local_o365')) . ' '; $linkstr = get_string('settings_systemapiuser_setuser', 'local_o365'); $message .= \html_writer::link($setuserurl, $linkstr, ['class' => 'btn', 'style' => 'margin-left: 0.5rem']); $messageattrs = ['class' => 'local_o365_statusmessage alert-info']; $icon = $OUTPUT->pix_icon('i/warning', 'warning', 'moodle'); $settinghtml .= \html_writer::tag('div', $icon . $message, $messageattrs); } return format_admin_setting($this, $this->visiblename, $settinghtml, $this->description); }
/** * Process an idtoken, extract uniqid and construct jwt object. * * @param string $idtoken Encoded id token. * @param string $orignonce Original nonce to validate received nonce against. * @return array List of oidcuniqid and constructed idtoken jwt. */ protected function process_idtoken($idtoken, $orignonce = '') { // Decode and verify idtoken. $idtoken = \auth_oidc\jwt::instance_from_encoded($idtoken); $sub = $idtoken->claim('sub'); if (empty($sub)) { throw new \moodle_exception('errorauthinvalididtoken', 'auth_oidc'); } $receivednonce = $idtoken->claim('nonce'); if (!empty($orignonce) && (empty($receivednonce) || $receivednonce !== $orignonce)) { throw new \moodle_exception('errorauthinvalididtoken', 'auth_oidc'); } // Use 'oid' if available (Azure-specific), or fall back to standard "sub" claim. $oidcuniqid = $idtoken->claim('oid'); if (empty($oidcuniqid)) { $oidcuniqid = $idtoken->claim('sub'); } return [$oidcuniqid, $idtoken]; }
/** * Update plugin. * * @param int $oldversion the version we are upgrading from * @return bool result */ function xmldb_auth_oidc_upgrade($oldversion) { global $DB; $dbman = $DB->get_manager(); $result = true; if ($result && $oldversion < 2014111703) { // Lengthen field. $table = new xmldb_table('auth_oidc_token'); $field = new xmldb_field('scope', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'username'); $dbman->change_field_type($table, $field); upgrade_plugin_savepoint($result, '2014111703', 'auth', 'oidc'); } if ($result && $oldversion < 2015012702) { $table = new xmldb_table('auth_oidc_state'); $field = new xmldb_field('additionaldata', XMLDB_TYPE_TEXT, null, null, null, null, null, 'timecreated'); if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } upgrade_plugin_savepoint($result, '2015012702', 'auth', 'oidc'); } if ($result && $oldversion < 2015012703) { $table = new xmldb_table('auth_oidc_token'); $field = new xmldb_field('oidcusername', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'username'); if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } upgrade_plugin_savepoint($result, '2015012703', 'auth', 'oidc'); } if ($result && $oldversion < 2015012704) { // Update OIDC users. $sql = 'SELECT u.id as userid, u.username as username, tok.id as tokenid, tok.oidcuniqid as oidcuniqid, tok.idtoken as idtoken, tok.oidcusername as oidcusername FROM {auth_oidc_token} tok JOIN {user} u ON u.username = tok.username WHERE u.auth = ? AND deleted = 0'; $params = ['oidc']; $userstoupdate = $DB->get_recordset_sql($sql, $params); foreach ($userstoupdate as $user) { if (empty($user->idtoken)) { continue; } try { // Decode idtoken and determine oidc username. $idtoken = \auth_oidc\jwt::instance_from_encoded($user->idtoken); $oidcusername = $idtoken->claim('upn'); if (empty($oidcusername)) { $oidcusername = $idtoken->claim('sub'); } // Populate token oidcusername. if (empty($user->oidcusername)) { $updatedtoken = new \stdClass(); $updatedtoken->id = $user->tokenid; $updatedtoken->oidcusername = $oidcusername; $DB->update_record('auth_oidc_token', $updatedtoken); } // Update user username (if applicable), so user can use rocreds loginflow. if ($user->username == strtolower($user->oidcuniqid)) { // Old username, update to upn/sub. if ($oidcusername != $user->username) { // Update username. $updateduser = new \stdClass(); $updateduser->id = $user->userid; $updateduser->username = $oidcusername; $DB->update_record('user', $updateduser); $updatedtoken = new \stdClass(); $updatedtoken->id = $user->tokenid; $updatedtoken->username = $oidcusername; $DB->update_record('auth_oidc_token', $updatedtoken); } } } catch (\Exception $e) { continue; } } upgrade_plugin_savepoint($result, '2015012704', 'auth', 'oidc'); } if ($result && $oldversion < 2015012707) { if (!$dbman->table_exists('auth_oidc_prevlogin')) { $dbman->install_one_table_from_xmldb_file(__DIR__ . '/install.xml', 'auth_oidc_prevlogin'); } upgrade_plugin_savepoint($result, '2015012707', 'auth', 'oidc'); } if ($result && $oldversion < 2015012710) { // Lengthen field. $table = new xmldb_table('auth_oidc_token'); $field = new xmldb_field('scope', XMLDB_TYPE_TEXT, null, null, null, null, null, 'oidcusername'); $dbman->change_field_type($table, $field); upgrade_plugin_savepoint($result, '2015012710', 'auth', 'oidc'); } return $result; }