ENHANCEMENT #2856 Limiting of relative URLs for Director::forceSSL() using a map of PCRE regular expressions

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/branches/2.4@108428 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Sean Harvey 2010-07-23 05:49:37 +00:00 committed by Sam Minnee
parent 248979b4c5
commit c52529215f
2 changed files with 90 additions and 8 deletions

View File

@ -605,19 +605,55 @@ class Director {
}
/**
* Force the site to run on SSL. To use, call from _config.php.
* Force the site to run on SSL.
*
* For example:
* To use, call from _config.php. For example:
* <code>
* if(Director::isLive()) Director::forceSSL();
* </code>
*
* If you don't want your entire site to be on SSL, you can pass an array of PCRE regular expression
* patterns for matching relative URLs. For example:
* <code>
* if(Director::isLive()) Director::forceSSL(array('/^admin/', '/^Security/.*'));
* </code>
*
* Note that the session data will be lost when moving from HTTP to HTTPS.
* It is your responsibility to ensure that this won't cause usability problems.
*
* CAUTION: This does not respect the site environment mode. You should check this
* as per the above examples using Director::isLive() or Director::isTest() for example.
*
* @return boolean|string String of URL when unit tests running, boolean FALSE if patterns don't match request URI
*/
static function forceSSL() {
if((Director::protocol() != "https://") && !Director::isDev() && !Director::is_cli()) {
static function forceSSL($patterns = null) {
$matched = false;
if($patterns) {
// protect portions of the site based on the pattern
$relativeURL = self::makeRelative(Director::absoluteURL($_SERVER['REQUEST_URI']));
foreach($patterns as $pattern) {
if(preg_match($pattern, $relativeURL)) {
$matched = true;
break;
}
}
} else {
// protect the entire site
$matched = true;
}
if($matched && !isset($_SERVER['HTTPS'])) {
$destURL = str_replace('http:', 'https:', Director::absoluteURL($_SERVER['REQUEST_URI']));
header("Location: $destURL", true, 301);
die("<h1>Your browser is not accepting header redirects</h1><p>Please <a href=\"$destURL\">click here</a>");
header("Location: $destURL");
if(SapphireTest::is_running_test()) {
return $destURL;
} else {
die("<h1>Your browser is not accepting header redirects</h1><p>Please <a href=\"$destURL\">click here</a>");
}
} else {
return false;
}
}

View File

@ -5,7 +5,7 @@
*
* @todo test Director::alternateBaseFolder()
*/
class DirectorTest extends SapphireTest {
class DirectorTest extends FunctionalTest {
function setUp() {
parent::setUp();
@ -189,7 +189,53 @@ class DirectorTest extends SapphireTest {
)
);
}
function testForceSSLProtectsEntireSite() {
$originalURI = $_SERVER['REQUEST_URI'];
$_SERVER['REQUEST_URI'] = Director::baseURL() . 'admin';
$output = Director::forceSSL();
$this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
$_SERVER['REQUEST_URI'] = $originalURI;
$_SERVER['REQUEST_URI'] = Director::baseURL() . 'some-url';
$output = Director::forceSSL();
$this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
$_SERVER['REQUEST_URI'] = $originalURI;
}
function testForceSSLOnTopLevelPagePattern() {
$originalURI = $_SERVER['REQUEST_URI'];
$_SERVER['REQUEST_URI'] = Director::baseURL() . 'admin';
$output = Director::forceSSL(array('/^admin/'));
$this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
$_SERVER['REQUEST_URI'] = $originalURI;
}
function testForceSSLOnSubPagesPattern() {
$originalURI = $_SERVER['REQUEST_URI'];
$_SERVER['REQUEST_URI'] = Director::baseURL() . 'Security/login';
$output = Director::forceSSL(array('/^Security/'));
$this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
$_SERVER['REQUEST_URI'] = $originalURI;
}
function testForceSSLWithPatternDoesNotMatchOtherPages() {
$originalURI = $_SERVER['REQUEST_URI'];
$_SERVER['REQUEST_URI'] = Director::baseURL() . 'normal-page';
$output = Director::forceSSL(array('/^admin/'));
$this->assertFalse($output);
$_SERVER['REQUEST_URI'] = $originalURI;
$_SERVER['REQUEST_URI'] = Director::baseURL() . 'just-another-page/sub-url';
$output = Director::forceSSL(array('/^admin/', '/^Security/'));
$this->assertFalse($output);
$_SERVER['REQUEST_URI'] = $originalURI;
}
}
class DirectorTestRequest_Controller extends Controller implements TestOnly {