Skip to content

Commit

Permalink
MSFTMPP-697: Update auth_oidc_token to include Moodle user id
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesmcq committed Oct 27, 2018
1 parent ba1bf6d commit 0f8bcee
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 27 deletions.
16 changes: 16 additions & 0 deletions auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,23 @@ public function is_internal() {
* @param string $password plain text password (with system magic quotes)
*/
public function user_authenticated_hook(&$user, $username, $password) {
global $DB;
if (!empty($user) && !empty($user->auth) && $user->auth === 'oidc') {
$tokenrec = $DB->get_record('auth_oidc_token', ['userid' => $user->id]);
if (empty($tokenrec)) {
// There should always be a token record here, so a failure here means
// the user's token record doesn't yet contain their userid.
$tokenrec = $DB->get_record('auth_oidc_token', ['username' => $username]);
if (!empty($tokenrec)) {
$tokenrec->userid = $user->id;
$updatedtokenrec = new \stdClass;
$updatedtokenrec->id = $tokenrec->id;
$updatedtokenrec->userid = $user->id;
$DB->update_record('auth_oidc_token', $updatedtokenrec);
$tokenrec = $updatedtokenrec;
}
}

$eventdata = [
'objectid' => $user->id,
'userid' => $user->id,
Expand Down
74 changes: 50 additions & 24 deletions classes/loginflow/authcode.php
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ protected function handlemigration($oidcuniqid, $authparams, $tokenparams, $idto
}

// Create token data.
$tokenrec = $this->createtoken($oidcuniqid, $USER->username, $authparams, $tokenparams, $idtoken);
$tokenrec = $this->createtoken($oidcuniqid, $USER->username, $authparams, $tokenparams, $idtoken, $USER->id);

$eventdata = [
'objectid' => $USER->id,
Expand Down Expand Up @@ -407,14 +407,37 @@ protected function handlelogin($oidcuniqid, $authparams, $tokenparams, $idtoken)

$tokenrec = $DB->get_record('auth_oidc_token', ['oidcuniqid' => $oidcuniqid]);
if (!empty($tokenrec)) {
$username = $tokenrec->username;
// Already connected user.

if (empty($tokenrec->userid)) {
// ERROR.
echo 'ERROR1';die();
}
$user = $DB->get_record('user', ['id' => $tokenrec->userid]);
if (empty($user)) {
// ERROR.
echo 'ERROR2';die();
}
$username = $user->username;
$this->updatetoken($tokenrec->id, $authparams, $tokenparams);
$user = authenticate_user_login($username, null, true);
complete_user_login($user);
return true;
} else {
// No existing token, user not connected.
//
// Possibilities:
// - Matched user.
// - New user (maybe create).

// Generate a Moodle username.
// Use 'upn' if available for username (Azure-specific), or fall back to lower-case oidcuniqid.
$username = $idtoken->claim('upn');
if (empty($username)) {
$username = $oidcuniqid;
}

// See if we have an object listing.
$username = $this->check_objects($oidcuniqid, $username);
$matchedwith = $this->check_for_matched($username);
if (!empty($matchedwith)) {
Expand All @@ -423,33 +446,36 @@ protected function handlelogin($oidcuniqid, $authparams, $tokenparams, $idtoken)
}
$username = trim(\core_text::strtolower($username));
$tokenrec = $this->createtoken($oidcuniqid, $username, $authparams, $tokenparams, $idtoken);
}

$existinguserparams = ['username' => $username, 'mnethostid' => $CFG->mnet_localhost_id];
if ($DB->record_exists('user', $existinguserparams) !== true) {
// User does not exist. Create user if site allows, otherwise fail.
if (empty($CFG->authpreventaccountcreation)) {
$user = create_user_record($username, null, 'oidc');
} else {
// Trigger login failed event.
$failurereason = AUTH_LOGIN_NOUSER;
$eventdata = ['other' => ['username' => $username, 'reason' => $failurereason]];
$event = \core\event\user_login_failed::create($eventdata);
$event->trigger();
throw new \moodle_exception('errorauthloginfailednouser', 'auth_oidc', null, null, '1');
$existinguserparams = ['username' => $username, 'mnethostid' => $CFG->mnet_localhost_id];
if ($DB->record_exists('user', $existinguserparams) !== true) {
// User does not exist. Create user if site allows, otherwise fail.
if (empty($CFG->authpreventaccountcreation)) {
$user = create_user_record($username, null, 'oidc');
} else {
// Trigger login failed event.
$failurereason = AUTH_LOGIN_NOUSER;
$eventdata = ['other' => ['username' => $username, 'reason' => $failurereason]];
$event = \core\event\user_login_failed::create($eventdata);
$event->trigger();
throw new \moodle_exception('errorauthloginfailednouser', 'auth_oidc', null, null, '1');
}
}
}

$user = authenticate_user_login($username, null, true);
if (empty($user)) {
if (!empty($tokenrec)) {
throw new \moodle_exception('errorlogintoconnectedaccount', 'auth_oidc', null, null, '2');
$user = authenticate_user_login($username, null, true);

if (!empty($user)) {
complete_user_login($user);
return true;
} else {
throw new \moodle_exception('errorauthloginfailednouser', 'auth_oidc', null, null, '2');
if (!empty($tokenrec)) {
throw new \moodle_exception('errorlogintoconnectedaccount', 'auth_oidc', null, null, '2');
} else {
throw new \moodle_exception('errorauthloginfailednouser', 'auth_oidc', null, null, '2');
}
}
}

complete_user_login($user);
return true;
return true;
}
}
}
3 changes: 2 additions & 1 deletion classes/loginflow/base.php
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ protected function checkrestrictions(\auth_oidc\jwt $idtoken) {
* @param \auth_oidc\jwt $idtoken A JWT object representing the received id_token.
* @return \stdClass The created token database record.
*/
protected function createtoken($oidcuniqid, $username, $authparams, $tokenparams, \auth_oidc\jwt $idtoken) {
protected function createtoken($oidcuniqid, $username, $authparams, $tokenparams, \auth_oidc\jwt $idtoken, $userid = 0) {
global $DB;

// Determine remote username. Use 'upn' if available (Azure-specific), or fall back to standard 'sub'.
Expand All @@ -452,6 +452,7 @@ protected function createtoken($oidcuniqid, $username, $authparams, $tokenparams
$tokenrec = new \stdClass;
$tokenrec->oidcuniqid = $oidcuniqid;
$tokenrec->username = $username;
$tokenrec->userid = $userid;
$tokenrec->oidcusername = $oidcusername;
$tokenrec->scope = !empty($tokenparams['scope']) ? $tokenparams['scope'] : 'openid profile email';
$tokenrec->resource = !empty($tokenparams['resource']) ? $tokenparams['resource'] : $this->config->oidcresource;
Expand Down
3 changes: 2 additions & 1 deletion db/install.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="oidcuniqid" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="oidc uniqid"/>
<FIELD NAME="username" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" COMMENT="username"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="moodle userid"/>
<FIELD NAME="oidcusername" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="oidc username"/>
<FIELD NAME="scope" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="token scope"/>
<FIELD NAME="resource" TYPE="char" LENGTH="127" NOTNULL="true" SEQUENCE="false" COMMENT="token resource"/>
Expand All @@ -57,4 +58,4 @@
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>
</XMLDB>
18 changes: 18 additions & 0 deletions db/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,5 +161,23 @@ function xmldb_auth_oidc_upgrade($oldversion) {
upgrade_plugin_savepoint($result, '2015111905.01', 'auth', 'oidc');
}

if ($result && $oldversion < 2018051700.01) {
$table = new xmldb_table('auth_oidc_token');
$field = new xmldb_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'username');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
$sql = 'SELECT tok.id, tok.username, u.username, u.id as userid
FROM {auth_oidc_token} tok
JOIN {user} u ON u.username = tok.username';
$records = $DB->get_recordset_sql($sql);
foreach ($records as $record) {
$newrec = new \stdClass;
$newrec->id = $record->id;
$newrec->userid = $record->userid;
$DB->update_record('auth_oidc_token', $newrec);
}
}
upgrade_plugin_savepoint($result, '2018051700.01', 'auth', 'oidc');
}
return $result;
}
2 changes: 1 addition & 1 deletion version.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

defined('MOODLE_INTERNAL') || die();

$plugin->version = 2018051700;
$plugin->version = 2018051700.01;
$plugin->requires = 2018051700;
$plugin->release = '3.5.0.0';
$plugin->component = 'auth_oidc';
Expand Down

0 comments on commit 0f8bcee

Please sign in to comment.