changed domain_remap to use an exclusive list in reseller_prefixes. added tests

This commit is contained in:
John Dickinson 2011-01-24 13:24:47 -06:00
parent 643476c3b0
commit 918d5feaa8
2 changed files with 64 additions and 26 deletions

View File

@ -28,9 +28,23 @@ class DomainRemapMiddleware(object):
account.storageurl/path_root/container/object gets translated to account.storageurl/path_root/container/object gets translated to
account.storageurl/path_root/account/container/object account.storageurl/path_root/account/container/object
Browsers can convert a url to lowercase, so check that reseller_prefix Browsers can convert a host header to lowercase, so check that reseller
is the correct case and fix if necessary prefix on the account is the correct case. This is done by comparing the
items in the reseller_prefixes config option to the found prefix. If they
match except for case, the item from reseller_prefixes will be used
instead of the found reseller prefix. The reseller_prefixes list is
exclusive. If defined, any request with an account prefix not in that list
will be ignored by this middleware. reseller_prefixes defaults to 'AUTH'.
Note that this middleware requires that container names and account names
(except as described above) must be DNS-compatible. This means that the
account name created in the system and the containers created by users
cannot exceede 63 characters or have UTF-8 characters. These are
restrictions over and above what swift requires and are not explicitly
checked. Simply put, the this middleware will do a best-effort attempt to
derive account and container names from elements in the domain name and
put those derived values into the URL path (leaving the Host header
unchanged).
""" """
def __init__(self, app, conf): def __init__(self, app, conf):
@ -39,7 +53,11 @@ class DomainRemapMiddleware(object):
if self.storage_domain and self.storage_domain[0] != '.': if self.storage_domain and self.storage_domain[0] != '.':
self.storage_domain = '.' + self.storage_domain self.storage_domain = '.' + self.storage_domain
self.path_root = conf.get('path_root', 'v1').strip('/') self.path_root = conf.get('path_root', 'v1').strip('/')
self.reseller_prefixes = conf.get('reseller_prefixes','AUTH').split(','); prefixes = conf.get('reseller_prefixes', 'AUTH')
self.reseller_prefixes = [x.strip() for x in prefixes.split(',')
if x.strip()]
self.reseller_prefixes_lower = [x.lower()
for x in self.reseller_prefixes]
def __call__(self, env, start_response): def __call__(self, env, start_response):
if not self.storage_domain: if not self.storage_domain:
@ -63,12 +81,16 @@ class DomainRemapMiddleware(object):
return resp(env, start_response) return resp(env, start_response)
if '_' not in account and '-' in account: if '_' not in account and '-' in account:
account = account.replace('-', '_', 1) account = account.replace('-', '_', 1)
for reseller_prefix in self.reseller_prefixes: account_reseller_prefix = account.split('_', 1)[0].lower()
if account.lower().startswith(reseller_prefix.lower()): if account_reseller_prefix not in self.reseller_prefixes_lower:
if not account.startswith(reseller_prefix): # account prefix is not in config list. bail.
account_suffix = account[len(reseller_prefix):] return self.app(env, start_response)
account = reseller_prefix + account_suffix prefix_index = self.reseller_prefixes_lower.index(
break account_reseller_prefix)
real_prefix = self.reseller_prefixes[prefix_index]
if not account.startswith(real_prefix):
account_suffix = account[len(real_prefix):]
account = real_prefix + account_suffix
path = env['PATH_INFO'].strip('/') path = env['PATH_INFO'].strip('/')
new_path_parts = ['', self.path_root, account] new_path_parts = ['', self.path_root, account]
if container: if container:

View File

@ -47,49 +47,49 @@ class TestDomainRemap(unittest.TestCase):
def test_domain_remap_account(self): def test_domain_remap_account(self):
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'}, req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'},
headers={'Host': 'a.example.com'}) headers={'Host': 'AUTH_a.example.com'})
resp = self.app(req.environ, start_response) resp = self.app(req.environ, start_response)
self.assertEquals(resp, '/v1/a') self.assertEquals(resp, '/v1/AUTH_a')
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'}, req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'},
headers={'Host': 'a-uuid.example.com'}) headers={'Host': 'AUTH-uuid.example.com'})
resp = self.app(req.environ, start_response) resp = self.app(req.environ, start_response)
self.assertEquals(resp, '/v1/a_uuid') self.assertEquals(resp, '/v1/AUTH_uuid')
def test_domain_remap_account_container(self): def test_domain_remap_account_container(self):
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'}, req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'},
headers={'Host': 'c.a.example.com'}) headers={'Host': 'c.AUTH_a.example.com'})
resp = self.app(req.environ, start_response) resp = self.app(req.environ, start_response)
self.assertEquals(resp, '/v1/a/c') self.assertEquals(resp, '/v1/AUTH_a/c')
def test_domain_remap_extra_subdomains(self): def test_domain_remap_extra_subdomains(self):
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'}, req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'},
headers={'Host': 'x.y.c.a.example.com'}) headers={'Host': 'x.y.c.AUTH_a.example.com'})
resp = self.app(req.environ, start_response) resp = self.app(req.environ, start_response)
self.assertEquals(resp, ['Bad domain in host header']) self.assertEquals(resp, ['Bad domain in host header'])
def test_domain_remap_account_with_path_root(self): def test_domain_remap_account_with_path_root(self):
req = Request.blank('/v1', environ={'REQUEST_METHOD': 'GET'}, req = Request.blank('/v1', environ={'REQUEST_METHOD': 'GET'},
headers={'Host': 'a.example.com'}) headers={'Host': 'AUTH_a.example.com'})
resp = self.app(req.environ, start_response) resp = self.app(req.environ, start_response)
self.assertEquals(resp, '/v1/a') self.assertEquals(resp, '/v1/AUTH_a')
def test_domain_remap_account_container_with_path_root(self): def test_domain_remap_account_container_with_path_root(self):
req = Request.blank('/v1', environ={'REQUEST_METHOD': 'GET'}, req = Request.blank('/v1', environ={'REQUEST_METHOD': 'GET'},
headers={'Host': 'c.a.example.com'}) headers={'Host': 'c.AUTH_a.example.com'})
resp = self.app(req.environ, start_response) resp = self.app(req.environ, start_response)
self.assertEquals(resp, '/v1/a/c') self.assertEquals(resp, '/v1/AUTH_a/c')
def test_domain_remap_account_container_with_path(self): def test_domain_remap_account_container_with_path(self):
req = Request.blank('/obj', environ={'REQUEST_METHOD': 'GET'}, req = Request.blank('/obj', environ={'REQUEST_METHOD': 'GET'},
headers={'Host': 'c.a.example.com'}) headers={'Host': 'c.AUTH_a.example.com'})
resp = self.app(req.environ, start_response) resp = self.app(req.environ, start_response)
self.assertEquals(resp, '/v1/a/c/obj') self.assertEquals(resp, '/v1/AUTH_a/c/obj')
def test_domain_remap_account_container_with_path_root_and_path(self): def test_domain_remap_account_container_with_path_root_and_path(self):
req = Request.blank('/v1/obj', environ={'REQUEST_METHOD': 'GET'}, req = Request.blank('/v1/obj', environ={'REQUEST_METHOD': 'GET'},
headers={'Host': 'c.a.example.com'}) headers={'Host': 'c.AUTH_a.example.com'})
resp = self.app(req.environ, start_response) resp = self.app(req.environ, start_response)
self.assertEquals(resp, '/v1/a/c/obj') self.assertEquals(resp, '/v1/AUTH_a/c/obj')
def test_domain_remap_account_matching_ending_not_domain(self): def test_domain_remap_account_matching_ending_not_domain(self):
req = Request.blank('/dontchange', environ={'REQUEST_METHOD': 'GET'}, req = Request.blank('/dontchange', environ={'REQUEST_METHOD': 'GET'},
@ -101,7 +101,23 @@ class TestDomainRemap(unittest.TestCase):
self.app = domain_remap.DomainRemapMiddleware(FakeApp(), self.app = domain_remap.DomainRemapMiddleware(FakeApp(),
{'storage_domain': ''}) {'storage_domain': ''})
req = Request.blank('/test', environ={'REQUEST_METHOD': 'GET'}, req = Request.blank('/test', environ={'REQUEST_METHOD': 'GET'},
headers={'Host': 'c.a.example.com'}) headers={'Host': 'c.AUTH_a.example.com'})
resp = self.app(req.environ, start_response)
self.assertEquals(resp, '/test')
def test_domain_remap_configured_with_prefixes(self):
conf = {'reseller_prefixes': 'PREFIX'}
self.app = domain_remap.DomainRemapMiddleware(FakeApp(), conf)
req = Request.blank('/test', environ={'REQUEST_METHOD': 'GET'},
headers={'Host': 'c.prefix_uuid.example.com'})
resp = self.app(req.environ, start_response)
self.assertEquals(resp, '/v1/PREFIX_uuid/c/test')
def test_domain_remap_configured_with_bad_prefixes(self):
conf = {'reseller_prefixes': 'UNKNOWN'}
self.app = domain_remap.DomainRemapMiddleware(FakeApp(), conf)
req = Request.blank('/test', environ={'REQUEST_METHOD': 'GET'},
headers={'Host': 'c.prefix_uuid.example.com'})
resp = self.app(req.environ, start_response) resp = self.app(req.environ, start_response)
self.assertEquals(resp, '/test') self.assertEquals(resp, '/test')