mirror of
https://github.com/moodle/moodle.git
synced 2025-01-17 21:49:15 +01:00
MDL-79121 lib: Normalize proxybypass value
This changes prevent the admin to define an incorrect proxybypass value. Dropped out formats in MDL-74289 are now fixed automatically. e.g.: "192.168." becomes "192.168.0.0/16" and ".domain.tld" becomes "*.domain.tld".
This commit is contained in:
parent
aa55f38820
commit
b390286ed9
20
.upgradenotes/MDL-79121-2024121616391169.yml
Normal file
20
.upgradenotes/MDL-79121-2024121616391169.yml
Normal file
@ -0,0 +1,20 @@
|
||||
issueNumber: MDL-79121
|
||||
notes:
|
||||
core:
|
||||
- message: >
|
||||
A new core\ip_utils::normalize_internet_address() method is created to
|
||||
sanitize an IP address, a range of IP addresses, a domain name or a
|
||||
wildcard domain matching pattern.
|
||||
|
||||
|
||||
Moodle previously allowed entries such as 192.168. or .moodle.org for
|
||||
certain variables (eg: $CFG->proxybypass). Since MDL-74289, these
|
||||
formats are no longer allowed. This method converts this informations
|
||||
into an authorized format. For example, 192.168. becomes 192.168.0.0/16
|
||||
and .moodle.org becomes *.moodle.org.
|
||||
|
||||
|
||||
Also a new core\ip_utils::normalize_internet_address_list() method is
|
||||
created. Based on core\ip_utils::normalize_internet_address(), this
|
||||
method normalizes a string containing a series of Internet addresses.
|
||||
type: improved
|
@ -181,8 +181,16 @@ if ($hassiteconfig) {
|
||||
new lang_string('configproxyuser', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configpasswordunmask('proxypassword', new lang_string('proxypassword', 'admin'),
|
||||
new lang_string('configproxypassword', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configtext('proxybypass', new lang_string('proxybypass', 'admin'),
|
||||
new lang_string('configproxybypass', 'admin'), 'localhost, 127.0.0.1'));
|
||||
|
||||
$setting = new admin_setting_configtext('proxybypass', new lang_string('proxybypass', 'admin'),
|
||||
new lang_string('configproxybypass', 'admin'), 'localhost,127.0.0.1');
|
||||
$setting->set_updatedcallback(function() {
|
||||
// Normalize $CFG->proxybypass value.
|
||||
$normalizedvalue = \core\ip_utils::normalize_internet_address_list(get_config('core', 'proxybypass'));
|
||||
set_config('proxybypass', $normalizedvalue);
|
||||
});
|
||||
$temp->add($setting);
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('proxylogunsafe', new lang_string('proxylogunsafe', 'admin'),
|
||||
new lang_string('configproxylogunsafe_help', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('proxyfixunsafe', new lang_string('proxyfixunsafe', 'admin'),
|
||||
|
@ -341,7 +341,7 @@ $string['configperfdebug'] = 'If you turn this on, performance info will be prin
|
||||
$string['configprofileroles'] = 'Roles that are listed in user profiles and on the participants page.';
|
||||
$string['configprofilesforenrolledusersonly'] = 'To prevent misuse by spammers, profile descriptions of users who are not yet enrolled in any course are hidden. New users must enrol in at least one course before they can add a profile description.';
|
||||
$string['configprotectusernames'] = 'If enabled, the forgotten password form will not display any hints allowing account usernames or email addresses to be guessed.';
|
||||
$string['configproxybypass'] = 'Comma separated list of (partial) hostnames or IPs that should bypass proxy (e.g., 192.168., .mydomain.com)';
|
||||
$string['configproxybypass'] = 'List of (partial) hostnames or IP addresses that should bypass the proxy. Separate each item by commas, with no spaces. For example: 192.168.0.0/16,*.mydomain.com.';
|
||||
$string['configproxyhost'] = 'If this <b>server</b> needs to use a proxy computer (eg a firewall) to access the Internet, then provide the proxy hostname here. Otherwise leave it blank.';
|
||||
$string['configproxypassword'] = 'Password needed to access internet through proxy if required, empty if none (PHP cURL extension required).';
|
||||
$string['configproxyport'] = 'If this server needs to use a proxy computer, then provide the proxy port here.';
|
||||
|
@ -263,4 +263,94 @@ final class ip_utils {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize internet address.
|
||||
*
|
||||
* Accepted input formats are :
|
||||
* - a valid range or full ip address (e.g.: 192.168.0.0/16, fe80::ffff, 127.0.0.1 or fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80)
|
||||
* - a valid domain name or pattern (e.g.: www.moodle.com or *.moodle.org)
|
||||
*
|
||||
* Convert forbidden syntaxes since MDL-74289 to allowed values. For examples:
|
||||
* - 192.168. => 192.168.0.0/16
|
||||
* - .domain.tld => *.domain.tld
|
||||
*
|
||||
* @param string $address The input string to normalize.
|
||||
*
|
||||
* @return string If $address is not normalizable, an empty string is returned.
|
||||
*/
|
||||
public static function normalize_internet_address(string $address): string {
|
||||
$address = str_replace([" ", "\n", "\r", "\t", "\v", "\x00"], '', strtolower($address));
|
||||
|
||||
// Replace previous allowed "192.168." format to CIDR format (192.168.0.0/16).
|
||||
if (str_ends_with($address, '.') && preg_match('/^[0-9\.]+$/', $address) === 1) {
|
||||
$count = substr_count($address, '.');
|
||||
|
||||
// Remove final dot.
|
||||
$address = substr($address, 0, -1);
|
||||
|
||||
// Fill address with missing ".0".
|
||||
$address .= str_repeat('.0', 4 - $count);
|
||||
|
||||
// Add subnet mask.
|
||||
$address .= '/' . ($count * 8);
|
||||
}
|
||||
|
||||
if (self::is_ip_address($address) ||
|
||||
self::is_ipv4_range($address) || self::is_ipv6_range($address)) {
|
||||
|
||||
// Keep full or range ip addresses.
|
||||
return $address;
|
||||
}
|
||||
|
||||
// Replace previous allowed ".domain.tld" format to "*.domain.tld" format.
|
||||
if (str_starts_with($address, '.')) {
|
||||
$address = '*'.$address;
|
||||
}
|
||||
|
||||
// Usually the trailing dot (null label) is omitted, but is valid if supplied. We'll just remove it and validate as normal.
|
||||
$address = rtrim($address, '.');
|
||||
|
||||
if (self::is_domain_name($address) || self::is_domain_matching_pattern($address)) {
|
||||
// Keep valid or pattern domain name.
|
||||
return $address;
|
||||
}
|
||||
|
||||
// Return empty string for invalid values.
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a list of internet addresses.
|
||||
*
|
||||
* This function will:
|
||||
* - normalize internet addresses {@see normalize_internet_address()}
|
||||
* - remove invalid values
|
||||
* - remove duplicate values
|
||||
*
|
||||
* @param string $addresslist A string representing a list of internet addresses separated by a common value.
|
||||
* @param string $separator A separator character used within the list string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function normalize_internet_address_list(string $addresslist, string $separator = ','): string {
|
||||
$addresses = [];
|
||||
foreach (explode($separator, $addresslist) as $value) {
|
||||
$address = self::normalize_internet_address($value);
|
||||
|
||||
if (empty($address)) {
|
||||
// Ignore invalid input.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($address, $addresses, true)) {
|
||||
// Ignore duplicate value.
|
||||
continue;
|
||||
}
|
||||
|
||||
$addresses[] = $address;
|
||||
}
|
||||
|
||||
return implode($separator, $addresses);
|
||||
}
|
||||
}
|
||||
|
@ -400,4 +400,155 @@ final class ip_utils_test extends \basic_testcase {
|
||||
$this->assertEquals($expected, \core\ip_utils::is_ip_in_subnet_list($ip, $list, $delim));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_normalize_internet_address.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function normalize_internet_address_provider(): array {
|
||||
return [
|
||||
'Strip all white spaces on IP address' => [
|
||||
' 192.168.5.5 ',
|
||||
'192.168.5.5',
|
||||
],
|
||||
'Strip all white spaces on domain name' => [
|
||||
' www.moodle.org ',
|
||||
'www.moodle.org',
|
||||
],
|
||||
'Preserve IPv4 address' => [
|
||||
'127.0.0.1',
|
||||
'127.0.0.1',
|
||||
],
|
||||
'Preserve IPv4 address range' => [
|
||||
'192.168.0.0/16',
|
||||
'192.168.0.0/16',
|
||||
],
|
||||
'Preserve IPv6 address' => [
|
||||
'fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80',
|
||||
'fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80',
|
||||
],
|
||||
'Preserve IPv6 address range' => [
|
||||
'fe80::ffff',
|
||||
'fe80::ffff',
|
||||
],
|
||||
'Preserve valid domain' => [
|
||||
'localhost',
|
||||
'localhost',
|
||||
],
|
||||
'Preserve valid FQDN' => [
|
||||
'www.moodle.org',
|
||||
'www.moodle.org',
|
||||
],
|
||||
'Preserve valid FQDN with trailing dot' => [
|
||||
'www.moodle.com.',
|
||||
'www.moodle.com',
|
||||
],
|
||||
'Preserve valid domain with wildcard' => [
|
||||
'*.moodledev.io',
|
||||
'*.moodledev.io',
|
||||
],
|
||||
'Convert previous allowed "127." format to CIDR format (127.0.0.0/8)' => [
|
||||
'127.',
|
||||
'127.0.0.0/8',
|
||||
],
|
||||
'Convert previous allowed "169.8." format to CIDR format (169.8.0.0/16)' => [
|
||||
'169.8.',
|
||||
'169.8.0.0/16',
|
||||
],
|
||||
'Convert previous allowed "192.168.10." format to CIDR format (192.168.10.0/24)' => [
|
||||
'192.168.10.',
|
||||
'192.168.10.0/24',
|
||||
],
|
||||
'Convert previous allowed ".moodle.org" subdomain format to new format (*.moodle.org)' => [
|
||||
'.moodle.org',
|
||||
'*.moodle.org',
|
||||
],
|
||||
'Ignore invalid IPv4' => [
|
||||
'327.0.0.1',
|
||||
'',
|
||||
],
|
||||
'Ignore invalid IPv4 range' => [
|
||||
'192.168',
|
||||
'',
|
||||
],
|
||||
'Ignore invalid IPv6' => [
|
||||
'fe80::ddddd',
|
||||
'',
|
||||
],
|
||||
'Ignore invalid IPv6 range' => [
|
||||
'fe80:',
|
||||
'',
|
||||
],
|
||||
'Ignore invalid domain' => [
|
||||
'-example.com',
|
||||
'',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if input address value is correctly normalized.
|
||||
*
|
||||
* @covers ::normalize_internet_address
|
||||
*
|
||||
* @dataProvider normalize_internet_address_provider
|
||||
*
|
||||
* @param string $input Raw input value.
|
||||
* @param string $expected Expected value after normalization.
|
||||
*/
|
||||
public function test_normalize_internet_address(string $input, string $expected): void {
|
||||
$this->assertEquals($expected, \core\ip_utils::normalize_internet_address($input));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_normalize_internet_address_list.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function normalize_internet_address_list_provider(): array {
|
||||
return [
|
||||
'Strip all white spaces' => [
|
||||
' 192.168.5.5, 127.0.0.1, www.moodle.org ',
|
||||
'192.168.5.5,127.0.0.1,www.moodle.org',
|
||||
],
|
||||
'Trim input' => [
|
||||
' 192.168.5.5,127.0.0.1,www.moodle.org ',
|
||||
'192.168.5.5,127.0.0.1,www.moodle.org',
|
||||
],
|
||||
'Preserve valid full and partial IP' => [
|
||||
'127.0.0.1,192.168.0.0/16,fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80,fe80::ffff',
|
||||
'127.0.0.1,192.168.0.0/16,fe80:fe80:fe80:fe80:fe80:fe80:fe80:fe80,fe80::ffff',
|
||||
],
|
||||
'Convert previous allowed format to new allowed format' => [
|
||||
'127.,169.8.,192.168.10.,.moodle.org',
|
||||
'127.0.0.0/8,169.8.0.0/16,192.168.10.0/24,*.moodle.org',
|
||||
],
|
||||
'Preserve valid domain and pattern domain' => [
|
||||
'localhost,www.moodle.org,.moodle.com,*.moodledev.io',
|
||||
'localhost,www.moodle.org,*.moodle.com,*.moodledev.io',
|
||||
],
|
||||
'Remove all invalid IP and domains' => [
|
||||
'327.0.0.1,192.168,fe80::ddddd,fe80:,-example.com',
|
||||
'',
|
||||
],
|
||||
'Remove duplicate values' => [
|
||||
'.moodle.org,*.moodle.org,*.moodle.org,.moodle.org',
|
||||
'*.moodle.org',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if input address list is correctly normalized.
|
||||
*
|
||||
* @covers ::normalize_internet_address_list
|
||||
*
|
||||
* @dataProvider normalize_internet_address_list_provider
|
||||
*
|
||||
* @param string $input Raw input value.
|
||||
* @param string $expected Expected value after normalization.
|
||||
*/
|
||||
public function test_normalize_internet_address_list(string $input, string $expected): void {
|
||||
$this->assertEquals($expected, \core\ip_utils::normalize_internet_address_list($input));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user