moto/tests/test_core/test_request_passthrough.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

157 lines
5.7 KiB
Python
Raw Normal View History

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
from moto.core.versions import is_werkzeug_2_0_x_or_older
def test_passthrough_calls_for_entire_service() -> None:
if not settings.TEST_DECORATOR_MODE:
raise SkipTest("Can only test config when using decorators")
if is_werkzeug_2_0_x_or_older():
raise SkipTest(
"Bug in old werkzeug versions where headers with byte-values throw errors"
)
# 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")
if is_werkzeug_2_0_x_or_older():
raise SkipTest(
"Bug in old werkzeug versions where headers with byte-values throw errors"
)
# 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"]},
}
}
):
workdocs = boto3.client("workdocs", "us-east-1")
with pytest.raises(ClientError) as exc:
workdocs.describe_users()
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)