From 2d286ef8f8f9c4a3b57e8594333c3fce7bfd0391 Mon Sep 17 00:00:00 2001 From: Brendan Heywood Date: Thu, 21 Mar 2024 00:09:12 +1100 Subject: [PATCH] MDL-80612 auth: Allow plugins to identify Moodle users on the CLI --- auth/upgrade.txt | 1 + lib/authlib.php | 60 ++++++++++++++++++++++++ lib/setup.php | 5 ++ lib/tests/authlib_test.php | 46 ++++++++++++++++++ lib/tests/fixtures/testable_auth_plugin_base.php | 58 +++++++++++++++++++++++ 5 files changed, 170 insertions(+) create mode 100644 lib/tests/fixtures/testable_auth_plugin_base.php diff --git a/auth/upgrade.txt b/auth/upgrade.txt index d566ee08802..ad14b4bab33 100644 --- a/auth/upgrade.txt +++ b/auth/upgrade.txt @@ -4,6 +4,7 @@ information provided here is intended especially for developers. === 4.4 === * A sesskey is no longer passed to the auth/test_settings.php page so it can no longer be required in test_settings(). +* Auth plugins can now attempt to identify users running CLI scripts using a new method find_cli_user() === 4.2 === * Support for configuration with the deprecated auth_config.php file has been removed. diff --git a/lib/authlib.php b/lib/authlib.php index 5a178835b1e..7a8d9097f7b 100644 --- a/lib/authlib.php +++ b/lib/authlib.php @@ -832,6 +832,66 @@ class auth_plugin_base { public function get_extrauserinfo(): array { return $this->extrauserinfo; } + + /** + * Returns the enabled auth plugins + * + * @return array of plugin classes + */ + public static function get_enabled_auth_plugin_classes(): array { + $plugins = []; + $authsequence = get_enabled_auth_plugins(); + foreach ($authsequence as $authname) { + $plugins[] = get_auth_plugin($authname); + } + return $plugins; + } + + /** + * Find an OS level admin Moodle user account + * + * Used when running CLI scripts. Only accounts which are + * site admin will be accepted. + * + * @return null|stdClass Admin user record if found + */ + public static function find_cli_admin_user(): ?stdClass { + $plugins = static::get_enabled_auth_plugin_classes(); + foreach ($plugins as $authplugin) { + $user = $authplugin->find_cli_user(); + // This MUST be a valid admin user. + if (!empty($user) && is_siteadmin($user->id)) { + return $user; + } + } + return null; + } + + /** + * Find and login as an OS level admin Moodle user account + * + * Used for running CLI scripts which must be admin accounts. + */ + public static function login_cli_admin_user(): void { + $user = static::find_cli_admin_user(); + if (!empty($user)) { + \core\session\manager::set_user($user); + } + } + + /** + * Identify a Moodle account on the CLI + * + * For example a plugin might use posix_geteuid and posix_getpwuid + * to find the username of the OS level user and then match that + * against Moodle user accounts. + * + * @return null|stdClass User user record if found + */ + public function find_cli_user(): ?stdClass { + // Override if needed. + return null; + } } /** diff --git a/lib/setup.php b/lib/setup.php index cba63271ab6..11107aa0520 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -1027,6 +1027,11 @@ if (!empty($CFG->debugvalidators) and !empty($CFG->guestloginbutton)) { // can be using in the logfile and stripped out if needed. set_access_log_user(); +if (CLI_SCRIPT && !empty($CFG->version)) { + // Allow auth plugins to optionally authenticate users on the CLI. + require_once($CFG->libdir. '/authlib.php'); + auth_plugin_base::login_cli_admin_user(); +} // Ensure the urlrewriteclass is setup correctly (to avoid crippling site). if (isset($CFG->urlrewriteclass)) { diff --git a/lib/tests/authlib_test.php b/lib/tests/authlib_test.php index cb448bd4a87..8d70a0a79b5 100644 --- a/lib/tests/authlib_test.php +++ b/lib/tests/authlib_test.php @@ -504,4 +504,50 @@ class authlib_test extends \advanced_testcase { // Restore the original email address validator. \moodle_phpmailer::$validator = $defaultvalidator; } + + /** + * Test the find_cli_user method + * @covers ::find_cli_user + */ + public function test_find_cli_user(): void { + global $CFG, $USER; + require_once("$CFG->libdir/authlib.php"); + require_once("$CFG->libdir/tests/fixtures/testable_auth_plugin_base.php"); + + $this->resetAfterTest(); + + $user = \testable_auth_plugin_base::find_cli_admin_user(); + $this->assertEmpty($user); + + $u1 = $this->getDataGenerator()->create_user([ + 'username' => 'abcdef', + 'email' => 'abcdef@example.com', + ]); + $user = \testable_auth_plugin_base::find_cli_admin_user(); + $this->assertEmpty($user); // User is not an admin yet. + + \testable_auth_plugin_base::login_cli_admin_user(); + $this->assertEquals($USER->id, 0); // User is not logged in. + + $CFG->siteadmins .= "," . $u1->id; + + \testable_auth_plugin_base::login_cli_admin_user(); + $this->assertEquals($USER->id, $u1->id); // User is now logged in. + + $user = \testable_auth_plugin_base::find_cli_admin_user(); + $this->assertNotEmpty($user); + } + + /** + * Test the get_enabled_auth_plugin_classes method + * @covers ::get_enabled_auth_plugin_classes + */ + public function test_get_enabled_auth_plugin_classes(): void { + global $CFG; + require_once("$CFG->libdir/authlib.php"); + $plugins = \auth_plugin_base::get_enabled_auth_plugin_classes(); + $this->assertEquals(get_class($plugins[0]), 'auth_plugin_manual'); + $this->assertEquals(count($plugins), 3); + } + } diff --git a/lib/tests/fixtures/testable_auth_plugin_base.php b/lib/tests/fixtures/testable_auth_plugin_base.php new file mode 100644 index 00000000000..c6b0c1c6abc --- /dev/null +++ b/lib/tests/fixtures/testable_auth_plugin_base.php @@ -0,0 +1,58 @@ +. + +/** + * Provides testable_auth_plugin_base class. + * + * @package core + * @subpackage fixtures + * @category test + * @copyright 2024 Catalyst IT + * @author Brendan Heywood + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class testable_auth_plugin_base extends \auth_plugin_base { + + /** + * Override to add test auth plugin + * + * @return array of plugin classes + */ + public static function get_enabled_auth_plugin_classes(): array { + $plugins = parent::get_enabled_auth_plugin_classes(); + $plugins[] = new testable_auth_plugin_base(); + return $plugins; + } + + /** + * Identify a Moodle account on the CLI + * + * For example a plugin might use posix_geteuid and posix_getpwuid + * to find the username of the OS level user and then match that + * against Moodle user accounts. + * + * @return null|stdClass User user record if found + */ + public function find_cli_user(): ?stdClass { + global $DB; + $user = $DB->get_record('user', ['username' => 'abcdef']); + if ($user) { + return $user; + } + return null; + } + +} -- 2.11.4.GIT