diff --git a/lib/classes/ip_utils.php b/lib/classes/ip_utils.php index d95f71014a1..42abcb4b9f3 100644 --- a/lib/classes/ip_utils.php +++ b/lib/classes/ip_utils.php @@ -185,4 +185,43 @@ final class ip_utils { } return false; } + + /** + * Checks the domain name against a list of allowed domains. The list of allowed domains is may use + * wildcards that match {@link is_domain_matching_pattern()}. + * + * @param string $domain Domain address + * @param array $alloweddomains An array of allowed domains. + * @return boolean True if the domain matches one of the entries in the allowed domains list. + */ + public static function is_domain_in_allowed_list($domain, $alloweddomains) { + + if (!self::is_domain_name($domain)) { + return false; + } + + foreach ($alloweddomains as $alloweddomain) { + if (strpos($alloweddomain, '*') !== false) { + if (!self::is_domain_matching_pattern($alloweddomain)) { + continue; + } + // Use of wildcard for possible subdomains. + $escapeperiods = str_replace('.', '\.', $alloweddomain); + $replacewildcard = str_replace('*', '.*', $escapeperiods); + $ultimatepattern = '/' . $replacewildcard . '$/'; + if (preg_match($ultimatepattern, $domain)) { + return true; + } + } else { + if (!self::is_domain_name($alloweddomain)) { + continue; + } + // Strict domain setting. + if ($domain === $alloweddomain) { + return true; + } + } + } + return false; + } } diff --git a/lib/tests/ip_utils_test.php b/lib/tests/ip_utils_test.php index 455bb654636..0fa9d395894 100644 --- a/lib/tests/ip_utils_test.php +++ b/lib/tests/ip_utils_test.php @@ -335,4 +335,43 @@ class core_ip_utils_testcase extends basic_testcase { ["fe80:::aaaa-dddd", false], ]; } + + /** + * Test checking domains against a list of allowed domains. + * + * @param bool $expected Expected result + * @param string $domain domain address + * @dataProvider data_domain_addresses + */ + public function test_check_domain_against_allowed_domains($expected, $domain) { + $alloweddomains = ['example.com', + '*.moodle.com', + '*.per.this.penny-arcade.com', + 'bad.*.url.com', + ' trouble.com.au']; + $this->assertEquals($expected, \core\ip_utils::is_domain_in_allowed_list($domain, $alloweddomains)); + } + + /** + * Data provider for test_check_domain_against_allowed_domains. + * + * @return array + */ + public function data_domain_addresses() { + return [ + [true, 'example.com'], + [false, 'sub.example.com'], + [false, 'example.com.au'], + [false, ' example.com'], // A space at the front of the domain is invalid. + [false, 'example.123'], // Numbers at the end is invalid. + [false, 'test.example.com'], + [false, 'moodle.com'], + [true, 'test.moodle.com'], + [false, 'test.moodle.com.au'], + [true, 'nice.address.per.this.penny-arcade.com'], + [false, 'normal.per.this.penny-arcade.com.au'], + [false, 'bad.thing.url.com'], // The allowed domain (above) has a bad wildcard and so this address will return false. + [false, 'trouble.com.au'] // The allowed domain (above) has a space at the front and so will return false. + ]; + } }