Implements configurable swift_owner_headers

These are headers that will be stripped unless the WSGI environment
contains a true value for 'swift_owner'. The exact definition of a
swift_owner is up to the auth system in use, but usually indicates
administrative responsibilities.

DocImpact

Change-Id: I972772fbbd235414e00130ca663428e8750cabca
This commit is contained in:
gholt 2013-06-27 14:11:25 +00:00 committed by Clay Gerrard
parent 716ad3e07b
commit 52eca4d8a7
7 changed files with 70 additions and 3 deletions

View File

@ -836,6 +836,13 @@ request_node_count 2 * replicas Set to the number of nodes to
given times the number of given times the number of
replicas for the ring being used replicas for the ring being used
for the request. for the request.
swift_owner_headers <see the sample These are the headers whose
conf file for values will only be shown to
the list of swift_owners. The exact
default definition of a swift_owner is
headers> up to the auth system in use,
but usually indicates
administrative responsibilities.
============================ =============== ============================= ============================ =============== =============================
[tempauth] [tempauth]

View File

@ -176,6 +176,11 @@ use = egg:swift#proxy
# times the number of replicas for the ring being used for the # times the number of replicas for the ring being used for the
# request. # request.
# write_affinity_node_count = 2 * replicas # write_affinity_node_count = 2 * replicas
#
# 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
# 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
[filter:tempauth] [filter:tempauth]

View File

@ -63,8 +63,12 @@ class AccountController(Controller):
content_type, error = account_listing_content_type(req) content_type, error = account_listing_content_type(req)
if error: if error:
return error return error
return account_listing_response(self.account_name, req, resp = account_listing_response(self.account_name, req,
content_type) content_type)
if not req.environ.get('swift_owner', False):
for key in self.app.swift_owner_headers:
if key in resp.headers:
del resp.headers[key]
return resp return resp
@public @public

View File

@ -82,8 +82,7 @@ class ContainerController(Controller):
if aresp: if aresp:
return aresp return aresp
if not req.environ.get('swift_owner', False): if not req.environ.get('swift_owner', False):
for key in ('x-container-read', 'x-container-write', for key in self.app.swift_owner_headers:
'x-container-sync-key', 'x-container-sync-to'):
if key in resp.headers: if key in resp.headers:
del resp.headers[key] del resp.headers[key]
return resp return resp

View File

@ -155,6 +155,14 @@ class Application(object):
else: else:
raise ValueError( raise ValueError(
'Invalid write_affinity_node_count value: %r' % ''.join(value)) 'Invalid write_affinity_node_count value: %r' % ''.join(value))
swift_owner_headers = conf.get(
'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')
self.swift_owner_headers = [
name.strip()
for name in swift_owner_headers.split(',') if name.strip()]
def get_controller(self, path): def get_controller(self, path):
""" """

View File

@ -40,6 +40,28 @@ class TestAccountController(unittest.TestCase):
self.assertEqual(headers_to_account_info(resp.headers), self.assertEqual(headers_to_account_info(resp.headers),
resp.environ['swift.account/AUTH_bob']) resp.environ['swift.account/AUTH_bob'])
def test_swift_owner(self):
owner_headers = {
'x-account-meta-temp-url-key': 'value',
'x-account-meta-temp-url-key-2': 'value'}
controller = proxy_server.AccountController(self.app, 'a')
req = Request.blank('/a')
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200, 200, headers=owner_headers)):
resp = controller.HEAD(req)
self.assertEquals(2, resp.status_int // 100)
for key in owner_headers:
self.assertTrue(key not in resp.headers)
req = Request.blank('/a', environ={'swift_owner': True})
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200, 200, headers=owner_headers)):
resp = controller.HEAD(req)
self.assertEquals(2, resp.status_int // 100)
for key in owner_headers:
self.assertTrue(key in resp.headers)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -40,6 +40,28 @@ class TestContainerController(unittest.TestCase):
self.assertEqual(headers_to_container_info(resp.headers), self.assertEqual(headers_to_container_info(resp.headers),
resp.environ['swift.container/a/c']) resp.environ['swift.container/a/c'])
def test_swift_owner(self):
owner_headers = {
'x-container-read': 'value', 'x-container-write': 'value',
'x-container-sync-key': 'value', 'x-container-sync-to': 'value'}
controller = proxy_server.ContainerController(self.app, 'a', 'c')
req = Request.blank('/a/c')
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200, 200, headers=owner_headers)):
resp = controller.HEAD(req)
self.assertEquals(2, resp.status_int // 100)
for key in owner_headers:
self.assertTrue(key not in resp.headers)
req = Request.blank('/a/c', environ={'swift_owner': True})
with mock.patch('swift.proxy.controllers.base.http_connect',
fake_http_connect(200, 200, headers=owner_headers)):
resp = controller.HEAD(req)
self.assertEquals(2, resp.status_int // 100)
for key in owner_headers:
self.assertTrue(key in resp.headers)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()