Skip to content

Commit 86d458d

Browse files
authored
Validate region name from S3 redirect (boto#3644)
1 parent aeb108c commit 86d458d

File tree

3 files changed

+59
-14
lines changed

3 files changed

+59
-14
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"type": "enhancement",
3+
"category": "S3 redirect",
4+
"description": "Validate new region name when redirecting."
5+
}

botocore/utils.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,21 +1887,19 @@ def get_bucket_region(self, bucket, response):
18871887
service_response = response[1]
18881888
response_headers = service_response['ResponseMetadata']['HTTPHeaders']
18891889
if 'x-amz-bucket-region' in response_headers:
1890-
return response_headers['x-amz-bucket-region']
1891-
1890+
region = response_headers['x-amz-bucket-region']
18921891
# Next, check the error body
1893-
region = service_response.get('Error', {}).get('Region', None)
1894-
if region is not None:
1895-
return region
1896-
1897-
# Finally, HEAD the bucket. No other choice sadly.
1898-
try:
1899-
response = self._client.head_bucket(Bucket=bucket)
1900-
headers = response['ResponseMetadata']['HTTPHeaders']
1901-
except ClientError as e:
1902-
headers = e.response['ResponseMetadata']['HTTPHeaders']
1903-
1904-
region = headers.get('x-amz-bucket-region', None)
1892+
elif r := service_response.get('Error', {}).get('Region', None):
1893+
region = r
1894+
else:
1895+
# Finally, HEAD the bucket. No other choice sadly.
1896+
try:
1897+
response = self._client.head_bucket(Bucket=bucket)
1898+
headers = response['ResponseMetadata']['HTTPHeaders']
1899+
except ClientError as e:
1900+
headers = e.response['ResponseMetadata']['HTTPHeaders']
1901+
region = headers.get('x-amz-bucket-region', None)
1902+
validate_region_name(region)
19051903
return region
19061904

19071905
def set_request_url(self, old_url, new_endpoint, **kwargs):

tests/unit/test_utils.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
InvalidExpressionError,
3939
InvalidIMDSEndpointError,
4040
InvalidIMDSEndpointModeError,
41+
InvalidRegionError,
4142
MetadataRetrievalError,
4243
ReadTimeoutError,
4344
SSOTokenLoadError,
@@ -2113,6 +2114,47 @@ def test_no_redirect_from_error_for_mrap_accesspoint(self):
21132114
)
21142115
self.assertEqual(redirect_response, None)
21152116

2117+
def test_get_region_validates_region_from_header(self):
2118+
response = (
2119+
None,
2120+
{
2121+
'Error': {'Code': 'PermanentRedirect'},
2122+
'ResponseMetadata': {
2123+
'HTTPHeaders': {'x-amz-bucket-region': 'invalid region!'}
2124+
},
2125+
},
2126+
)
2127+
with self.assertRaises(InvalidRegionError):
2128+
self.redirector.get_bucket_region('foo', response)
2129+
2130+
def test_get_region_validates_region_from_error_body(self):
2131+
response = (
2132+
None,
2133+
{
2134+
'Error': {
2135+
'Code': 'PermanentRedirect',
2136+
'Region': 'invalid region!',
2137+
},
2138+
'ResponseMetadata': {'HTTPHeaders': {}},
2139+
},
2140+
)
2141+
with self.assertRaises(InvalidRegionError):
2142+
self.redirector.get_bucket_region('foo', response)
2143+
2144+
def test_get_region_validates_region_from_head_bucket(self):
2145+
self.set_client_response_headers(
2146+
{'x-amz-bucket-region': 'invalid region!'}
2147+
)
2148+
response = (
2149+
None,
2150+
{
2151+
'Error': {'Code': 'PermanentRedirect'},
2152+
'ResponseMetadata': {'HTTPHeaders': {}},
2153+
},
2154+
)
2155+
with self.assertRaises(InvalidRegionError):
2156+
self.redirector.get_bucket_region('foo', response)
2157+
21162158

21172159
class TestArnParser(unittest.TestCase):
21182160
def setUp(self):

0 commit comments

Comments
 (0)