Addition of s3control support in server mode (#4885)

This commit is contained in:
Cristopher Pinzón 2022-02-24 16:35:07 -05:00 committed by GitHub
parent e84cc20abe
commit 8b81481d3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 86 deletions

View File

@ -13,37 +13,38 @@ class S3ControlResponse(BaseResponse):
def public_access_block(cls, request, full_url, headers): def public_access_block(cls, request, full_url, headers):
response_instance = S3ControlResponse() response_instance = S3ControlResponse()
try: try:
return response_instance._public_access_block(request, headers) return response_instance._public_access_block(request)
except S3ClientError as err: except S3ClientError as err:
return err.code, {}, err.description return err.code, {}, err.description
@amzn_request_id @amzn_request_id
def _public_access_block(self, request, headers): def _public_access_block(self, request):
if request.method == "GET": if request.method == "GET":
return self.get_public_access_block(headers) return self.get_public_access_block(request)
elif request.method == "PUT": elif request.method == "PUT":
return self.put_public_access_block(request, headers) return self.put_public_access_block(request)
elif request.method == "DELETE": elif request.method == "DELETE":
return self.delete_public_access_block(headers) return self.delete_public_access_block(request)
def get_public_access_block(self, headers): def get_public_access_block(self, request):
account_id = headers["x-amz-account-id"] account_id = request.headers.get("x-amz-account-id")
public_block_config = s3control_backend.get_public_access_block( public_block_config = s3control_backend.get_public_access_block(
account_id=account_id, account_id=account_id,
) )
template = self.response_template(S3_PUBLIC_ACCESS_BLOCK_CONFIGURATION) template = self.response_template(S3_PUBLIC_ACCESS_BLOCK_CONFIGURATION)
return 200, {}, template.render(public_block_config=public_block_config) return 200, {}, template.render(public_block_config=public_block_config)
def put_public_access_block(self, request, headers): def put_public_access_block(self, request):
account_id = headers["x-amz-account-id"] account_id = request.headers.get("x-amz-account-id")
pab_config = self._parse_pab_config(request.body) data = request.body if hasattr(request, "body") else request.data
pab_config = self._parse_pab_config(data)
s3control_backend.put_public_access_block( s3control_backend.put_public_access_block(
account_id, pab_config["PublicAccessBlockConfiguration"] account_id, pab_config["PublicAccessBlockConfiguration"]
) )
return 201, {}, json.dumps({}) return 201, {}, json.dumps({})
def delete_public_access_block(self, headers): def delete_public_access_block(self, request):
account_id = headers["x-amz-account-id"] account_id = request.headers.get("x-amz-account-id")
s3control_backend.delete_public_access_block(account_id=account_id,) s3control_backend.delete_public_access_block(account_id=account_id,)
return 204, {}, json.dumps({}) return 204, {}, json.dumps({})

View File

@ -118,6 +118,7 @@ class DomainDispatcherApplication(object):
# S3 is the last resort when the target is also unknown # S3 is the last resort when the target is also unknown
service, region = DEFAULT_SERVICE_REGION service, region = DEFAULT_SERVICE_REGION
path = environ.get("PATH_INFO", "")
if service in ["budgets", "cloudfront"]: if service in ["budgets", "cloudfront"]:
# Global Services - they do not have/expect a region # Global Services - they do not have/expect a region
host = f"{service}.amazonaws.com" host = f"{service}.amazonaws.com"
@ -145,6 +146,10 @@ class DomainDispatcherApplication(object):
host = "ingest.{service}.{region}.amazonaws.com".format( host = "ingest.{service}.{region}.amazonaws.com".format(
service=service, region=region service=service, region=region
) )
elif service == "s3" and (
path.startswith("/v20180820/") or "s3-control" in environ["HTTP_HOST"]
):
host = "s3control"
else: else:
host = "{service}.{region}.amazonaws.com".format( host = "{service}.{region}.amazonaws.com".format(
service=service, region=region service=service, region=region

View File

@ -4,87 +4,76 @@ import sure # noqa # pylint: disable=unused-import
from boto3 import Session from boto3 import Session
from botocore.client import ClientError from botocore.client import ClientError
from moto import settings, mock_s3control from moto import mock_s3control
# All tests for s3-control cannot be run under the server without a modification of the
# hosts file on your system. This is due to the fact that the URL to the host is in the form of:
# ACCOUNT_ID.s3-control.amazonaws.com <-- That Account ID part is the problem. If you want to
# make use of the moto server, update your hosts file for `THE_ACCOUNT_ID_FOR_MOTO.localhost`
# and this will work fine.
if not settings.TEST_SERVER_MODE: @mock_s3control
def test_get_public_access_block_for_account():
from moto.s3.models import ACCOUNT_ID
@mock_s3control client = boto3.client("s3control", region_name="us-west-2")
def test_get_public_access_block_for_account():
from moto.s3.models import ACCOUNT_ID
client = boto3.client("s3control", region_name="us-west-2") # With an invalid account ID:
with pytest.raises(ClientError) as ce:
client.get_public_access_block(AccountId="111111111111")
assert ce.value.response["Error"]["Code"] == "AccessDenied"
# With an invalid account ID: # Without one defined:
with pytest.raises(ClientError) as ce: with pytest.raises(ClientError) as ce:
client.get_public_access_block(AccountId="111111111111") client.get_public_access_block(AccountId=ACCOUNT_ID)
assert ce.value.response["Error"]["Code"] == "AccessDenied" assert ce.value.response["Error"]["Code"] == "NoSuchPublicAccessBlockConfiguration"
# Without one defined: # Put a with an invalid account ID:
with pytest.raises(ClientError) as ce: with pytest.raises(ClientError) as ce:
client.get_public_access_block(AccountId=ACCOUNT_ID)
assert (
ce.value.response["Error"]["Code"] == "NoSuchPublicAccessBlockConfiguration"
)
# Put a with an invalid account ID:
with pytest.raises(ClientError) as ce:
client.put_public_access_block(
AccountId="111111111111",
PublicAccessBlockConfiguration={"BlockPublicAcls": True},
)
assert ce.value.response["Error"]["Code"] == "AccessDenied"
# Put with an invalid PAB:
with pytest.raises(ClientError) as ce:
client.put_public_access_block(
AccountId=ACCOUNT_ID, PublicAccessBlockConfiguration={}
)
assert ce.value.response["Error"]["Code"] == "InvalidRequest"
assert (
"Must specify at least one configuration."
in ce.value.response["Error"]["Message"]
)
# Correct PAB:
client.put_public_access_block( client.put_public_access_block(
AccountId=ACCOUNT_ID, AccountId="111111111111",
PublicAccessBlockConfiguration={ PublicAccessBlockConfiguration={"BlockPublicAcls": True},
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True,
},
) )
assert ce.value.response["Error"]["Code"] == "AccessDenied"
# Get the correct PAB (for all regions): # Put with an invalid PAB:
for region in Session().get_available_regions("s3control"): with pytest.raises(ClientError) as ce:
region_client = boto3.client("s3control", region_name=region) client.put_public_access_block(
assert region_client.get_public_access_block(AccountId=ACCOUNT_ID)[ AccountId=ACCOUNT_ID, PublicAccessBlockConfiguration={}
"PublicAccessBlockConfiguration"
] == {
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True,
}
# Delete with an invalid account ID:
with pytest.raises(ClientError) as ce:
client.delete_public_access_block(AccountId="111111111111")
assert ce.value.response["Error"]["Code"] == "AccessDenied"
# Delete successfully:
client.delete_public_access_block(AccountId=ACCOUNT_ID)
# Confirm that it's deleted:
with pytest.raises(ClientError) as ce:
client.get_public_access_block(AccountId=ACCOUNT_ID)
assert (
ce.value.response["Error"]["Code"] == "NoSuchPublicAccessBlockConfiguration"
) )
assert ce.value.response["Error"]["Code"] == "InvalidRequest"
assert (
"Must specify at least one configuration."
in ce.value.response["Error"]["Message"]
)
# Correct PAB:
client.put_public_access_block(
AccountId=ACCOUNT_ID,
PublicAccessBlockConfiguration={
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True,
},
)
# Get the correct PAB (for all regions):
for region in Session().get_available_regions("s3control"):
region_client = boto3.client("s3control", region_name=region)
assert region_client.get_public_access_block(AccountId=ACCOUNT_ID)[
"PublicAccessBlockConfiguration"
] == {
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True,
}
# Delete with an invalid account ID:
with pytest.raises(ClientError) as ce:
client.delete_public_access_block(AccountId="111111111111")
assert ce.value.response["Error"]["Code"] == "AccessDenied"
# Delete successfully:
client.delete_public_access_block(AccountId=ACCOUNT_ID)
# Confirm that it's deleted:
with pytest.raises(ClientError) as ce:
client.get_public_access_block(AccountId=ACCOUNT_ID)
assert ce.value.response["Error"]["Code"] == "NoSuchPublicAccessBlockConfiguration"