MDL-75171 Auth: extend user logged in event

Co-authored-by: Heena Agheda <heenaagheda@catalyst-au.net>
This commit is contained in:
Tomo Tsuyuki 2022-08-15 17:16:28 +10:00
parent 17ee072693
commit a6a7b16846
5 changed files with 105 additions and 6 deletions

View File

@ -398,6 +398,7 @@ class auth extends \auth_plugin_base {
public function complete_login(client $client, $redirecturl) {
global $CFG, $SESSION, $PAGE;
$rawuserinfo = $client->get_raw_userinfo();
$userinfo = $client->get_userinfo();
if (!$userinfo) {
@ -598,7 +599,11 @@ class auth extends \auth_plugin_base {
// We used to call authenticate_user - but that won't work if the current user has a different default authentication
// method. Since we now ALWAYS link a login - if we get to here we can directly allow the user in.
$user = (object) $userinfo;
complete_user_login($user);
// Add extra loggedin info.
$this->set_extrauserinfo((array)$rawuserinfo);
complete_user_login($user, $this->get_extrauserinfo());
$this->update_picture($user);
redirect($redirecturl);
}

View File

@ -23,6 +23,7 @@ namespace auth_oauth2;
* @category test
* @copyright 2019 Shamim Rezaie
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \auth_oauth2\auth
*/
class auth_test extends \advanced_testcase {
@ -38,4 +39,54 @@ class auth_test extends \advanced_testcase {
'your password cannot be reset because you are using your account on another site to log in',
$info['message']);
}
/**
* Test complete_login for oauth2.
* @covers ::complete_login
*/
public function test_oauth2_complete_login(): void {
global $CFG;
$this->resetAfterTest();
$this->setAdminUser();
$wantsurl = new \moodle_url('/');
$issuer = \core\oauth2\api::create_standard_issuer('microsoft');
$info = [];
$info['username'] = 'apple';
$info['email'] = 'apple@example.com';
$info['firstname'] = 'Apple';
$info['lastname'] = 'Fruit';
$info['url'] = 'http://apple.com/';
$info['alternamename'] = 'Beatles';
$info['auth'] = 'oauth2';
$user = \auth_oauth2\api::create_new_confirmed_account($info, $issuer);
$auth = get_auth_plugin($user->auth);
// Set up mock data.
$client = $this->createMock(\core\oauth2\client::class);
$client->expects($this->once())->method('get_raw_userinfo')->willReturn((object)$info);
$client->expects($this->once())->method('get_userinfo')->willReturn($info);
$client->expects($this->once())->method('get_issuer')->willReturn($issuer);
$sink = $this->redirectEvents();
try {
// Need @ as it will fail at \core\session\manager::login_user for session_regenerate_id.
@$auth->complete_login($client, $wantsurl);
} catch (\Exception $e) {
// This happens as complete login is using 'redirect'.
$this->assertInstanceOf(\moodle_exception::class, $e);
}
$events = $sink->get_events();
$sink->close();
// There are 2 events. First is core\event\user_updated and second is core\event\user_loggedin.
$event = $events[1];
$this->assertInstanceOf('core\event\user_loggedin', $event);
// Make sure the extra record is in the user_loggedin event.
$extrauserinfo = $event->other['extrauserinfo'];
$this->assertEquals($info, $extrauserinfo);
}
}

View File

@ -117,6 +117,9 @@ class auth_plugin_base {
*/
protected $errorlogtag = '';
/** @var array Stores extra information available to the logged in event. */
protected $extrauserinfo = [];
/**
* This is the primary method that is used by the authenticate_user_login()
* function in moodlelib.php.
@ -807,6 +810,25 @@ class auth_plugin_base {
'message' => $message
];
}
/**
* Set extra user information.
*
* @param array $values Any Key value pair.
* @return void
*/
public function set_extrauserinfo(array $values): void {
$this->extrauserinfo = $values;
}
/**
* Returns extra user information.
*
* @return array An array of keys and values
*/
public function get_extrauserinfo(): array {
return $this->extrauserinfo;
}
}
/**

View File

@ -49,6 +49,9 @@ class client extends \oauth2_client {
/** @var bool $autorefresh whether this client will use a refresh token to automatically renew access tokens.*/
protected $autorefresh = false;
/** @var array $rawuserinfo Keep rawuserinfo from . */
protected $rawuserinfo = [];
/**
* Constructor.
*
@ -483,13 +486,15 @@ class client extends \oauth2_client {
}
/**
* Fetch the user info from the user info endpoint and map all
* the fields back into moodle fields.
* Fetch the user info from the user info endpoint.
*
* @return array|false Moodle user fields for the logged in user (or false if request failed)
* @throws moodle_exception if the response is empty after decoding it.
*/
public function get_userinfo() {
public function get_raw_userinfo() {
if (!empty($this->rawuserinfo)) {
return $this->rawuserinfo;
}
$url = $this->get_issuer()->get_endpoint_url('userinfo');
if (empty($url)) {
return false;
@ -510,7 +515,19 @@ class client extends \oauth2_client {
// Throw an exception displaying the original response, because, at this point, $userinfo shouldn't be empty.
throw new moodle_exception($response);
}
$this->rawuserinfo = $userinfo;
return $userinfo;
}
/**
* Fetch the user info from the user info endpoint and map all
* the fields back into moodle fields.
*
* @return stdClass|false Moodle user fields for the logged in user (or false if request failed)
* @throws moodle_exception if the response is empty after decoding it.
*/
public function get_userinfo() {
$userinfo = $this->get_raw_userinfo();
return $this->map_userinfo_to_fields($userinfo);
}

View File

@ -4555,9 +4555,10 @@ function authenticate_user_login($username, $password, $ignorelockout=false, &$f
* - this function does not set any cookies any more!
*
* @param stdClass $user
* @param array $extrauserinfo
* @return stdClass A {@link $USER} object - BC only, do not use
*/
function complete_user_login($user) {
function complete_user_login($user, array $extrauserinfo = []) {
global $CFG, $DB, $USER, $SESSION;
\core\session\manager::login_user($user);
@ -4577,7 +4578,10 @@ function complete_user_login($user) {
array(
'userid' => $USER->id,
'objectid' => $USER->id,
'other' => array('username' => $USER->username),
'other' => [
'username' => $USER->username,
'extrauserinfo' => $extrauserinfo
]
)
);
$event->trigger();