Skip to content
Snippets Groups Projects
Commit 9fe75c40 authored by Jaime Pérez Crespo's avatar Jaime Pérez Crespo
Browse files

Merge pull request #380 from jdufresne/regex-trusted-url-domains

Allow regular expression matching of trusted.url.domains.
parents fc1ab9bf 6079b2f7
No related branches found
No related tags found
No related merge requests found
...@@ -104,6 +104,17 @@ $config = array( ...@@ -104,6 +104,17 @@ $config = array(
*/ */
'trusted.url.domains' => array(), 'trusted.url.domains' => array(),
/*
* Enable regular expression matching of trusted.url.domains.
*
* Set to true to treat the values in trusted.url.domains as regular
* expressions. Set to false to do exact string matching.
*
* If enabled, the start and end delimiters ('^' and '$') will be added to
* all regular expressions in trusted.url.domains.
*/
'trusted.url.regex' => false,
/* /*
* Enable secure POST from HTTPS to HTTP. * Enable secure POST from HTTPS to HTTP.
* *
......
...@@ -32,6 +32,7 @@ Released TBD ...@@ -32,6 +32,7 @@ Released TBD
* Added the SAML NameID to the attributes status page, when available. * Added the SAML NameID to the attributes status page, when available.
* Added attribute definitions for schacGender (schac), sisSchoolGrade and sisLegalGuardianFor (skolfederation.se). * Added attribute definitions for schacGender (schac), sisSchoolGrade and sisLegalGuardianFor (skolfederation.se).
* Attributes required in metadata are now taken into account when parsing. * Attributes required in metadata are now taken into account when parsing.
* Allow regular expression matching of trusted.url.domains. Off by default, set trusted.url.regex to true to enable.
### Bug fixes ### Bug fixes
......
...@@ -324,12 +324,30 @@ class HTTP ...@@ -324,12 +324,30 @@ class HTTP
preg_match('@^https?://([^/]+)@i', $url, $matches); preg_match('@^https?://([^/]+)@i', $url, $matches);
$hostname = $matches[1]; $hostname = $matches[1];
// add self host to the white list
$self_host = self::getSelfHostWithNonStandardPort(); $self_host = self::getSelfHostWithNonStandardPort();
$trustedSites[] = $self_host;
$trustedRegex = \SimpleSAML_Configuration::getInstance()->getValue('trusted.url.regex', false);
$trusted = false;
if ($trustedRegex) {
// add self host to the white list
$trustedSites[] = preg_quote($self_host);
foreach ($trustedSites as $regex) {
// Add start and end delimiters.
$regex = "@^{$regex}$@";
if (preg_match($regex, $hostname)) {
$trusted = true;
break;
}
}
} else {
// add self host to the white list
$trustedSites[] = $self_host;
$trusted = in_array($hostname, $trustedSites);
}
// throw exception due to redirection to untrusted site // throw exception due to redirection to untrusted site
if (!in_array($hostname, $trustedSites)) { if (!$trusted) {
throw new \SimpleSAML_Error_Exception('URL not allowed: '.$url); throw new \SimpleSAML_Error_Exception('URL not allowed: '.$url);
} }
} }
......
...@@ -88,4 +88,77 @@ class HTTPTest extends \PHPUnit_Framework_TestCase ...@@ -88,4 +88,77 @@ class HTTPTest extends \PHPUnit_Framework_TestCase
$_SERVER['SERVER_PORT'] = '443'; $_SERVER['SERVER_PORT'] = '443';
$this->assertEquals('localhost', HTTP::getSelfHostWithNonStandardPort()); $this->assertEquals('localhost', HTTP::getSelfHostWithNonStandardPort());
} }
/**
* Test SimpleSAML\Utils\HTTP::checkURLAllowed(), without regex.
*/
public function testCheckURLAllowedWithoutRegex()
{
\SimpleSAML_Configuration::loadFromArray(array(
'trusted.url.domains' => array('sp.example.com', 'app.example.com'),
'trusted.url.regex' => false,
), '[ARRAY]', 'simplesaml');
$_SERVER['REQUEST_URI'] = '/module.php';
$allowed = array(
'https://sp.example.com/',
'http://sp.example.com/',
'https://app.example.com/',
'http://app.example.com/',
);
foreach ($allowed as $url)
{
$this->assertEquals(HTTP::checkURLAllowed($url), $url);
}
$this->setExpectedException('SimpleSAML_Error_Exception');
HTTP::checkURLAllowed('https://evil.com');
}
/**
* Test SimpleSAML\Utils\HTTP::checkURLAllowed(), with regex.
*/
public function testCheckURLAllowedWithRegex()
{
\SimpleSAML_Configuration::loadFromArray(array(
'trusted.url.domains' => array('.*\.example\.com'),
'trusted.url.regex' => true,
), '[ARRAY]', 'simplesaml');
$_SERVER['REQUEST_URI'] = '/module.php';
$allowed = array(
'https://sp.example.com/',
'http://sp.example.com/',
'https://app1.example.com/',
'http://app1.example.com/',
'https://app2.example.com/',
'http://app2.example.com/',
);
foreach ($allowed as $url)
{
$this->assertEquals(HTTP::checkURLAllowed($url), $url);
}
$this->setExpectedException('SimpleSAML_Error_Exception');
HTTP::checkURLAllowed('https://evil.com');
}
/**
* Test SimpleSAML\Utils\HTTP::checkURLAllowed(), with the regex as a
* subdomain of an evil domain.
*/
public function testCheckURLAllowedWithRegexWithoutDelimiters()
{
\SimpleSAML_Configuration::loadFromArray(array(
'trusted.url.domains' => array('app\.example\.com'),
'trusted.url.regex' => true,
), '[ARRAY]', 'simplesaml');
$_SERVER['REQUEST_URI'] = '/module.php';
$this->setExpectedException('SimpleSAML_Error_Exception');
HTTP::checkURLAllowed('https://app.example.com.evil.com');
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment