diff --git a/admin/tool/oauth2/classes/form/endpoint.php b/admin/tool/oauth2/classes/form/endpoint.php
new file mode 100644
index 00000000000..b4bd4be3cda
--- /dev/null
+++ b/admin/tool/oauth2/classes/form/endpoint.php
@@ -0,0 +1,81 @@
+.
+
+/**
+ * This file contains the form add/update oauth2 endpoint.
+ *
+ * @package tool_oauth2
+ * @copyright 2017 Damyon Wiese
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_oauth2\form;
+defined('MOODLE_INTERNAL') || die();
+
+use stdClass;
+use core\form\persistent;
+
+/**
+ * Issuer form.
+ *
+ * @package tool_oauth2
+ * @copyright 2017 Damyon Wiese
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class endpoint extends persistent {
+
+ protected static $persistentclass = 'core\\oauth2\\endpoint';
+
+ protected static $fieldstoremove = array('submitbutton', 'action');
+
+ /**
+ * Define the form - called by parent constructor
+ */
+ public function definition() {
+ global $PAGE;
+
+ $mform = $this->_form;
+ $endpoint = $this->get_persistent();
+
+ $mform->addElement('header', 'generalhdr', get_string('general'));
+
+ // Name.
+ $mform->addElement('text', 'name', get_string('endpointname', 'tool_oauth2'), 'maxlength="255"');
+ $mform->addRule('name', null, 'required', null, 'client');
+ $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
+ $mform->addHelpButton('name', 'endpointname', 'tool_oauth2');
+
+ // Url.
+ $mform->addElement('text', 'url', get_string('endpointurl', 'tool_oauth2'), 'maxlength="1024"');
+ $mform->addRule('url', null, 'required', null, 'client');
+ $mform->addRule('url', get_string('maximumchars', '', 1024), 'maxlength', 1024, 'client');
+ $mform->addHelpButton('url', 'endpointurl', 'tool_oauth2');
+
+ $mform->addElement('hidden', 'action', 'edit');
+ $mform->setType('action', PARAM_RAW);
+
+ $mform->addElement('hidden', 'issuerid', $endpoint->get('issuerid'));
+ $mform->setType('issuerid', PARAM_INT);
+ $mform->setConstant('issuerid', $this->_customdata['issuerid']);
+
+ $mform->addElement('hidden', 'id', $endpoint->get('id'));
+ $mform->setType('id', PARAM_INT);
+
+ $this->add_action_buttons(true, get_string('savechanges', 'tool_oauth2'));
+ }
+
+}
+
diff --git a/admin/tool/oauth2/classes/form/issuer.php b/admin/tool/oauth2/classes/form/issuer.php
index ce03af63e4a..d16755c32bf 100644
--- a/admin/tool/oauth2/classes/form/issuer.php
+++ b/admin/tool/oauth2/classes/form/issuer.php
@@ -48,7 +48,7 @@ class issuer extends persistent {
global $PAGE;
$mform = $this->_form;
- $provider = $this->get_persistent();
+ $endpoint = $this->get_persistent();
$mform->addElement('header', 'generalhdr', get_string('general'));
@@ -77,7 +77,7 @@ class issuer extends persistent {
$mform->addHelpButton('baseurl', 'issuerbaseurl', 'tool_oauth2');
// Offline access type
- $options = $provider->get_behaviour_list();
+ $options = $endpoint->get_behaviour_list();
$mform->addElement('select', 'behaviour', get_string('issuerbehaviour', 'tool_oauth2'), $options);
$mform->addHelpButton('behaviour', 'issuerbehaviour', 'tool_oauth2');
@@ -97,7 +97,7 @@ class issuer extends persistent {
$mform->addElement('hidden', 'action', 'edit');
$mform->setType('action', PARAM_RAW);
- $mform->addElement('hidden', 'id', $provider->get('id'));
+ $mform->addElement('hidden', 'id', $endpoint->get('id'));
$mform->setType('id', PARAM_INT);
$this->add_action_buttons(true, get_string('savechanges', 'tool_oauth2'));
diff --git a/admin/tool/oauth2/classes/form/user_field_mapping.php b/admin/tool/oauth2/classes/form/user_field_mapping.php
new file mode 100644
index 00000000000..e8fa760356e
--- /dev/null
+++ b/admin/tool/oauth2/classes/form/user_field_mapping.php
@@ -0,0 +1,80 @@
+.
+
+/**
+ * This file contains the form add/update oauth2 user_field_mapping.
+ *
+ * @package tool_oauth2
+ * @copyright 2017 Damyon Wiese
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_oauth2\form;
+defined('MOODLE_INTERNAL') || die();
+
+use stdClass;
+use core\form\persistent;
+
+/**
+ * Issuer form.
+ *
+ * @package tool_oauth2
+ * @copyright 2017 Damyon Wiese
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class user_field_mapping extends persistent {
+
+ protected static $persistentclass = 'core\\oauth2\\user_field_mapping';
+
+ protected static $fieldstoremove = array('submitbutton', 'action');
+
+ /**
+ * Define the form - called by parent constructor
+ */
+ public function definition() {
+ global $PAGE;
+
+ $mform = $this->_form;
+ $userfieldmapping = $this->get_persistent();
+
+ $mform->addElement('header', 'generalhdr', get_string('general'));
+
+ // External.
+ $mform->addElement('text', 'externalfield', get_string('userfieldexternalfield', 'tool_oauth2'), 'maxlength="255"');
+ $mform->addRule('externalfield', null, 'required', null, 'client');
+ $mform->addRule('externalfield', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
+ $mform->addHelpButton('externalfield', 'userfieldexternalfield', 'tool_oauth2');
+
+ // Internal.
+ $choices = $userfieldmapping->get_internalfield_list();
+ $mform->addElement('select', 'internalfield', get_string('userfieldinternalfield', 'tool_oauth2'), $choices);
+ $mform->addHelpButton('internalfield', 'userfieldinternalfield', 'tool_oauth2');
+
+ $mform->addElement('hidden', 'action', 'edit');
+ $mform->setType('action', PARAM_RAW);
+
+ $mform->addElement('hidden', 'issuerid', $userfieldmapping->get('issuerid'));
+ $mform->setConstant('issuerid', $this->_customdata['issuerid']);
+ $mform->setType('issuerid', PARAM_INT);
+
+ $mform->addElement('hidden', 'id', $userfieldmapping->get('id'));
+ $mform->setType('id', PARAM_INT);
+
+ $this->add_action_buttons(true, get_string('savechanges', 'tool_oauth2'));
+ }
+
+}
+
diff --git a/admin/tool/oauth2/classes/output/renderer.php b/admin/tool/oauth2/classes/output/renderer.php
index f26ca777f91..0d4514d2bcc 100644
--- a/admin/tool/oauth2/classes/output/renderer.php
+++ b/admin/tool/oauth2/classes/output/renderer.php
@@ -79,7 +79,7 @@ class renderer extends plugin_renderer_base {
$name = $issuer->get('name');
$image = $issuer->get('image');
if ($image) {
- $name = '
' . $name;
+ $name = '
' . s($name);
}
$namecell = new html_table_cell($name);
$namecell->header = true;
@@ -104,7 +104,11 @@ class renderer extends plugin_renderer_base {
if (!empty($issuer->get('scopessupported'))) {
$discovered = $OUTPUT->pix_icon('yes', get_string('discovered', 'tool_oauth2'), 'tool_oauth2');
} else {
- $discovered = $OUTPUT->pix_icon('no', get_string('notdiscovered', 'tool_oauth2'), 'tool_oauth2');
+ if ($issuer->get('behaviour') == $issuer::BEHAVIOUR_OPENID_CONNECT) {
+ $discovered = $OUTPUT->pix_icon('no', get_string('notdiscovered', 'tool_oauth2'), 'tool_oauth2');
+ } else {
+ $discovered = '-';
+ }
}
$discoverystatuscell = new html_table_cell($discovered);
@@ -125,22 +129,37 @@ class renderer extends plugin_renderer_base {
$systemauthstatuscell = new html_table_cell($systemauth);
- // Action links.
$links = '';
+ // Action links.
$editurl = new moodle_url('/admin/tool/oauth2/issuers.php', ['id' => $issuer->get('id'), 'action' => 'edit']);
$editlink = html_writer::link($editurl, $OUTPUT->pix_icon('t/edit', get_string('edit')));
-
$links .= ' ' . $editlink;
+
+ // Endpoints.
+ $editendpointsurl = new moodle_url('/admin/tool/oauth2/endpoints.php', ['issuerid' => $issuer->get('id')]);
+ $str = get_string('editendpoints', 'tool_oauth2');
+ $editendpointlink = html_writer::link($editendpointsurl, $OUTPUT->pix_icon('t/viewdetails', $str));
+ $links .= ' ' . $editendpointlink;
+
+ // User field mapping.
+ $edituserfieldmappingsurl = new moodle_url('/admin/tool/oauth2/userfieldmappings.php', ['issuerid' => $issuer->get('id')]);
+ $str = get_string('edituserfieldmappings', 'tool_oauth2');
+ $edituserfieldmappinglink = html_writer::link($edituserfieldmappingsurl, $OUTPUT->pix_icon('t/user', $str));
+ $links .= ' ' . $edituserfieldmappinglink;
+
+ // Delete.
$deleteurl = new moodle_url('/admin/tool/oauth2/issuers.php', ['id' => $issuer->get('id'), 'action' => 'delete']);
$deletelink = html_writer::link($deleteurl, $OUTPUT->pix_icon('t/delete', get_string('delete')));
$links .= ' ' . $deletelink;
if (!$last) {
+ // Move down.
$params = ['id' => $issuer->get('id'), 'action' => 'movedown', 'sesskey' => sesskey()];
$movedownurl = new moodle_url('/admin/tool/oauth2/issuers.php', $params);
$movedownlink = html_writer::link($movedownurl, $OUTPUT->pix_icon('t/down', get_string('movedown')));
$links .= ' ' . $movedownlink;
}
if (!$first) {
+ // Move up.
$params = ['id' => $issuer->get('id'), 'action' => 'moveup', 'sesskey' => sesskey()];
$moveupurl = new moodle_url('/admin/tool/oauth2/issuers.php', $params);
$moveuplink = html_writer::link($moveupurl, $OUTPUT->pix_icon('t/up', get_string('moveup')));
@@ -164,4 +183,119 @@ class renderer extends plugin_renderer_base {
$table->data = $data;
return html_writer::table($table);
}
+
+ /**
+ * This function will render one beautiful table with all the endpoints.
+ *
+ * @param \core\oauth2\endpoint[] $endpoints - list of all endpoints.
+ * @return string HTML to output.
+ */
+ public function endpoints_table($endpoints, $issuerid) {
+ global $CFG, $OUTPUT;
+
+ $table = new html_table();
+ $table->head = [
+ get_string('name'),
+ get_string('url'),
+ get_string('edit'),
+ ];
+ $table->attributes['class'] = 'admintable generaltable';
+ $data = [];
+
+ $index = 0;
+
+ foreach ($endpoints as $endpoint) {
+ // Name.
+ $name = $endpoint->get('name');
+ $namecell = new html_table_cell(s($name));
+ $namecell->header = true;
+
+ // Url
+ $url = $endpoint->get('url');
+ $urlcell = new html_table_cell(s($url));
+
+ $links = '';
+ // Action links.
+ $editparams = ['issuerid' => $issuerid, 'endpointid' => $endpoint->get('id'), 'action' => 'edit'];
+ $editurl = new moodle_url('/admin/tool/oauth2/endpoints.php', $editparams);
+ $editlink = html_writer::link($editurl, $OUTPUT->pix_icon('t/edit', get_string('edit')));
+ $links .= ' ' . $editlink;
+
+ // Delete.
+ $deleteparams = ['issuerid' => $issuerid, 'endpointid' => $endpoint->get('id'), 'action' => 'delete'];
+ $deleteurl = new moodle_url('/admin/tool/oauth2/endpoints.php', $deleteparams);
+ $deletelink = html_writer::link($deleteurl, $OUTPUT->pix_icon('t/delete', get_string('delete')));
+ $links .= ' ' . $deletelink;
+
+ $editcell = new html_table_cell($links);
+
+ $row = new html_table_row([
+ $namecell,
+ $urlcell,
+ $editcell,
+ ]);
+
+ $data[] = $row;
+ $index++;
+ }
+ $table->data = $data;
+ return html_writer::table($table);
+ }
+
+ /**
+ * This function will render one beautiful table with all the user_field_mappings.
+ *
+ * @param \core\oauth2\user_field_mapping[] $userfieldmappings - list of all user_field_mappings.
+ * @return string HTML to output.
+ */
+ public function user_field_mappings_table($userfieldmappings, $issuerid) {
+ global $CFG, $OUTPUT;
+
+ $table = new html_table();
+ $table->head = [
+ get_string('userfieldexternalfield', 'tool_oauth2'),
+ get_string('userfieldinternalfield', 'tool_oauth2'),
+ get_string('edit'),
+ ];
+ $table->attributes['class'] = 'admintable generaltable';
+ $data = [];
+
+ $index = 0;
+
+ foreach ($userfieldmappings as $userfieldmapping) {
+ // External field
+ $externalfield = $userfieldmapping->get('externalfield');
+ $externalfieldcell = new html_table_cell(s($externalfield));
+
+ // Internal field
+ $internalfield = $userfieldmapping->get('internalfield');
+ $internalfieldcell = new html_table_cell(s($internalfield));
+
+ $links = '';
+ // Action links.
+ $editparams = ['issuerid' => $issuerid, 'userfieldmappingid' => $userfieldmapping->get('id'), 'action' => 'edit'];
+ $editurl = new moodle_url('/admin/tool/oauth2/userfieldmappings.php', $editparams);
+ $editlink = html_writer::link($editurl, $OUTPUT->pix_icon('t/edit', get_string('edit')));
+ $links .= ' ' . $editlink;
+
+ // Delete.
+ $deleteparams = ['issuerid' => $issuerid, 'userfieldmappingid' => $userfieldmapping->get('id'), 'action' => 'delete'];
+ $deleteurl = new moodle_url('/admin/tool/oauth2/userfieldmappings.php', $deleteparams);
+ $deletelink = html_writer::link($deleteurl, $OUTPUT->pix_icon('t/delete', get_string('delete')));
+ $links .= ' ' . $deletelink;
+
+ $editcell = new html_table_cell($links);
+
+ $row = new html_table_row([
+ $externalfieldcell,
+ $internalfieldcell,
+ $editcell,
+ ]);
+
+ $data[] = $row;
+ $index++;
+ }
+ $table->data = $data;
+ return html_writer::table($table);
+ }
}
diff --git a/admin/tool/oauth2/endpoints.php b/admin/tool/oauth2/endpoints.php
new file mode 100644
index 00000000000..cf3a3fe3b0b
--- /dev/null
+++ b/admin/tool/oauth2/endpoints.php
@@ -0,0 +1,128 @@
+.
+
+/**
+ * OAuth 2 Endpoing Configuration page.
+ *
+ * @package tool_oauth2
+ * @copyright 2017 Damyon Wiese
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->libdir.'/tablelib.php');
+
+$PAGE->set_url('/admin/tool/oauth2/endpoints.php', ['issuerid' => required_param('issuerid', PARAM_INT)]);
+$PAGE->set_context(context_system::instance());
+$PAGE->set_pagelayout('admin');
+$strheading = get_string('pluginname', 'tool_oauth2');
+$PAGE->set_title($strheading);
+$PAGE->set_heading($strheading);
+
+require_login();
+
+require_capability('moodle/site:config', context_system::instance());
+
+$renderer = $PAGE->get_renderer('tool_oauth2');
+
+$action = optional_param('action', '', PARAM_ALPHAEXT);
+$issuerid = required_param('issuerid', PARAM_INT);
+$endpointid = optional_param('endpointid', '', PARAM_INT);
+$endpoint = null;
+$mform = null;
+
+$issuer = \core\oauth2\api::get_issuer($issuerid);
+if (!$issuer) {
+ print_error('invaliddata');
+}
+$PAGE->navbar->override_active_url(new moodle_url('/admin/tool/oauth2/issuers.php'), true);
+
+if (!empty($endpointid)) {
+ $endpoint = \core\oauth2\api::get_endpoint($endpointid);
+}
+
+if ($action == 'edit') {
+ if ($endpoint) {
+ $strparams = [ 'issuer' => s($issuer->get('name')), 'endpoint' => s($endpoint->get('name')) ];
+ $PAGE->navbar->add(get_string('editendpoint', 'tool_oauth2', $strparams));
+ } else {
+ $PAGE->navbar->add(get_string('createnewendpoint', 'tool_oauth2', s($issuer->get('name'))));
+ }
+
+ $mform = new \tool_oauth2\form\endpoint(null, ['persistent' => $endpoint, 'issuerid' => $issuerid]);
+}
+
+if ($mform && $mform->is_cancelled()) {
+ redirect(new moodle_url('/admin/tool/oauth2/endpoints.php', ['issuerid' => $issuerid]));
+} else if ($action == 'edit') {
+
+ if ($data = $mform->get_data()) {
+
+ try {
+ if (!empty($data->id)) {
+ core\oauth2\api::update_endpoint($data);
+ } else {
+ core\oauth2\api::create_endpoint($data);
+ }
+ redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
+ } catch (Exception $e) {
+ redirect($PAGE->url, $e->getMessage(), null, \core\output\notification::NOTIFY_ERROR);
+ }
+ } else {
+ echo $OUTPUT->header();
+ if ($endpoint) {
+ $strparams = [ 'issuer' => s($issuer->get('name')), 'endpoint' => s($endpoint->get('name')) ];
+ echo $OUTPUT->heading(get_string('editendpoint', 'tool_oauth2', $strparams));
+ } else {
+ echo $OUTPUT->heading(get_string('createnewendpoint', 'tool_oauth2', s($issuer->get('name'))));
+ }
+ $mform->display();
+ echo $OUTPUT->footer();
+ }
+
+} else if ($action == 'delete') {
+
+ if (!optional_param('confirm', false, PARAM_BOOL)) {
+ $continueparams = [
+ 'action' => 'delete',
+ 'issuerid' => $issuerid,
+ 'endpointid' => $endpointid,
+ 'sesskey' => sesskey(),
+ 'confirm' => true
+ ];
+ $continueurl = new moodle_url('/admin/tool/oauth2/endpoints.php', $continueparams);
+ $cancelurl = new moodle_url('/admin/tool/oauth2/endpoints.php');
+ echo $OUTPUT->header();
+ $strparams = [ 'issuer' => s($issuer->get('name')), 'endpoint' => s($endpoint->get('name')) ];
+ echo $OUTPUT->confirm(get_string('deleteendpointconfirm', 'tool_oauth2', $strparams), $continueurl, $cancelurl);
+ echo $OUTPUT->footer();
+ } else {
+ require_sesskey();
+ core\oauth2\api::delete_endpoint($endpointid);
+ redirect($PAGE->url, get_string('endpointdeleted', 'tool_oauth2'), null, \core\output\notification::NOTIFY_SUCCESS);
+ }
+
+} else {
+ echo $OUTPUT->header();
+ echo $OUTPUT->heading(get_string('endpointsforissuer', 'tool_oauth2', s($issuer->get('name'))));
+ $endpoints = core\oauth2\api::get_endpoints($issuer);
+ echo $renderer->endpoints_table($endpoints, $issuerid);
+
+ $addurl = new moodle_url('/admin/tool/oauth2/endpoints.php', ['action' => 'edit', 'issuerid' => $issuerid]);
+ echo $renderer->single_button($addurl, get_string('createnewendpoint', 'tool_oauth2', s($issuer->get('name'))));
+ echo $OUTPUT->footer();
+}
diff --git a/admin/tool/oauth2/issuers.php b/admin/tool/oauth2/issuers.php
index d80f91d1e2a..af6c762bcf0 100644
--- a/admin/tool/oauth2/issuers.php
+++ b/admin/tool/oauth2/issuers.php
@@ -40,12 +40,12 @@ require_capability('moodle/site:config', context_system::instance());
$renderer = $PAGE->get_renderer('tool_oauth2');
$action = optional_param('action', '', PARAM_ALPHAEXT);
-$idpid = optional_param('id', '', PARAM_RAW);
+$issuerid = optional_param('id', '', PARAM_RAW);
$issuer = null;
$mform = null;
-if ($idpid) {
- $issuer = \core\oauth2\api::get_issuer($idpid);
+if ($issuerid) {
+ $issuer = \core\oauth2\api::get_issuer($issuerid);
if (!$issuer) {
print_error('invaliddata');
}
@@ -53,7 +53,7 @@ if ($idpid) {
if ($action == 'edit') {
if ($issuer) {
- $PAGE->navbar->add(get_string('editissuer', 'tool_oauth2', $issuer->get('name')));
+ $PAGE->navbar->add(get_string('editissuer', 'tool_oauth2', s($issuer->get('name'))));
} else {
$PAGE->navbar->add(get_string('createnewissuer', 'tool_oauth2'));
}
@@ -80,7 +80,7 @@ if ($mform && $mform->is_cancelled()) {
} else {
echo $OUTPUT->header();
if ($issuer) {
- echo $OUTPUT->heading(get_string('editissuer', 'tool_oauth2', $issuer->get('name')));
+ echo $OUTPUT->heading(get_string('editissuer', 'tool_oauth2', s($issuer->get('name'))));
} else {
echo $OUTPUT->heading(get_string('createnewissuer', 'tool_oauth2'));
}
@@ -91,30 +91,30 @@ if ($mform && $mform->is_cancelled()) {
} else if ($action == 'delete') {
if (!optional_param('confirm', false, PARAM_BOOL)) {
- $continueparams = ['action' => 'delete', 'id' => $idpid, 'sesskey' => sesskey(), 'confirm' => true];
+ $continueparams = ['action' => 'delete', 'id' => $issuerid, 'sesskey' => sesskey(), 'confirm' => true];
$continueurl = new moodle_url('/admin/tool/oauth2/issuers.php', $continueparams);
$cancelurl = new moodle_url('/admin/tool/oauth2/issuers.php');
echo $OUTPUT->header();
- echo $OUTPUT->confirm(get_string('deleteconfirm', 'tool_oauth2', $issuer->get('name')), $continueurl, $cancelurl);
+ echo $OUTPUT->confirm(get_string('deleteconfirm', 'tool_oauth2', s($issuer->get('name'))), $continueurl, $cancelurl);
echo $OUTPUT->footer();
} else {
require_sesskey();
- core\oauth2\api::delete_issuer($idpid);
+ core\oauth2\api::delete_issuer($issuerid);
redirect($PAGE->url, get_string('issuerdeleted', 'tool_oauth2'), null, \core\output\notification::NOTIFY_SUCCESS);
}
} else if ($action == 'auth') {
if (!optional_param('confirm', false, PARAM_BOOL)) {
- $continueparams = ['action' => 'auth', 'id' => $idpid, 'sesskey' => sesskey(), 'confirm' => true];
+ $continueparams = ['action' => 'auth', 'id' => $issuerid, 'sesskey' => sesskey(), 'confirm' => true];
$continueurl = new moodle_url('/admin/tool/oauth2/issuers.php', $continueparams);
$cancelurl = new moodle_url('/admin/tool/oauth2/issuers.php');
echo $OUTPUT->header();
- echo $OUTPUT->confirm(get_string('authconfirm', 'tool_oauth2', $issuer->get('name')), $continueurl, $cancelurl);
+ echo $OUTPUT->confirm(get_string('authconfirm', 'tool_oauth2', s($issuer->get('name'))), $continueurl, $cancelurl);
echo $OUTPUT->footer();
} else {
require_sesskey();
- $params = ['sesskey' => sesskey(), 'id' => $idpid, 'action' => 'auth', 'confirm' => true, 'response' => true];
+ $params = ['sesskey' => sesskey(), 'id' => $issuerid, 'action' => 'auth', 'confirm' => true, 'response' => true];
if (core\oauth2\api::connect_system_account($issuer, new moodle_url('/admin/tool/oauth2/issuers.php', $params))) {
redirect($PAGE->url, get_string('authconnected', 'tool_oauth2'), null, \core\output\notification::NOTIFY_SUCCESS);
} else {
@@ -123,12 +123,12 @@ if ($mform && $mform->is_cancelled()) {
}
} else if ($action == 'moveup') {
require_sesskey();
- core\oauth2\api::move_up_issuer($idpid);
+ core\oauth2\api::move_up_issuer($issuerid);
redirect($PAGE->url);
} else if ($action == 'movedown') {
require_sesskey();
- core\oauth2\api::move_down_issuer($idpid);
+ core\oauth2\api::move_down_issuer($issuerid);
redirect($PAGE->url);
} else {
diff --git a/admin/tool/oauth2/lang/en/tool_oauth2.php b/admin/tool/oauth2/lang/en/tool_oauth2.php
index 73bce13bed4..46dc3d8e47b 100644
--- a/admin/tool/oauth2/lang/en/tool_oauth2.php
+++ b/admin/tool/oauth2/lang/en/tool_oauth2.php
@@ -22,8 +22,17 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-$string['pluginname'] = 'Open ID Connect configuration';
+$string['pluginname'] = 'OAuth 2 Services';
$string['editissuer'] = 'Edit identity issuer: {$a}';
+$string['editendpoint'] = 'Edit endpoint: {$a->endpoint} for issuer {$a->issuer}';
+$string['endpointsforissuer'] = 'Endpoints for issuer: {$a}';
+$string['edituserfieldmapping'] = 'Edit user field mapping for issuer {$a}';
+$string['userfieldmappingsforissuer'] = 'User field mappings for issuer: {$a}';
+$string['issuers'] = 'Issuers';
+$string['endpointname'] = 'Name';
+$string['endpointname_help'] = 'Key used to search for this endpoint. Must end with "_endpoint".';
+$string['endpointurl'] = 'Url';
+$string['endpointurl_help'] = 'URL for this endpoint. Must use https:// protocol.';
$string['issuername'] = 'Name';
$string['issuername_help'] = 'Name of the identity issuer. May be displayed on login page.';
$string['issuerimage'] = 'Logo URL';
@@ -47,6 +56,8 @@ $string['configuredstatus'] = 'Configured';
$string['discoverystatus'] = 'Discovery';
$string['systemauthstatus'] = 'System account connected';
$string['configured'] = 'Configured';
+$string['editendpoints'] = 'Configure endpoints';
+$string['edituserfieldmappings'] = 'Configure user field mappings';
$string['notconfigured'] = 'Not configured';
$string['discovered'] = 'Service discovery successful';
$string['notdiscovered'] = 'Service discovery not successful';
@@ -55,9 +66,19 @@ $string['notloginissuer'] = 'Do not allow login';
$string['systemaccountconnected'] = 'System account connected';
$string['systemaccountnotconnected'] = 'System account not connected';
$string['createnewissuer'] = 'Create new identity issuer';
+$string['createnewendpoint'] = 'Create new endpoint for issuer "{$a}"';
+$string['createnewuserfieldmapping'] = 'Create new user field mapping for issuer "{$a}"';
$string['deleteconfirm'] = 'Are you sure you want to delete the identity issuer "{$a}"? Any plugins relying on this issuer will stop working.';
+$string['deleteendpointconfirm'] = 'Are you sure you want to delete the endpoint "{$a->endpoint}" for issuer "{$a->issuer}"? Any plugins relying on this endpoint will stop working.';
+$string['deleteuserfieldmappingconfirm'] = 'Are you sure you want to delete the user field mapping for issuer "{$a}"?';
$string['issuerdeleted'] = 'Identity issuer deleted';
+$string['endpointdeleted'] = 'Endpoint deleted';
+$string['userfieldmappingdeleted'] = 'User field mapping deleted';
$string['connectsystemaccount'] = 'Connect to a system account';
$string['authconfirm'] = 'This action will grant permanent API access to Moodle for the authenticated account. This is intended to be used as a system account for managing files owned by Moodle.';
$string['authconnected'] = 'The system account is now connected for offline access';
$string['authnotconnected'] = 'The system account was not connected for offline access';
+$string['userfieldexternalfield'] = 'External field name';
+$string['userfieldexternalfield_help'] = 'Name of the field provided by the external OAuth system.';
+$string['userfieldinternalfield'] = 'Internal field name';
+$string['userfieldinternalfield_help'] = 'Name of the Moodle user field that should be mapped from the external field.';
diff --git a/admin/tool/oauth2/userfieldmappings.php b/admin/tool/oauth2/userfieldmappings.php
new file mode 100644
index 00000000000..1bf277d9069
--- /dev/null
+++ b/admin/tool/oauth2/userfieldmappings.php
@@ -0,0 +1,126 @@
+.
+
+/**
+ * OAuth 2 Endpoing Configuration page.
+ *
+ * @package tool_oauth2
+ * @copyright 2017 Damyon Wiese
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->libdir.'/tablelib.php');
+
+$PAGE->set_url('/admin/tool/oauth2/userfieldmappings.php', ['issuerid' => required_param('issuerid', PARAM_INT)]);
+$PAGE->set_context(context_system::instance());
+$PAGE->set_pagelayout('admin');
+$strheading = get_string('pluginname', 'tool_oauth2');
+$PAGE->set_title($strheading);
+$PAGE->set_heading($strheading);
+
+require_login();
+
+require_capability('moodle/site:config', context_system::instance());
+
+$renderer = $PAGE->get_renderer('tool_oauth2');
+
+$action = optional_param('action', '', PARAM_ALPHAEXT);
+$issuerid = required_param('issuerid', PARAM_INT);
+$userfieldmappingid = optional_param('userfieldmappingid', '', PARAM_INT);
+$userfieldmapping = null;
+$mform = null;
+
+$issuer = \core\oauth2\api::get_issuer($issuerid);
+if (!$issuer) {
+ print_error('invaliddata');
+}
+$PAGE->navbar->override_active_url(new moodle_url('/admin/tool/oauth2/issuers.php'), true);
+
+if (!empty($userfieldmappingid)) {
+ $userfieldmapping = \core\oauth2\api::get_user_field_mapping($userfieldmappingid);
+}
+
+if ($action == 'edit') {
+ if ($userfieldmapping) {
+ $PAGE->navbar->add(get_string('edituserfieldmapping', 'tool_oauth2', s($issuer->get('name'))));
+ } else {
+ $PAGE->navbar->add(get_string('createnewuserfieldmapping', 'tool_oauth2', s($issuer->get('name'))));
+ }
+
+ $mform = new \tool_oauth2\form\user_field_mapping(null, ['persistent' => $userfieldmapping, 'issuerid' => $issuerid]);
+}
+
+if ($mform && $mform->is_cancelled()) {
+ redirect(new moodle_url('/admin/tool/oauth2/userfieldmappings.php', ['issuerid' => $issuerid]));
+} else if ($action == 'edit') {
+
+ if ($data = $mform->get_data()) {
+
+ try {
+ if (!empty($data->id)) {
+ core\oauth2\api::update_user_field_mapping($data);
+ } else {
+ core\oauth2\api::create_user_field_mapping($data);
+ }
+ redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
+ } catch (Exception $e) {
+ redirect($PAGE->url, $e->getMessage(), null, \core\output\notification::NOTIFY_ERROR);
+ }
+ } else {
+ echo $OUTPUT->header();
+ if ($issuer) {
+ echo $OUTPUT->heading(get_string('edituserfieldmapping', 'tool_oauth2', s($issuer->get('name'))));
+ } else {
+ echo $OUTPUT->heading(get_string('createnewuserfieldmapping', 'tool_oauth2', s($issuer->get('name'))));
+ }
+ $mform->display();
+ echo $OUTPUT->footer();
+ }
+
+} else if ($action == 'delete') {
+
+ if (!optional_param('confirm', false, PARAM_BOOL)) {
+ $continueparams = [
+ 'action' => 'delete',
+ 'issuerid' => $issuerid,
+ 'userfieldmappingid' => $userfieldmappingid,
+ 'sesskey' => sesskey(),
+ 'confirm' => true
+ ];
+ $continueurl = new moodle_url('/admin/tool/oauth2/userfieldmappings.php', $continueparams);
+ $cancelurl = new moodle_url('/admin/tool/oauth2/userfieldmappings.php');
+ echo $OUTPUT->header();
+ $str = get_string('deleteuserfieldmappingconfirm', 'tool_oauth2', s($issuer->get('name')));
+ echo $OUTPUT->confirm($str, $continueurl, $cancelurl);
+ echo $OUTPUT->footer();
+ } else {
+ require_sesskey();
+ core\oauth2\api::delete_user_field_mapping($userfieldmappingid);
+ redirect($PAGE->url, get_string('userfieldmappingdeleted', 'tool_oauth2'), null, \core\output\notification::NOTIFY_SUCCESS);
+ }
+
+} else {
+ echo $OUTPUT->header();
+ echo $OUTPUT->heading(get_string('userfieldmappingsforissuer', 'tool_oauth2', s($issuer->get('name'))));
+ $userfieldmappings = core\oauth2\api::get_user_field_mappings($issuer);
+ echo $renderer->user_field_mappings_table($userfieldmappings, $issuerid);
+
+ $addurl = new moodle_url('/admin/tool/oauth2/userfieldmappings.php', ['action' => 'edit', 'issuerid' => $issuerid]);
+ echo $renderer->single_button($addurl, get_string('createnewuserfieldmapping', 'tool_oauth2', s($issuer->get('name'))));
+ echo $OUTPUT->footer();
+}
diff --git a/auth/oauth2/classes/auth.php b/auth/oauth2/classes/auth.php
index 4bf2cc9fb68..545a162f2dd 100644
--- a/auth/oauth2/classes/auth.php
+++ b/auth/oauth2/classes/auth.php
@@ -318,6 +318,11 @@ class auth extends \auth_plugin_base {
$SESSION->loginerrormsg = $errormsg;
redirect(new moodle_url($CFG->httpswwwroot . '/login/index.php'));
}
+ if (empty($userinfo['username'])) {
+ $errormsg = get_string('notloggedin', 'auth_oauth2');
+ $SESSION->loginerrormsg = $errormsg;
+ redirect(new moodle_url($CFG->httpswwwroot . '/login/index.php'));
+ }
$userinfo['username'] = trim(core_text::strtolower($userinfo['username']));
diff --git a/lib/classes/oauth2/api.php b/lib/classes/oauth2/api.php
index 00230d1620e..5fc61507344 100644
--- a/lib/classes/oauth2/api.php
+++ b/lib/classes/oauth2/api.php
@@ -68,6 +68,7 @@ class api {
$endpoint = new endpoint(0, $record);
$endpoint->create();
+ // Microsoft is a custom setup.
$record = (object) [
'name' => 'Microsoft',
'image' => 'https://www.microsoft.com/favicon.ico',
@@ -81,29 +82,43 @@ class api {
$issuer = new issuer(0, $record);
$issuer->create();
- $record = (object) [
- 'issuerid' => $issuer->get('id'),
- 'name' => 'authorization_endpoint',
- 'url' => 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
+ $endpoints = [
+ 'authorization_endpoint' => 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
+ 'token_endpoint' => 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
+ 'userinfo_endpoint' => 'https://graph.microsoft.com/v1.0/me/',
+ 'userpicture_endpoint' => 'https://graph.microsoft.com/v1.0/me/photo/$value',
];
- $endpoint = new endpoint(0, $record);
- $endpoint->create();
- $record = (object) [
- 'issuerid' => $issuer->get('id'),
- 'name' => 'token_endpoint',
- 'url' => 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
- ];
- $endpoint = new endpoint(0, $record);
- $endpoint->create();
+ foreach ($endpoints as $name => $url) {
+ $record = (object) [
+ 'issuerid' => $issuer->get('id'),
+ 'name' => $name,
+ 'url' => $url
+ ];
+ $endpoint = new endpoint(0, $record);
+ $endpoint->create();
+ }
- $record = (object) [
- 'issuerid' => $issuer->get('id'),
- 'name' => 'end_session_endpoint',
- 'url' => 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
+ // Create the field mappings.
+ $mapping = [
+ 'givenName' => 'firstname',
+ 'surname' => 'lastname',
+ 'mail' => 'email',
+ 'userPrincipalName' => 'username',
+ 'displayName' => 'alternatename',
+ 'officeLocation' => 'address',
+ 'mobilePhone' => 'phone',
+ 'preferredLanguage' => 'lang'
];
- $endpoint = new endpoint(0, $record);
- $endpoint->create();
+ foreach ($mapping as $external => $internal) {
+ $record = (object) [
+ 'issuerid' => $issuer->get('id'),
+ 'externalfield' => $external,
+ 'internalfield' => $internal
+ ];
+ $userfieldmapping = new user_field_mapping(0, $record);
+ $userfieldmapping->create();
+ }
return issuer::count_records();
}
@@ -115,6 +130,14 @@ class api {
return new issuer($id);
}
+ public static function get_endpoint($id) {
+ return new endpoint($id);
+ }
+
+ public static function get_user_field_mapping($id) {
+ return new user_field_mapping($id);
+ }
+
public static function get_system_account(issuer $issuer) {
return system_account::get_record(['issuerid' => $issuer->get('id')]);
}
@@ -132,11 +155,13 @@ class api {
}
public static function get_endpoints(issuer $issuer) {
- require_capability('moodle/site:config', context_system::instance());
-
return endpoint::get_records(['issuerid' => $issuer->get('id')]);
}
+ public static function get_user_field_mappings(issuer $issuer) {
+ return user_field_mapping::get_records(['issuerid' => $issuer->get('id')]);
+ }
+
protected static function guess_image($issuer) {
if (empty($issuer->get('image'))) {
$baseurl = parse_url($issuer->get('discoveryurl'));
@@ -202,6 +227,32 @@ class api {
}
}
+ // We got to here - must be a decent OpenID connect service. Add the default user field mapping list.
+
+ // Create the field mappings.
+ $mapping = [
+ 'given_name' => 'firstname',
+ 'middle_name' => 'middlename',
+ 'family_name' => 'lastname',
+ 'email' => 'email',
+ 'sub' => 'username',
+ 'website' => 'url',
+ 'nickname' => 'alternatename',
+ 'picture' => 'picture',
+ 'address' => 'address',
+ 'phone' => 'phone',
+ 'locale' => 'lang'
+ ];
+ foreach ($mapping as $external => $internal) {
+ $record = (object) [
+ 'issuerid' => $issuer->get('id'),
+ 'externalfield' => $external,
+ 'internalfield' => $internal
+ ];
+ $userfieldmapping = new user_field_mapping(0, $record);
+ $userfieldmapping->create();
+ }
+
return endpoint::count_records(['issuerid' => $issuer->get('id')]);
}
@@ -215,6 +266,7 @@ class api {
// Perform service discovery.
self::discover_endpoints($issuer);
self::guess_image($issuer);
+ return $issuer;
}
public static function create_issuer($data) {
@@ -227,6 +279,45 @@ class api {
// Perform service discovery.
self::discover_endpoints($issuer);
self::guess_image($issuer);
+ return $issuer;
+ }
+
+ public static function update_endpoint($data) {
+ require_capability('moodle/site:config', context_system::instance());
+ $endpoint = new endpoint(0, $data);
+
+ // Will throw exceptions on validation failures.
+ $endpoint->update();
+
+ return $endpoint;
+ }
+
+ public static function create_endpoint($data) {
+ require_capability('moodle/site:config', context_system::instance());
+ $endpoint = new endpoint(0, $data);
+
+ // Will throw exceptions on validation failures.
+ $endpoint->create();
+ return $endpoint;
+ }
+
+ public static function update_user_field_mapping($data) {
+ require_capability('moodle/site:config', context_system::instance());
+ $userfieldmapping = new user_field_mapping(0, $data);
+
+ // Will throw exceptions on validation failures.
+ $userfieldmapping->update();
+
+ return $userfieldmapping;
+ }
+
+ public static function create_user_field_mapping($data) {
+ require_capability('moodle/site:config', context_system::instance());
+ $userfieldmapping = new user_field_mapping(0, $data);
+
+ // Will throw exceptions on validation failures.
+ $userfieldmapping->create();
+ return $userfieldmapping;
}
/**
@@ -307,7 +398,23 @@ class api {
}
// Will throw exceptions on validation failures.
- $issuer->delete();
+ return $issuer->delete();
+ }
+
+ public static function delete_endpoint($id) {
+ require_capability('moodle/site:config', context_system::instance());
+ $endpoint = new endpoint($id);
+
+ // Will throw exceptions on validation failures.
+ return $endpoint->delete();
+ }
+
+ public static function delete_user_field_mapping($id) {
+ require_capability('moodle/site:config', context_system::instance());
+ $userfieldmapping = new user_field_mapping($id);
+
+ // Will throw exceptions on validation failures.
+ return $userfieldmapping->delete();
}
public static function connect_system_account($issuer, $returnurl) {
@@ -324,6 +431,10 @@ class api {
$client->log_out();
}
+ if (optional_param('error', '', PARAM_RAW)) {
+ return false;
+ }
+
if (!$client->is_logged_in()) {
redirect($client->get_login_url());
}
diff --git a/lib/classes/oauth2/client.php b/lib/classes/oauth2/client.php
index 7410e64fad5..9b3b579107a 100644
--- a/lib/classes/oauth2/client.php
+++ b/lib/classes/oauth2/client.php
@@ -30,6 +30,7 @@ require_once($CFG->libdir . '/filelib.php');
use moodle_url;
use curl;
+use stdClass;
/**
* Configurable oauth2 client class where the urls come from DB.
@@ -83,35 +84,98 @@ abstract class client extends \oauth2_client {
return $this->issuer->get_endpoint_url('authorization');
}
- public function get_issuer() {
+ /**
+ * Get the oauth2 issuer for this client.
+ *
+ * @return \core\oauth2\issuer Issuer
+ */
+ public function get_issuer() {
return $this->issuer;
}
+ /**
+ * Override to append additional params to a authentication request.
+ *
+ * @return array (name value pairs).
+ */
public function get_additional_login_parameters() {
- if ($this->issuer->get('behaviour') == issuer::BEHAVIOUR_OPENID_CONNECT) {
- return ['access_type' => 'offline', 'prompt' => 'consent'];
- }
return [];
}
+ /**
+ * Override to change the scopes requested with an authentiction request.
+ *
+ * @return string
+ */
protected function get_login_scopes() {
return 'openid profile email';
}
/**
* Returns the token url for OAuth 2.0 request
+ *
+ * We are overriding the parent function so we get this from the configured endpoint.
+ *
* @return string the auth url
*/
protected function token_url() {
return $this->issuer->get_endpoint_url('token');
}
+ /**
+ * We want a unique key for each issuer / and a different key for system vs user oauth.
+ *
+ * @return string The unique key for the session value.
+ */
protected function get_tokenname() {
- $name = static::class;
+ $name = 'oauth2-state-' . $this->issuer->get('id');
if ($this->system) {
$name .= '-system';
}
return $name;
}
+ protected function get_userinfo_mapping() {
+ $fields = user_field_mapping::get_records(['issuerid' => $this->issuer->get('id')]);
+
+ $map = [];
+ foreach ($fields as $field) {
+ $map[$field->get('externalfield')] = $field->get('internalfield');
+ }
+ return $map;
+ }
+
+ public function get_userinfo() {
+ $url = $this->get_issuer()->get_endpoint_url('userinfo');
+ $response = $this->get($url);
+ if (!$response) {
+ return false;
+ }
+ $userinfo = new stdClass();
+ try {
+ $userinfo = json_decode($response);
+ } catch (Exception $e) {
+ return false;
+ }
+
+ $map = $this->get_userinfo_mapping();
+
+ $user = new stdClass();
+ foreach ($map as $openidproperty => $moodleproperty) {
+ if (!empty($userinfo->$openidproperty)) {
+ $user->$moodleproperty = $userinfo->$openidproperty;
+ }
+ }
+
+ if (!empty($user->picture)) {
+ $user->picture = download_file_content($user->picture, null, null, false, 10, 10, true, null, false);
+ } else {
+ $pictureurl = $this->issuer->get_endpoint_url('userpicture');
+ if (!empty($pictureurl)) {
+ $user->picture = $this->get($pictureurl);
+ }
+ }
+
+ return (array)$user;
+ }
}
diff --git a/lib/classes/oauth2/client_microsoft.php b/lib/classes/oauth2/client_microsoft.php
index 3d0bcd617e7..7059c4d9e6a 100644
--- a/lib/classes/oauth2/client_microsoft.php
+++ b/lib/classes/oauth2/client_microsoft.php
@@ -26,6 +26,7 @@ namespace core\oauth2;
defined('MOODLE_INTERNAL') || die();
use moodle_url;
+use stdClass;
/**
* We have to call directly to the graph APIs because the Microsoft Open ID Connect API is
@@ -36,19 +37,13 @@ use moodle_url;
*/
class client_microsoft extends client {
- public function get_additional_login_parameters() {
- return ['prompt' => 'consent'];
- }
-
public function get_login_scopes() {
- return 'openid profile email user.read';
+ if ($this->system) {
+ return 'openid profile email user.read offline_access';
+ } else {
+ return 'openid profile email user.read';
+ }
}
- public function get_userinfo() {
- $me = $client->get('https://graph.microsoft.com/v1.0/me/');
- var_dump($me);
-
-
- }
}
diff --git a/lib/classes/oauth2/client_openid_connect.php b/lib/classes/oauth2/client_openid_connect.php
index 4ff9837f0cb..805102c0f8d 100644
--- a/lib/classes/oauth2/client_openid_connect.php
+++ b/lib/classes/oauth2/client_openid_connect.php
@@ -37,62 +37,10 @@ use Exception;
*/
class client_openid_connect extends client {
- /**
- * Returns a mapping of openid properties to moodle properties.
- *
- * @return array
- */
- private function get_mapping() {
- return [
- 'given_name' => 'firstname',
- 'middle_name' => 'middlename',
- 'family_name' => 'lastname',
- 'email' => 'email',
- 'username' => 'username',
- 'website' => 'url',
- 'nickname' => 'alternatename',
- 'picture' => 'picture',
- 'address' => 'address',
- 'phone' => 'phone',
- 'locale' => 'lang'
- ];
- }
-
public function get_additional_login_parameters() {
if ($this->system) {
return ['access_type' => 'offline', 'prompt' => 'consent'];
}
return [];
}
-
- public function get_userinfo() {
- $url = $this->get_issuer()->get_endpoint_url('userinfo');
- $response = $this->get($url);
- if (!$response) {
- return false;
- }
- $userinfo = new stdClass();
- try {
- $userinfo = json_decode($response);
- } catch (Exception $e) {
- return false;
- }
- if (!empty($userinfo->preferred_username)) {
- $userinfo->username = $userinfo->preferred_username;
- } else {
- $userinfo->username = $userinfo->sub;
- }
-
- $map = $this->get_mapping();
-
- $user = new stdClass();
- foreach ($map as $openidproperty => $moodleproperty) {
- if (!empty($userinfo->$openidproperty)) {
- $user->$moodleproperty = $userinfo->$openidproperty;
- }
- }
-
- return (array)$user;
- }
-
}
diff --git a/lib/classes/oauth2/endpoint.php b/lib/classes/oauth2/endpoint.php
index fe3a0122e90..5916455a172 100644
--- a/lib/classes/oauth2/endpoint.php
+++ b/lib/classes/oauth2/endpoint.php
@@ -26,6 +26,7 @@ namespace core\oauth2;
defined('MOODLE_INTERNAL') || die();
use core\persistent;
+use lang_string;
/**
* Class for loading/storing oauth2 endpoints from the DB
@@ -55,4 +56,11 @@ class endpoint extends persistent {
)
);
}
+
+ protected function validate_url($value) {
+ if (strpos($value, 'https://') !== 0) {
+ return new lang_string('sslonlyaccess', 'error');
+ }
+ return true;
+ }
}
diff --git a/lib/classes/oauth2/user_field_mapping.php b/lib/classes/oauth2/user_field_mapping.php
new file mode 100644
index 00000000000..1ccf26b0e9e
--- /dev/null
+++ b/lib/classes/oauth2/user_field_mapping.php
@@ -0,0 +1,78 @@
+.
+
+/**
+ * Class for loading/storing oauth2 endpoints from the DB.
+ *
+ * @package core_oauth2
+ * @copyright 2017 Damyon Wiese
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace core\oauth2;
+
+defined('MOODLE_INTERNAL') || die();
+
+use core\persistent;
+
+/**
+ * Class for loading/storing oauth2 user field mappings from the DB
+ *
+ * @copyright 2017 Damyon Wiese
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class user_field_mapping extends persistent {
+
+ const TABLE = 'oauth2_user_field_mapping';
+
+ private static $userfields = [
+ 'firstname',
+ 'middlename',
+ 'lastname',
+ 'email',
+ 'username',
+ 'idnumber',
+ 'url',
+ 'alternatename',
+ 'picture',
+ 'address',
+ 'phone',
+ 'lang'
+ ];
+
+ /**
+ * Return the definition of the properties of this model.
+ *
+ * @return array
+ */
+ protected static function define_properties() {
+ return array(
+ 'issuerid' => array(
+ 'type' => PARAM_INT
+ ),
+ 'externalfield' => array(
+ 'type' => PARAM_ALPHANUMEXT,
+ ),
+ 'internalfield' => array(
+ 'type' => PARAM_ALPHANUMEXT,
+ 'choices' => self::$userfields,
+ )
+ );
+ }
+
+ public function get_internalfield_list() {
+ return array_combine(self::$userfields, self::$userfields);
+ }
+}
diff --git a/lib/db/install.xml b/lib/db/install.xml
index 0233dedcf37..ba926fd74af 100755
--- a/lib/db/install.xml
+++ b/lib/db/install.xml
@@ -1,5 +1,5 @@
-
@@ -3513,5 +3513,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 189c3338734..5666423c38c 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -2699,10 +2699,39 @@ function xmldb_main_upgrade($oldversion) {
if ($oldversion < 2017033100.01) {
- \core\oauth2\api::install_default_issuers();
+ // Define table oauth2_user_field_mapping to be created.
+ $table = new xmldb_table('oauth2_user_field_mapping');
+
+ // Adding fields to table oauth2_user_field_mapping.
+ $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+ $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+ $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+ $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+ $table->add_field('issuerid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+ $table->add_field('externalfield', XMLDB_TYPE_CHAR, '64', null, XMLDB_NOTNULL, null, null);
+ $table->add_field('internalfield', XMLDB_TYPE_CHAR, '64', null, XMLDB_NOTNULL, null, null);
+
+ // Adding keys to table oauth2_user_field_mapping.
+ $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+ $table->add_key('issuerkey', XMLDB_KEY_FOREIGN, array('issuerid'), 'oauth2_issuer', array('id'));
+ $table->add_key('uniqexternal', XMLDB_KEY_UNIQUE, array('issuerid', 'externalfield'));
+ $table->add_key('uniqinternal', XMLDB_KEY_UNIQUE, array('issuerid', 'internalfield'));
+
+ // Conditionally launch create table for oauth2_user_field_mapping.
+ if (!$dbman->table_exists($table)) {
+ $dbman->create_table($table);
+ }
+
// Main savepoint reached.
upgrade_main_savepoint(true, 2017033100.01);
}
+ if ($oldversion < 2017033100.02) {
+
+ \core\oauth2\api::install_default_issuers();
+ // Main savepoint reached.
+ upgrade_main_savepoint(true, 2017033100.02);
+ }
+
return true;
}
diff --git a/lib/filelib.php b/lib/filelib.php
index bdc90bd114b..e326406e13b 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -2766,9 +2766,9 @@ class curl {
// All settings of this class should be init here.
$this->resetopt();
- //if (!empty($settings['debug'])) {
+ if (!empty($settings['debug'])) {
$this->debug = true;
- //}
+ }
if (!empty($settings['cookie'])) {
if($settings['cookie'] === true) {
$this->cookie = $CFG->dataroot.'/curl_cookie.txt';
diff --git a/lib/oauthlib.php b/lib/oauthlib.php
index 9efb6d100f6..7260defeb96 100644
--- a/lib/oauthlib.php
+++ b/lib/oauthlib.php
@@ -441,6 +441,15 @@ abstract class oauth2_client extends curl {
// We have a token so we are logged in.
if (isset($this->accesstoken->token)) {
+ // Check that the access token has all the requested scopes.
+ $scopecheck = ' ' . $this->accesstoken->scope . ' ';
+
+ $requiredscopes = explode(' ', $this->scope);
+ foreach ($requiredscopes as $requiredscope) {
+ if (strpos($scopecheck, ' ' . $requiredscope . ' ') === false) {
+ return false;
+ }
+ }
return true;
}
@@ -533,6 +542,10 @@ abstract class oauth2_client extends curl {
$r = json_decode($response);
+ if (!empty($r->error)) {
+ throw new moodle_exception($r->error . ' ' . $r->error_description);
+ }
+
if (!isset($r->access_token)) {
return false;
}
@@ -548,6 +561,12 @@ abstract class oauth2_client extends curl {
// Expires 10 seconds before actual expiry.
$accesstoken->expires = (time() + ($r->expires_in - 10));
}
+ if (isset($r->scope)) {
+ $accesstoken->scope = $r->scope;
+ } else {
+ $accesstoken->scope = $this->scope;
+ }
+ // Also add the scopes.
$this->store_token($accesstoken);
return true;
diff --git a/theme/boost/templates/core/login.mustache b/theme/boost/templates/core/login.mustache
index c253f728136..90fb24c96c5 100644
--- a/theme/boost/templates/core/login.mustache
+++ b/theme/boost/templates/core/login.mustache
@@ -178,7 +178,7 @@