mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 22:08:20 +01:00
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:
parent
d5bb9f1ffc
commit
28b592d5a6
@ -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
|
||||
*
|
||||
|
@ -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);
|
||||
|
@ -55,6 +55,12 @@ class linked_login extends persistent {
|
||||
),
|
||||
'email' => array(
|
||||
'type' => PARAM_RAW
|
||||
),
|
||||
'confirmtoken' => array(
|
||||
'type' => PARAM_RAW
|
||||
),
|
||||
'confirmtokenexpires' => array(
|
||||
'type' => PARAM_INT
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -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);
|
||||
|
91
auth/oauth2/confirm-account.php
Normal file
91
auth/oauth2/confirm-account.php
Normal 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/");
|
78
auth/oauth2/confirm-linkedlogin.php
Normal file
78
auth/oauth2/confirm-linkedlogin.php
Normal 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/");
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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';
|
||||
|
@ -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).
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user