Skip to content

Commit

Permalink
MDL-75171 Auth: extend user logged in event
Browse files Browse the repository at this point in the history
Co-authored-by: Heena Agheda <[email protected]>
  • Loading branch information
TomoTsuyuki and hdagheda committed Aug 19, 2022
1 parent 17ee072 commit a6a7b16
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 6 deletions.
7 changes: 6 additions & 1 deletion auth/oauth2/classes/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ public function print_confirm_required($title, $message) {
public function complete_login(client $client, $redirecturl) {
global $CFG, $SESSION, $PAGE;

$rawuserinfo = $client->get_raw_userinfo();
$userinfo = $client->get_userinfo();

if (!$userinfo) {
Expand Down Expand Up @@ -598,7 +599,11 @@ public function complete_login(client $client, $redirecturl) {
// 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);
}
Expand Down
51 changes: 51 additions & 0 deletions auth/oauth2/tests/auth_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* @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 {

Expand All @@ -38,4 +39,54 @@ public function test_get_password_change_info() {
'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'] = '[email protected]';
$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);
}
}
22 changes: 22 additions & 0 deletions lib/authlib.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -807,6 +810,25 @@ public function get_password_change_info(stdClass $user) : array {
'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;
}
}

/**
Expand Down
23 changes: 20 additions & 3 deletions lib/classes/oauth2/client.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -483,13 +486,15 @@ public function upgrade_refresh_token(system_account $systemaccount) {
}

/**
* 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;
Expand All @@ -510,7 +515,19 @@ public function get_userinfo() {
// 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);
}

Expand Down
8 changes: 6 additions & 2 deletions lib/moodlelib.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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();
Expand Down

0 comments on commit a6a7b16

Please sign in to comment.