diff --git a/README.rst b/README.rst index 4dc870c..8cd467c 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,8 @@ http-message-signatures: An implementation of the IETF HTTP Message Signatures draft standard ============================================================================================= -*http-message-signatures* is an implementation of the IETF `HTTP Message Signatures `_ draft standard in +*http-message-signatures* is an implementation of the IETF +`HTTP Message Signatures `_ draft standard in Python. Installation @@ -52,7 +53,16 @@ builds upon this package to provide integrated signing and validation of the req In http-message-signatures, you can ensure that the information signed is what you expect to be signed by only trusting the data returned by the ``verify()`` method:: - FIXME: example + verify_result = verifier.verify(request) + + This returns VerifyResult, a namedtuple with the following attributes: + + * label (str): The label for the signature + * algorithm: (same as signature_algorithm above) + * covered_components: A mapping of component names to their values, as covered by the signature + * parameters: A mapping of signature parameters to their values, as covered by the signature + * body: Always ``None`` (the `requests-http-signature `_ package + implements returning the body upon successful digest validation). Authors ------- diff --git a/http_message_signatures/signatures.py b/http_message_signatures/signatures.py index e2fbea3..64706b9 100644 --- a/http_message_signatures/signatures.py +++ b/http_message_signatures/signatures.py @@ -67,7 +67,6 @@ def sign(self, request, *, include_alg: bool = True, covered_component_ids: List[str] = ("@method", "@authority", "@target-uri")): # TODO: Accept-Signature autonegotiation - # TODO: if sign_body=True and body exists: inject content-digest if not set, add to covered components key = self.key_resolver.resolve_private_key(key_id) if created is None: created = datetime.datetime.utcnow() @@ -81,8 +80,6 @@ def sign(self, request, *, signature_params["nonce"] = nonce if include_alg: signature_params["alg"] = self.signature_algorithm.algorithm_id - # TODO: content-digest autoconfiguration - # - if request has a body and no content-digest header, compute content-digest as a structured header and set it sig_base, sig_params_node, _ = self.build_signature_base(request, covered_component_ids=covered_component_ids, signature_params=signature_params) @@ -97,12 +94,11 @@ def sign(self, request, *, request.headers["Signature"] = str(sig_node) -VerifyResult = collections.namedtuple("VerifyResult", "label algorithm covered_components parameters") +VerifyResult = collections.namedtuple("VerifyResult", "label algorithm covered_components parameters body") class HTTPMessageVerifier(HTTPSignatureHandler): def verify(self, response): - # TODO: verify content-digest automatically if "Signature-Input" not in response.headers: raise InvalidSignature("Expected Signature-Input header to be present") sig_inputs = http_sfv.Dictionary() @@ -141,6 +137,7 @@ def verify(self, response): verify_result = VerifyResult(label=label, algorithm=self.signature_algorithm, covered_components=sig_elements, - parameters=dict(sig_params_node.params)) + parameters=dict(sig_params_node.params), + body=None) verify_results.append(verify_result) return verify_results