From 2f273a58a77e36dfa8a215c6fa31036fb9e29ab4 Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Tue, 3 May 2016 17:56:20 -0700 Subject: [PATCH] Perform authorization check before copying old version Previously, versioned_writes would perform pre-authed requests to copy the old object (if one exists) to the versions container, even when the user was not allowed to write to a versioned container. Now, we'll perform an auth check before doing any copying, similar to what's done when deleting an object. Change-Id: I8a46c917884209bc20a52a46df1fbc38da62a492 Closes-Bug: 1562175 --- swift/common/middleware/versioned_writes.py | 15 ++++++++++---- .../common/middleware/test_versioned_writes.py | 23 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/swift/common/middleware/versioned_writes.py b/swift/common/middleware/versioned_writes.py index 5d6c4ca..9d62f1b 100644 --- a/swift/common/middleware/versioned_writes.py +++ b/swift/common/middleware/versioned_writes.py @@ -311,6 +311,16 @@ class VersionedWritesContext(WSGIContext): :param account_name: account name. :param object_name: name of object of original request """ + if 'swift.authorize' in req.environ: + container_info = get_container_info( + req.environ, self.app) + req.acl = container_info.get('write_acl') + aresp = req.environ['swift.authorize'](req) + if aresp: + return aresp + req.environ['swift.authorize'] = lambda req: None + req.environ['swift.authorize_override'] = True + if 'X-Object-Manifest' in req.headers: # do not version DLO manifest, proceed with original request return self.app @@ -532,10 +542,7 @@ class VersionedWritesMiddleware(object): return self.app def __call__(self, env, start_response): - # making a duplicate, because if this is a COPY request, we will - # modify the PATH_INFO to find out if the 'Destination' is in a - # versioned container - req = Request(env.copy()) + req = Request(env) try: (api_version, account, container, obj) = req.split_path(3, 4, True) except ValueError: diff --git a/test/unit/common/middleware/test_versioned_writes.py b/test/unit/common/middleware/test_versioned_writes.py index c997fbd..72990f4 100644 --- a/test/unit/common/middleware/test_versioned_writes.py +++ b/test/unit/common/middleware/test_versioned_writes.py @@ -679,6 +679,29 @@ class VersionedWritesTestCase(VersionedWritesBaseTestCase): ('GET', prefix_listing_prefix + 'marker=&reverse=on'), ]) + def test_denied_PUT_of_versioned_object(self): + authorize_call = [] + + def fake_authorize(req): + # we should deny the object PUT + authorize_call.append(req) + return swob.HTTPForbidden() + + cache = FakeCache({'sysmeta': {'versions-location': 'ver_cont'}}) + req = Request.blank( + '/v1/a/c/o', + environ={'REQUEST_METHOD': 'PUT', 'swift.cache': cache, + 'swift.authorize': fake_authorize, + 'CONTENT_LENGTH': '0'}) + # Save off a copy, as the middleware may modify the original + expected_req = Request(req.environ.copy()) + status, headers, body = self.call_vw(req) + self.assertEqual(status, '403 Forbidden') + self.assertEqual(len(authorize_call), 1) + self.assertRequestEqual(expected_req, authorize_call[0]) + + self.assertEqual(self.app.calls, []) + class VersionedWritesOldContainersTestCase(VersionedWritesBaseTestCase): def test_delete_latest_version_success(self): -- 2.8.1