MDL-58338 oauth2: Force email confirmation

New accounts and linking a login to an existing account MUST go through email verification.
We cannot trust the emails we get from oauth providers have been confirmed.

Part of MDL-58220
This commit is contained in:
Damyon Wiese 2017-03-21 16:43:23 +08:00
parent d5bb9f1ffc
commit 28b592d5a6
11 changed files with 573 additions and 65 deletions

View File

@ -26,6 +26,7 @@ namespace auth_oauth2;
use context_user;
use stdClass;
use moodle_exception;
use moodle_url;
defined('MOODLE_INTERNAL') || die();
@ -60,7 +61,7 @@ class api {
$context = context_user::instance($userid);
require_capability('auth/oauth2:managelinkedlogins', $context);
return linked_login::get_records(['userid' => $userid]);
return linked_login::get_records(['userid' => $userid, 'confirmtoken' => '']);
}
/**
@ -75,14 +76,7 @@ class api {
'issuerid' => $issuer->get('id'),
'username' => $username
];
$match = linked_login::get_record($params);
if ($match) {
$user = get_complete_user_data('id', $match->get('userid'));
return $user;
}
return false;
return linked_login::get_record($params);
}
/**
@ -93,9 +87,10 @@ class api {
* @param array $userinfo as returned from an oauth client.
* @param \core\oauth2\issuer $issuer
* @param int $userid (defaults to $USER->id)
* @return boolean
* @param bool $skippermissions During signup we need to set this before the user is setup for capability checks.
* @return bool
*/
public static function link_login($userinfo, $issuer, $userid = false) {
public static function link_login($userinfo, $issuer, $userid = false, $skippermissions = false) {
global $USER;
if ($userid === false) {
@ -107,21 +102,194 @@ class api {
}
$context = context_user::instance($userid);
require_capability('auth/oauth2:managelinkedlogins', $context);
if (!$skippermissions) {
require_capability('auth/oauth2:managelinkedlogins', $context);
}
$record = new stdClass();
$record->issuerid = $issuer->get('id');
$record->username = $userinfo['username'];
$record->email = $userinfo['email'];
$record->userid = $userid;
$existing = linked_login::get_record((array)$record);
if ($existing) {
$existing->set('confirmtoken', '');
$existing->update();
return $existing;
}
$record->email = $userinfo['email'];
$record->confirmtoken = '';
$linkedlogin = new linked_login(0, $record);
return $linkedlogin->create();
}
/**
* Send an email with a link to confirm linking this account.
*
* @param array $userinfo as returned from an oauth client.
* @param \core\oauth2\issuer $issuer
* @param int $userid (defaults to $USER->id)
* @return bool
*/
public static function send_confirm_link_login_email($userinfo, $issuer, $userid) {
$record = new stdClass();
$record->issuerid = $issuer->get('id');
$record->username = $userinfo['username'];
$record->userid = $userid;
$existing = linked_login::get_record((array)$record);
if ($existing) {
return false;
}
$record->email = $userinfo['email'];
$record->confirmtoken = random_string(32);
$expires = new \DateTime('NOW');
$expires->add(new \DateInterval('PT30M'));
$record->confirmtokenexpires = $expires->getTimestamp();
$linkedlogin = new linked_login(0, $record);
$linkedlogin->create();
// Construct the email.
$site = get_site();
$supportuser = \core_user::get_support_user();
$user = get_complete_user_data('id', $userid);
$data = new stdClass();
$data->fullname = fullname($user);
$data->sitename = format_string($site->fullname);
$data->admin = generate_email_signoff();
$data->issuername = format_string($issuer->get('name'));
$data->linkedemail = format_string($linkedlogin->get('email'));
$subject = get_string('confirmlinkedloginemailsubject', 'auth_oauth2', format_string($site->fullname));
$params = [
'token' => $linkedlogin->get('confirmtoken'),
'userid' => $userid,
'username' => $userinfo['username'],
'issuerid' => $issuer->get('id'),
];
$confirmationurl = new moodle_url('/auth/oauth2/confirm-linkedlogin.php', $params);
// Remove data parameter just in case it was included in the confirmation so we can add it manually later.
$data->link = $confirmationurl->out();
$message = get_string('confirmlinkedloginemail', 'auth_oauth2', $data);
$messagehtml = text_to_html(get_string('confirmlinkedloginemail', 'auth_oauth2', $data), false, false, true);
$user->mailformat = 1; // Always send HTML version as well.
// Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
return email_to_user($user, $supportuser, $subject, $message, $messagehtml);
}
/**
* Look for a waiting confirmation token, and if we find a match - confirm it.
*
* @param int $userid
* @param string $username
* @param int $issuerid
* @param string $token
* @return boolean True if we linked.
*/
public static function confirm_link_login($userid, $username, $issuerid, $token) {
if (empty($token) || empty($userid) || empty($issuerid) || empty($username)) {
return false;
}
$params = [
'userid' => $userid,
'username' => $username,
'issuerid' => $issuerid,
'confirmtoken' => $token,
];
$login = linked_login::get_record($params);
if (empty($login)) {
return false;
}
$expires = $login->get('confirmtokenexpires');
if (time() > $expires) {
$login->delete();
return;
}
$login->set('confirmtokenexpires', 0);
$login->set('confirmtoken', '');
$login->update();
return true;
}
/**
* Send an email with a link to confirm creating this account.
*
* @param array $userinfo as returned from an oauth client.
* @param \core\oauth2\issuer $issuer
* @param int $userid (defaults to $USER->id)
* @return bool
*/
public static function send_confirm_account_email($userinfo, $issuer) {
global $CFG, $DB;
require_once($CFG->dirroot.'/user/profile/lib.php');
require_once($CFG->dirroot.'/user/lib.php');
$user = new stdClass();
$user->username = $userinfo['username'];
$user->email = $userinfo['email'];
$user->auth = 'oauth2';
$user->mnethostid = $CFG->mnet_localhost_id;
$user->lastname = isset($userinfo['lastname']) ? $userinfo['lastname'] : '';
$user->firstname = isset($userinfo['firstname']) ? $userinfo['firstname'] : '';
$user->url = isset($userinfo['url']) ? $userinfo['url'] : '';
$user->alternatename = isset($userinfo['alternatename']) ? $userinfo['alternatename'] : '';
$user->secret = random_string(15);
$user->password = '';
// This user is not confirmed.
$user->confirmed = 0;
$user->id = user_create_user($user, false, true);
// The linked account is pre-confirmed.
$record = new stdClass();
$record->issuerid = $issuer->get('id');
$record->username = $userinfo['username'];
$record->userid = $user->id;
$record->email = $userinfo['email'];
$record->confirmtoken = '';
$record->confirmtokenexpires = 0;
$linkedlogin = new linked_login(0, $record);
$linkedlogin->create();
// Construct the email.
$site = get_site();
$supportuser = \core_user::get_support_user();
$user = get_complete_user_data('id', $user->id);
$data = new stdClass();
$data->fullname = fullname($user);
$data->sitename = format_string($site->fullname);
$data->admin = generate_email_signoff();
$subject = get_string('confirmaccountemailsubject', 'auth_oauth2', format_string($site->fullname));
$params = [
'token' => $user->secret,
'username' => $userinfo['username']
];
$confirmationurl = new moodle_url('/auth/oauth2/confirm-account.php', $params);
$data->link = $confirmationurl->out();
$message = get_string('confirmaccountemail', 'auth_oauth2', $data);
$messagehtml = text_to_html(get_string('confirmaccountemail', 'auth_oauth2', $data), false, false, true);
$user->mailformat = 1; // Always send HTML version as well.
// Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
email_to_user($user, $supportuser, $subject, $message, $messagehtml);
return $user;
}
/**
* Delete linked login
*

View File

@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
use pix_icon;
use moodle_url;
use core_text;
use context_system;
use stdClass;
use core\oauth2\issuer;
use core\oauth2\client;
@ -105,7 +106,7 @@ class auth extends \auth_plugin_base {
* @return bool true means automatically copy data from ext to user table
*/
public function is_synchronised_with_external() {
return true;
return false;
}
/**
@ -309,15 +310,45 @@ class auth extends \auth_plugin_base {
}
/**
* Process the config after the form is saved.
* @param stdClass $config
* Confirm the new user as registered.
*
* @param string $username
* @param string $confirmsecret
*/
public function process_config($config) {
// Set to defaults if undefined.
if (!isset($config->allowlinkedlogins)) {
$config->allowlinkedlogins = false;
function user_confirm($username, $confirmsecret) {
global $DB;
$user = get_complete_user_data('username', $username);
if (!empty($user)) {
if ($user->auth != $this->authtype) {
return AUTH_CONFIRM_ERROR;
} else if ($user->secret == $confirmsecret && $user->confirmed) {
return AUTH_CONFIRM_ALREADY;
} else if ($user->secret == $confirmsecret) { // They have provided the secret key to get in
$DB->set_field("user", "confirmed", 1, array("id"=>$user->id));
return AUTH_CONFIRM_OK;
}
} else {
return AUTH_CONFIRM_ERROR;
}
set_config('allowlinkedlogins', trim($config->allowlinkedlogins), 'auth_oauth2');
}
/**
* Print a page showing that a confirm email was sent with instructions.
*
* @param string title
* @param string message
*/
public function print_confirm_required($title, $message) {
global $PAGE, $OUTPUT, $CFG;
$PAGE->navbar->add($title);
$PAGE->set_title($title);
$PAGE->set_heading($PAGE->course->fullname);
echo $OUTPUT->header();
notice($message, "$CFG->httpswwwroot/index.php");
}
/**
@ -327,7 +358,7 @@ class auth extends \auth_plugin_base {
* @return none Either redirects or throws an exception
*/
public function complete_login(client $client, $redirecturl) {
global $CFG, $SESSION;
global $CFG, $SESSION, $PAGE;
$userinfo = $client->get_userinfo();
@ -336,7 +367,7 @@ class auth extends \auth_plugin_base {
$SESSION->loginerrormsg = $errormsg;
redirect(new moodle_url($CFG->httpswwwroot . '/login/index.php'));
}
if (empty($userinfo['username'])) {
if (empty($userinfo['username']) || empty($userinfo['email'])) {
$errormsg = get_string('notloggedin', 'auth_oauth2');
$SESSION->loginerrormsg = $errormsg;
redirect(new moodle_url($CFG->httpswwwroot . '/login/index.php'));
@ -344,38 +375,100 @@ class auth extends \auth_plugin_base {
$userinfo['username'] = trim(core_text::strtolower($userinfo['username']));
// Once we get here we have the user info from oauth.
$userwasmapped = false;
if (get_config('auth_oauth2', 'allowlinkedlogins')) {
$mappeduser = api::match_username_to_user($userinfo['username'], $client->get_issuer());
if ($mappeduser) {
// Clean and remember the picture / lang.
if (!empty($userinfo['picture'])) {
$this->set_static_user_picture($userinfo['picture']);
unset($userinfo['picture']);
}
if (!empty($userinfo['lang'])) {
$userinfo['lang'] = str_replace('-', '_', trim(core_text::strtolower($userinfo['lang'])));
if (!get_string_manager()->translation_exists($userinfo['lang'], false)) {
unset($userinfo['lang']);
}
}
// First we try and find a defined mapping.
$linkedlogin = api::match_username_to_user($userinfo['username'], $client->get_issuer());
if (!empty($linkedlogin) && empty($linkedlogin->get('confirmtoken'))) {
$mappeduser = get_complete_user_data('id', $linkedlogin->get('userid'));
if ($mappeduser && $mappeduser->confirmed) {
$userinfo = (array) $mappeduser;
$userwasmapped = true;
} else {
$errormsg = get_string('confirmationpending', 'auth_oauth2');
$SESSION->loginerrormsg = $errormsg;
redirect(new moodle_url($CFG->httpswwwroot . '/login/index.php'));
}
} else if (!empty($linkedlogin)) {
$errormsg = get_string('confirmationpending', 'auth_oauth2');
$SESSION->loginerrormsg = $errormsg;
redirect(new moodle_url($CFG->httpswwwroot . '/login/index.php'));
}
$issuer = $client->get_issuer();
if (!$issuer->is_valid_login_domain($userinfo['email'])) {
$errormsg = get_string('notloggedin', 'auth_oauth2');
$SESSION->loginerrormsg = $errormsg;
redirect(new moodle_url($CFG->httpswwwroot . '/login/index.php'));
}
if (!$userwasmapped) {
if (!empty($userinfo['picture'])) {
$this->set_static_user_picture($userinfo['picture']);
unset($userinfo['picture']);
}
// No defined mapping - we need to see if there is an existing account with the same email.
if (!empty($userinfo['lang'])) {
$userinfo['lang'] = str_replace('-', '_', trim(core_text::strtolower($userinfo['lang'])));
if (!get_string_manager()->translation_exists($userinfo['lang'], false)) {
unset($userinfo['lang']);
$moodleuser = \core_user::get_user_by_email($userinfo['email']);
if (!empty($moodleuser)) {
$PAGE->set_url('/auth/oauth2/confirm-link-login.php');
$PAGE->set_context(context_system::instance());
\auth_oauth2\api::send_confirm_link_login_email($userinfo, $issuer, $moodleuser->id);
// Request to link to existing account.
$emailconfirm = get_string('emailconfirmlink', 'auth_oauth2');
$message = get_string('emailconfirmlinksent', 'auth_oauth2', $moodleuser->email);
$this->print_confirm_required($emailconfirm, $message);
exit();
} else {
// This is a new account.
$exists = \core_user::get_user_by_username($userinfo['username']);
// Creating a new user?
if ($exists) {
// The username exists but the emails don't match. Refuse to continue.
$errormsg = get_string('accountexists', 'auth_oauth2');
$SESSION->loginerrormsg = $errormsg;
redirect(new moodle_url($CFG->httpswwwroot . '/login/index.php'));
}
if (email_is_not_allowed($userinfo['email'])) {
// The username exists but the emails don't match. Refuse to continue.
$errormsg = get_string('emailnotallowed', 'auth_oauth2');
$SESSION->loginerrormsg = $errormsg;
redirect(new moodle_url($CFG->httpswwwroot . '/login/index.php'));
}
$PAGE->set_url('/auth/oauth2/confirm-account.php');
$PAGE->set_context(context_system::instance());
// Create a new (unconfirmed account) and send an email to confirm it.
$user = \auth_oauth2\api::send_confirm_account_email($userinfo, $issuer);
$this->update_picture($user);
$emailconfirm = get_string('emailconfirm');
$message = get_string('emailconfirmsent', '', $userinfo['email']);
$this->print_confirm_required($emailconfirm, $message);
exit();
}
}
$issuer = $client->get_issuer();
$user = false;
if ($issuer->is_valid_login_domain($userinfo['email'])) {
$this->set_static_user_info($userinfo);
$user = authenticate_user_login($userinfo['username'], '');
}
// If we got to here - we must have found a real user account that is confirmed.
$this->set_static_user_info($userinfo);
$user = authenticate_user_login($userinfo['username'], '');
if ($user) {
complete_user_login($user);

View File

@ -55,6 +55,12 @@ class linked_login extends persistent {
),
'email' => array(
'type' => PARAM_RAW
),
'confirmtoken' => array(
'type' => PARAM_RAW
),
'confirmtokenexpires' => array(
'type' => PARAM_INT
)
);
}

View File

@ -2,28 +2,8 @@
<div style="text-align: center"><?php print_string('plugindescription', 'auth_oauth2'); ?></div>
<div class="alert alert-warning m-y-2" style="text-align: center"><?php print_string('createaccountswarning', 'auth_oauth2'); ?></div>
<?php
// Set to defaults if undefined.
if (!isset($config->allowlinkedlogins)) {
$config->allowlinkedlogins = true;
}
?>
<table cellspacing="0" cellpadding="5" border="0">
<tr valign="top" class="required">
<td align="right">
<label for="allowlinkedlogins"><?php print_string('allowlinkedlogins', 'auth_oauth2') ?></label>
</td>
<td>
<input name="allowlinkedlogins" id="allowlinkedlogins" type="checkbox"
<?php if ($config->allowlinkedlogins) { echo 'checked="checked"'; } ?>
>
<?php if (isset($err['allowlinkedlogins'])) { echo $OUTPUT->error_text($err['allowlinkedlogins']); } ?>
</td>
<td>
<?php print_string('allowlinkedloginsdesc', 'auth_oauth2') ?>
</td>
</tr>
<?php
print_auth_lock_options($this->authtype, $userfields, get_string('auth_fieldlocks_help', 'auth'), false, false);

View File

@ -0,0 +1,91 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Confirm self oauth2 user.
*
* @package auth_oauth2
* @copyright 2017 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require('../../config.php');
require_once($CFG->libdir . '/authlib.php');
$usersecret = required_param('token', PARAM_RAW);
$username = required_param('username', PARAM_USERNAME);
$redirect = optional_param('redirect', '', PARAM_LOCALURL); // Where to redirect the browser once the user has been confirmed.
$PAGE->set_url('/auth/oauth2/confirm-account.php');
$PAGE->set_context(context_system::instance());
$auth = get_auth_plugin('oauth2');
$confirmed = $auth->user_confirm($username, $usersecret);
if ($confirmed == AUTH_CONFIRM_ALREADY) {
$user = get_complete_user_data('username', $username);
$PAGE->navbar->add(get_string("alreadyconfirmed"));
$PAGE->set_title(get_string("alreadyconfirmed"));
$PAGE->set_heading($COURSE->fullname);
echo $OUTPUT->header();
echo $OUTPUT->box_start('generalbox centerpara boxwidthnormal boxaligncenter');
echo "<p>".get_string("alreadyconfirmed")."</p>\n";
echo $OUTPUT->single_button("$CFG->wwwroot/course/", get_string('courses'));
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
exit;
} else if ($confirmed == AUTH_CONFIRM_OK) {
// The user has confirmed successfully, let's log them in.
if (!$user = get_complete_user_data('username', $username)) {
print_error('cannotfinduser', '', '', s($username));
}
if (!$user->suspended) {
complete_user_login($user);
\core\session\manager::apply_concurrent_login_limit($user->id, session_id());
// Check where to go, $redirect has a higher preference.
if (empty($redirect) and !empty($SESSION->wantsurl) ) {
$redirect = $SESSION->wantsurl;
unset($SESSION->wantsurl);
}
if (!empty($redirect)) {
redirect($redirect);
}
}
$PAGE->navbar->add(get_string("confirmed"));
$PAGE->set_title(get_string("confirmed"));
$PAGE->set_heading($COURSE->fullname);
echo $OUTPUT->header();
echo $OUTPUT->box_start('generalbox centerpara boxwidthnormal boxaligncenter');
echo "<h3>".get_string("thanks").", ". fullname($USER) . "</h3>\n";
echo "<p>".get_string("confirmed")."</p>\n";
echo $OUTPUT->single_button("$CFG->wwwroot/course/", get_string('courses'));
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
exit;
} else {
print_error('invalidconfirmdata');
}
redirect("$CFG->wwwroot/");

View File

@ -0,0 +1,78 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Confirm self oauth2 user.
*
* @package auth_oauth2
* @copyright 2017 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require('../../config.php');
require_once($CFG->libdir . '/authlib.php');
$token = required_param('token', PARAM_RAW);
$username = required_param('username', PARAM_USERNAME);
$userid = required_param('userid', PARAM_INT);
$issuerid = required_param('issuerid', PARAM_INT);
$redirect = optional_param('redirect', '', PARAM_LOCALURL); // Where to redirect the browser once the user has been confirmed.
$PAGE->set_url('/auth/oauth2/confirm-linkedlogin.php');
$PAGE->set_context(context_system::instance());
$confirmed = \auth_oauth2\api::confirm_link_login($userid, $username, $issuerid, $token);
if ($confirmed) {
// The user has confirmed successfully, let's log them in.
if (!$user = get_complete_user_data('username', $username)) {
print_error('cannotfinduser', '', '', s($username));
}
if (!$user->suspended) {
complete_user_login($user);
\core\session\manager::apply_concurrent_login_limit($user->id, session_id());
// Check where to go, $redirect has a higher preference.
if (empty($redirect) and !empty($SESSION->wantsurl) ) {
$redirect = $SESSION->wantsurl;
unset($SESSION->wantsurl);
}
if (!empty($redirect)) {
redirect($redirect);
}
}
$PAGE->navbar->add(get_string("confirmed"));
$PAGE->set_title(get_string("confirmed"));
$PAGE->set_heading($COURSE->fullname);
echo $OUTPUT->header();
echo $OUTPUT->box_start('generalbox centerpara boxwidthnormal boxaligncenter');
echo "<h3>".get_string("thanks").", ". fullname($USER) . "</h3>\n";
echo "<p>".get_string("confirmed")."</p>\n";
echo $OUTPUT->single_button("$CFG->wwwroot/course/", get_string('courses'));
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
exit;
} else {
print_error('invalidconfirmdata');
}
redirect("$CFG->wwwroot/");

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="auth/oauth2/db" VERSION="20170310" COMMENT="XMLDB file for Moodle auth/oauth2"
<XMLDB PATH="auth/oauth2/db" VERSION="20170323" COMMENT="XMLDB file for Moodle auth/oauth2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
@ -14,6 +14,8 @@
<FIELD NAME="issuerid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="username" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The external username to map to this moodle account"/>
<FIELD NAME="email" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="The external email to map to this moodle account"/>
<FIELD NAME="confirmtoken" TYPE="char" LENGTH="64" NOTNULL="true" SEQUENCE="false" COMMENT="If this is not empty - the user has not confirmed their email to create the link."/>
<FIELD NAME="confirmtokenexpires" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
@ -27,4 +29,4 @@
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>
</XMLDB>

View File

@ -85,5 +85,27 @@ function xmldb_auth_oauth2_upgrade($oldversion) {
upgrade_plugin_savepoint(true, 2017031000, 'auth', 'oauth2');
}
if ($oldversion < 2017032300) {
// Define field confirmtoken to be added to auth_oauth2_linked_login.
$table = new xmldb_table('auth_oauth2_linked_login');
$field = new xmldb_field('confirmtoken', XMLDB_TYPE_CHAR, '64', null, XMLDB_NOTNULL, null, null, 'email');
// Conditionally launch add field confirmtoken.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
$field = new xmldb_field('confirmtokenexpires', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'confirmtoken');
// Conditionally launch add field confirmtokenexpires.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Oauth2 savepoint reached.
upgrade_plugin_savepoint(true, 2017032300, 'auth', 'oauth2');
}
return true;
}

View File

@ -27,13 +27,58 @@ $string['auth_oauth2settings'] = 'OAuth 2 authentication settings.';
$string['notloggedin'] = 'The login attempt failed.';
$string['plugindescription'] = 'This authentication plugin displays a list of the configured identity providers on the moodle login page. Selecting an identity provider allows users to login with their credentials from an OAuth 2 provider.';
$string['pluginname'] = 'OAuth 2';
$string['emailconfirmlink'] = 'Link your accounts';
$string['emailconfirmlinksent'] = '<p>An existing account was found with this email address but it is not linked yet.</p>
<p>The accounts must be linked before you can login.</p>
<p>An email should have been sent to your address at <b>{$a}</b></p>
<p>It contains easy instructions to link your accounts.</p>
<p>If you continue to have difficulty, contact the site administrator.</p>';
$string['oauth2:managelinkedlogins'] = 'Manage own linked login accounts';
$string['linkedlogins'] = 'Linked logins';
$string['accountexists'] = 'A user already exists on this site with this username. If this is your account, login manually and link this link from your preferences page.';
$string['linkedloginshelp'] = 'Help with linked logins.';
$string['notwhileloggedinas'] = 'Linked logins cannot be managed while logged in as another user.';
$string['issuer'] = 'OAuth 2 Service';
$string['info'] = 'External account';
$string['createnewlinkedlogin'] = 'Link a new account ({$a})';
$string['confirmationpending'] = 'This account is pending email confirmation.';
$string['emailnotallowed'] = 'The email address is not permitted at this site.';
$string['allowlinkedlogins'] = 'Allow linked logins';
$string['allowlinkedloginsdesc'] = 'Linked logins allow users to link their Moodle account to another external account which they can use to login with.';
$string['createaccountswarning'] = 'This authentication plugin allows users to create accounts on your site. You may want to enable the setting "authpreventaccountcreation" if you use this plugin.';
$string['selfregistrationdisabled'] = 'No matching account could be found on this site, and this site does not allow self registration.';
$string['confirmlinkedloginemail'] = 'Hi {$a->fullname},
A request has been made to link the {$a->issuername} login
{$a->linkedemail} to your account at \'{$a->sitename}\'
using your email address.
To confirm this request and link these logins, please go to this web address:
{$a->link}
In most mail programs, this should appear as a blue link
which you can just click on. If that doesn\'t work,
then cut and paste the address into the address
line at the top of your web browser window.
If you need help, please contact the site administrator,
{$a->admin}';
$string['confirmlinkedloginemailsubject'] = '{$a}: linked login confirmation';
$string['confirmaccountemail'] = 'Hi {$a->fullname},
A new account has been requested at \'{$a->sitename}\'
using your email address.
To confirm your new account, please go to this web address:
{$a->link}
In most mail programs, this should appear as a blue link
which you can just click on. If that doesn\'t work,
then cut and paste the address into the address
line at the top of your web browser window.
If you need help, please contact the site administrator,
{$a->admin}';
$string['confirmaccountemailsubject'] = '{$a}: account confirmation';

View File

@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2017031000; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2017032300; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2016112900; // Requires this Moodle version.
$plugin->component = 'auth_oauth2'; // Full name of the plugin (used for diagnostics).

View File

@ -100,6 +100,29 @@ class core_user {
}
}
/**
* Return user object from db based on their email.
*
* @param string $email The email of the user searched.
* @param string $fields A comma separated list of user fields to be returned, support and noreply user.
* @param int $mnethostid The id of the remote host.
* @param int $strictness IGNORE_MISSING means compatible mode, false returned if user not found, debug message if more found;
* IGNORE_MULTIPLE means return first user, ignore multiple user records found(not recommended);
* MUST_EXIST means throw an exception if no user record or multiple records found.
* @return stdClass|bool user record if found, else false.
* @throws dml_exception if user record not found and respective $strictness is set.
*/
public static function get_user_by_email($email, $fields = '*', $mnethostid = null, $strictness = IGNORE_MISSING) {
global $DB, $CFG;
// Because we use the username as the search criteria, we must also restrict our search based on mnet host.
if (empty($mnethostid)) {
// If empty, we restrict to local users.
$mnethostid = $CFG->mnet_localhost_id;
}
return $DB->get_record('user', array('email' => $email, 'mnethostid' => $mnethostid), $fields, $strictness);
}
/**
* Return user object from db based on their username.