From b5575a9de39758687bce64681ed2317dd1cbe912 Mon Sep 17 00:00:00 2001 From: John Dickinson Date: Thu, 28 Oct 2010 15:33:31 -0500 Subject: [PATCH 1/5] reset bytes_transferred for copy requests --- swift/proxy/server.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/swift/proxy/server.py b/swift/proxy/server.py index 231aa467f8..e034860055 100644 --- a/swift/proxy/server.py +++ b/swift/proxy/server.py @@ -774,6 +774,8 @@ class ObjectController(Controller): for k, v in req.headers.items(): if k.lower().startswith('x-object-meta-'): resp.headers[k] = v + # reset the bytes, since the user didn't actually send anything + req.bytes_transferred = 0 resp.last_modified = float(req.headers['X-Timestamp']) return resp From 34525d6c6a4ccfdca7a628179d2f47c71e50ff40 Mon Sep 17 00:00:00 2001 From: John Dickinson Date: Thu, 28 Oct 2010 15:34:16 -0500 Subject: [PATCH 2/5] changed env var in request to properly log the method --- swift/proxy/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/proxy/server.py b/swift/proxy/server.py index e034860055..f5bb8015c0 100644 --- a/swift/proxy/server.py +++ b/swift/proxy/server.py @@ -848,7 +848,7 @@ class ObjectController(Controller): del new_headers['Destination'] new_path = '/' + self.account_name + dest new_req = Request.blank(new_path, - environ={'REQUEST_METHOD': 'PUT'}, headers=new_headers) + environ={'REQUEST_METHOD': 'COPY'}, headers=new_headers) return self.PUT(new_req) From dc5f0be414b22b930eaa4306bde9844dc9690c91 Mon Sep 17 00:00:00 2001 From: Clay Gerrard Date: Thu, 28 Oct 2010 16:33:54 -0500 Subject: [PATCH 3/5] added failing test for COPY from private container --- test/functionalnosetests/test_object.py | 78 ++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/test/functionalnosetests/test_object.py b/test/functionalnosetests/test_object.py index 4a12bf088f..92f54ea97e 100644 --- a/test/functionalnosetests/test_object.py +++ b/test/functionalnosetests/test_object.py @@ -7,7 +7,7 @@ from uuid import uuid4 from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \ MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH -from swift_testing import check_response, retry, skip +from swift_testing import check_response, retry, skip, skip3, swift_test_user class TestObject(unittest.TestCase): @@ -86,6 +86,82 @@ class TestObject(unittest.TestCase): except Exception, err: self.assert_(str(err).startswith('No result after ')) + def test_private_object(self): + if skip or skip3: + raise SkipTest + # Ensure we can't access the object with the third account + def get(url, token, parsed, conn): + conn.request('GET', '%s/%s/%s' % (parsed.path, self.container, + self.obj), '', + {'X-Auth-Token': token}) + return check_response(conn) + resp = retry(get, use_account=3) + resp.read() + self.assertEquals(resp.status, 403) + # create a shared container writable by account3 + shared_container = uuid4().hex + def put(url, token, parsed, conn): + conn.request('PUT', '%s/%s' % (parsed.path, + shared_container), '', + {'X-Auth-Token': token, + 'X-Container-Read': swift_test_user[2], + 'X-Container-Write': swift_test_user[2]}) + return check_response(conn) + resp = retry(put) + resp.read() + self.assertEquals(resp.status, 201) + # verify third account can not copy from private container + def copy(url, token, parsed, conn): + conn.request('PUT', '%s/%s/%s' % (parsed.path, + shared_container, + 'private_object'), + '', {'X-Auth-Token': token, + 'Content-Length': '0', + 'X-Copy-From': '%s/%s' % (self.container, + self.obj)}) + return check_response(conn) + resp = retry(put, use_account=3) + resp.read() + self.assertEquals(resp.status, 403) + # verify third account can write "obj1" to shared container + def put(url, token, parsed, conn): + conn.request('PUT', '%s/%s/%s' % (parsed.path, shared_container, + 'obj1'), 'test', {'X-Auth-Token': token}) + return check_response(conn) + resp = retry(put, use_account=3) + resp.read() + self.assertEquals(resp.status, 201) + # verify third account STILL can not copy from private container + def copy(url, token, parsed, conn): + conn.request('PUT', '%s/%s/%s' % (parsed.path, + shared_container, + 'private_object'), + '', {'X-Auth-Token': token, + 'Content-Length': '0', + 'X-Copy-From': '%s/%s' % (self.container, + self.obj)}) + return check_response(conn) + resp = retry(put, use_account=3) + resp.read() + self.assertEquals(resp.status, 403) + # clean up "obj1" + def delete(url, token, parsed, conn): + conn.request('DELETE', '%s/%s/%s' % (parsed.path, shared_container, + 'obj1'), '', {'X-Auth-Token': token}) + return check_response(conn) + resp = retry(delete) + resp.read() + self.assertEquals(resp.status, 204) + # clean up shared_container + def delete(url, token, parsed, conn): + conn.request('DELETE', + parsed.path + '/' + shared_container, '', + {'X-Auth-Token': token}) + return check_response(conn) + resp = retry(delete) + resp.read() + self.assertEquals(resp.status, 204) + if __name__ == '__main__': unittest.main() From ce48a3c709d3784730873607e9a70e691fe13de9 Mon Sep 17 00:00:00 2001 From: gholt Date: Wed, 3 Nov 2010 14:06:30 -0700 Subject: [PATCH 4/5] Fix tests; fix copy/auth problem --- swift/proxy/server.py | 2 +- test/functionalnosetests/test_object.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/swift/proxy/server.py b/swift/proxy/server.py index ca7543cc8f..ac9beafa52 100644 --- a/swift/proxy/server.py +++ b/swift/proxy/server.py @@ -629,7 +629,7 @@ class ObjectController(Controller): return HTTPPreconditionFailed(request=req, body='X-Copy-From header must be of the form' '/') - source_req = Request.blank(source_header) + source_req = Request.blank(source_header, environ=req.environ) orig_obj_name = self.object_name orig_container_name = self.container_name self.object_name = src_obj_name diff --git a/test/functionalnosetests/test_object.py b/test/functionalnosetests/test_object.py index 92f54ea97e..0ceaee8fc1 100644 --- a/test/functionalnosetests/test_object.py +++ b/test/functionalnosetests/test_object.py @@ -120,7 +120,7 @@ class TestObject(unittest.TestCase): 'X-Copy-From': '%s/%s' % (self.container, self.obj)}) return check_response(conn) - resp = retry(put, use_account=3) + resp = retry(copy, use_account=3) resp.read() self.assertEquals(resp.status, 403) # verify third account can write "obj1" to shared container @@ -141,7 +141,7 @@ class TestObject(unittest.TestCase): 'X-Copy-From': '%s/%s' % (self.container, self.obj)}) return check_response(conn) - resp = retry(put, use_account=3) + resp = retry(copy, use_account=3) resp.read() self.assertEquals(resp.status, 403) # clean up "obj1" From 208d7b8e0040db6ad2a428f5a3345e2e0ba9cbd1 Mon Sep 17 00:00:00 2001 From: Clay Gerrard Date: Thu, 4 Nov 2010 14:39:29 -0500 Subject: [PATCH 5/5] fixed auth_copy bug, and early denial for proxy.server.ObjectController.COPY method; added tests --- swift/proxy/server.py | 8 ++++--- test/functionalnosetests/test_object.py | 29 +++++++++++++++++-------- test/unit/proxy/test_server.py | 17 +++++++++++++++ 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/swift/proxy/server.py b/swift/proxy/server.py index ac9beafa52..62b1835271 100644 --- a/swift/proxy/server.py +++ b/swift/proxy/server.py @@ -629,7 +629,8 @@ class ObjectController(Controller): return HTTPPreconditionFailed(request=req, body='X-Copy-From header must be of the form' '/') - source_req = Request.blank(source_header, environ=req.environ) + source_req = req.copy_get() + source_req.path_info = source_header orig_obj_name = self.object_name orig_container_name = self.container_name self.object_name = src_obj_name @@ -820,6 +821,7 @@ class ObjectController(Controller): 'Object DELETE') @public + @delay_denial def COPY(self, req): """HTTP COPY request handler.""" dest = req.headers.get('Destination') @@ -845,8 +847,8 @@ class ObjectController(Controller): new_headers['Content-Length'] = 0 del new_headers['Destination'] new_path = '/' + self.account_name + dest - new_req = Request.blank(new_path, - environ={'REQUEST_METHOD': 'PUT'}, headers=new_headers) + new_req = Request.blank(new_path, environ=req.environ, + headers=new_headers) return self.PUT(new_req) diff --git a/test/functionalnosetests/test_object.py b/test/functionalnosetests/test_object.py index 0ceaee8fc1..e4b2fc48c5 100644 --- a/test/functionalnosetests/test_object.py +++ b/test/functionalnosetests/test_object.py @@ -131,17 +131,28 @@ class TestObject(unittest.TestCase): resp = retry(put, use_account=3) resp.read() self.assertEquals(resp.status, 201) - # verify third account STILL can not copy from private container - def copy(url, token, parsed, conn): - conn.request('PUT', '%s/%s/%s' % (parsed.path, - shared_container, - 'private_object'), + # verify third account can copy "obj1" to shared container + def copy2(url, token, parsed, conn): + conn.request('COPY', '%s/%s/%s' % (parsed.path, + shared_container, + 'obj1'), '', {'X-Auth-Token': token, - 'Content-Length': '0', - 'X-Copy-From': '%s/%s' % (self.container, - self.obj)}) + 'Destination': '%s/%s' % (shared_container, + 'obj1')}) return check_response(conn) - resp = retry(copy, use_account=3) + resp = retry(copy2, use_account=3) + resp.read() + self.assertEquals(resp.status, 201) + # verify third account STILL can not copy from private container + def copy3(url, token, parsed, conn): + conn.request('COPY', '%s/%s/%s' % (parsed.path, + self.container, + self.obj), + '', {'X-Auth-Token': token, + 'Destination': '%s/%s' % (shared_container, + 'private_object')}) + return check_response(conn) + resp = retry(copy3, use_account=3) resp.read() self.assertEquals(resp.status, 403) # clean up "obj1" diff --git a/test/unit/proxy/test_server.py b/test/unit/proxy/test_server.py index 72aac0eb5e..2ae1803b79 100644 --- a/test/unit/proxy/test_server.py +++ b/test/unit/proxy/test_server.py @@ -1904,6 +1904,23 @@ class TestObjectController(unittest.TestCase): res = controller.PUT(req) self.assert_(called[0]) + def test_COPY_calls_authorize(self): + called = [False] + + def authorize(req): + called[0] = True + return HTTPUnauthorized(request=req) + with save_globals(): + proxy_server.http_connect = \ + fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201) + controller = proxy_server.ObjectController(self.app, 'account', + 'container', 'object') + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'COPY'}, + headers={'Destination': 'c/o'}) + req.environ['swift.authorize'] = authorize + self.app.update_request(req) + res = controller.COPY(req) + self.assert_(called[0]) class TestContainerController(unittest.TestCase): "Test swift.proxy_server.ContainerController"