77import hashlib
88import hmac
99from collections import defaultdict
10+ from collections .abc import Sequence
1011from posixpath import normpath
1112from typing import Generator
1213from urllib .parse import quote
@@ -22,7 +23,15 @@ class AWS4Auth(httpx.Auth):
2223 requires_request_body = True
2324
2425 def __init__ (
25- self , access_id : str , secret_key : str , region : str , service : str , ** kwargs
26+ self ,
27+ access_id : str ,
28+ secret_key : str ,
29+ region : str ,
30+ service : str ,
31+ security_token : str | None = None ,
32+ include_headers : Sequence [str ] = tuple (),
33+ enable_payload_signing : bool = True ,
34+ ** kwargs ,
2635 ):
2736 """
2837
@@ -34,6 +43,9 @@ def __init__(
3443 :param service: The name of the service you're connecting to, as per endpoints at:
3544 http://docs.aws.amazon.com/general/latest/gr/rande.html
3645 e.g. elasticbeanstalk.
46+ :param enable_payload_signing: Whether to include payload hash in signature
47+ AWS Lattice service does not support payload signing - https://docs.aws.amazon.com/vpc-lattice/latest/ug/sigv4-authenticated-requests.html
48+ Setting this parameter to False will set x-amz-content-sha256 header value to "UNSIGNED-PAYLOAD"
3749 :param security_token: Used for the x-amz-security-token header, for use with STS temporary credentials.
3850 :param include_headers: Set of headers to include in the canonical and signed headers, in addition to:
3951 * host
@@ -48,12 +60,9 @@ def __init__(
4860 self .access_id = access_id
4961 self .region = region
5062 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- }
63+ self .enable_payload_signing = enable_payload_signing
64+ self .security_token = security_token
65+ self .include_headers = {header .lower () for header in include_headers }
5766
5867 def auth_flow (
5968 self , request : httpx .Request
@@ -69,9 +78,13 @@ def auth_flow(
6978 # The x-amz-content-sha256 header is required for all AWS Signature Version 4 requests.
7079 # It provides a hash of the request payload.
7180 # 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 ()
81+ # This does not apply to AWS Lattice which does not support payload signing.
82+ # In this case the value of this header must be set to "UNSIGNED-PAYLOAD".
83+ if self .enable_payload_signing :
84+ content_hash_digest = hashlib .sha256 (request .read ()).hexdigest ()
85+ else :
86+ content_hash_digest = "UNSIGNED-PAYLOAD"
87+ request .headers ["x-amz-content-sha256" ] = content_hash_digest
7588
7689 # https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
7790 # if you are using temporary security credentials, you need to include x-amz-security-token in your request.
0 commit comments