88import hmac
99from collections import defaultdict
1010from posixpath import normpath
11- from typing import Generator
11+ from typing import Generator , Sequence , Optional
1212from urllib .parse import quote
1313
1414import httpx
@@ -22,7 +22,15 @@ class AWS4Auth(httpx.Auth):
2222 requires_request_body = True
2323
2424 def __init__ (
25- self , access_id : str , secret_key : str , region : str , service : str , ** kwargs
25+ self ,
26+ access_id : str ,
27+ secret_key : str ,
28+ region : str ,
29+ service : str ,
30+ security_token : Optional [str ] = None ,
31+ include_headers : Sequence [str ] = tuple (),
32+ enable_payload_signing : bool = True ,
33+ ** kwargs ,
2634 ):
2735 """
2836
@@ -34,6 +42,9 @@ def __init__(
3442 :param service: The name of the service you're connecting to, as per endpoints at:
3543 http://docs.aws.amazon.com/general/latest/gr/rande.html
3644 e.g. elasticbeanstalk.
45+ :param enable_payload_signing: Whether to include payload hash in signature
46+ AWS Lattice service does not support payload signing - https://docs.aws.amazon.com/vpc-lattice/latest/ug/sigv4-authenticated-requests.html
47+ Setting this parameter to False will set x-amz-content-sha256 header value to "UNSIGNED-PAYLOAD"
3748 :param security_token: Used for the x-amz-security-token header, for use with STS temporary credentials.
3849 :param include_headers: Set of headers to include in the canonical and signed headers, in addition to:
3950 * host
@@ -48,12 +59,9 @@ def __init__(
4859 self .access_id = access_id
4960 self .region = region
5061 self .service = service
51-
52- self .security_token = kwargs .get ("security_token" )
53-
54- self .include_headers = {
55- header .lower () for header in kwargs .get ("include_headers" , [])
56- }
62+ self .enable_payload_signing = enable_payload_signing
63+ self .security_token = security_token
64+ self .include_headers = {header .lower () for header in include_headers }
5765
5866 def auth_flow (
5967 self , request : httpx .Request
@@ -69,9 +77,13 @@ def auth_flow(
6977 # The x-amz-content-sha256 header is required for all AWS Signature Version 4 requests.
7078 # It provides a hash of the request payload.
7179 # If there is no payload, you must provide the hash of an empty string.
72- request .headers ["x-amz-content-sha256" ] = hashlib .sha256 (
73- request .read ()
74- ).hexdigest ()
80+ # This does not apply to AWS Lattice which does not support payload signing.
81+ # In this case the value of this header must be set to "UNSIGNED-PAYLOAD".
82+ if self .enable_payload_signing :
83+ content_hash_digest = hashlib .sha256 (request .read ()).hexdigest ()
84+ else :
85+ content_hash_digest = "UNSIGNED-PAYLOAD"
86+ request .headers ["x-amz-content-sha256" ] = content_hash_digest
7587
7688 # https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
7789 # if you are using temporary security credentials, you need to include x-amz-security-token in your request.
0 commit comments