protected function handlelogin()

in classes/loginflow/authcode.php [425:548]


    protected function handlelogin($oidcuniqid, $authparams, $tokenparams, $idtoken) {
        global $DB, $CFG;

        $tokenrec = $DB->get_record('auth_oidc_token', ['oidcuniqid' => $oidcuniqid]);

        // Do not continue if auth plugin is not enabled.
        if (!is_enabled_auth('oidc')) {
            throw new \moodle_exception('erroroidcnotenabled', 'auth_oidc', null, null, '1');
        }

        if (!empty($tokenrec)) {
            // Already connected user.
            if (empty($tokenrec->userid)) {
                // Existing token record, but missing the user ID.
                $user = $DB->get_record('user', ['username' => $tokenrec->username]);
                if (empty($user)) {
                    // Token exists, but it doesn't have a valid username.
                    // In this case, delete the token, and try to process login again.
                    $DB->delete_records('auth_oidc_token', ['id' => $tokenrec->id]);
                    return $this->handlelogin($oidcuniqid, $authparams, $tokenparams, $idtoken);
                }
                $tokenrec->userid = $user->id;
                $DB->update_record('auth_oidc_token', $tokenrec);
            } else {
                // Existing token with a user ID.
                $user = $DB->get_record('user', ['id' => $tokenrec->userid]);
                if (empty($user)) {
                    $failurereason = AUTH_LOGIN_NOUSER;
                    $eventdata = ['other' => ['username' => $tokenrec->username, 'reason' => $failurereason]];
                    $event = \core\event\user_login_failed::create($eventdata);
                    $event->trigger();
                    // Token is invalid, delete it.
                    $DB->delete_records('auth_oidc_token', ['id' => $tokenrec->id]);
                    return $this->handlelogin($oidcuniqid, $authparams, $tokenparams, $idtoken);
                }
            }
            $username = $user->username;
            $this->updatetoken($tokenrec->id, $authparams, $tokenparams);
            $user = authenticate_user_login($username, null, true);

            if (!empty($user)) {
                complete_user_login($user);
            } else {
                // There was a problem in authenticate_user_login.
                throw new \moodle_exception('errorauthgeneral', 'auth_oidc', null, null, '2');
            }

            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');
            $originalupn = null;
            if (empty($username)) {
                $username = $oidcuniqid;

                // If upn claim is missing, it can mean either the IdP is not Azure AD, or it's a guest user.
                if (\auth_oidc_is_local_365_installed()) {
                    $apiclient = \local_o365\utils::get_api();
                    $userdetails = $apiclient->get_user($oidcuniqid, true);
                    if (!is_null($userdetails) && isset($userdetails['userPrincipalName']) &&
                        stripos($userdetails['userPrincipalName'], '#EXT#') !== false && $idtoken->claim('unique_name')) {
                        $originalupn = $userdetails['userPrincipalName'];
                        $username = $idtoken->claim('unique_name');
                    }
                }
            }

            // See if we have an object listing.
            $username = $this->check_objects($oidcuniqid, $username);
            $matchedwith = $this->check_for_matched($username);
            if (!empty($matchedwith)) {
                if ($matchedwith->auth != 'oidc') {
                    $matchedwith->aadupn = $username;
                    throw new \moodle_exception('errorusermatched', 'auth_oidc', null, $matchedwith);
                }
            }
            $username = trim(\core_text::strtolower($username));
            $tokenrec = $this->createtoken($oidcuniqid, $username, $authparams, $tokenparams, $idtoken, 0, $originalupn);

            $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)) {
                $tokenrec = $DB->get_record('auth_oidc_token', ['id' => $tokenrec->id]);
                // This should be already done in auth_plugin_oidc::user_authenticated_hook, but just in case...
                if (!empty($tokenrec) && empty($tokenrec->userid)) {
                    $updatedtokenrec = new \stdClass;
                    $updatedtokenrec->id = $tokenrec->id;
                    $updatedtokenrec->userid = $user->id;
                    $DB->update_record('auth_oidc_token', $updatedtokenrec);
                }
                complete_user_login($user);
            } else {
                // There was a problem in authenticate_user_login. Clean up incomplete token record.
                if (!empty($tokenrec)) {
                    $DB->delete_records('auth_oidc_token', ['id' => $tokenrec->id]);
                }

                redirect($CFG->wwwroot, get_string('errorauthgeneral', 'auth_oidc'), null, \core\output\notification::NOTIFY_ERROR);
            }

            return true;
        }
    }