Add async interface for finalization to acme.client.ClientV2 (#9622)

* Add async interface for finalization to acme.client.ClientV2

Add `begin_order_finalization()`/`poll_finalization()` to
`acme.client.ClientV2`, which are directly analogous to
`answer_challenge()`/`poll_authorizations()`. This allows us to
finalize an order and then later poll for its completion as separate
steps.

* Address code review feedback

Rename `begin_order_finalization` -> `begin_finalization` and tweak
wording of changelog entry
This commit is contained in:
Anna Glasgall 2023-03-22 20:09:14 -04:00 committed by GitHub
parent 5d5dc429c4
commit 8e28e36178
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 8 deletions

View file

@ -210,23 +210,35 @@ class ClientV2:
raise errors.ValidationError(failed)
return orderr.update(authorizations=responses)
def finalize_order(self, orderr: messages.OrderResource, deadline: datetime.datetime,
fetch_alternative_chains: bool = False) -> messages.OrderResource:
"""Finalize an order and obtain a certificate.
def begin_finalization(self, orderr: messages.OrderResource
) -> messages.OrderResource:
"""Start the process of finalizing an order.
:param messages.OrderResource orderr: order to finalize
:param datetime.datetime deadline: when to stop polling and timeout
:param bool fetch_alternative_chains: whether to also fetch alternative
certificate chains
:returns: finalized order
:returns: updated order
:rtype: messages.OrderResource
"""
csr = OpenSSL.crypto.load_certificate_request(
OpenSSL.crypto.FILETYPE_PEM, orderr.csr_pem)
wrapped_csr = messages.CertificateRequest(csr=jose.ComparableX509(csr))
self._post(orderr.body.finalize, wrapped_csr)
res = self._post(orderr.body.finalize, wrapped_csr)
orderr = orderr.update(body=messages.Order.from_json(res.json()))
return orderr
def poll_finalization(self, orderr: messages.OrderResource,
deadline: datetime.datetime,
fetch_alternative_chains: bool = False
) -> messages.OrderResource:
"""
Poll an order that has been finalized for its status.
If it becomes valid, obtain the certificate.
:returns: finalized order (with certificate)
:rtype: messages.OrderResource
"""
while datetime.datetime.now() < deadline:
time.sleep(1)
response = self._post_as_get(orderr.uri)
@ -247,6 +259,22 @@ class ClientV2:
return orderr
raise errors.TimeoutError()
def finalize_order(self, orderr: messages.OrderResource, deadline: datetime.datetime,
fetch_alternative_chains: bool = False) -> messages.OrderResource:
"""Finalize an order and obtain a certificate.
:param messages.OrderResource orderr: order to finalize
:param datetime.datetime deadline: when to stop polling and timeout
:param bool fetch_alternative_chains: whether to also fetch alternative
certificate chains
:returns: finalized order
:rtype: messages.OrderResource
"""
self.begin_finalization(orderr)
return self.poll_finalization(orderr, deadline, fetch_alternative_chains)
def revoke(self, cert: jose.ComparableX509, rsn: int) -> None:
"""Revoke certificate.

View file

@ -8,6 +8,9 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
* `acme.messages.OrderResource` now supports being round-tripped
through JSON
* acme.client.ClientV2 now provides separate `begin_finalization`
and `poll_finalization` methods, in addition to the existing
`finalize_order` method.
### Changed