From d35330a49e2a2170e4fadeb0b2931c3d2d6f429d Mon Sep 17 00:00:00 2001 From: raortegar Date: Tue, 22 Aug 2023 21:46:01 +0200 Subject: [PATCH] MDL-78511 tool_mfa: Include useful code from local_aws In this patch we have included some useful classes implemented In the plugin local_aws developed by Catalyst --- .../sms/classes/admin_settings_aws_region.php | 87 +++++++++++++++ .../factor/sms/classes/local/aws_helper.php | 100 ++++++++++++++++++ .../sms/classes/local/client_factory.php | 62 +++++++++++ .../tests/admin_settings_aws_region_test.php | 63 +++++++++++ .../mfa/factor/sms/tests/aws_helper_test.php | 60 +++++++++++ 5 files changed, 372 insertions(+) create mode 100644 admin/tool/mfa/factor/sms/classes/admin_settings_aws_region.php create mode 100644 admin/tool/mfa/factor/sms/classes/local/aws_helper.php create mode 100644 admin/tool/mfa/factor/sms/classes/local/client_factory.php create mode 100644 admin/tool/mfa/factor/sms/tests/admin_settings_aws_region_test.php create mode 100644 admin/tool/mfa/factor/sms/tests/aws_helper_test.php diff --git a/admin/tool/mfa/factor/sms/classes/admin_settings_aws_region.php b/admin/tool/mfa/factor/sms/classes/admin_settings_aws_region.php new file mode 100644 index 00000000000..2bb47441895 --- /dev/null +++ b/admin/tool/mfa/factor/sms/classes/admin_settings_aws_region.php @@ -0,0 +1,87 @@ +. + +/** + * Admin setting for AWS regions. + * + * @package local_aws + * @author Dmitrii Metelkin + * @copyright 2020 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace local_aws; + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/lib/adminlib.php'); + +/** + * Admin setting for a list of AWS regions. + * + * @package local_aws + * @copyright 2020 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class admin_settings_aws_region extends \admin_setting_configtext { + + /** + * Return part of form with setting. + * + * @param mixed $data array or string depending on setting + * @param string $query + * @return string + */ + public function output_html($data, $query='') { + global $CFG; + + $default = $this->get_defaultsetting(); + + $options = []; + + $all = require($CFG->dirroot . '/local/aws/sdk/Aws/data/endpoints.json.php'); + $ends = $all['partitions'][0]['regions']; + if ($ends) { + foreach ($ends as $key => $value) { + $options[] = [ + 'value' => $key, + 'label' => $key . ' - ' . $value['description'], + ]; + } + } + + $inputparams = array( + 'type' => 'text', + 'list' => $this->get_full_name(), + 'name' => $this->get_full_name(), + 'value' => $data, + 'size' => $this->size, + 'id' => $this->get_id(), + 'class' => 'form-control text-ltr', + ); + + $element = \html_writer::start_tag('div', array('class' => 'form-text defaultsnext')); + $element .= \html_writer::empty_tag('input', $inputparams); + $element .= \html_writer::start_tag('datalist', array('id' => $this->get_full_name())); + foreach ($options as $option) { + $element .= \html_writer::tag('option', $option['label'], array('value' => $option['value'])); + } + $element .= \html_writer::end_tag('datalist'); + $element .= \html_writer::end_tag('div'); + + return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query); + } +} diff --git a/admin/tool/mfa/factor/sms/classes/local/aws_helper.php b/admin/tool/mfa/factor/sms/classes/local/aws_helper.php new file mode 100644 index 00000000000..5c52a8db8ac --- /dev/null +++ b/admin/tool/mfa/factor/sms/classes/local/aws_helper.php @@ -0,0 +1,100 @@ +. + +/** + * AWS helper class. Contains useful functions when interacting with the SDK. + * + * @package local_aws + * @author Peter Burnett + * @copyright 2020 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace local_aws\local; + +use Aws\CommandInterface; +use Aws\AwsClient; +use Psr\Http\Message\RequestInterface; + +/** + * This class contains functions that help plugins to interact with the AWS SDK. + * + * @copyright 2020 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class aws_helper { + + /** + * This creates a proxy string suitable for use with the AWS SDK. + * + * @return string the string to use for proxy settings. + */ + public static function get_proxy_string() { + global $CFG; + $proxy = ''; + if (empty($CFG->proxytype)) { + return $proxy; + } + if ($CFG->proxytype === 'SOCKS5') { + // If it is a SOCKS proxy, append the protocol info. + $protocol = 'socks5://'; + } else { + $protocol = ''; + } + if (!empty($CFG->proxyhost)) { + $proxy = $CFG->proxyhost; + if (!empty($CFG->proxyport)) { + $proxy .= ':'. $CFG->proxyport; + } + if (!empty($CFG->proxyuser) && !empty($CFG->proxypassword)) { + $proxy = $protocol . $CFG->proxyuser . ':' . $CFG->proxypassword . '@' . $proxy; + } + } + return $proxy; + } + + /** + * Configure the provided AWS client to route traffic via the moodle proxy for any hosts not excluded. + * + * @param AwsClient $client + * @return AwsClient + */ + public static function configure_client_proxy(AwsClient $client): AwsClient { + $client->getHandlerList()->appendBuild(self::add_proxy_when_required(), 'proxy_bypass'); + return $client; + } + + /** + * Generate a middleware higher order function to wrap the handler and append proxy configuration based on target. + * + * @return callable Middleware high order callable. + */ + protected static function add_proxy_when_required(): callable { + return function (callable $fn) { + return function (CommandInterface $command, ?RequestInterface $request = null) use ($fn) { + if (isset($request)) { + $target = (string) $request->getUri(); + if (!is_proxybypass($target)) { + $command['@http']['proxy'] = self::get_proxy_string(); + } + } + + $promise = $fn($command, $request); + return $promise; + }; + }; + } +} diff --git a/admin/tool/mfa/factor/sms/classes/local/client_factory.php b/admin/tool/mfa/factor/sms/classes/local/client_factory.php new file mode 100644 index 00000000000..32ed64a06e5 --- /dev/null +++ b/admin/tool/mfa/factor/sms/classes/local/client_factory.php @@ -0,0 +1,62 @@ +. + +/** + * AWS Client factory. Retrieves a client with moodle specific HTTP configuration. + * + * @package local_aws + * @author Peter Burnett + * @copyright 2022 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace local_aws\local; +use \Aws\AwsClient; + +/** + * AWS Client factory. Retrieves a client with moodle specific HTTP configuration. + * + * @copyright 2022 Catalyst IT + * @author Peter Burnett + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class client_factory { + /** + * Get an AWS client with moodle specific HTTP configuration. + * + * @param string $class Fully qualified AWS classname e.g. \Aws\S3\S3Client + * @param array $opts array of constructor options for AWS Client. + * @return AwsClient + */ + public static function get_client(string $class, array $opts): AwsClient { + // Modify the opts to add HTTP timeouts. + if (empty($opts['http'])) { + $opts['http'] = ['connect_timeout' => HOURSECS]; + } else if (is_array($opts['http'] && !array_key_exists('connect_timeout', $opts['http']))) { + // Try not to override existing settings. + $opts['http']['connect_timeout'] = HOURSECS; + } + + // Blindly trust the call here. If it exceptions, the raw message is the most useful. + $client = new $class($opts); + if (!$client instanceof \Aws\AwsClient) { + throw new \moodle_exception('clientnotfound', 'local_aws'); + } + + // Now we can configure the proxy with the routing aware middleware. + return aws_helper::configure_client_proxy($client); + } +} diff --git a/admin/tool/mfa/factor/sms/tests/admin_settings_aws_region_test.php b/admin/tool/mfa/factor/sms/tests/admin_settings_aws_region_test.php new file mode 100644 index 00000000000..494ed24fec6 --- /dev/null +++ b/admin/tool/mfa/factor/sms/tests/admin_settings_aws_region_test.php @@ -0,0 +1,63 @@ +. + +/** + * local_aws unit tests. + * + * @package local_aws + * @author Mikhail Golenkov + * @copyright 2020 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace local_aws; + +/** + * Testcase for the list of AWS regions admin setting. + * + * @package local_aws + * @author Mikhail Golenkov + * @copyright 2020 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \local_aws\admin_settings_aws_region + */ +class admin_settings_aws_region_test extends \advanced_testcase { + + /** + * Cleanup after all tests are executed. + * + * @return void + */ + public function tearDown(): void { + $admin = admin_get_root(); + $admin->purge_children(true); + } + /** + * Test that output_html() method works and returns HTML string with expected content. + */ + public function test_output_html() { + $this->resetAfterTest(); + $setting = new admin_settings_aws_region('test_aws_region', + 'Test visible name', 'Test description', 'Test default setting'); + $html = $setting->output_html(''); + $this->assertTrue(strpos($html, 'Test visible name') !== false); + $this->assertTrue(strpos($html, 'Test description') !== false); + $this->assertTrue(strpos($html, 'Default: Test default setting') !== false); + $this->assertTrue(strpos($html, 'assertTrue(strpos($html, '') !== false); + $this->assertTrue(strpos($html, '