Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions packages/aws-sdk-signers/src/aws_sdk_signers/signers.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class SigV4SigningProperties(TypedDict, total=False):
date: str
payload_signing_enabled: bool
content_checksum_enabled: bool
uri_encode_path: bool


class SigV4Signer:
Expand Down Expand Up @@ -232,7 +233,9 @@ def canonical_request(
canonical_payload = self._format_canonical_payload(
request=request, signing_properties=signing_properties
)
canonical_path = self._format_canonical_path(path=request.destination.path)
canonical_path = self._format_canonical_path(
path=request.destination.path, signing_properties=signing_properties
)
canonical_query = self._format_canonical_query(query=request.destination.query)
normalized_fields = self._normalize_signing_fields(request=request)
canonical_fields = self._format_canonical_fields(fields=normalized_fields)
Expand Down Expand Up @@ -290,11 +293,17 @@ def _scope(self, signing_properties: SigV4SigningProperties) -> str:
# Scope format: <YYYYMMDD>/<AWS Region>/<AWS Service>/aws4_request
return f"{formatted_date}/{region}/{service}/aws4_request"

def _format_canonical_path(self, *, path: str | None) -> str:
def _format_canonical_path(
self, *, path: str | None, signing_properties: SigV4SigningProperties
) -> str:
if path is None:
path = "/"
normalized_path = _remove_dot_segments(path)
return quote(string=normalized_path, safe="/%")

if signing_properties.get("uri_encode_path", True):
normalized_path = _remove_dot_segments(path)
return quote(string=normalized_path, safe="/")
else:
return _remove_dot_segments(path, remove_consecutive_slashes=False)

def _format_canonical_query(self, *, query: str | None) -> str:
if query is None:
Expand Down Expand Up @@ -596,7 +605,7 @@ async def canonical_request(
request=request, signing_properties=signing_properties
)
canonical_path = await self._format_canonical_path(
path=request.destination.path
path=request.destination.path, signing_properties=signing_properties
)
canonical_query = await self._format_canonical_query(
query=request.destination.query
Expand Down Expand Up @@ -658,11 +667,17 @@ async def _scope(self, signing_properties: SigV4SigningProperties) -> str:
# Scope format: <YYYYMMDD>/<AWS Region>/<AWS Service>/aws4_request
return f"{formatted_date}/{region}/{service}/aws4_request"

async def _format_canonical_path(self, *, path: str | None) -> str:
async def _format_canonical_path(
self, *, path: str | None, signing_properties: SigV4SigningProperties
) -> str:
if path is None:
path = "/"
normalized_path = _remove_dot_segments(path)
return quote(string=normalized_path, safe="/%")

if signing_properties.get("uri_encode_path", True):
normalized_path = _remove_dot_segments(path)
return quote(string=normalized_path, safe="/")
else:
return _remove_dot_segments(path, remove_consecutive_slashes=False)

async def _format_canonical_query(self, *, query: str | None) -> str:
if query is None:
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=652487583200325589f1fba4c7e578f72c47cb61beeca81406b39ddec1366741
AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=446b817944c553435b35e813c261ff4e161fff982d1bacdef1c87f6785dd1662
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
GET
/example%20space/
/example%2520space/

host:example.amazonaws.com
x-amz-date:20150830T123600Z
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
GET /example%20space/ HTTP/1.1
Host:example.amazonaws.com
X-Amz-Date:20150830T123600Z
Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=652487583200325589f1fba4c7e578f72c47cb61beeca81406b39ddec1366741
Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=446b817944c553435b35e813c261ff4e161fff982d1bacdef1c87f6785dd1662
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
AWS4-HMAC-SHA256
20150830T123600Z
20150830/us-east-1/service/aws4_request
63ee75631ed7234ae61b5f736dfc7754cdccfedbff4b5128a915706ee9390d86
6a04b36fa5a84d8d24b4287d506da70f4d5289a1772e6c608495a841a8f38627
5 changes: 2 additions & 3 deletions packages/aws-sdk-signers/tests/unit/auth/test_sigv4.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,7 @@ def _test_signature_version_4_sync(test_case_name: str, signer: SigV4Signer) ->
request = create_request_from_raw_request(test_case)

signing_props = SigV4SigningProperties(
region=REGION,
service=SERVICE,
date=DATE_STR,
region=REGION, service=SERVICE, date=DATE_STR
)
with pytest.warns(AWSSDKWarning):
actual_canonical_request = signer.canonical_request(
Expand Down Expand Up @@ -198,6 +196,7 @@ def create_request_from_raw_request(
query = ""
host = raw.headers.get("host", "")
url = URI(host=host, path=path, query=query)

return AWSRequest(
destination=url,
method=request_method,
Expand Down