diff --git a/auth/oauth2/classes/api.php b/auth/oauth2/classes/api.php index a7090bdf95b..58028a9f573 100644 --- a/auth/oauth2/classes/api.php +++ b/auth/oauth2/classes/api.php @@ -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 * diff --git a/auth/oauth2/classes/auth.php b/auth/oauth2/classes/auth.php index 82e58e24311..951d8757d77 100644 --- a/auth/oauth2/classes/auth.php +++ b/auth/oauth2/classes/auth.php @@ -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); diff --git a/auth/oauth2/classes/linked_login.php b/auth/oauth2/classes/linked_login.php index 7098e4ece5c..e4a56ca600b 100644 --- a/auth/oauth2/classes/linked_login.php +++ b/auth/oauth2/classes/linked_login.php @@ -55,6 +55,12 @@ class linked_login extends persistent { ), 'email' => array( 'type' => PARAM_RAW + ), + 'confirmtoken' => array( + 'type' => PARAM_RAW + ), + 'confirmtokenexpires' => array( + 'type' => PARAM_INT ) ); } diff --git a/auth/oauth2/config.html b/auth/oauth2/config.html index b78655a748d..e7ce6066b3d 100644 --- a/auth/oauth2/config.html +++ b/auth/oauth2/config.html @@ -2,28 +2,8 @@
-allowlinkedlogins)) { - $config->allowlinkedlogins = true; -} -?> - - - - -authtype, $userfields, get_string('auth_fieldlocks_help', 'auth'), false, false); diff --git a/auth/oauth2/confirm-account.php b/auth/oauth2/confirm-account.php new file mode 100644 index 00000000000..54e338327f5 --- /dev/null +++ b/auth/oauth2/confirm-account.php @@ -0,0 +1,91 @@ +. + +/** + * 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 "

".get_string("alreadyconfirmed")."

\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 "

".get_string("thanks").", ". fullname($USER) . "

\n"; + echo "

".get_string("confirmed")."

\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/"); diff --git a/auth/oauth2/confirm-linkedlogin.php b/auth/oauth2/confirm-linkedlogin.php new file mode 100644 index 00000000000..6dc69a2066c --- /dev/null +++ b/auth/oauth2/confirm-linkedlogin.php @@ -0,0 +1,78 @@ +. + +/** + * 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 "

".get_string("thanks").", ". fullname($USER) . "

\n"; + echo "

".get_string("confirmed")."

\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/"); diff --git a/auth/oauth2/db/install.xml b/auth/oauth2/db/install.xml index be895b68d36..09cecf41aa6 100755 --- a/auth/oauth2/db/install.xml +++ b/auth/oauth2/db/install.xml @@ -1,5 +1,5 @@ - @@ -14,6 +14,8 @@ + + @@ -27,4 +29,4 @@
- - - allowlinkedlogins) { echo 'checked="checked"'; } ?> - > - error_text($err['allowlinkedlogins']); } ?> - - -
- \ No newline at end of file + diff --git a/auth/oauth2/db/upgrade.php b/auth/oauth2/db/upgrade.php index ca1bd5851a7..71dd0a5e1a9 100644 --- a/auth/oauth2/db/upgrade.php +++ b/auth/oauth2/db/upgrade.php @@ -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; } diff --git a/auth/oauth2/lang/en/auth_oauth2.php b/auth/oauth2/lang/en/auth_oauth2.php index 74ee233d0c4..f4395bf4e36 100644 --- a/auth/oauth2/lang/en/auth_oauth2.php +++ b/auth/oauth2/lang/en/auth_oauth2.php @@ -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'] = '

An existing account was found with this email address but it is not linked yet.

+

The accounts must be linked before you can login.

+

An email should have been sent to your address at {$a}

+

It contains easy instructions to link your accounts.

+

If you continue to have difficulty, contact the site administrator.

'; $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'; diff --git a/auth/oauth2/version.php b/auth/oauth2/version.php index 0a014690f25..2ff2041e851 100644 --- a/auth/oauth2/version.php +++ b/auth/oauth2/version.php @@ -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). diff --git a/lib/classes/user.php b/lib/classes/user.php index 8ae89dcc87e..26cb195df67 100644 --- a/lib/classes/user.php +++ b/lib/classes/user.php @@ -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.