MotoServer: skip using HTTP_HOST header when determining request origin (#7225)
This commit is contained in:
parent
8199a88446
commit
09c5751671
@ -63,7 +63,9 @@ class DomainDispatcherApplication:
|
|||||||
self.app_instances: Dict[str, Flask] = {}
|
self.app_instances: Dict[str, Flask] = {}
|
||||||
self.backend_url_patterns = backend_index.backend_url_patterns
|
self.backend_url_patterns = backend_index.backend_url_patterns
|
||||||
|
|
||||||
def get_backend_for_host(self, host: str) -> Any:
|
def get_backend_for_host(self, host: Optional[str]) -> Any:
|
||||||
|
if host is None:
|
||||||
|
return None
|
||||||
|
|
||||||
if host == "moto_api":
|
if host == "moto_api":
|
||||||
return host
|
return host
|
||||||
@ -82,8 +84,8 @@ class DomainDispatcherApplication:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def infer_service_region_host(
|
def infer_service_region_host(
|
||||||
self, body: Optional[str], environ: Dict[str, Any]
|
self, environ: Dict[str, Any], path: str
|
||||||
) -> str:
|
) -> Optional[str]:
|
||||||
auth = environ.get("HTTP_AUTHORIZATION")
|
auth = environ.get("HTTP_AUTHORIZATION")
|
||||||
target = environ.get("HTTP_X_AMZ_TARGET")
|
target = environ.get("HTTP_X_AMZ_TARGET")
|
||||||
service = None
|
service = None
|
||||||
@ -109,25 +111,24 @@ class DomainDispatcherApplication:
|
|||||||
# infer a service-region. A reduced set of services still use
|
# infer a service-region. A reduced set of services still use
|
||||||
# the deprecated SigV2, ergo prefer S3 as most likely default.
|
# the deprecated SigV2, ergo prefer S3 as most likely default.
|
||||||
# https://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
|
# https://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
|
||||||
service, region = DEFAULT_SERVICE_REGION
|
return None
|
||||||
else:
|
else:
|
||||||
# Unsigned request
|
# Unsigned request
|
||||||
|
body = self._get_body(environ)
|
||||||
action = self.get_action_from_body(body)
|
action = self.get_action_from_body(body)
|
||||||
if target:
|
if target:
|
||||||
service, _ = target.split(".", 1)
|
service, _ = target.split(".", 1)
|
||||||
service, region = UNSIGNED_REQUESTS.get(service, DEFAULT_SERVICE_REGION)
|
service, region = UNSIGNED_REQUESTS.get(service, (None, None))
|
||||||
elif action and action in UNSIGNED_ACTIONS:
|
elif action and action in UNSIGNED_ACTIONS:
|
||||||
# See if we can match the Action to a known service
|
# See if we can match the Action to a known service
|
||||||
service, region = UNSIGNED_ACTIONS[action]
|
service, region = UNSIGNED_ACTIONS[action]
|
||||||
if not service:
|
if not service:
|
||||||
service, region = self.get_service_from_body(body, environ)
|
service, region = self.get_service_from_body(body, environ)
|
||||||
if not service:
|
if not service:
|
||||||
service, region = self.get_service_from_path(environ)
|
service, region = self.get_service_from_path(path)
|
||||||
if not service:
|
if not service:
|
||||||
# S3 is the last resort when the target is also unknown
|
return None
|
||||||
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"
|
||||||
@ -177,14 +178,16 @@ class DomainDispatcherApplication:
|
|||||||
elif path_info.startswith("/latest/meta-data/"):
|
elif path_info.startswith("/latest/meta-data/"):
|
||||||
host = "instance_metadata"
|
host = "instance_metadata"
|
||||||
else:
|
else:
|
||||||
host = environ["HTTP_HOST"].split(":")[0]
|
host = None
|
||||||
|
|
||||||
with self.lock:
|
with self.lock:
|
||||||
backend = self.get_backend_for_host(host)
|
backend = self.get_backend_for_host(host)
|
||||||
if not backend:
|
if not backend:
|
||||||
# No regular backend found; try parsing body/other headers
|
# No regular backend found; try parsing body/other headers
|
||||||
body = self._get_body(environ)
|
host = self.infer_service_region_host(environ, path_info)
|
||||||
host = self.infer_service_region_host(body, environ)
|
if host is None:
|
||||||
|
service, region = DEFAULT_SERVICE_REGION
|
||||||
|
host = f"{service}.{region}.amazonaws.com"
|
||||||
backend = self.get_backend_for_host(host)
|
backend = self.get_backend_for_host(host)
|
||||||
|
|
||||||
app = self.app_instances.get(backend, None)
|
app = self.app_instances.get(backend, None)
|
||||||
@ -239,12 +242,11 @@ class DomainDispatcherApplication:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def get_service_from_path(
|
def get_service_from_path(
|
||||||
self, environ: Dict[str, Any]
|
self, path_info: str
|
||||||
) -> Tuple[Optional[str], Optional[str]]:
|
) -> Tuple[Optional[str], Optional[str]]:
|
||||||
# Moto sometimes needs to send a HTTP request to itself
|
# Moto sometimes needs to send a HTTP request to itself
|
||||||
# In which case it will send a request to 'http://localhost/service_region/whatever'
|
# In which case it will send a request to 'http://localhost/service_region/whatever'
|
||||||
try:
|
try:
|
||||||
path_info = environ.get("PATH_INFO", "/")
|
|
||||||
service, region = path_info[1 : path_info.index("/", 1)].split("_")
|
service, region = path_info[1 : path_info.index("/", 1)].split("_")
|
||||||
return service, region
|
return service, region
|
||||||
except (AttributeError, KeyError, ValueError):
|
except (AttributeError, KeyError, ValueError):
|
||||||
|
@ -18,7 +18,7 @@ def test_table_list():
|
|||||||
raise SkipTest("Only run test with external server")
|
raise SkipTest("Only run test with external server")
|
||||||
headers = {
|
headers = {
|
||||||
"X-Amz-Target": "DynamoDB_20111205.ListTables",
|
"X-Amz-Target": "DynamoDB_20111205.ListTables",
|
||||||
"Host": "dynamodb.us-east-1.amazonaws.com",
|
"AUTHORIZATION": "AWS4-HMAC-SHA256 Credential=ACCESS_KEY/20220226/us-east-1/dynamodb/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=sig",
|
||||||
}
|
}
|
||||||
requests.post(settings.test_server_mode_endpoint() + "/moto-api/reset")
|
requests.post(settings.test_server_mode_endpoint() + "/moto-api/reset")
|
||||||
res = requests.get(settings.test_server_mode_endpoint(), headers=headers)
|
res = requests.get(settings.test_server_mode_endpoint(), headers=headers)
|
||||||
|
Loading…
Reference in New Issue
Block a user