Skip to content

Commit d13cca4

Browse files
authored
Merge pull request #27 from NewtonDer/master
fix: missing Auth header returns 400 Bad Request
2 parents ceaced5 + cbba8eb commit d13cca4

File tree

3 files changed

+142
-4
lines changed

3 files changed

+142
-4
lines changed

aws_jupyter_proxy/awsproxy.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -378,10 +378,21 @@ def _build_upstream_auth_info(self) -> UpstreamAuthInfo:
378378
379379
:return: the UpstreamAuthInfo instance
380380
"""
381-
auth_header_parts = self.upstream_request.headers["Authorization"].split(" ")
382381

383-
signed_headers = auth_header_parts[2].strip(",").split("=")[1].split(";")
384-
_, _, region, service_name, _ = auth_header_parts[1].split("=")[1].split("/")
382+
try:
383+
auth_header_parts = self.upstream_request.headers["Authorization"].split(
384+
" "
385+
)
386+
387+
signed_headers = auth_header_parts[2].strip(",").split("=")[1].split(";")
388+
_, _, region, service_name, _ = (
389+
auth_header_parts[1].split("=")[1].split("/")
390+
)
391+
except KeyError:
392+
raise HTTPError(400, message=f"Missing Authorization header")
393+
except (IndexError, ValueError):
394+
raise HTTPError(400, message=f"Malformed Authorization header")
395+
385396
return UpstreamAuthInfo(service_name, region, signed_headers)
386397

387398

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="aws_jupyter_proxy",
8-
version="0.3.6",
8+
version="0.3.7",
99
url="https://github.com/aws/aws-jupyter-proxy",
1010
author="Amazon Web Services",
1111
description="A Jupyter server extension to proxy requests with AWS SigV4 authentication",

tests/unit/test_awsproxy.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,133 @@ async def test_request_with_base_url(mock_getenv, mock_fetch, mock_session):
889889
assert_http_response(mock_fetch, expected)
890890

891891

892+
@pytest.mark.asyncio
893+
@patch("os.getenv")
894+
async def test_missing_authorization_header(mock_getenv, mock_session):
895+
# Given
896+
upstream_request = HTTPServerRequest(
897+
method="HEAD",
898+
uri="/awsproxy/bucket-name-1",
899+
headers=HTTPHeaders(
900+
{
901+
"Host": "localhost:8888",
902+
"X-Amz-User-Agent": "aws-sdk-js/2.507.0 promise",
903+
"X-Amz-Content-Sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
904+
"X-Amz-Date": "20190828T173626Z",
905+
}
906+
),
907+
body=None,
908+
host="localhost:8888",
909+
)
910+
mock_getenv.return_value = ""
911+
912+
# When
913+
with pytest.raises(HTTPError) as e:
914+
await AwsProxyRequest(
915+
upstream_request, create_endpoint_resolver(), mock_session
916+
).execute_downstream()
917+
918+
# Then
919+
assert 400 == e.value.code
920+
assert "Missing Authorization header" == e.value.message
921+
922+
923+
@pytest.mark.asyncio
924+
@patch("os.getenv")
925+
async def test_missing_region_in_authorization_header(mock_getenv, mock_session):
926+
# Given
927+
upstream_request = HTTPServerRequest(
928+
method="HEAD",
929+
uri="/awsproxy/bucket-name-1",
930+
headers=HTTPHeaders(
931+
{
932+
"Host": "localhost:8888",
933+
"X-Amz-User-Agent": "aws-sdk-js/2.507.0 promise",
934+
"X-Amz-Content-Sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
935+
"X-Amz-Date": "20190828T173626Z",
936+
"Authorization": "AWS4-HMAC-SHA256 Credential=IGNOREDIGNO/20230317/some-service/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-user-agent;x-service-endpoint-url;x-xsrftoken, Signature=123456789",
937+
}
938+
),
939+
body=None,
940+
host="localhost:8888",
941+
)
942+
mock_getenv.return_value = ""
943+
944+
# When
945+
with pytest.raises(HTTPError) as e:
946+
await AwsProxyRequest(
947+
upstream_request, create_endpoint_resolver(), mock_session
948+
).execute_downstream()
949+
950+
# Then
951+
assert 400 == e.value.code
952+
assert "Malformed Authorization header" == e.value.message
953+
954+
955+
@pytest.mark.asyncio
956+
@patch("os.getenv")
957+
async def test_missing_service_in_authorization_header(mock_getenv, mock_session):
958+
# Given
959+
upstream_request = HTTPServerRequest(
960+
method="HEAD",
961+
uri="/awsproxy/bucket-name-1",
962+
headers=HTTPHeaders(
963+
{
964+
"Host": "localhost:8888",
965+
"X-Amz-User-Agent": "aws-sdk-js/2.507.0 promise",
966+
"X-Amz-Content-Sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
967+
"X-Amz-Date": "20190828T173626Z",
968+
"Authorization": "AWS4-HMAC-SHA256 Credential=IGNOREDIGNO/20230317/us-west-2/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-user-agent;x-service-endpoint-url;x-xsrftoken, Signature=123456789",
969+
}
970+
),
971+
body=None,
972+
host="localhost:8888",
973+
)
974+
mock_getenv.return_value = ""
975+
976+
# When
977+
with pytest.raises(HTTPError) as e:
978+
await AwsProxyRequest(
979+
upstream_request, create_endpoint_resolver(), mock_session
980+
).execute_downstream()
981+
982+
# Then
983+
assert 400 == e.value.code
984+
assert "Malformed Authorization header" == e.value.message
985+
986+
987+
@pytest.mark.asyncio
988+
@patch("os.getenv")
989+
async def test_malformed_authorization_header(mock_getenv, mock_session):
990+
# Given
991+
upstream_request = HTTPServerRequest(
992+
method="HEAD",
993+
uri="/awsproxy/bucket-name-1",
994+
headers=HTTPHeaders(
995+
{
996+
"Host": "localhost:8888",
997+
"X-Amz-User-Agent": "aws-sdk-js/2.507.0 promise",
998+
"X-Amz-Content-Sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
999+
"X-Amz-Date": "20190828T173626Z",
1000+
"Authorization": "AWS4-HMAC-SHA256 malformed-content",
1001+
}
1002+
),
1003+
body=None,
1004+
host="localhost:8888",
1005+
)
1006+
mock_getenv.return_value = ""
1007+
1008+
# When
1009+
with pytest.raises(HTTPError) as e:
1010+
await AwsProxyRequest(
1011+
upstream_request, create_endpoint_resolver(), mock_session
1012+
).execute_downstream()
1013+
1014+
# Then
1015+
assert 400 == e.value.code
1016+
assert "Malformed Authorization header" == e.value.message
1017+
1018+
8921019
def assert_http_response(mock_fetch, expected_http_request):
8931020
mock_fetch.assert_awaited_once()
8941021
actual_http_request: HTTPRequest = mock_fetch.await_args[0][0]

0 commit comments

Comments
 (0)