From ed046b8eb17c81847d8403778ac40f76cbab0ecb Mon Sep 17 00:00:00 2001 From: Xuan Gui Date: Wed, 3 Feb 2021 09:54:54 +1000 Subject: [PATCH] MDL-70649 files: Alternative security helper Augument all installed plugin's security helper if there is any. Plugins function has to be defined as plugintype_pluginname_security_helper in pluginname/lib.php file. --- lib/filelib.php | 67 +++++++++++++++++++++++++++++++++++++++++-------- lib/upgrade.txt | 3 +++ 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/lib/filelib.php b/lib/filelib.php index 2ea5d616fc8..b19e630c9ab 100644 --- a/lib/filelib.php +++ b/lib/filelib.php @@ -3567,6 +3567,51 @@ class curl { } } + /** + * check_securityhelper_blocklist. + * Checks whether the given URL is blocked by checking both plugin's security helpers + * and core curl security helper or any curl security helper that passed to curl class constructor. + * If ignoresecurity is set to true, skip checking and consider the url is not blocked. + * This augments all installed plugin's security helpers if there is any. + * + * @param string $url the url to check. + * @return string - an error message if URL is blocked or null if URL is not blocked. + */ + protected function check_securityhelper_blocklist(string $url): ?string { + + // If curl security is not enabled, do not proceed. + if ($this->ignoresecurity) { + return null; + } + + // Augment all installed plugin's security helpers if there is any. + // The plugin's function has to be defined as plugintype_pluginname_curl_security_helper in pluginname/lib.php. + $plugintypes = get_plugins_with_function('curl_security_helper'); + + // If any of the security helper's function returns true, treat as URL is blocked. + foreach ($plugintypes as $plugins) { + foreach ($plugins as $pluginfunction) { + // Get curl security helper object from plugin lib.php. + $pluginsecurityhelper = $pluginfunction(); + if ($pluginsecurityhelper instanceof \core\files\curl_security_helper_base) { + if ($pluginsecurityhelper->url_is_blocked($url)) { + $this->error = $pluginsecurityhelper->get_blocked_url_string(); + return $this->error; + } + } + } + } + + // Check if the URL is blocked in core curl_security_helper or + // curl security helper that passed to curl class constructor. + if ($this->securityhelper->url_is_blocked($url)) { + $this->error = $this->securityhelper->get_blocked_url_string(); + return $this->error; + } + + return null; + } + /** * Single HTTP Request * @@ -3585,11 +3630,10 @@ class curl { } } - // If curl security is enabled, check the URL against the list of blocked URLs before calling curl_exec. - // Note: This will only check the base url. In the case of redirects, the blocking check is also after the curl_exec. - if (!$this->ignoresecurity && $this->securityhelper->url_is_blocked($url)) { - $this->error = $this->securityhelper->get_blocked_url_string(); - return $this->error; + // This will only check the base url. In the case of redirects, the blocking check is also after the curl_exec. + $urlisblocked = $this->check_securityhelper_blocklist($url); + if (!is_null($urlisblocked)) { + return $urlisblocked; } // Set the URL as a curl option. @@ -3610,12 +3654,13 @@ class curl { // Note: $this->response and $this->rawresponse are filled by $hits->formatHeader callback. // In the case of redirects (which curl blindly follows), check the post-redirect URL against the list of blocked list too. - if (intval($this->info['redirect_count']) > 0 && !$this->ignoresecurity - && $this->securityhelper->url_is_blocked($this->info['url'])) { - $this->reset_request_state_vars(); - $this->error = $this->securityhelper->get_blocked_url_string(); - curl_close($curl); - return $this->error; + if (intval($this->info['redirect_count']) > 0) { + $urlisblocked = $this->check_securityhelper_blocklist($this->info['url']); + if (!is_null($urlisblocked)) { + $this->reset_request_state_vars(); + curl_close($curl); + return $urlisblocked; + } } if ($this->emulateredirects and $this->options['CURLOPT_FOLLOWLOCATION'] and $this->info['http_code'] != 200) { diff --git a/lib/upgrade.txt b/lib/upgrade.txt index 5a31aa433ba..6ff2e742640 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -115,6 +115,9 @@ information provided here is intended especially for developers. those fields. This replaces existing functions get_extra_user_fields(), get_extra_user_fields_sql(), get_user_field_name(), get_all_user_name_fields(), and user_picture::fields(), which have all been deprecated. +* Allow plugins to augment the curl security helper via callback. The plugin's function has to be defined as + plugintype_pluginname_curl_security_helper in pluginname/lib.php file and the function should return a plugin's security + helper instance. * The behat transformation 'string time to timestamp' no longer supports datetime format. If provided, the format must be strftime compatible. Example: - I should see "##tomorrow noon##%A, %d %B %Y, %I:%M %p##"