acl: use S3 ACL for object and bucket APIs
Change-Id: I8ec79fe4cea1370cbf433a5c20f5e4cdf5b0d298
This commit is contained in:
@@ -24,6 +24,7 @@ from swift3.etree import Element, SubElement, tostring, fromstring, \
|
|||||||
from swift3.response import HTTPOk, S3NotImplemented, InvalidArgument, \
|
from swift3.response import HTTPOk, S3NotImplemented, InvalidArgument, \
|
||||||
MalformedXML, InvalidLocationConstraint
|
MalformedXML, InvalidLocationConstraint
|
||||||
from swift3.cfg import CONF
|
from swift3.cfg import CONF
|
||||||
|
from swift3.subresource import ACL, Owner
|
||||||
from swift3.utils import LOGGER
|
from swift3.utils import LOGGER
|
||||||
|
|
||||||
MAX_PUT_BUCKET_BODY_SIZE = 10240
|
MAX_PUT_BUCKET_BODY_SIZE = 10240
|
||||||
@@ -116,9 +117,6 @@ class BucketController(Controller):
|
|||||||
"""
|
"""
|
||||||
Handle PUT Bucket request
|
Handle PUT Bucket request
|
||||||
"""
|
"""
|
||||||
if 'HTTP_X_AMZ_ACL' in req.environ:
|
|
||||||
handle_acl_header(req)
|
|
||||||
|
|
||||||
xml = req.xml(MAX_PUT_BUCKET_BODY_SIZE)
|
xml = req.xml(MAX_PUT_BUCKET_BODY_SIZE)
|
||||||
if xml:
|
if xml:
|
||||||
# check location
|
# check location
|
||||||
@@ -135,7 +133,26 @@ class BucketController(Controller):
|
|||||||
# Swift3 cannot support multiple reagions now.
|
# Swift3 cannot support multiple reagions now.
|
||||||
raise InvalidLocationConstraint()
|
raise InvalidLocationConstraint()
|
||||||
|
|
||||||
resp = req.get_response(self.app)
|
if CONF.s3_acl:
|
||||||
|
req_acl = ACL.from_headers(req.headers,
|
||||||
|
Owner(req.user_id, req.user_id))
|
||||||
|
|
||||||
|
# To avoid overwriting the existing bucket's ACL, we send PUT
|
||||||
|
# request first before setting the ACL to make sure that the target
|
||||||
|
# container does not exist.
|
||||||
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
|
# update metadata
|
||||||
|
req.bucket_acl = req_acl
|
||||||
|
# FIXME If this request is failed, there is a possibility that the
|
||||||
|
# bucket which has no ACL is left.
|
||||||
|
req.get_response(self.app, 'POST')
|
||||||
|
else:
|
||||||
|
if 'HTTP_X_AMZ_ACL' in req.environ:
|
||||||
|
handle_acl_header(req)
|
||||||
|
|
||||||
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
resp.status = HTTP_OK
|
resp.status = HTTP_OK
|
||||||
resp.location = '/' + req.container_name
|
resp.location = '/' + req.container_name
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,13 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from swift.common.http import HTTP_OK
|
from swift.common.http import HTTP_OK
|
||||||
|
from swift.common.utils import split_path
|
||||||
|
|
||||||
from swift3.controllers.base import Controller
|
from swift3.controllers.base import Controller
|
||||||
from swift3.response import AccessDenied, HTTPOk
|
from swift3.response import AccessDenied, HTTPOk, NoSuchKey
|
||||||
from swift3.etree import Element, SubElement, tostring
|
from swift3.etree import Element, SubElement, tostring
|
||||||
|
from swift3.subresource import ACL, Owner
|
||||||
|
from swift3.cfg import CONF
|
||||||
|
|
||||||
|
|
||||||
class ObjectController(Controller):
|
class ObjectController(Controller):
|
||||||
@@ -26,6 +29,7 @@ class ObjectController(Controller):
|
|||||||
"""
|
"""
|
||||||
def GETorHEAD(self, req):
|
def GETorHEAD(self, req):
|
||||||
resp = req.get_response(self.app)
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
if req.method == 'HEAD':
|
if req.method == 'HEAD':
|
||||||
resp.app_iter = None
|
resp.app_iter = None
|
||||||
|
|
||||||
@@ -53,6 +57,30 @@ class ObjectController(Controller):
|
|||||||
"""
|
"""
|
||||||
Handle PUT Object and PUT Object (Copy) request
|
Handle PUT Object and PUT Object (Copy) request
|
||||||
"""
|
"""
|
||||||
|
if CONF.s3_acl:
|
||||||
|
if 'HTTP_X_AMZ_COPY_SOURCE' in req.environ:
|
||||||
|
src_path = req.environ['HTTP_X_AMZ_COPY_SOURCE']
|
||||||
|
src_path = src_path if src_path[0] == '/' else ('/' + src_path)
|
||||||
|
src_bucket, src_obj = split_path(src_path, 0, 2, True)
|
||||||
|
|
||||||
|
req.get_response(self.app, 'HEAD', src_bucket, src_obj,
|
||||||
|
permission='READ')
|
||||||
|
|
||||||
|
b_resp = req.get_response(self.app, 'HEAD', obj='')
|
||||||
|
# To avoid overwriting the existing object by unauthorized user,
|
||||||
|
# we send HEAD request first before writing the object to make
|
||||||
|
# sure that the target object does not exist or the user that sent
|
||||||
|
# the PUT request have write permission.
|
||||||
|
try:
|
||||||
|
req.get_response(self.app, 'HEAD')
|
||||||
|
except NoSuchKey:
|
||||||
|
pass
|
||||||
|
req_acl = ACL.from_headers(req.headers,
|
||||||
|
b_resp.bucket_acl.owner,
|
||||||
|
Owner(req.user_id, req.user_id))
|
||||||
|
|
||||||
|
req.object_acl = req_acl
|
||||||
|
|
||||||
resp = req.get_response(self.app)
|
resp = req.get_response(self.app)
|
||||||
|
|
||||||
if 'HTTP_X_COPY_FROM' in req.environ:
|
if 'HTTP_X_COPY_FROM' in req.environ:
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ def get_acl(headers, body, bucket_owner, object_owner=None):
|
|||||||
"""
|
"""
|
||||||
Get ACL instance from S3 (e.g. x-amz-grant) headers or S3 acl xml body.
|
Get ACL instance from S3 (e.g. x-amz-grant) headers or S3 acl xml body.
|
||||||
"""
|
"""
|
||||||
acl = ACL.from_headers(headers, bucket_owner, object_owner)
|
acl = ACL.from_headers(headers, bucket_owner, object_owner,
|
||||||
|
as_private=False)
|
||||||
|
|
||||||
if acl is None:
|
if acl is None:
|
||||||
# Get acl from request body if possible.
|
# Get acl from request body if possible.
|
||||||
@@ -65,13 +66,9 @@ class AclController(Controller):
|
|||||||
"""
|
"""
|
||||||
Handles GET Bucket acl and GET Object acl.
|
Handles GET Bucket acl and GET Object acl.
|
||||||
"""
|
"""
|
||||||
resp = req.get_response(self.app, 'HEAD')
|
resp = req.get_response(self.app, 'HEAD', permission='READ_ACP')
|
||||||
if req.is_object_request:
|
acl = getattr(resp, '%s_acl' %
|
||||||
acl = resp.object_acl
|
('object' if req.is_object_request else 'bucket'))
|
||||||
else:
|
|
||||||
acl = resp.bucket_acl
|
|
||||||
|
|
||||||
acl.check_permission(req.user_id, 'READ_ACP')
|
|
||||||
|
|
||||||
resp = HTTPOk()
|
resp = HTTPOk()
|
||||||
resp.body = tostring(acl.elem())
|
resp.body = tostring(acl.elem())
|
||||||
@@ -83,16 +80,15 @@ class AclController(Controller):
|
|||||||
Handles PUT Bucket acl and PUT Object acl.
|
Handles PUT Bucket acl and PUT Object acl.
|
||||||
"""
|
"""
|
||||||
if req.is_object_request:
|
if req.is_object_request:
|
||||||
b_resp = req.get_response(self.app, 'HEAD', obj='')
|
b_resp = req.get_response(self.app, 'HEAD', obj='',
|
||||||
o_resp = req.get_response(self.app, 'HEAD')
|
skip_check=True)
|
||||||
|
o_resp = req.get_response(self.app, 'HEAD', permission='WRITE_ACP')
|
||||||
req_acl = get_acl(req.headers, req.xml(ACL.max_xml_length),
|
req_acl = get_acl(req.headers, req.xml(ACL.max_xml_length),
|
||||||
b_resp.bucket_acl.owner,
|
b_resp.bucket_acl.owner,
|
||||||
o_resp.object_acl.owner)
|
o_resp.object_acl.owner)
|
||||||
|
|
||||||
# Don't change the owner of the resource by PUT acl request.
|
# Don't change the owner of the resource by PUT acl request.
|
||||||
o_resp.object_acl.check_owner(req_acl.owner.id)
|
o_resp.object_acl.check_owner(req_acl.owner.id)
|
||||||
o_resp.object_acl.check_permission(req.user_id, 'WRITE_ACP')
|
|
||||||
|
|
||||||
for g in req_acl.grants:
|
for g in req_acl.grants:
|
||||||
LOGGER.debug('Grant %s %s permission on the object /%s/%s' %
|
LOGGER.debug('Grant %s %s permission on the object /%s/%s' %
|
||||||
@@ -107,22 +103,22 @@ class AclController(Controller):
|
|||||||
# So headers['X-Copy-From'] for copy request is added here.
|
# So headers['X-Copy-From'] for copy request is added here.
|
||||||
headers['X-Copy-From'] = quote(src_path)
|
headers['X-Copy-From'] = quote(src_path)
|
||||||
headers['Content-Length'] = 0
|
headers['Content-Length'] = 0
|
||||||
req.get_response(self.app, 'PUT', headers=headers)
|
req.get_response(self.app, 'PUT', headers=headers,
|
||||||
|
skip_check=True)
|
||||||
else:
|
else:
|
||||||
resp = req.get_response(self.app, 'HEAD')
|
resp = req.get_response(self.app, 'HEAD', permission='WRITE_ACP')
|
||||||
|
|
||||||
req_acl = get_acl(req.headers, req.xml(ACL.max_xml_length),
|
req_acl = get_acl(req.headers, req.xml(ACL.max_xml_length),
|
||||||
resp.bucket_acl.owner)
|
resp.bucket_acl.owner)
|
||||||
|
|
||||||
# Don't change the owner of the resource by PUT acl request.
|
# Don't change the owner of the resource by PUT acl request.
|
||||||
resp.bucket_acl.check_owner(req_acl.owner.id)
|
resp.bucket_acl.check_owner(req_acl.owner.id)
|
||||||
resp.bucket_acl.check_permission(req.user_id, 'WRITE_ACP')
|
|
||||||
|
|
||||||
for g in req_acl.grants:
|
for g in req_acl.grants:
|
||||||
LOGGER.debug('Grant %s %s permission on the bucket /%s' %
|
LOGGER.debug('Grant %s %s permission on the bucket /%s' %
|
||||||
(g.grantee, g.permission, req.container_name))
|
(g.grantee, g.permission, req.container_name))
|
||||||
|
|
||||||
req.bucket_acl = req_acl
|
req.bucket_acl = req_acl
|
||||||
req.get_response(self.app, 'POST')
|
req.get_response(self.app, 'POST', skip_check=True)
|
||||||
|
|
||||||
return HTTPOk()
|
return HTTPOk()
|
||||||
|
|||||||
@@ -571,18 +571,12 @@ class Request(swob.Request):
|
|||||||
|
|
||||||
return code_map[method]
|
return code_map[method]
|
||||||
|
|
||||||
def get_response(self, app, method=None, container=None, obj=None,
|
def _get_response(self, app, method, container, obj,
|
||||||
body=None, query=None, headers=None):
|
headers=None, body=None, query=None):
|
||||||
"""
|
"""
|
||||||
Calls the application with this request's environment. Returns a
|
Calls the application with this request's environment. Returns a
|
||||||
Response object that wraps up the application's result.
|
Response object that wraps up the application's result.
|
||||||
"""
|
"""
|
||||||
method = method or self.environ['REQUEST_METHOD']
|
|
||||||
if container is None:
|
|
||||||
container = self.container_name
|
|
||||||
if obj is None:
|
|
||||||
obj = self.object_name
|
|
||||||
|
|
||||||
sw_req = self.to_swift_req(method, container, obj, headers=headers,
|
sw_req = self.to_swift_req(method, container, obj, headers=headers,
|
||||||
body=body, query=query)
|
body=body, query=query)
|
||||||
|
|
||||||
@@ -634,3 +628,94 @@ class Request(swob.Request):
|
|||||||
raise AccessDenied()
|
raise AccessDenied()
|
||||||
|
|
||||||
raise InternalError('unexpected status code %d' % status)
|
raise InternalError('unexpected status code %d' % status)
|
||||||
|
|
||||||
|
def get_response(self, app, method=None, container=None, obj=None,
|
||||||
|
headers=None, body=None, query=None, permission=None,
|
||||||
|
skip_check=False):
|
||||||
|
"""
|
||||||
|
Calls the application with this request's environment. Returns a
|
||||||
|
Response object that wraps up the application's result.
|
||||||
|
"""
|
||||||
|
sw_method = method or self.environ['REQUEST_METHOD']
|
||||||
|
if container is None:
|
||||||
|
container = self.container_name
|
||||||
|
if obj is None:
|
||||||
|
obj = self.object_name
|
||||||
|
|
||||||
|
if CONF.s3_acl and not skip_check:
|
||||||
|
resource = 'object' if obj else 'container'
|
||||||
|
s3_method = self.environ['REQUEST_METHOD']
|
||||||
|
if not permission and (s3_method, sw_method, resource) in ACL_MAP:
|
||||||
|
acl_check = ACL_MAP[(s3_method, sw_method, resource)]
|
||||||
|
resource = acl_check.get('Resource') or resource
|
||||||
|
permission = acl_check['Permission']
|
||||||
|
|
||||||
|
if permission:
|
||||||
|
match_resource = True
|
||||||
|
if resource == 'object':
|
||||||
|
resp = self._get_response(app, 'HEAD', container, obj)
|
||||||
|
acl = resp.object_acl
|
||||||
|
elif resource == 'container':
|
||||||
|
resp = self._get_response(app, 'HEAD', container, None)
|
||||||
|
acl = resp.bucket_acl
|
||||||
|
if obj:
|
||||||
|
match_resource = False
|
||||||
|
|
||||||
|
acl.check_permission(self.user_id, permission)
|
||||||
|
|
||||||
|
if sw_method == 'HEAD' and match_resource:
|
||||||
|
# If the request to swift is HEAD and the resource is
|
||||||
|
# consistent with the confirmation subject of ACL, not
|
||||||
|
# request again. This is because that contains the
|
||||||
|
# information required in the HEAD response at the time of
|
||||||
|
# ACL acquisition.
|
||||||
|
return resp
|
||||||
|
|
||||||
|
return self._get_response(app, sw_method, container, obj,
|
||||||
|
headers, body, query)
|
||||||
|
|
||||||
|
"""
|
||||||
|
ACL_MAP =
|
||||||
|
{
|
||||||
|
('<s3_method>', '<swift_method>', '<swift_resource>'):
|
||||||
|
{'Resource': '<check_resource>',
|
||||||
|
'Permission': '<check_permission>'},
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
s3_method: Method of S3 Request from user to swift3
|
||||||
|
swift_method: Method of Swift Request from swift3 to swift
|
||||||
|
swift_resource: Resource of Swift Request from swift3 to swift
|
||||||
|
check_resource: <container/object>
|
||||||
|
check_permission: <OWNER/READ/WRITE/READ_ACP/WRITE_ACP>
|
||||||
|
"""
|
||||||
|
ACL_MAP = {
|
||||||
|
# HEAD Bucket
|
||||||
|
('HEAD', 'HEAD', 'container'):
|
||||||
|
{'Permission': 'READ'},
|
||||||
|
# GET Service
|
||||||
|
('GET', 'HEAD', 'container'):
|
||||||
|
{'Permission': 'OWNER'},
|
||||||
|
# GET Bucket
|
||||||
|
('GET', 'GET', 'container'):
|
||||||
|
{'Permission': 'READ'},
|
||||||
|
# PUT Object, PUT Object Copy
|
||||||
|
('PUT', 'HEAD', 'container'):
|
||||||
|
{'Permission': 'WRITE'},
|
||||||
|
# DELETE Bucket
|
||||||
|
('DELETE', 'DELETE', 'container'):
|
||||||
|
{'Permission': 'OWNER'},
|
||||||
|
# HEAD Object
|
||||||
|
('HEAD', 'HEAD', 'object'):
|
||||||
|
{'Permission': 'READ'},
|
||||||
|
# GET Object
|
||||||
|
('GET', 'GET', 'object'):
|
||||||
|
{'Permission': 'READ'},
|
||||||
|
# PUT Object, PUT Object Copy
|
||||||
|
('PUT', 'HEAD', 'object'):
|
||||||
|
{'Permission': 'WRITE'},
|
||||||
|
# Delete Object
|
||||||
|
('DELETE', 'DELETE', 'object'):
|
||||||
|
{'Resource': 'container',
|
||||||
|
'Permission': 'WRITE'},
|
||||||
|
}
|
||||||
|
|||||||
@@ -437,6 +437,10 @@ class ACL(object):
|
|||||||
"""
|
"""
|
||||||
Check that the user is an owner.
|
Check that the user is an owner.
|
||||||
"""
|
"""
|
||||||
|
if not CONF.s3_acl:
|
||||||
|
# Ignore Swift3 ACL.
|
||||||
|
return
|
||||||
|
|
||||||
if not self.owner.id:
|
if not self.owner.id:
|
||||||
if CONF.allow_no_owner:
|
if CONF.allow_no_owner:
|
||||||
# No owner means public.
|
# No owner means public.
|
||||||
@@ -450,6 +454,10 @@ class ACL(object):
|
|||||||
"""
|
"""
|
||||||
Check that the user has a permission.
|
Check that the user has a permission.
|
||||||
"""
|
"""
|
||||||
|
if not CONF.s3_acl:
|
||||||
|
# Ignore Swift3 ACL.
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# owners have full control permission
|
# owners have full control permission
|
||||||
self.check_owner(user_id)
|
self.check_owner(user_id)
|
||||||
@@ -457,15 +465,17 @@ class ACL(object):
|
|||||||
except AccessDenied:
|
except AccessDenied:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for g in self.grants:
|
if permission in PERMISSIONS:
|
||||||
if g.allow(user_id, 'FULL_CONTROL') or \
|
for g in self.grants:
|
||||||
g.allow(user_id, permission):
|
if g.allow(user_id, 'FULL_CONTROL') or \
|
||||||
return
|
g.allow(user_id, permission):
|
||||||
|
return
|
||||||
|
|
||||||
raise AccessDenied()
|
raise AccessDenied()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_headers(cls, headers, bucket_owner, object_owner=None):
|
def from_headers(cls, headers, bucket_owner, object_owner=None,
|
||||||
|
as_private=True):
|
||||||
"""
|
"""
|
||||||
Convert HTTP headers to an ACL instance.
|
Convert HTTP headers to an ACL instance.
|
||||||
"""
|
"""
|
||||||
@@ -495,7 +505,10 @@ class ACL(object):
|
|||||||
|
|
||||||
if len(grants) == 0:
|
if len(grants) == 0:
|
||||||
# No ACL headers
|
# No ACL headers
|
||||||
return None
|
if as_private:
|
||||||
|
return ACLPrivate(bucket_owner, object_owner)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
return cls(object_owner or bucket_owner, grants)
|
return cls(object_owner or bucket_owner, grants)
|
||||||
|
|
||||||
|
|||||||
180
swift3/test/unit/test_request.py
Normal file
180
swift3/test/unit/test_request.py
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
# Copyright (c) 2014 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from contextlib import nested
|
||||||
|
from mock import patch
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from swift.common.swob import Request
|
||||||
|
|
||||||
|
from swift3.subresource import ACL, User, Owner, Grant
|
||||||
|
from swift3.test.unit.test_middleware import Swift3TestCase
|
||||||
|
from swift3.cfg import CONF
|
||||||
|
from swift3.request import Request as S3_Request
|
||||||
|
|
||||||
|
|
||||||
|
Fake_ACL_MAP = {
|
||||||
|
# HEAD Bucket
|
||||||
|
('HEAD', 'HEAD', 'container'):
|
||||||
|
{'Resource': 'container',
|
||||||
|
'Permission': 'READ'},
|
||||||
|
# GET Bucket
|
||||||
|
('GET', 'GET', 'container'):
|
||||||
|
{'Resource': 'container',
|
||||||
|
'Permission': 'READ'},
|
||||||
|
# HEAD Object
|
||||||
|
('HEAD', 'HEAD', 'object'):
|
||||||
|
{'Resource': 'object',
|
||||||
|
'Permission': 'READ'},
|
||||||
|
# GET Object
|
||||||
|
('GET', 'GET', 'object'):
|
||||||
|
{'Resource': 'object',
|
||||||
|
'Permission': 'READ'},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _gen_test_acl(owner, permission=None, grantee=None):
|
||||||
|
if permission is None:
|
||||||
|
return ACL(owner, [])
|
||||||
|
|
||||||
|
if grantee is None:
|
||||||
|
grantee = User('test:tester')
|
||||||
|
return ACL(owner, [Grant(grantee, permission)])
|
||||||
|
|
||||||
|
|
||||||
|
class FakeResponse(object):
|
||||||
|
def __init__(self, s3_acl):
|
||||||
|
self.bucket_acl = None
|
||||||
|
self.object_acl = None
|
||||||
|
if s3_acl:
|
||||||
|
owner = Owner(id='test:tester', name='test:tester')
|
||||||
|
self.bucket_acl = _gen_test_acl(owner, 'FULL_CONTROL')
|
||||||
|
self.object_acl = _gen_test_acl(owner, 'FULL_CONTROL')
|
||||||
|
|
||||||
|
|
||||||
|
class TestRequest(Swift3TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestRequest, self).setUp()
|
||||||
|
CONF.s3_acl = True
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
CONF.s3_acl = False
|
||||||
|
|
||||||
|
@patch('swift3.request.ACL_MAP', Fake_ACL_MAP)
|
||||||
|
def _test_get_response(self, method, container='bucket', obj=None,
|
||||||
|
permission=None, skip_check=False):
|
||||||
|
path = '/' + container + ('/' + obj if obj else '')
|
||||||
|
req = Request.blank(path,
|
||||||
|
environ={'REQUEST_METHOD': method},
|
||||||
|
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||||
|
s3_req = S3_Request(req.environ)
|
||||||
|
|
||||||
|
with nested(patch('swift3.request.Request._get_response'),
|
||||||
|
patch('swift3.subresource.ACL.check_permission')) \
|
||||||
|
as (mock_get_resp, m_check_permission):
|
||||||
|
mock_get_resp.return_value = FakeResponse(CONF.s3_acl)
|
||||||
|
return mock_get_resp, m_check_permission,\
|
||||||
|
s3_req.get_response(self.swift3, permission=permission,
|
||||||
|
skip_check=skip_check)
|
||||||
|
|
||||||
|
def test_get_response_without_s3_acl(self):
|
||||||
|
CONF.s3_acl = False
|
||||||
|
mock_get_resp, m_check_permission, s3_resp = \
|
||||||
|
self._test_get_response('HEAD')
|
||||||
|
CONF.s3_acl = True
|
||||||
|
self.assertTrue(s3_resp.bucket_acl is None)
|
||||||
|
self.assertTrue(s3_resp.object_acl is None)
|
||||||
|
self.assertEqual(mock_get_resp.call_count, 1)
|
||||||
|
self.assertEqual(m_check_permission.call_count, 0)
|
||||||
|
|
||||||
|
def test_get_response_without_check_permission(self):
|
||||||
|
mock_get_resp, m_check_permission, s3_resp = \
|
||||||
|
self._test_get_response('HEAD', skip_check=True)
|
||||||
|
self.assertTrue(s3_resp.bucket_acl is not None)
|
||||||
|
self.assertTrue(s3_resp.object_acl is not None)
|
||||||
|
self.assertEqual(mock_get_resp.call_count, 1)
|
||||||
|
self.assertEqual(m_check_permission.call_count, 0)
|
||||||
|
|
||||||
|
def test_get_response_with_permission_specified(self):
|
||||||
|
obj = 'object'
|
||||||
|
mock_get_resp, m_check_permission, s3_resp = \
|
||||||
|
self._test_get_response('GET', obj=obj,
|
||||||
|
permission='READ_ACP')
|
||||||
|
self.assertTrue(s3_resp.bucket_acl is not None)
|
||||||
|
self.assertTrue(s3_resp.object_acl is not None)
|
||||||
|
self.assertEqual(mock_get_resp.call_count, 2)
|
||||||
|
args, kargs = mock_get_resp.call_args_list[0]
|
||||||
|
get_resp_obj = args[3]
|
||||||
|
self.assertEqual(get_resp_obj, obj)
|
||||||
|
self.assertEqual(m_check_permission.call_count, 1)
|
||||||
|
args, kargs = m_check_permission.call_args
|
||||||
|
permission = args[1]
|
||||||
|
self.assertEqual(permission, 'READ_ACP')
|
||||||
|
|
||||||
|
def test_get_response_without_match_ACL_MAP(self):
|
||||||
|
mock_get_resp, m_check_permission, s3_resp = \
|
||||||
|
self._test_get_response('POST')
|
||||||
|
self.assertTrue(s3_resp.bucket_acl is not None)
|
||||||
|
self.assertTrue(s3_resp.object_acl is not None)
|
||||||
|
self.assertEqual(mock_get_resp.call_count, 1)
|
||||||
|
self.assertEqual(m_check_permission.call_count, 0)
|
||||||
|
|
||||||
|
def test_get_response_without_duplication_HEAD_request(self):
|
||||||
|
obj = 'object'
|
||||||
|
mock_get_resp, m_check_permission, s3_resp = \
|
||||||
|
self._test_get_response('HEAD', obj=obj)
|
||||||
|
self.assertTrue(s3_resp.bucket_acl is not None)
|
||||||
|
self.assertTrue(s3_resp.object_acl is not None)
|
||||||
|
self.assertEqual(mock_get_resp.call_count, 1)
|
||||||
|
args, kargs = mock_get_resp.call_args_list[0]
|
||||||
|
get_resp_obj = args[3]
|
||||||
|
self.assertEqual(get_resp_obj, obj)
|
||||||
|
self.assertEqual(m_check_permission.call_count, 1)
|
||||||
|
args, kargs = m_check_permission.call_args
|
||||||
|
permission = args[1]
|
||||||
|
self.assertEqual(permission, 'READ')
|
||||||
|
|
||||||
|
def test_get_response_with_check_object_permission(self):
|
||||||
|
obj = 'object'
|
||||||
|
mock_get_resp, m_check_permission, s3_resp = \
|
||||||
|
self._test_get_response('GET', obj=obj)
|
||||||
|
self.assertTrue(s3_resp.bucket_acl is not None)
|
||||||
|
self.assertTrue(s3_resp.object_acl is not None)
|
||||||
|
self.assertEqual(mock_get_resp.call_count, 2)
|
||||||
|
args, kargs = mock_get_resp.call_args_list[0]
|
||||||
|
get_resp_obj = args[3]
|
||||||
|
self.assertEqual(get_resp_obj, obj)
|
||||||
|
self.assertEqual(m_check_permission.call_count, 1)
|
||||||
|
args, kargs = m_check_permission.call_args
|
||||||
|
permission = args[1]
|
||||||
|
self.assertEqual(permission, 'READ')
|
||||||
|
|
||||||
|
def test_get_response_with_check_container_permission(self):
|
||||||
|
mock_get_resp, m_check_permission, s3_resp = \
|
||||||
|
self._test_get_response('GET')
|
||||||
|
self.assertTrue(s3_resp.bucket_acl is not None)
|
||||||
|
self.assertTrue(s3_resp.object_acl is not None)
|
||||||
|
self.assertEqual(mock_get_resp.call_count, 2)
|
||||||
|
args, kargs = mock_get_resp.call_args_list[0]
|
||||||
|
get_resp_obj = args[3]
|
||||||
|
self.assertTrue(get_resp_obj is None)
|
||||||
|
self.assertEqual(m_check_permission.call_count, 1)
|
||||||
|
args, kargs = m_check_permission.call_args
|
||||||
|
permission = args[1]
|
||||||
|
self.assertEqual(permission, 'READ')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -14,26 +14,28 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
import simplejson as json
|
||||||
|
|
||||||
from swift.common import swob
|
from swift.common import swob
|
||||||
from swift.common.swob import Request
|
from swift.common.swob import Request
|
||||||
|
|
||||||
from swift3.etree import tostring, Element, SubElement
|
from swift3.etree import tostring, Element, SubElement
|
||||||
from swift3.subresource import ACL, ACLPrivate, User, encode_acl, \
|
from swift3.subresource import ACL, ACLPrivate, User, encode_acl, \
|
||||||
Owner, Grant
|
decode_acl, AuthenticatedUsers, AllUsers, Owner, Grant
|
||||||
from swift3.test.unit.test_middleware import Swift3TestCase
|
from swift3.test.unit.test_middleware import Swift3TestCase
|
||||||
from swift3.cfg import CONF
|
from swift3.cfg import CONF
|
||||||
|
|
||||||
XMLNS_XSI = 'http://www.w3.org/2001/XMLSchema-instance'
|
XMLNS_XSI = 'http://www.w3.org/2001/XMLSchema-instance'
|
||||||
|
|
||||||
|
|
||||||
def _gen_test_acl(owner, permission=None, grantee=None):
|
def _gen_test_headers(owner, permission=None, grantee=None,
|
||||||
|
resource='container'):
|
||||||
if permission is None:
|
if permission is None:
|
||||||
return ACL(owner, [])
|
return encode_acl(resource, ACL(owner, []))
|
||||||
|
|
||||||
if grantee is None:
|
if grantee is None:
|
||||||
grantee = User('test:tester')
|
grantee = User('test:tester')
|
||||||
return ACL(owner, [Grant(grantee, permission)])
|
return encode_acl(resource, ACL(owner, [Grant(grantee, permission)]))
|
||||||
|
|
||||||
|
|
||||||
def _make_xml(grantee):
|
def _make_xml(grantee):
|
||||||
@@ -51,6 +53,12 @@ def _make_xml(grantee):
|
|||||||
|
|
||||||
|
|
||||||
class TestSwift3S3Acl(Swift3TestCase):
|
class TestSwift3S3Acl(Swift3TestCase):
|
||||||
|
"""
|
||||||
|
This class has been tested in the following Controller.
|
||||||
|
[S3AclController]
|
||||||
|
[BucketController] Case: Conf.s3_acl == True
|
||||||
|
[Object Controller] Case: Conf.s3_acl == True
|
||||||
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestSwift3S3Acl, self).setUp()
|
super(TestSwift3S3Acl, self).setUp()
|
||||||
@@ -85,6 +93,9 @@ class TestSwift3S3Acl(Swift3TestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
CONF.s3_acl = False
|
CONF.s3_acl = False
|
||||||
|
|
||||||
|
"""
|
||||||
|
[S3AclController]
|
||||||
|
"""
|
||||||
def test_bucket_acl_PUT_with_other_owner(self):
|
def test_bucket_acl_PUT_with_other_owner(self):
|
||||||
req = Request.blank('/bucket?acl',
|
req = Request.blank('/bucket?acl',
|
||||||
environ={'REQUEST_METHOD': 'PUT'},
|
environ={'REQUEST_METHOD': 'PUT'},
|
||||||
@@ -298,11 +309,10 @@ class TestSwift3S3Acl(Swift3TestCase):
|
|||||||
|
|
||||||
def _test_bucket_acl_GET(self, owner, permission):
|
def _test_bucket_acl_GET(self, owner, permission):
|
||||||
owner = Owner(id=owner, name=owner)
|
owner = Owner(id=owner, name=owner)
|
||||||
acl = _gen_test_acl(owner, permission)
|
headers = _gen_test_headers(owner, permission)
|
||||||
|
|
||||||
self.swift.register('HEAD', '/v1/AUTH_test/bucket', swob.HTTPNoContent,
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket', swob.HTTPNoContent,
|
||||||
encode_acl('container', acl),
|
headers, None)
|
||||||
None)
|
|
||||||
req = Request.blank('/bucket?acl',
|
req = Request.blank('/bucket?acl',
|
||||||
environ={'REQUEST_METHOD': 'GET'},
|
environ={'REQUEST_METHOD': 'GET'},
|
||||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||||
@@ -313,14 +323,28 @@ class TestSwift3S3Acl(Swift3TestCase):
|
|||||||
status, headers, body = self._test_bucket_acl_GET('test:other', None)
|
status, headers, body = self._test_bucket_acl_GET('test:other', None)
|
||||||
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
def test_bucket_GET_with_owner_permission(self):
|
def test_bucket_acl_GET_with_read_acp_permission(self):
|
||||||
|
status, headers, body = self._test_bucket_acl_GET('test:other',
|
||||||
|
'READ_ACP')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_bucket_acl_GET_with_fullcontrol_permission(self):
|
||||||
|
status, headers, body = self._test_bucket_acl_GET('test:other',
|
||||||
|
'FULL_CONTROL')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_bucket_acl_GET_with_owner_permission(self):
|
||||||
status, headers, body = self._test_bucket_acl_GET('test:tester', None)
|
status, headers, body = self._test_bucket_acl_GET('test:tester', None)
|
||||||
self.assertEquals(status.split()[0], '200')
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
def _test_bucket_acl_PUT(self, owner, permission):
|
def _test_bucket_acl_PUT(self, owner, permission, grantee='test:tester'):
|
||||||
owner = Owner(id=owner, name=owner)
|
owner = Owner(id=owner, name=owner)
|
||||||
acl = _gen_test_acl(owner, permission)
|
grantee = User(grantee)
|
||||||
|
headers = _gen_test_headers(owner, permission, grantee)
|
||||||
|
acl = decode_acl('container', headers)
|
||||||
|
|
||||||
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket', swob.HTTPNoContent,
|
||||||
|
headers, None)
|
||||||
req = Request.blank('/bucket?acl',
|
req = Request.blank('/bucket?acl',
|
||||||
environ={'REQUEST_METHOD': 'PUT'},
|
environ={'REQUEST_METHOD': 'PUT'},
|
||||||
headers={'Authorization': 'AWS test:tester:hmac'},
|
headers={'Authorization': 'AWS test:tester:hmac'},
|
||||||
@@ -329,21 +353,34 @@ class TestSwift3S3Acl(Swift3TestCase):
|
|||||||
return self.call_swift3(req)
|
return self.call_swift3(req)
|
||||||
|
|
||||||
def test_bucket_acl_PUT_without_permission(self):
|
def test_bucket_acl_PUT_without_permission(self):
|
||||||
status, headers, body = self._test_bucket_acl_PUT('test:other', None)
|
status, headers, body = self._test_bucket_acl_PUT('test:other', None,
|
||||||
|
'test:other')
|
||||||
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
|
def test_bucket_acl_PUT_with_write_acp_permission(self):
|
||||||
|
|
||||||
|
status, headers, body = self._test_bucket_acl_PUT('test:other',
|
||||||
|
'WRITE_ACP')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_bucket_acl_PUT_with_fullcontrol_permission(self):
|
||||||
|
|
||||||
|
status, headers, body = self._test_bucket_acl_PUT('test:other',
|
||||||
|
'FULL_CONTROL')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
def test_bucket_acl_PUT_with_owner_permission(self):
|
def test_bucket_acl_PUT_with_owner_permission(self):
|
||||||
status, headers, body = self._test_bucket_acl_PUT('test:tester', None)
|
|
||||||
|
status, headers, body = self._test_bucket_acl_PUT('test:tester',
|
||||||
|
'FULL_CONTROL')
|
||||||
self.assertEquals(status.split()[0], '200')
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
def _test_object_acl_GET(self, owner, permission):
|
def _test_object_acl_GET(self, owner, permission):
|
||||||
owner = Owner(id=owner, name=owner)
|
owner = Owner(id=owner, name=owner)
|
||||||
acl = _gen_test_acl(owner, permission)
|
headers = _gen_test_headers(owner, permission, resource='object')
|
||||||
|
|
||||||
self.swift.register('HEAD', '/v1/AUTH_test/bucket/object',
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket/object',
|
||||||
swob.HTTPOk,
|
swob.HTTPOk, headers, None)
|
||||||
encode_acl('object', acl),
|
|
||||||
None)
|
|
||||||
req = Request.blank('/bucket/object?acl',
|
req = Request.blank('/bucket/object?acl',
|
||||||
environ={'REQUEST_METHOD': 'GET'},
|
environ={'REQUEST_METHOD': 'GET'},
|
||||||
headers={'Authorization': 'AWS test:tester:hmac'})
|
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||||
@@ -354,18 +391,27 @@ class TestSwift3S3Acl(Swift3TestCase):
|
|||||||
status, headers, body = self._test_object_acl_GET('test:other', None)
|
status, headers, body = self._test_object_acl_GET('test:other', None)
|
||||||
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
|
def test_object_acl_GET_with_read_acp_permission(self):
|
||||||
|
status, headers, body = self._test_object_acl_GET('test:other',
|
||||||
|
'READ_ACP')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_acl_GET_with_fullcontrol_permission(self):
|
||||||
|
status, headers, body = self._test_object_acl_GET('test:other',
|
||||||
|
'FULL_CONTROL')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
def test_object_acl_GET_with_owner_permission(self):
|
def test_object_acl_GET_with_owner_permission(self):
|
||||||
status, headers, body = self._test_object_acl_GET('test:tester', None)
|
status, headers, body = self._test_object_acl_GET('test:tester', None)
|
||||||
self.assertEquals(status.split()[0], '200')
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
def _test_object_acl_PUT(self, owner, permission):
|
def _test_object_acl_PUT(self, owner, permission):
|
||||||
owner = Owner(id=owner, name=owner)
|
owner = Owner(id=owner, name=owner)
|
||||||
acl = _gen_test_acl(owner, permission)
|
headers = _gen_test_headers(owner, permission, resource='object')
|
||||||
|
acl = decode_acl('object', headers)
|
||||||
|
|
||||||
self.swift.register('HEAD', '/v1/AUTH_test/bucket/object',
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket/object',
|
||||||
swob.HTTPOk,
|
swob.HTTPOk, headers, None)
|
||||||
encode_acl('object', acl),
|
|
||||||
None)
|
|
||||||
req = Request.blank('/bucket/object?acl',
|
req = Request.blank('/bucket/object?acl',
|
||||||
environ={'REQUEST_METHOD': 'PUT'},
|
environ={'REQUEST_METHOD': 'PUT'},
|
||||||
headers={'Authorization': 'AWS test:tester:hmac'},
|
headers={'Authorization': 'AWS test:tester:hmac'},
|
||||||
@@ -377,9 +423,285 @@ class TestSwift3S3Acl(Swift3TestCase):
|
|||||||
status, headers, body = self._test_object_acl_PUT('test:other', None)
|
status, headers, body = self._test_object_acl_PUT('test:other', None)
|
||||||
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
|
def test_object_acl_PUT_with_write_acp_permission(self):
|
||||||
|
status, headers, body = self._test_object_acl_PUT('test:other',
|
||||||
|
'WRITE_ACP')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_acl_PUT_with_fullcontrol_permission(self):
|
||||||
|
status, headers, body = self._test_object_acl_PUT('test:other',
|
||||||
|
'FULL_CONTROL')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
def test_object_acl_PUT_with_owner_permission(self):
|
def test_object_acl_PUT_with_owner_permission(self):
|
||||||
status, headers, body = self._test_object_acl_PUT('test:tester', None)
|
status, headers, body = self._test_object_acl_PUT('test:tester', None)
|
||||||
self.assertEquals(status.split()[0], '200')
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
"""
|
||||||
|
[BucketController] Case: Conf.s3_acl == True
|
||||||
|
"""
|
||||||
|
def _test_bucket(self, method, owner, permission):
|
||||||
|
owner = Owner(id=owner, name=owner)
|
||||||
|
headers = _gen_test_headers(owner, permission)
|
||||||
|
|
||||||
|
self.swift.register('HEAD', '/v1/AUTH_test/acltest',
|
||||||
|
swob.HTTPNoContent, headers, None)
|
||||||
|
self.swift.register('GET', '/v1/AUTH_test/acltest', swob.HTTPNoContent,
|
||||||
|
headers, json.dumps([]))
|
||||||
|
self.swift.register('POST', '/v1/AUTH_test/acltest',
|
||||||
|
swob.HTTPNoContent, {}, None)
|
||||||
|
self.swift.register('DELETE', '/v1/AUTH_test/acltest',
|
||||||
|
swob.HTTPNoContent, {}, None)
|
||||||
|
|
||||||
|
req = Request.blank('/acltest',
|
||||||
|
environ={'REQUEST_METHOD': method},
|
||||||
|
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||||
|
|
||||||
|
return self.call_swift3(req)
|
||||||
|
|
||||||
|
def test_bucket_GET_without_permission(self):
|
||||||
|
status, headers, body = self._test_bucket('GET', 'test:other', None)
|
||||||
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
|
def test_bucket_GET_with_read_permission(self):
|
||||||
|
status, headers, body = self._test_bucket('GET', 'test:other', 'READ')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_bucket_GET_with_fullcontrol_permission(self):
|
||||||
|
status, headers, body = self._test_bucket('GET', 'test:other',
|
||||||
|
'FULL_CONTROL')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_bucket_GET_with_owner_permission(self):
|
||||||
|
status, headers, body = self._test_bucket('GET', 'test:tester', None)
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def _test_bucket_GET_canned_acl(self, group):
|
||||||
|
owner = Owner(id='test:other', name='test:other')
|
||||||
|
headers = _gen_test_headers(owner, 'READ', group)
|
||||||
|
self.swift.register('GET', '/v1/AUTH_test/acltest', swob.HTTPNoContent,
|
||||||
|
headers, json.dumps([]))
|
||||||
|
req = Request.blank('/acltest',
|
||||||
|
environ={'REQUEST_METHOD': 'GET'},
|
||||||
|
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||||
|
|
||||||
|
return self.call_swift3(req)
|
||||||
|
|
||||||
|
def test_bucket_GET_authenticated_users(self):
|
||||||
|
status, headers, body = \
|
||||||
|
self._test_bucket_GET_canned_acl(AuthenticatedUsers())
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_bucket_GET_all_users(self):
|
||||||
|
status, headers, body = self._test_bucket_GET_canned_acl(AllUsers())
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_bucket_PUT_with_already_exist(self):
|
||||||
|
self.swift.register('PUT', '/v1/AUTH_test/acltest',
|
||||||
|
swob.HTTPAccepted, {}, None)
|
||||||
|
status, headers, body = self._test_bucket('PUT', 'test:other', None)
|
||||||
|
self.assertEquals(self._get_error_code(body), 'BucketAlreadyExists')
|
||||||
|
|
||||||
|
def test_bucket_PUT(self):
|
||||||
|
self.swift.register('PUT', '/v1/AUTH_test/acltest',
|
||||||
|
swob.HTTPCreated, {}, None)
|
||||||
|
status, headers, body = self._test_bucket('PUT', 'test:other', 'WRITE')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_bucket_DELETE_without_permission(self):
|
||||||
|
status, headers, body = self._test_bucket('DELETE', 'test:other', None)
|
||||||
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
|
def test_bucket_DELETE_with_write_permission(self):
|
||||||
|
status, headers, body = self._test_bucket('DELETE', 'test:other',
|
||||||
|
'WRITE')
|
||||||
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
|
def test_bucket_DELETE_with_fullcontrol_permission(self):
|
||||||
|
status, headers, body = self._test_bucket('DELETE', 'test:other',
|
||||||
|
'FULL_CONTROL')
|
||||||
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
|
def test_bucket_DELETE_with_owner_permission(self):
|
||||||
|
status, headers, body = self._test_bucket('DELETE', 'test:tester',
|
||||||
|
None)
|
||||||
|
self.assertEquals(status.split()[0], '204')
|
||||||
|
|
||||||
|
"""
|
||||||
|
[Object Controller] Case: Conf.s3_acl == True
|
||||||
|
"""
|
||||||
|
def _test_object(self, method, o_owner, o_permission,
|
||||||
|
grantee='test:tester', c_owner='test:tester',
|
||||||
|
c_permission='FULL_CONTROL', existObject=True):
|
||||||
|
c_owner = Owner(id=c_owner, name=c_owner)
|
||||||
|
o_owner = Owner(id=o_owner, name=o_owner)
|
||||||
|
grantee = User(grantee)
|
||||||
|
c_headers = _gen_test_headers(c_owner, c_permission, grantee)
|
||||||
|
o_headers = _gen_test_headers(o_owner, o_permission, grantee, 'object')
|
||||||
|
|
||||||
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket',
|
||||||
|
swob.HTTPNoContent, c_headers, None)
|
||||||
|
if existObject:
|
||||||
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket/object',
|
||||||
|
swob.HTTPOk, o_headers, None)
|
||||||
|
else:
|
||||||
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket/object',
|
||||||
|
swob.HTTPNotFound, {}, None)
|
||||||
|
self.swift.register('GET', '/v1/AUTH_test/bucket/object',
|
||||||
|
swob.HTTPOk, o_headers, '')
|
||||||
|
self.swift.register('PUT', '/v1/AUTH_test/bucket/object',
|
||||||
|
swob.HTTPCreated, {}, None)
|
||||||
|
self.swift.register('DELETE', '/v1/AUTH_test/bucket/object',
|
||||||
|
swob.HTTPNoContent, {}, None)
|
||||||
|
|
||||||
|
req = Request.blank('/bucket/object',
|
||||||
|
environ={'REQUEST_METHOD': method},
|
||||||
|
headers={'Authorization': 'AWS test:tester:hmac'})
|
||||||
|
return self.call_swift3(req)
|
||||||
|
|
||||||
|
def test_object_GET_without_permission(self):
|
||||||
|
status, headers, body = self._test_object('GET', 'test:other', None)
|
||||||
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
|
def test_object_GET_with_read_permission(self):
|
||||||
|
status, headers, body = self._test_object('GET', 'test:other', 'READ')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_GET_with_fullcontrol_permission(self):
|
||||||
|
status, headers, body = self._test_object('GET', 'test:other',
|
||||||
|
'FULL_CONTROL')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_GET_with_owner_permission(self):
|
||||||
|
status, headers, body = self._test_object('GET', 'test:tester', None)
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_PUT_without_permission(self):
|
||||||
|
status, headers, body = self._test_object('PUT', 'test:other', None)
|
||||||
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
|
def test_object_PUT_with_write_permission(self):
|
||||||
|
status, headers, body = self._test_object('PUT', 'test:other', 'WRITE',
|
||||||
|
existObject=False)
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_PUT_with_fullcontrol_permission(self):
|
||||||
|
status, headers, body = self._test_object('PUT', 'test:other',
|
||||||
|
'FULL_CONTROL',
|
||||||
|
existObject=False)
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_PUT_with_owner_permission(self):
|
||||||
|
status, headers, body = self._test_object('PUT', 'test:tester', None,
|
||||||
|
existObject=False)
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_PUT_without_overwriting_permission(self):
|
||||||
|
status, headers, body = self._test_object('PUT', 'test:other', None)
|
||||||
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
|
def test_object_PUT_with_overwriting_permission(self):
|
||||||
|
status, headers, body = self._test_object('PUT', 'test:other',
|
||||||
|
'WRITE')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_DELETE_without_permission(self):
|
||||||
|
status, headers, body = self._test_object('DELETE', 'test:other', None,
|
||||||
|
c_owner='test:other',
|
||||||
|
c_permission='READ')
|
||||||
|
self.assertEquals(self._get_error_code(body), 'AccessDenied')
|
||||||
|
|
||||||
|
def test_object_DELETE_with_write_permission(self):
|
||||||
|
status, headers, body = self._test_object('DELETE', 'test:tester',
|
||||||
|
None,
|
||||||
|
c_owner='test:other',
|
||||||
|
c_permission='WRITE')
|
||||||
|
self.assertEquals(status.split()[0], '204')
|
||||||
|
|
||||||
|
def test_object_DELETE_with_fullcontrol_permission(self):
|
||||||
|
status, headers, body = self._test_object('DELETE', 'test:tester',
|
||||||
|
None,
|
||||||
|
c_owner='test:other')
|
||||||
|
self.assertEquals(status.split()[0], '204')
|
||||||
|
|
||||||
|
def test_object_DELETE_with_owner_permission(self):
|
||||||
|
status, headers, body = self._test_object('DELETE', 'test:tester',
|
||||||
|
None)
|
||||||
|
self.assertEquals(status.split()[0], '204')
|
||||||
|
|
||||||
|
def _test_object_copy(self, src_owner='test:tester', src_permission=None,
|
||||||
|
dst_c_owner='test:tester', dst_c_permission=None,
|
||||||
|
dst_c_grantee=None, dst_o_owner='test:tester',
|
||||||
|
dst_o_permission=None, dst_o_grantee=None):
|
||||||
|
|
||||||
|
src_o_headers = _gen_test_headers(Owner(id=src_owner, name=src_owner),
|
||||||
|
src_permission, None, 'object')
|
||||||
|
self.swift.register('HEAD', '/v1/AUTH_test/src_bucket/src_obj',
|
||||||
|
swob.HTTPOk, src_o_headers, None)
|
||||||
|
|
||||||
|
dst_c_headers = _gen_test_headers(Owner(id=dst_c_owner,
|
||||||
|
name=dst_c_owner),
|
||||||
|
dst_c_permission, dst_c_grantee)
|
||||||
|
self.swift.register('HEAD', '/v1/AUTH_test/dst_bucket',
|
||||||
|
swob.HTTPNoContent, dst_c_headers, None)
|
||||||
|
|
||||||
|
dst_o_headers = _gen_test_headers(Owner(id=dst_o_owner,
|
||||||
|
name=dst_o_owner),
|
||||||
|
dst_o_permission, dst_o_grantee,
|
||||||
|
'object')
|
||||||
|
self.swift.register('HEAD', '/v1/AUTH_test/dst_bucket/dst_obj',
|
||||||
|
swob.HTTPOk, dst_o_headers, None)
|
||||||
|
|
||||||
|
self.swift.register('PUT', '/v1/AUTH_test/dst_bucket/dst_obj',
|
||||||
|
swob.HTTPCreated, {}, None)
|
||||||
|
|
||||||
|
req = Request.blank(
|
||||||
|
'/dst_bucket/dst_obj',
|
||||||
|
environ={'REQUEST_METHOD': 'PUT'},
|
||||||
|
headers={'Authorization': 'AWS test:tester:hmac',
|
||||||
|
'X-Amz-Copy-Source': '/src_bucket/src_obj'})
|
||||||
|
|
||||||
|
return self.call_swift3(req)
|
||||||
|
|
||||||
|
def test_object_PUT_copy_with_owner_permission(self):
|
||||||
|
status, headers, body = \
|
||||||
|
self._test_object_copy()
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_PUT_copy_with_fullcontrol_permission(self):
|
||||||
|
status, headers, body = \
|
||||||
|
self._test_object_copy(src_owner='test:other',
|
||||||
|
src_permission='FULL_CONTROL',
|
||||||
|
dst_c_owner='test:other',
|
||||||
|
dst_c_permission='FULL_CONTROL',
|
||||||
|
dst_o_owner='test:other',
|
||||||
|
dst_o_permission='FULL_CONTROL')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_PUT_copy_with_grantee_permission(self):
|
||||||
|
status, headers, body = \
|
||||||
|
self._test_object_copy(src_owner='test:other',
|
||||||
|
src_permission='READ',
|
||||||
|
dst_c_owner='test:other',
|
||||||
|
dst_c_permission='WRITE',
|
||||||
|
dst_o_owner='test:other',
|
||||||
|
dst_o_permission='WRITE')
|
||||||
|
self.assertEquals(status.split()[0], '200')
|
||||||
|
|
||||||
|
def test_object_PUT_copy_without_src_obj_permission(self):
|
||||||
|
status, headers, body = \
|
||||||
|
self._test_object_copy(src_owner='test:other')
|
||||||
|
self.assertEquals(status.split()[0], '403')
|
||||||
|
|
||||||
|
def test_object_PUT_copy_without_dst_container_permission(self):
|
||||||
|
status, headers, body = \
|
||||||
|
self._test_object_copy(dst_c_owner='test:other')
|
||||||
|
self.assertEquals(status.split()[0], '403')
|
||||||
|
|
||||||
|
def test_object_PUT_copy_without_dst_obj_permission(self):
|
||||||
|
status, headers, body = \
|
||||||
|
self._test_object_copy(dst_o_owner='test:other')
|
||||||
|
self.assertEquals(status.split()[0], '403')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user