ENHANCEMENT Allowing strict subdomain checks on 'www.example.com' vs. 'example.com' via Subsite::$strict_domain_matching (AIR-54)

This commit is contained in:
Ingo Schommer 2011-09-09 11:59:46 +02:00
parent 32d51ed986
commit 2b506b02b1
3 changed files with 171 additions and 11 deletions

View File

@ -65,6 +65,13 @@ You can mix the two together, if you want to have some subsites hosted off subdo
Note that every site also has a ''www.''-prefixed version of the domain available. For example, if your subsite is accessible from ''wellington.example.org'' then it will also be accessible from '''www.wellington.example.org''.
### Strict Subdomain Matching ###
The module tries to provide sensible defaults, in which it regards `example.com` and `www.example.com`
as the same domains. In case you want to distinguish between these variations,
set `Subsite::$strict_subdomain_matching` to TRUE. This won't affect wildcard/asterisk checks,
but removes the ambiguity about default subdomains.
### Permissions ###
Groups can be associated with one or more subsites, in which case the granted permissions

View File

@ -20,6 +20,7 @@ class Subsite extends DataObject implements PermissionProvider {
static $force_subsite = null;
static $write_hostmap = true;
static $default_sort = "\"Title\" ASC";
static $db = array(
@ -76,6 +77,13 @@ class Subsite extends DataObject implements PermissionProvider {
* are listed.
*/
protected static $allowed_themes = array();
/**
* @var Boolean If set to TRUE, don't assume 'www.example.com' and 'example.com' are the same.
* Doesn't affect wildcard matching, so '*.example.com' will match 'www.example.com' (but not 'example.com')
* in both TRUE or FALSE setting.
*/
static $strict_subdomain_matching = false;
static function set_allowed_domains($domain){
user_error('Subsite::set_allowed_domains() is deprecated; it is no longer necessary '
@ -320,7 +328,7 @@ JS;
static function getSubsiteIDForDomain($host = null, $returnMainIfNotFound = true) {
if($host == null) $host = $_SERVER['HTTP_HOST'];
$host = str_replace('www.','',$host);
if(!Subsite::$strict_subdomain_matching) $host = preg_replace('/^www\./', '', $host);
$SQL_host = Convert::raw2sql($host);
$matchingDomains = DataObject::get("SubsiteDomain", "'$SQL_host' LIKE replace(\"SubsiteDomain\".\"Domain\",'*','%')",
@ -329,7 +337,15 @@ JS;
if($matchingDomains) {
$subsiteIDs = array_unique($matchingDomains->column('SubsiteID'));
if(sizeof($subsiteIDs) > 1) user_error("Multiple subsites match '$host'", E_USER_WARNING);
$subsiteDomains = array_unique($matchingDomains->column('Domain'));
if(sizeof($subsiteIDs) > 1) {
throw new UnexpectedValueException(sprintf(
"Multiple subsites match on '%s': %s",
$host,
implode(',', $subsiteDomains)
));
}
return $subsiteIDs[0];
}
@ -538,7 +554,9 @@ JS;
if ($subsites) foreach($subsites as $subsite) {
$domains = $subsite->Domains();
if ($domains) foreach($domains as $domain) {
$hostmap[str_replace('www.', '', $domain->Domain)] = $subsite->domain();
$domainStr = $domain->Domain;
if(!Subsite::$strict_subdomain_matching) $domainStr = preg_replace('/^www\./', '', $domainStr);
$hostmap[$domainStr] = $subsite->domain();
}
if ($subsite->DefaultSite) $hostmap['default'] = $subsite->domain();
}

View File

@ -1,7 +1,21 @@
<?php
class SubsiteTest extends SapphireTest {
static $fixture_file = 'subsites/tests/SubsiteTest.yml';
function setUp() {
parent::setUp();
$this->origStrictSubdomainMatching = Subsite::$strict_subdomain_matching;
Subsite::$strict_subdomain_matching = false;
}
function tearDown() {
parent::tearDown();
Subsite::$strict_subdomain_matching = $this->origStrictSubdomainMatching;
}
/**
* Create a new subsite from the template and verify that all the template's pages are copied
@ -57,28 +71,65 @@ class SubsiteTest extends SapphireTest {
* Confirm that domain lookup is working
*/
function testDomainLookup() {
// Clear existing fixtures
foreach(DataObject::get('Subsite') as $subsite) $subsite->delete();
foreach(DataObject::get('SubsiteDomain') as $domain) $domain->delete();
// Much more expressive than YML in this case
$subsite1 = $this->createSubsiteWithDomains(array(
'one.example.org' => true,
'one.*' => false,
));
$subsite2 = $this->createSubsiteWithDomains(array(
'two.mysite.com' => true,
'*.mysite.com' => false,
'subdomain.onmultiplesubsites.com' => false,
));
$subsite3 = $this->createSubsiteWithDomains(array(
'three.*' => true, // wildcards in primary domain are not recommended
'subdomain.unique.com' => false,
'*.onmultiplesubsites.com' => false,
));
$this->assertEquals(
$this->idFromFixture('Subsite','domaintest1'),
$subsite3->ID,
Subsite::getSubsiteIDForDomain('subdomain.unique.com'),
'Full unique match'
);
$this->assertEquals(
$subsite1->ID,
Subsite::getSubsiteIDForDomain('one.example.org'),
'Full match'
'Full match, doesn\'t complain about multiple matches within a single subsite'
);
$failed = false;
try {
Subsite::getSubsiteIDForDomain('subdomain.onmultiplesubsites.com');
} catch(UnexpectedValueException $e) {
$failed = true;
}
$this->assertTrue(
$failed,
'Fails on multiple matches with wildcard vs. www across multiple subsites'
);
$this->assertEquals(
$this->idFromFixture('Subsite','domaintest1'),
Subsite::getSubsiteIDForDomain('one.localhost'),
'Fuzzy match suffixed with asterisk (rule "one.*")'
$subsite1->ID,
Subsite::getSubsiteIDForDomain('one.unique.com'),
'Fuzzy match suffixed with wildcard (rule "one.*")'
);
$this->assertEquals(
$this->idFromFixture('Subsite','domaintest2'),
$subsite2->ID,
Subsite::getSubsiteIDForDomain('two.mysite.com'),
'Matches correct subsite for rule'
);
$this->assertEquals(
$this->idFromFixture('Subsite','domaintest2'),
$subsite2->ID,
Subsite::getSubsiteIDForDomain('other.mysite.com'),
'Fuzzy match prefixed with asterisk (rule "*.mysite.com")'
'Fuzzy match prefixed with wildcard (rule "*.mysite.com")'
);
$this->assertEquals(
@ -88,6 +139,90 @@ class SubsiteTest extends SapphireTest {
);
}
function testStrictSubdomainMatching() {
// Clear existing fixtures
foreach(DataObject::get('Subsite') as $subsite) $subsite->delete();
foreach(DataObject::get('SubsiteDomain') as $domain) $domain->delete();
// Much more expressive than YML in this case
$subsite1 = $this->createSubsiteWithDomains(array(
'example.org' => true,
'example.com' => false,
'*.wildcard.com' => false,
));
$subsite2 = $this->createSubsiteWithDomains(array(
'www.example.org' => true,
'www.wildcard.com' => false,
));
Subsite::$strict_subdomain_matching = false;
$this->assertEquals(
$subsite1->ID,
Subsite::getSubsiteIDForDomain('example.org'),
'Exact matches without strict checking when not using www prefix'
);
$this->assertEquals(
$subsite1->ID,
Subsite::getSubsiteIDForDomain('www.example.org'),
'Matches without strict checking when using www prefix, still matching first domain regardless of www prefix (falling back to subsite primary key ordering)'
);
$this->assertEquals(
$subsite1->ID,
Subsite::getSubsiteIDForDomain('www.example.com'),
'Fuzzy matches without strict checking with www prefix'
);
$this->assertEquals(
0,
Subsite::getSubsiteIDForDomain('www.wildcard.com'),
'Doesn\'t match www prefix without strict check, even if a wildcard subdomain is in place'
);
Subsite::$strict_subdomain_matching = true;
$this->assertEquals(
$subsite1->ID,
Subsite::getSubsiteIDForDomain('example.org'),
'Matches with strict checking when not using www prefix'
);
$this->assertEquals(
$subsite2->ID, // not 1
Subsite::getSubsiteIDForDomain('www.example.org'),
'Matches with strict checking when using www prefix'
);
$this->assertEquals(
0,
Subsite::getSubsiteIDForDomain('www.example.com'),
'Doesn\'t fuzzy match with strict checking when using www prefix'
);
$failed = false;
try {
Subsite::getSubsiteIDForDomain('www.wildcard.com');
} catch(UnexpectedValueException $e) {
$failed = true;
}
$this->assertTrue(
$failed,
'Fails on multiple matches with strict checking and wildcard vs. www'
);
}
protected function createSubsiteWithDomains($domains) {
$subsite = new Subsite();
$subsite->write();
foreach($domains as $domainStr => $isPrimary) {
$domain = new SubsiteDomain(array(
'Domain' => $domainStr,
'IsPrimary' => $isPrimary,
'SubsiteID' => $subsite->ID
));
$domain->write();
}
return $subsite;
}
/**
* Test the Subsite->domain() method