MDL-41115 add option to allow login via email

This commit is contained in:
Petr Škoda 2014-03-13 11:23:26 +08:00
parent c0e88129d1
commit 50f5c84359
4 changed files with 81 additions and 20 deletions

View File

@ -72,6 +72,7 @@ if ($hassiteconfig) {
$temp->add(new admin_setting_manageauths());
$temp->add(new admin_setting_heading('manageauthscommonheading', new lang_string('commonsettings', 'admin'), ''));
$temp->add(new admin_setting_special_registerauth());
$temp->add(new admin_setting_configcheckbox('authloginviaemail', new lang_string('authloginviaemail', 'core_auth'), new lang_string('authloginviaemail_desc', 'core_auth'), 0));
$temp->add(new admin_setting_configcheckbox('authpreventaccountcreation', new lang_string('authpreventaccountcreation', 'admin'), new lang_string('authpreventaccountcreation_help', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('loginpageautofocus', new lang_string('loginpageautofocus', 'admin'), new lang_string('loginpageautofocus_help', 'admin'), 0));
$temp->add(new admin_setting_configselect('guestloginbutton', new lang_string('guestloginbutton', 'auth'),

View File

@ -108,6 +108,8 @@ $string['informpasswordpolicy'] = 'The password must have {$a}';
$string['instructions'] = 'Instructions';
$string['internal'] = 'Internal';
$string['locked'] = 'Locked';
$string['authloginviaemail'] = 'Allow login via email';
$string['authloginviaemail_desc'] = 'Allow users to use both username and email address (if unique) for site login.';
$string['md5'] = 'MD5 hash';
$string['nopasswordchange'] = 'Password can not be changed';
$string['nopasswordchangeforced'] = 'You cannot proceed without changing your password, however there is no available page for changing it. Please contact your Moodle Administrator.';

View File

@ -4052,16 +4052,31 @@ function create_user_record($username, $password, $auth = 'manual') {
*/
function update_user_record($username) {
global $DB, $CFG;
require_once($CFG->dirroot."/user/profile/lib.php");
require_once($CFG->dirroot.'/user/lib.php');
// Just in case check text case.
$username = trim(core_text::strtolower($username));
$oldinfo = $DB->get_record('user', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id), '*', MUST_EXIST);
return update_user_record_by_id($oldinfo->id);
}
/**
* Will update a local user record from an external source (MNET users can not be updated using this method!).
*
* @param int $id user id
* @return stdClass A complete user object
*/
function update_user_record_by_id($id) {
global $DB, $CFG;
require_once($CFG->dirroot."/user/profile/lib.php");
require_once($CFG->dirroot.'/user/lib.php');
$params = array('mnethostid' => $CFG->mnet_localhost_id, 'id' => $id, 'deleted' => 0);
$oldinfo = $DB->get_record('user', $params, '*', MUST_EXIST);
$newuser = array();
$userauth = get_auth_plugin($oldinfo->auth);
if ($newinfo = $userauth->get_userinfo($username)) {
if ($newinfo = $userauth->get_userinfo($oldinfo->username)) {
$newinfo = truncate_userinfo($newinfo);
$customfields = $userauth->get_custom_user_profile_fields();
@ -4325,7 +4340,7 @@ function guest_user() {
*
* Note: this function works only with non-mnet accounts!
*
* @param string $username User's username
* @param string $username User's username (or also email if $CFG->authloginviaemail enabled)
* @param string $password User's password
* @param bool $ignorelockout useful when guessing is prevented by other mechanism such as captcha or SSO
* @param int $failurereason login failure reason, can be used in renderers (it may disclose if account exists)
@ -4335,9 +4350,27 @@ function authenticate_user_login($username, $password, $ignorelockout=false, &$f
global $CFG, $DB;
require_once("$CFG->libdir/authlib.php");
if ($user = get_complete_user_data('username', $username, $CFG->mnet_localhost_id)) {
// we have found the user
} else if (!empty($CFG->authloginviaemail)) {
if ($email = clean_param($username, PARAM_EMAIL)) {
$select = "mnethostid = :mnethostid AND LOWER(email) = LOWER(:email) AND deleted = 0";
$params = array('mnethostid' => $CFG->mnet_localhost_id, 'email' => $email);
$users = $DB->get_records_select('user', $select, $params, 'id', 'id', 0, 2);
if (count($users) === 1) {
// Use email for login only if unique.
$user = reset($users);
$user = get_complete_user_data('id', $user->id);
$username = $user->username;
}
unset($users);
}
}
$authsenabled = get_enabled_auth_plugins();
if ($user = get_complete_user_data('username', $username, $CFG->mnet_localhost_id)) {
if ($user) {
// Use manual if auth not set.
$auth = empty($user->auth) ? 'manual' : $user->auth;
if (!empty($user->suspended)) {
@ -4376,7 +4409,7 @@ function authenticate_user_login($username, $password, $ignorelockout=false, &$f
return false;
}
// Do not try to authenticate non-existent accounts when user creation is not disabled.
// Do not try to authenticate non-existent accounts when user creation is disabled.
if (!empty($CFG->authpreventaccountcreation)) {
$failurereason = AUTH_LOGIN_NOUSER;
@ -4429,7 +4462,7 @@ function authenticate_user_login($username, $password, $ignorelockout=false, &$f
// User already exists in database.
if (empty($user->auth)) {
// For some reason auth isn't set yet.
$DB->set_field('user', 'auth', $auth, array('username' => $username));
$DB->set_field('user', 'auth', $auth, array('id' => $user->id));
$user->auth = $auth;
}
@ -4439,7 +4472,7 @@ function authenticate_user_login($username, $password, $ignorelockout=false, &$f
if ($authplugin->is_synchronised_with_external()) {
// Update user record from external DB.
$user = update_user_record($username);
$user = update_user_record_by_id($user->id);
}
} else {
// Create account, we verified above that user creation is allowed.

View File

@ -130,31 +130,56 @@ class core_authlib_testcase extends advanced_testcase {
$_SERVER['HTTP_USER_AGENT'] = 'no browser'; // Hack around missing user agent in CLI scripts.
$user1 = $this->getDataGenerator()->create_user(array('username'=>'username1', 'password'=>'password1'));
$user2 = $this->getDataGenerator()->create_user(array('username'=>'username2', 'password'=>'password2', 'suspended'=>1));
$user3 = $this->getDataGenerator()->create_user(array('username'=>'username3', 'password'=>'password3', 'auth'=>'nologin'));
// Capture events.
$user1 = $this->getDataGenerator()->create_user(array('username'=>'username1', 'password'=>'password1', 'email'=>'email1@example.com'));
$user2 = $this->getDataGenerator()->create_user(array('username'=>'username2', 'password'=>'password2', 'email'=>'email2@example.com', 'suspended'=>1));
$user3 = $this->getDataGenerator()->create_user(array('username'=>'username3', 'password'=>'password3', 'email'=>'email2@example.com', 'auth'=>'nologin'));
// Normal login.
$sink = $this->redirectEvents();
$result = authenticate_user_login('username1', 'password1');
$events = $sink->get_events();
$sink->close();
$this->assertEmpty($events);
$this->assertInstanceOf('stdClass', $result);
$this->assertEquals($user1->id, $result->id);
// No event is triggred.
// Normal login with reason.
$reason = null;
$sink = $this->redirectEvents();
$result = authenticate_user_login('username1', 'password1', false, $reason);
$events = $sink->get_events();
$sink->close();
$this->assertEmpty($events);
$this->assertInstanceOf('stdClass', $result);
$this->assertEquals(AUTH_LOGIN_OK, $reason);
// Test login via email
$reason = null;
$this->assertEmpty($CFG->authloginviaemail);
$sink = $this->redirectEvents();
$result = authenticate_user_login('email1@example.com', 'password1', false, $reason);
$sink->close();
$this->assertFalse($result);
$this->assertEquals(AUTH_LOGIN_NOUSER, $reason);
set_config('authloginviaemail', 1);
$this->assertNotEmpty($CFG->authloginviaemail);
$sink = $this->redirectEvents();
$result = authenticate_user_login('email1@example.com', 'password1');
$events = $sink->get_events();
$sink->close();
$this->assertEmpty($events);
$this->assertInstanceOf('stdClass', $result);
$this->assertEquals($user1->id, $result->id);
$reason = null;
// Capture event.
$sink = $this->redirectEvents();
$result = authenticate_user_login('username1', 'password1', false, $reason);
$result = authenticate_user_login('email2@example.com', 'password2', false, $reason);
$events = $sink->get_events();
$sink->close();
// No event is triggred.
$this->assertEmpty($events);
$this->assertInstanceOf('stdClass', $result);
$this->assertEquals(AUTH_LOGIN_OK, $reason);
$this->assertFalse($result);
$this->assertEquals(AUTH_LOGIN_NOUSER, $reason);
set_config('authloginviaemail', 0);
$reason = null;
// Capture failed login event.