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, \
|
||||
MalformedXML, InvalidLocationConstraint
|
||||
from swift3.cfg import CONF
|
||||
from swift3.subresource import ACL, Owner
|
||||
from swift3.utils import LOGGER
|
||||
|
||||
MAX_PUT_BUCKET_BODY_SIZE = 10240
|
||||
@@ -116,9 +117,6 @@ class BucketController(Controller):
|
||||
"""
|
||||
Handle PUT Bucket request
|
||||
"""
|
||||
if 'HTTP_X_AMZ_ACL' in req.environ:
|
||||
handle_acl_header(req)
|
||||
|
||||
xml = req.xml(MAX_PUT_BUCKET_BODY_SIZE)
|
||||
if xml:
|
||||
# check location
|
||||
@@ -135,7 +133,26 @@ class BucketController(Controller):
|
||||
# Swift3 cannot support multiple reagions now.
|
||||
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.location = '/' + req.container_name
|
||||
|
||||
|
||||
@@ -14,10 +14,13 @@
|
||||
# limitations under the License.
|
||||
|
||||
from swift.common.http import HTTP_OK
|
||||
from swift.common.utils import split_path
|
||||
|
||||
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.subresource import ACL, Owner
|
||||
from swift3.cfg import CONF
|
||||
|
||||
|
||||
class ObjectController(Controller):
|
||||
@@ -26,6 +29,7 @@ class ObjectController(Controller):
|
||||
"""
|
||||
def GETorHEAD(self, req):
|
||||
resp = req.get_response(self.app)
|
||||
|
||||
if req.method == 'HEAD':
|
||||
resp.app_iter = None
|
||||
|
||||
@@ -53,6 +57,30 @@ class ObjectController(Controller):
|
||||
"""
|
||||
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)
|
||||
|
||||
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.
|
||||
"""
|
||||
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:
|
||||
# Get acl from request body if possible.
|
||||
@@ -65,13 +66,9 @@ class AclController(Controller):
|
||||
"""
|
||||
Handles GET Bucket acl and GET Object acl.
|
||||
"""
|
||||
resp = req.get_response(self.app, 'HEAD')
|
||||
if req.is_object_request:
|
||||
acl = resp.object_acl
|
||||
else:
|
||||
acl = resp.bucket_acl
|
||||
|
||||
acl.check_permission(req.user_id, 'READ_ACP')
|
||||
resp = req.get_response(self.app, 'HEAD', permission='READ_ACP')
|
||||
acl = getattr(resp, '%s_acl' %
|
||||
('object' if req.is_object_request else 'bucket'))
|
||||
|
||||
resp = HTTPOk()
|
||||
resp.body = tostring(acl.elem())
|
||||
@@ -83,16 +80,15 @@ class AclController(Controller):
|
||||
Handles PUT Bucket acl and PUT Object acl.
|
||||
"""
|
||||
if req.is_object_request:
|
||||
b_resp = req.get_response(self.app, 'HEAD', obj='')
|
||||
o_resp = req.get_response(self.app, 'HEAD')
|
||||
|
||||
b_resp = req.get_response(self.app, 'HEAD', obj='',
|
||||
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),
|
||||
b_resp.bucket_acl.owner,
|
||||
o_resp.object_acl.owner)
|
||||
|
||||
# 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_permission(req.user_id, 'WRITE_ACP')
|
||||
|
||||
for g in req_acl.grants:
|
||||
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.
|
||||
headers['X-Copy-From'] = quote(src_path)
|
||||
headers['Content-Length'] = 0
|
||||
req.get_response(self.app, 'PUT', headers=headers)
|
||||
req.get_response(self.app, 'PUT', headers=headers,
|
||||
skip_check=True)
|
||||
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),
|
||||
resp.bucket_acl.owner)
|
||||
|
||||
# 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_permission(req.user_id, 'WRITE_ACP')
|
||||
|
||||
for g in req_acl.grants:
|
||||
LOGGER.debug('Grant %s %s permission on the bucket /%s' %
|
||||
(g.grantee, g.permission, req.container_name))
|
||||
|
||||
req.bucket_acl = req_acl
|
||||
req.get_response(self.app, 'POST')
|
||||
req.get_response(self.app, 'POST', skip_check=True)
|
||||
|
||||
return HTTPOk()
|
||||
|
||||
Reference in New Issue
Block a user