Add support for container TempURL Keys

Change-Id: Ic22b0b84b657e6cac7e0062fa410eefb09bc0f4d
Co-Authored-By: Christian Schwede <christian.schwede@enovance.com>
This commit is contained in:
Richard Hawkins
2015-02-09 17:51:01 -06:00
committed by Christian Schwede
parent b54532ca05
commit 489dd5ff5d
6 changed files with 128 additions and 21 deletions

View File

@@ -203,7 +203,7 @@ use = egg:swift#proxy
# These are the headers whose values will only be shown to swift_owners. The # These are the headers whose values will only be shown to swift_owners. The
# exact definition of a swift_owner is up to the auth system in use, but # exact definition of a swift_owner is up to the auth system in use, but
# usually indicates administrative responsibilities. # usually indicates administrative responsibilities.
# swift_owner_headers = x-container-read, x-container-write, x-container-sync-key, x-container-sync-to, x-account-meta-temp-url-key, x-account-meta-temp-url-key-2, x-account-access-control # swift_owner_headers = x-container-read, x-container-write, x-container-sync-key, x-container-sync-to, x-account-meta-temp-url-key, x-account-meta-temp-url-key-2, x-container-meta-temp-url-key, x-container-meta-temp-url-key-2, x-account-access-control
[filter:tempauth] [filter:tempauth]
use = egg:swift#tempauth use = egg:swift#tempauth

View File

@@ -90,8 +90,9 @@ sample code for computing the signature::
max_file_size, max_file_count, expires) max_file_size, max_file_count, expires)
signature = hmac.new(key, hmac_body, sha1).hexdigest() signature = hmac.new(key, hmac_body, sha1).hexdigest()
The key is the value of either the X-Account-Meta-Temp-URL-Key or the The key is the value of either the account (X-Account-Meta-Temp-URL-Key,
X-Account-Meta-Temp-Url-Key-2 header on the account. X-Account-Meta-Temp-Url-Key-2) or the container
(X-Container-Meta-Temp-URL-Key, X-Container-Meta-Temp-Url-Key-2) TempURL keys.
Be certain to use the full path, from the /v1/ onward. Be certain to use the full path, from the /v1/ onward.
Note that x_delete_at and x_delete_after are not used in signature generation Note that x_delete_at and x_delete_after are not used in signature generation
@@ -123,7 +124,7 @@ from swift.common.utils import streq_const_time, register_swift_info, \
parse_content_disposition, iter_multipart_mime_documents parse_content_disposition, iter_multipart_mime_documents
from swift.common.wsgi import make_pre_authed_env from swift.common.wsgi import make_pre_authed_env
from swift.common.swob import HTTPUnauthorized from swift.common.swob import HTTPUnauthorized
from swift.proxy.controllers.base import get_account_info from swift.proxy.controllers.base import get_account_info, get_container_info
#: The size of data to read from the form at any given time. #: The size of data to read from the form at any given time.
@@ -393,7 +394,13 @@ class FormPost(object):
def _get_keys(self, env): def _get_keys(self, env):
""" """
Fetch the tempurl keys for the account. Also validate that the request Returns the X-[Account|Container]-Meta-Temp-URL-Key[-2] header values
for the account or container, or an empty list if none are set.
Returns 0-4 elements depending on how many keys are set in the
account's or container's metadata.
Also validate that the request
path indicates a valid container; if not, no keys will be returned. path indicates a valid container; if not, no keys will be returned.
:param env: The WSGI environment for the request. :param env: The WSGI environment for the request.
@@ -405,12 +412,20 @@ class FormPost(object):
return [] return []
account_info = get_account_info(env, self.app, swift_source='FP') account_info = get_account_info(env, self.app, swift_source='FP')
return get_tempurl_keys_from_metadata(account_info['meta']) account_keys = get_tempurl_keys_from_metadata(account_info['meta'])
container_info = get_container_info(env, self.app, swift_source='FP')
container_keys = get_tempurl_keys_from_metadata(
container_info.get('meta', []))
return account_keys + container_keys
def filter_factory(global_conf, **local_conf): def filter_factory(global_conf, **local_conf):
"""Returns the WSGI filter for use with paste.deploy.""" """Returns the WSGI filter for use with paste.deploy."""
conf = global_conf.copy() conf = global_conf.copy()
conf.update(local_conf) conf.update(local_conf)
register_swift_info('formpost') register_swift_info('formpost')
return lambda app: FormPost(app, conf) return lambda app: FormPost(app, conf)

View File

@@ -81,10 +81,13 @@ Using this in combination with browser form post translation
middleware could also allow direct-from-browser uploads to specific middleware could also allow direct-from-browser uploads to specific
locations in Swift. locations in Swift.
TempURL supports up to two keys, specified by X-Account-Meta-Temp-URL-Key and TempURL supports both account and container level keys. Each allows up to two
X-Account-Meta-Temp-URL-Key-2. Signatures are checked against both keys, if keys to be set, allowing key rotation without invalidating all existing
present. This is to allow for key rotation without invalidating all existing temporary URLs. Account keys are specified by X-Account-Meta-Temp-URL-Key and
temporary URLs. X-Account-Meta-Temp-URL-Key-2, while container keys are specified by
X-Container-Meta-Temp-URL-Key and X-Container-Meta-Temp-URL-Key-2.
Signatures are checked against account and container keys, if
present.
With GET TempURLs, a Content-Disposition header will be set on the With GET TempURLs, a Content-Disposition header will be set on the
response so that browsers will interpret this as a file attachment to response so that browsers will interpret this as a file attachment to
@@ -118,7 +121,7 @@ from time import time
from urllib import urlencode from urllib import urlencode
from urlparse import parse_qs from urlparse import parse_qs
from swift.proxy.controllers.base import get_account_info from swift.proxy.controllers.base import get_account_info, get_container_info
from swift.common.swob import HeaderKeyDict, HTTPUnauthorized from swift.common.swob import HeaderKeyDict, HTTPUnauthorized
from swift.common.utils import split_path, get_valid_utf8_str, \ from swift.common.utils import split_path, get_valid_utf8_str, \
register_swift_info, get_hmac, streq_const_time, quote register_swift_info, get_hmac, streq_const_time, quote
@@ -409,11 +412,11 @@ class TempURL(object):
def _get_keys(self, env, account): def _get_keys(self, env, account):
""" """
Returns the X-Account-Meta-Temp-URL-Key[-2] header values for the Returns the X-[Account|Container]-Meta-Temp-URL-Key[-2] header values
account, or an empty list if none is set. for the account or container, or an empty list if none are set.
Returns 0, 1, or 2 elements depending on how many keys are set Returns 0-4 elements depending on how many keys are set in the
in the account's metadata. account's or container's metadata.
:param env: The WSGI environment for the request. :param env: The WSGI environment for the request.
:param account: Account str. :param account: Account str.
@@ -421,7 +424,13 @@ class TempURL(object):
X-Account-Meta-Temp-URL-Key-2 str value if set] X-Account-Meta-Temp-URL-Key-2 str value if set]
""" """
account_info = get_account_info(env, self.app, swift_source='TU') account_info = get_account_info(env, self.app, swift_source='TU')
return get_tempurl_keys_from_metadata(account_info['meta']) account_keys = get_tempurl_keys_from_metadata(account_info['meta'])
container_info = get_container_info(env, self.app, swift_source='TU')
container_keys = get_tempurl_keys_from_metadata(
container_info.get('meta', []))
return account_keys + container_keys
def _get_hmacs(self, env, expires, keys, request_method=None): def _get_hmacs(self, env, expires, keys, request_method=None):
""" """

View File

@@ -186,6 +186,7 @@ class Application(object):
'x-container-read, x-container-write, ' 'x-container-read, x-container-write, '
'x-container-sync-key, x-container-sync-to, ' 'x-container-sync-key, x-container-sync-to, '
'x-account-meta-temp-url-key, x-account-meta-temp-url-key-2, ' 'x-account-meta-temp-url-key, x-account-meta-temp-url-key-2, '
'x-container-meta-temp-url-key, x-container-meta-temp-url-key-2, '
'x-account-access-control') 'x-account-access-control')
self.swift_owner_headers = [ self.swift_owner_headers = [
name.strip().title() name.strip().title()

View File

@@ -345,6 +345,7 @@ class TestFormPost(unittest.TestCase):
'SERVER_PROTOCOL': 'HTTP/1.0', 'SERVER_PROTOCOL': 'HTTP/1.0',
'swift.account/AUTH_test': self._fake_cache_env( 'swift.account/AUTH_test': self._fake_cache_env(
'AUTH_test', [key]), 'AUTH_test', [key]),
'swift.container/AUTH_test/container': {'meta': {}},
'wsgi.errors': wsgi_errors, 'wsgi.errors': wsgi_errors,
'wsgi.input': wsgi_input, 'wsgi.input': wsgi_input,
'wsgi.multiprocess': False, 'wsgi.multiprocess': False,
@@ -457,6 +458,7 @@ class TestFormPost(unittest.TestCase):
'SERVER_PROTOCOL': 'HTTP/1.0', 'SERVER_PROTOCOL': 'HTTP/1.0',
'swift.account/AUTH_test': self._fake_cache_env( 'swift.account/AUTH_test': self._fake_cache_env(
'AUTH_test', [key]), 'AUTH_test', [key]),
'swift.container/AUTH_test/container': {'meta': {}},
'wsgi.errors': wsgi_errors, 'wsgi.errors': wsgi_errors,
'wsgi.input': wsgi_input, 'wsgi.input': wsgi_input,
'wsgi.multiprocess': False, 'wsgi.multiprocess': False,
@@ -572,6 +574,7 @@ class TestFormPost(unittest.TestCase):
'SERVER_PROTOCOL': 'HTTP/1.0', 'SERVER_PROTOCOL': 'HTTP/1.0',
'swift.account/AUTH_test': self._fake_cache_env( 'swift.account/AUTH_test': self._fake_cache_env(
'AUTH_test', [key]), 'AUTH_test', [key]),
'swift.container/AUTH_test/container': {'meta': {}},
'wsgi.errors': wsgi_errors, 'wsgi.errors': wsgi_errors,
'wsgi.input': wsgi_input, 'wsgi.input': wsgi_input,
'wsgi.multiprocess': False, 'wsgi.multiprocess': False,
@@ -683,6 +686,7 @@ class TestFormPost(unittest.TestCase):
'SERVER_PROTOCOL': 'HTTP/1.0', 'SERVER_PROTOCOL': 'HTTP/1.0',
'swift.account/AUTH_test': self._fake_cache_env( 'swift.account/AUTH_test': self._fake_cache_env(
'AUTH_test', [key]), 'AUTH_test', [key]),
'swift.container/AUTH_test/container': {'meta': {}},
'wsgi.errors': wsgi_errors, 'wsgi.errors': wsgi_errors,
'wsgi.input': wsgi_input, 'wsgi.input': wsgi_input,
'wsgi.multiprocess': False, 'wsgi.multiprocess': False,
@@ -728,6 +732,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('XX' + '\r\n'.join(body)) env['wsgi.input'] = StringIO('XX' + '\r\n'.join(body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -763,6 +768,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('\r\n'.join(body)) env['wsgi.input'] = StringIO('\r\n'.join(body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -793,6 +799,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('\r\n'.join(body)) env['wsgi.input'] = StringIO('\r\n'.join(body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -833,6 +840,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('\r\n'.join(body)) env['wsgi.input'] = StringIO('\r\n'.join(body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp( self.app = FakeApp(
iter([('201 Created', {}, ''), iter([('201 Created', {}, ''),
('201 Created', {}, '')]), ('201 Created', {}, '')]),
@@ -867,6 +875,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('\r\n'.join(body)) env['wsgi.input'] = StringIO('\r\n'.join(body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('404 Not Found', {}, ''), self.app = FakeApp(iter([('404 Not Found', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -949,6 +958,7 @@ class TestFormPost(unittest.TestCase):
])) ]))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -1016,6 +1026,7 @@ class TestFormPost(unittest.TestCase):
])) ]))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -1055,6 +1066,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('\r\n'.join(body)) env['wsgi.input'] = StringIO('\r\n'.join(body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -1075,6 +1087,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('\r\n'.join(body)) env['wsgi.input'] = StringIO('\r\n'.join(body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
env['HTTP_ORIGIN'] = 'http://localhost:5000' env['HTTP_ORIGIN'] = 'http://localhost:5000'
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', ('201 Created',
@@ -1103,6 +1116,43 @@ class TestFormPost(unittest.TestCase):
# Stick it in X-Account-Meta-Temp-URL-Key-2 and make sure we get it # Stick it in X-Account-Meta-Temp-URL-Key-2 and make sure we get it
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', ['bert', key]) 'AUTH_test', ['bert', key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app)
self.formpost = formpost.filter_factory({})(self.auth)
status = [None]
headers = [None]
def start_response(s, h, e=None):
status[0] = s
headers[0] = h
body = ''.join(self.formpost(env, start_response))
self.assertEqual('303 See Other', status[0])
self.assertEqual(
'http://redirect?status=201&message=',
dict(headers[0]).get('Location'))
def test_formpost_with_multiple_container_keys(self):
first_key = 'ernie'
second_key = 'bert'
keys = [first_key, second_key]
meta = {}
for idx, key in enumerate(keys):
meta_name = 'temp-url-key' + ("-%d" % (idx + 1) if idx else "")
if key:
meta[meta_name] = key
for key in keys:
sig, env, body = self._make_sig_env_body(
'/v1/AUTH_test/container', 'http://redirect', 1024, 10,
int(time() + 86400), key)
env['wsgi.input'] = StringIO('\r\n'.join(body))
env['swift.account/AUTH_test'] = self._fake_cache_env('AUTH_test')
# Stick it in X-Container-Meta-Temp-URL-Key-2 and ensure we get it
env['swift.container/AUTH_test/container'] = {'meta': meta}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -1128,6 +1178,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('\r\n'.join(body)) env['wsgi.input'] = StringIO('\r\n'.join(body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -1165,6 +1216,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('\r\n'.join(body)) env['wsgi.input'] = StringIO('\r\n'.join(body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -1202,6 +1254,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('\r\n'.join(body)) env['wsgi.input'] = StringIO('\r\n'.join(body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -1550,6 +1603,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('\r\n'.join(x_delete_body_part + body)) env['wsgi.input'] = StringIO('\r\n'.join(x_delete_body_part + body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)
@@ -1625,6 +1679,7 @@ class TestFormPost(unittest.TestCase):
env['wsgi.input'] = StringIO('\r\n'.join(x_delete_body_part + body)) env['wsgi.input'] = StringIO('\r\n'.join(x_delete_body_part + body))
env['swift.account/AUTH_test'] = self._fake_cache_env( env['swift.account/AUTH_test'] = self._fake_cache_env(
'AUTH_test', [key]) 'AUTH_test', [key])
env['swift.container/AUTH_test/container'] = {'meta': {}}
self.app = FakeApp(iter([('201 Created', {}, ''), self.app = FakeApp(iter([('201 Created', {}, ''),
('201 Created', {}, '')])) ('201 Created', {}, '')]))
self.auth = tempauth.filter_factory({})(self.app) self.auth = tempauth.filter_factory({})(self.app)

View File

@@ -97,6 +97,9 @@ class TestTempURL(unittest.TestCase):
'bytes': '0', 'bytes': '0',
'meta': meta} 'meta': meta}
container_cache_key = 'swift.container/' + account + '/c'
environ.setdefault(container_cache_key, {'meta': {}})
def test_passthrough(self): def test_passthrough(self):
resp = self._make_request('/v1/a/c/o').get_response(self.tempurl) resp = self._make_request('/v1/a/c/o').get_response(self.tempurl)
self.assertEquals(resp.status_int, 401) self.assertEquals(resp.status_int, 401)
@@ -109,11 +112,12 @@ class TestTempURL(unittest.TestCase):
environ={'REQUEST_METHOD': 'OPTIONS'}).get_response(self.tempurl) environ={'REQUEST_METHOD': 'OPTIONS'}).get_response(self.tempurl)
self.assertEquals(resp.status_int, 200) self.assertEquals(resp.status_int, 200)
def assert_valid_sig(self, expires, path, keys, sig): def assert_valid_sig(self, expires, path, keys, sig, environ=None):
req = self._make_request( if not environ:
path, keys=keys, environ = {}
environ={'QUERY_STRING': environ['QUERY_STRING'] = 'temp_url_sig=%s&temp_url_expires=%s' % (
'temp_url_sig=%s&temp_url_expires=%s' % (sig, expires)}) sig, expires)
req = self._make_request(path, keys=keys, environ=environ)
self.tempurl.app = FakeApp(iter([('200 Ok', (), '123')])) self.tempurl.app = FakeApp(iter([('200 Ok', (), '123')]))
resp = req.get_response(self.tempurl) resp = req.get_response(self.tempurl)
self.assertEquals(resp.status_int, 200) self.assertEquals(resp.status_int, 200)
@@ -143,6 +147,29 @@ class TestTempURL(unittest.TestCase):
for sig in (sig1, sig2): for sig in (sig1, sig2):
self.assert_valid_sig(expires, path, [key1, key2], sig) self.assert_valid_sig(expires, path, [key1, key2], sig)
def test_get_valid_container_keys(self):
environ = {}
# Add two static container keys
container_keys = ['me', 'other']
meta = {}
for idx, key in enumerate(container_keys):
meta_name = 'Temp-URL-key' + (("-%d" % (idx + 1) if idx else ""))
if key:
meta[meta_name] = key
environ['swift.container/a/c'] = {'meta': meta}
method = 'GET'
expires = int(time() + 86400)
path = '/v1/a/c/o'
key1 = 'me'
key2 = 'other'
hmac_body = '%s\n%s\n%s' % (method, expires, path)
sig1 = hmac.new(key1, hmac_body, sha1).hexdigest()
sig2 = hmac.new(key2, hmac_body, sha1).hexdigest()
account_keys = []
for sig in (sig1, sig2):
self.assert_valid_sig(expires, path, account_keys, sig, environ)
def test_get_valid_with_filename(self): def test_get_valid_with_filename(self):
method = 'GET' method = 'GET'
expires = int(time() + 86400) expires = int(time() + 86400)