2024-01-13 18:38:05 +00:00
|
|
|
import os
|
|
|
|
from unittest import SkipTest
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
|
|
import boto3
|
|
|
|
import pytest
|
|
|
|
import requests
|
|
|
|
from botocore.exceptions import ClientError
|
|
|
|
|
|
|
|
from moto import mock_aws, settings
|
2024-01-17 10:02:15 +00:00
|
|
|
from moto.core.versions import is_werkzeug_2_0_x_or_older
|
2024-01-13 18:38:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_passthrough_calls_for_entire_service() -> None:
|
|
|
|
if not settings.TEST_DECORATOR_MODE:
|
|
|
|
raise SkipTest("Can only test config when using decorators")
|
2024-01-17 10:02:15 +00:00
|
|
|
if is_werkzeug_2_0_x_or_older():
|
|
|
|
raise SkipTest(
|
|
|
|
"Bug in old werkzeug versions where headers with byte-values throw errors"
|
|
|
|
)
|
2024-01-13 18:38:05 +00:00
|
|
|
# Still mock the credentials ourselves, we don't want to reach out to AWS for real
|
|
|
|
with patch.dict(
|
|
|
|
os.environ, {"AWS_ACCESS_KEY_ID": "a", "AWS_SECRET_ACCESS_KEY": "b"}
|
|
|
|
):
|
|
|
|
list_buckets_url = "https://s3.amazonaws.com/"
|
|
|
|
|
|
|
|
# All requests to S3 are passed through
|
|
|
|
with mock_aws(
|
|
|
|
config={
|
|
|
|
"core": {"mock_credentials": False, "passthrough": {"services": ["s3"]}}
|
|
|
|
}
|
|
|
|
):
|
|
|
|
s3 = boto3.client("s3", "us-east-1")
|
|
|
|
with pytest.raises(ClientError) as exc:
|
|
|
|
s3.list_buckets()
|
|
|
|
assert exc.value.response["Error"]["Code"] == "InvalidAccessKeyId"
|
|
|
|
|
|
|
|
resp = _aws_request(list_buckets_url)
|
|
|
|
assert resp.status_code == 403
|
|
|
|
|
|
|
|
# Calls to SQS are mocked normally
|
|
|
|
sqs = boto3.client("sqs", "us-east-1")
|
|
|
|
sqs.list_queues()
|
|
|
|
|
|
|
|
# Sanity check that the passthrough does not persist
|
|
|
|
with mock_aws():
|
|
|
|
s3 = boto3.client("s3", "us-east-1")
|
|
|
|
assert s3.list_buckets()["Buckets"] == []
|
|
|
|
|
|
|
|
resp = _aws_request(list_buckets_url)
|
|
|
|
assert resp.status_code == 200
|
|
|
|
assert b"<Buckets></Buckets>" in resp.content
|
|
|
|
|
|
|
|
|
|
|
|
def test_passthrough_calls_for_specific_url() -> None:
|
|
|
|
if not settings.TEST_DECORATOR_MODE:
|
|
|
|
raise SkipTest("Can only test config when using decorators")
|
2024-01-17 10:02:15 +00:00
|
|
|
if is_werkzeug_2_0_x_or_older():
|
|
|
|
raise SkipTest(
|
|
|
|
"Bug in old werkzeug versions where headers with byte-values throw errors"
|
|
|
|
)
|
2024-01-13 18:38:05 +00:00
|
|
|
# Still mock the credentials ourselves, we don't want to reach out to AWS for real
|
|
|
|
with patch.dict(
|
|
|
|
os.environ, {"AWS_ACCESS_KEY_ID": "a", "AWS_SECRET_ACCESS_KEY": "b"}
|
|
|
|
):
|
|
|
|
list_buckets_url = "https://s3.amazonaws.com/"
|
|
|
|
|
|
|
|
# All requests to these URL's are passed through
|
|
|
|
with mock_aws(
|
|
|
|
config={
|
|
|
|
"core": {
|
|
|
|
"mock_credentials": False,
|
|
|
|
"passthrough": {"urls": ["https://realbucket.s3.amazonaws.com/"]},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
):
|
|
|
|
s3 = boto3.client("s3", "us-east-1")
|
|
|
|
with pytest.raises(ClientError) as exc:
|
|
|
|
s3.create_bucket(Bucket="realbucket")
|
|
|
|
assert exc.value.response["Error"]["Code"] == "InvalidAccessKeyId"
|
|
|
|
|
|
|
|
# List buckets works
|
|
|
|
assert _aws_request(list_buckets_url).status_code == 200
|
|
|
|
assert s3.list_buckets()["Buckets"] == []
|
|
|
|
|
|
|
|
# Creating different buckets works
|
|
|
|
s3.create_bucket(Bucket="diff")
|
|
|
|
|
|
|
|
# Manual requests are also not allowed
|
|
|
|
assert (
|
|
|
|
_aws_request("https://realbucket.s3.amazonaws.com/").status_code == 403
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_passthrough_calls_for_wildcard_urls() -> None:
|
|
|
|
if not settings.TEST_DECORATOR_MODE:
|
|
|
|
raise SkipTest("Can only test config when using decorators")
|
|
|
|
# Still mock the credentials ourselves, we don't want to reach out to AWS for real
|
|
|
|
with patch.dict(
|
|
|
|
os.environ, {"AWS_ACCESS_KEY_ID": "a", "AWS_SECRET_ACCESS_KEY": "b"}
|
|
|
|
):
|
|
|
|
|
|
|
|
# All requests to these URL's are passed through
|
|
|
|
with mock_aws(
|
|
|
|
config={
|
|
|
|
"core": {
|
|
|
|
"mock_credentials": False,
|
|
|
|
"passthrough": {
|
|
|
|
"urls": [
|
|
|
|
"https://companyname_*.s3.amazonaws.com/",
|
|
|
|
"https://s3.amazonaws.com/companyname_*",
|
|
|
|
]
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
):
|
|
|
|
s3 = boto3.client("s3", "us-east-1")
|
|
|
|
with pytest.raises(ClientError) as exc:
|
|
|
|
s3.create_bucket(Bucket="companyname_prod")
|
|
|
|
assert exc.value.response["Error"]["Code"] == "InvalidAccessKeyId"
|
|
|
|
|
|
|
|
# Creating different buckets works
|
|
|
|
s3.create_bucket(Bucket="diffcompany_prod")
|
|
|
|
|
|
|
|
# Manual requests are also not allowed
|
|
|
|
assert (
|
|
|
|
_aws_request("https://s3.amazonaws.com/companyname_prod").status_code
|
|
|
|
== 403
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_passthrough__using_unsupported_service() -> None:
|
|
|
|
if not settings.TEST_DECORATOR_MODE:
|
|
|
|
raise SkipTest("Can only test config when using decorators")
|
|
|
|
with patch.dict(
|
|
|
|
os.environ, {"AWS_ACCESS_KEY_ID": "a", "AWS_SECRET_ACCESS_KEY": "b"}
|
|
|
|
):
|
|
|
|
# Requests to unsupported services still throw a NotYetImplemented
|
|
|
|
with mock_aws(
|
|
|
|
config={
|
|
|
|
"core": {
|
|
|
|
"mock_credentials": False,
|
|
|
|
"passthrough": {"services": ["s3"]},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
):
|
2024-01-17 10:02:15 +00:00
|
|
|
workdocs = boto3.client("workdocs", "us-east-1")
|
2024-01-13 18:38:05 +00:00
|
|
|
with pytest.raises(ClientError) as exc:
|
2024-01-17 10:02:15 +00:00
|
|
|
workdocs.describe_users()
|
2024-01-13 18:38:05 +00:00
|
|
|
assert "Not yet implemented" in str(exc.value)
|
|
|
|
|
|
|
|
|
|
|
|
def _aws_request(url: str) -> requests.Response:
|
|
|
|
creds = b"AWS4-HMAC-SHA256 Credential=a/20240107/us-east-1/s3/aws4_request, Signature=sig"
|
|
|
|
headers = {"Authorization": creds, "X-Amz-Content-SHA256": b"UNSIGNED-PAYLOAD"}
|
|
|
|
return requests.get(url, headers=headers)
|