@@ -66,10 +66,14 @@ class HTTPSignatureAuth(requests.auth.AuthBase):
6666 the nonce can be controlled by subclassing this class and overloading the ``get_nonce()`` method.
6767 :param expires_in:
6868 Use this to set the ``expires`` signature parameter to the time of signing plus the given timedelta.
69- :param component_resolver_class:
70- Use this to subclass ``http_message_signatures.HTTPSignatureComponentResolver`` and customize header and
71- derived component retrieval if needed.
7269 """
70+
71+ component_resolver_class : type = HTTPSignatureComponentResolver
72+ """
73+ A subclass of ``http_message_signatures.HTTPSignatureComponentResolver`` can be used to override this value
74+ to customize the retrieval of header and derived component values if needed.
75+ """
76+
7377 _digest_hashers = {"sha-256" : hashlib .sha256 , "sha-512" : hashlib .sha512 }
7478
7579 def __init__ (self , * ,
@@ -81,8 +85,7 @@ def __init__(self, *,
8185 label : str = None ,
8286 include_alg : bool = True ,
8387 use_nonce : bool = False ,
84- expires_in : datetime .timedelta = None ,
85- component_resolver_class : type = HTTPSignatureComponentResolver ):
88+ expires_in : datetime .timedelta = None ):
8689 if key_resolver is None and key is None :
8790 raise RequestsHttpSignatureException ("Either key_resolver or key must be specified." )
8891 if key_resolver is not None and key is not None :
@@ -96,10 +99,9 @@ def __init__(self, *,
9699 self .use_nonce = use_nonce
97100 self .covered_component_ids = covered_component_ids
98101 self .expires_in = expires_in
99- handler_args = dict (signature_algorithm = signature_algorithm ,
100- key_resolver = key_resolver ,
101- component_resolver_class = component_resolver_class )
102- self .signer = HTTPMessageSigner (** handler_args )
102+ self .signer = HTTPMessageSigner (signature_algorithm = signature_algorithm ,
103+ key_resolver = key_resolver ,
104+ component_resolver_class = self .component_resolver_class )
103105
104106 def add_date (self , request , timestamp ):
105107 if "Date" not in request .headers :
@@ -108,13 +110,14 @@ def add_date(self, request, timestamp):
108110 def add_digest (self , request , algorithm = "sha-256" ):
109111 if request .body is None and "content-digest" in self .covered_component_ids :
110112 raise RequestsHttpSignatureException ("Could not compute digest header for request without a body" )
111- if request .body is not None and "Content-Digest" not in request . headers :
113+ if request .body is not None :
112114 if "content-digest" not in self .covered_component_ids :
113115 self .covered_component_ids = list (self .covered_component_ids ) + ["content-digest" ]
114- hasher = self ._digest_hashers [algorithm ]
115- digest = hasher (request .body ).digest ()
116- digest_node = http_sfv .Dictionary ({algorithm : digest })
117- request .headers ["Content-Digest" ] = str (digest_node )
116+ if "Content-Digest" not in request .headers :
117+ hasher = self ._digest_hashers [algorithm ]
118+ digest = hasher (request .body ).digest ()
119+ digest_node = http_sfv .Dictionary ({algorithm : digest })
120+ request .headers ["Content-Digest" ] = str (digest_node )
118121
119122 def get_nonce (self , request ):
120123 if self .use_nonce :
@@ -148,8 +151,7 @@ def __call__(self, request):
148151 def verify (cls , request , * ,
149152 require_components : List [str ] = ("@method" , "@authority" , "@target-uri" ),
150153 signature_algorithm : HTTPSignatureAlgorithm ,
151- key_resolver : HTTPSignatureKeyResolver ,
152- component_resolver_class : type = HTTPSignatureComponentResolver ):
154+ key_resolver : HTTPSignatureKeyResolver ):
153155 """
154156 Verify an HTTP message signature.
155157
@@ -176,8 +178,8 @@ def verify(cls, request, *,
176178 for requests without a body, and ("@method", "@authority", "@target-uri", "content-digest") for requests
177179 with a body.
178180 :param signature_algorithm:
179- The algorithm expected to be used by the signature. Any signature not using the expected algorithm will be
180- rejected. One of ``requests_http_signature.algorithms.HMAC_SHA256``,
181+ The algorithm expected to be used by the signature. Any signature not using the expected algorithm will
182+ cause an ``InvalidSignature`` exception. Must be one of ``requests_http_signature.algorithms.HMAC_SHA256``,
181183 ``requests_http_signature.algorithms.ECDSA_P256_SHA256``,
182184 ``requests_http_signature.algorithms.ED25519``,
183185 ``requests_http_signature.algorithms.RSA_PSS_SHA512``, or
@@ -188,16 +190,15 @@ def verify(cls, request, *,
188190 ``get_private_key(key_id)`` (required only for signing) and ``get_public_key(key_id)`` (required only for
189191 verifying). Your implementation should ensure that the key id is recognized and return the corresponding
190192 key material as PEM bytes (or shared secret bytes for HMAC).
191- :param component_resolver_class:
192- Use this to subclass ``http_message_signatures.HTTPSignatureComponentResolver`` and customize header and
193- derived component retrieval if needed.
194193
195194 :returns: *VerifyResult*, a namedtuple with the following attributes:
196195
197196 * ``label`` (str): The label for the signature
198197 * ``algorithm``: (same as ``signature_algorithm`` above)
199198 * ``covered_components``: A mapping of component names to their values, as covered by the signature
200199 * ``parameters``: A mapping of signature parameters to their values, as covered by the signature
200+ * ``body``: The message body for requests that have a body and pass validation of the covered
201+ content-digest; ``None`` otherwise.
201202
202203 :raises: ``InvalidSignature`` - raised whenever signature validation fails for any reason.
203204 """
@@ -207,7 +208,7 @@ def verify(cls, request, *,
207208
208209 verifier = HTTPMessageVerifier (signature_algorithm = signature_algorithm ,
209210 key_resolver = key_resolver ,
210- component_resolver_class = component_resolver_class )
211+ component_resolver_class = cls . component_resolver_class )
211212 verify_results = verifier .verify (request )
212213 if len (verify_results ) != 1 :
213214 raise InvalidSignature ("Multiple signatures are not supported." )
@@ -223,6 +224,8 @@ def verify(cls, request, *,
223224 raise InvalidSignature ("Found a content-digest header in a request with no body" )
224225 digest = http_sfv .Dictionary ()
225226 digest .parse (verify_result .covered_components [component_key ].encode ())
227+ if len (digest ) < 1 :
228+ raise InvalidSignature ("Found a content-digest header with no digests" )
226229 for k , v in digest .items ():
227230 if k not in cls ._digest_hashers :
228231 raise InvalidSignature (f'Unsupported digest algorithm "{ k } "' )
@@ -231,4 +234,5 @@ def verify(cls, request, *,
231234 expect_digest = hasher (request .body ).digest ()
232235 if raw_digest != expect_digest :
233236 raise InvalidSignature ("The content-digest header does not match the request body" )
237+ verify_result = verify_result ._replace (body = request .body )
234238 return verify_result
0 commit comments