Merge "Pass empty etag override values through encrypter"

This commit is contained in:
Zuul 2018-10-11 08:07:36 +00:00 committed by Gerrit Code Review
commit 4ae9ce76e7
2 changed files with 103 additions and 6 deletions

View File

@ -146,12 +146,16 @@ class EncInputWrapper(object):
# * override in the footer, otherwise # * override in the footer, otherwise
# * override in the header, and finally # * override in the header, and finally
# * MD5 of the plaintext received # * MD5 of the plaintext received
# This may be None if no override was set and no data was read # This may be None if no override was set and no data was read. An
# override value of '' will be passed on.
container_listing_etag = footers.get( container_listing_etag = footers.get(
'X-Object-Sysmeta-Container-Update-Override-Etag', 'X-Object-Sysmeta-Container-Update-Override-Etag',
container_listing_etag_header) or plaintext_etag container_listing_etag_header)
if (container_listing_etag is not None and if container_listing_etag is None:
container_listing_etag = plaintext_etag
if (container_listing_etag and
(container_listing_etag != MD5_OF_EMPTY_STRING or (container_listing_etag != MD5_OF_EMPTY_STRING or
plaintext_etag)): plaintext_etag)):
# Encrypt the container-listing etag using the container key # Encrypt the container-listing etag using the container key

View File

@ -227,7 +227,6 @@ class TestEncrypter(unittest.TestCase):
def _test_PUT_with_other_footers(self, override_etag): def _test_PUT_with_other_footers(self, override_etag):
# verify handling of another middleware's footer callback # verify handling of another middleware's footer callback
cont_key = fetch_crypto_keys()['container']
body_key = os.urandom(32) body_key = os.urandom(32)
object_key = fetch_crypto_keys()['object'] object_key = fetch_crypto_keys()['object']
plaintext = 'FAKE APP' plaintext = 'FAKE APP'
@ -324,7 +323,7 @@ class TestEncrypter(unittest.TestCase):
def test_PUT_with_other_footers(self): def test_PUT_with_other_footers(self):
self._test_PUT_with_other_footers('override etag') self._test_PUT_with_other_footers('override etag')
def test_PUT_with_other_footers_and_empty_etag(self): def test_PUT_with_other_footers_and_etag_of_empty_body(self):
# verify that an override etag value of EMPTY_ETAG will be encrypted # verify that an override etag value of EMPTY_ETAG will be encrypted
# when there was a non-zero body length # when there was a non-zero body length
self._test_PUT_with_other_footers(EMPTY_ETAG) self._test_PUT_with_other_footers(EMPTY_ETAG)
@ -380,11 +379,82 @@ class TestEncrypter(unittest.TestCase):
def test_PUT_with_etag_override_in_headers(self): def test_PUT_with_etag_override_in_headers(self):
self._test_PUT_with_etag_override_in_headers('override_etag') self._test_PUT_with_etag_override_in_headers('override_etag')
def test_PUT_with_etag_override_in_headers_and_empty_etag(self): def test_PUT_with_etag_of_empty_body_override_in_headers(self):
# verify that an override etag value of EMPTY_ETAG will be encrypted # verify that an override etag value of EMPTY_ETAG will be encrypted
# when there was a non-zero body length # when there was a non-zero body length
self._test_PUT_with_etag_override_in_headers(EMPTY_ETAG) self._test_PUT_with_etag_override_in_headers(EMPTY_ETAG)
def _test_PUT_with_empty_etag_override_in_headers(self, plaintext):
# verify that an override etag value of '' from other middleware is
# passed through unencrypted
plaintext_etag = md5hex(plaintext)
override_etag = ''
env = {'REQUEST_METHOD': 'PUT',
CRYPTO_KEY_CALLBACK: fetch_crypto_keys}
hdrs = {'content-type': 'text/plain',
'content-length': str(len(plaintext)),
'Etag': plaintext_etag,
'X-Object-Sysmeta-Container-Update-Override-Etag':
override_etag}
req = Request.blank(
'/v1/a/c/o', environ=env, body=plaintext, headers=hdrs)
self.app.register('PUT', '/v1/a/c/o', HTTPCreated, {})
resp = req.get_response(self.encrypter)
self.assertEqual('201 Created', resp.status)
self.assertEqual(plaintext_etag, resp.headers['Etag'])
self.assertEqual(1, len(self.app.calls), self.app.calls)
self.assertEqual(('PUT', '/v1/a/c/o'), self.app.calls[0])
req_hdrs = self.app.headers[0]
self.assertIn(
'X-Object-Sysmeta-Container-Update-Override-Etag', req_hdrs)
self.assertEqual(
override_etag,
req_hdrs['X-Object-Sysmeta-Container-Update-Override-Etag'])
def test_PUT_with_empty_etag_override_in_headers(self):
self._test_PUT_with_empty_etag_override_in_headers('body')
def test_PUT_with_empty_etag_override_in_headers_no_body(self):
self._test_PUT_with_empty_etag_override_in_headers('')
def _test_PUT_with_empty_etag_override_in_footers(self, plaintext):
# verify that an override etag value of '' from other middleware is
# passed through unencrypted
plaintext_etag = md5hex(plaintext)
override_etag = ''
other_footers = {
'X-Object-Sysmeta-Container-Update-Override-Etag': override_etag}
env = {'REQUEST_METHOD': 'PUT',
CRYPTO_KEY_CALLBACK: fetch_crypto_keys,
'swift.callback.update_footers':
lambda footers: footers.update(other_footers)}
hdrs = {'content-type': 'text/plain',
'content-length': str(len(plaintext)),
'Etag': plaintext_etag}
req = Request.blank(
'/v1/a/c/o', environ=env, body=plaintext, headers=hdrs)
self.app.register('PUT', '/v1/a/c/o', HTTPCreated, {})
resp = req.get_response(self.encrypter)
self.assertEqual('201 Created', resp.status)
self.assertEqual(plaintext_etag, resp.headers['Etag'])
self.assertEqual(1, len(self.app.calls), self.app.calls)
self.assertEqual(('PUT', '/v1/a/c/o'), self.app.calls[0])
req_hdrs = self.app.headers[0]
self.assertIn(
'X-Object-Sysmeta-Container-Update-Override-Etag', req_hdrs)
self.assertEqual(
override_etag,
req_hdrs['X-Object-Sysmeta-Container-Update-Override-Etag'])
def test_PUT_with_empty_etag_override_in_footers(self):
self._test_PUT_with_empty_etag_override_in_footers('body')
def test_PUT_with_empty_etag_override_in_footers_no_body(self):
self._test_PUT_with_empty_etag_override_in_footers('')
def test_PUT_with_bad_etag_in_other_footers(self): def test_PUT_with_bad_etag_in_other_footers(self):
# verify that etag supplied in footers from other middleware overrides # verify that etag supplied in footers from other middleware overrides
# header etag when validating inbound plaintext etags # header etag when validating inbound plaintext etags
@ -531,6 +601,29 @@ class TestEncrypter(unittest.TestCase):
for k in call_headers[0]: for k in call_headers[0]:
self.assertFalse(k.lower().startswith('x-object-sysmeta-crypto-')) self.assertFalse(k.lower().startswith('x-object-sysmeta-crypto-'))
# if upstream footer override etag is an empty string then check that
# it is not encrypted
other_footers = {
'Etag': EMPTY_ETAG,
'X-Object-Sysmeta-Container-Update-Override-Etag': ''}
env.update({'swift.callback.update_footers':
lambda footers: footers.update(other_footers)})
req = Request.blank('/v1/a/c/o', environ=env, body='', headers=hdrs)
call_headers = []
resp = req.get_response(encrypter.Encrypter(NonReadingApp(), {}))
self.assertEqual('201 Created', resp.status)
self.assertEqual('response etag', resp.headers['Etag'])
self.assertEqual(1, len(call_headers))
# verify that other middleware's footers made it to app
for k, v in other_footers.items():
self.assertEqual(v, call_headers[0][k])
# verify no encryption footers
for k in call_headers[0]:
self.assertFalse(k.lower().startswith('x-object-sysmeta-crypto-'))
def test_POST_req(self): def test_POST_req(self):
body = 'FAKE APP' body = 'FAKE APP'
env = {'REQUEST_METHOD': 'POST', env = {'REQUEST_METHOD': 'POST',