mirror of
https://github.com/certbot/certbot.git
synced 2026-05-28 04:34:11 -04:00
Respect Retry-After header when polling for order finalization (#10288)
Fixes #10273. --------- Co-authored-by: Brad Warren <bmw@users.noreply.github.com>
This commit is contained in:
parent
5d03191493
commit
7a27a67cdb
3 changed files with 26 additions and 5 deletions
|
|
@ -281,7 +281,9 @@ class ClientV2Test(unittest.TestCase):
|
|||
with pytest.raises(errors.Error, match="The certificate order failed"):
|
||||
self.client.finalize_order(self.orderr, datetime.datetime(9999, 9, 9))
|
||||
|
||||
def test_finalize_order_orderNotReady(self):
|
||||
@mock.patch('acme.client.time.sleep')
|
||||
@mock.patch('acme.client.datetime')
|
||||
def test_finalize_order_orderNotReady(self, dt_mock, mock_sleep):
|
||||
# https://github.com/certbot/certbot/issues/9766
|
||||
updated_order_processing = self.order.update(status=messages.STATUS_PROCESSING)
|
||||
updated_order_ready = self.order.update(status=messages.STATUS_READY)
|
||||
|
|
@ -297,11 +299,18 @@ class ClientV2Test(unittest.TestCase):
|
|||
updated_order_ready.to_json(),
|
||||
updated_order_valid.to_json()]
|
||||
|
||||
dt_mock.datetime.now.return_value = datetime.datetime(2015, 3, 27)
|
||||
dt_mock.timedelta = datetime.timedelta
|
||||
self.response.headers['Retry-After'] = '50'
|
||||
|
||||
post = mock.MagicMock()
|
||||
post.side_effect = [messages.Error.with_code('orderNotReady'), # first begin_finalization
|
||||
self.response, # first poll_finalization poll --> still returns pending
|
||||
# sleep 1
|
||||
self.response, # first poll_finalization poll --> returns processing
|
||||
# retry-after sleep here
|
||||
self.response, # second poll_finalization poll --> returns ready
|
||||
mock.MagicMock(), # second begin_finalization
|
||||
# sleep 1
|
||||
self.response, # third poll_finalization poll --> returns valid
|
||||
self.response # fetch cert
|
||||
]
|
||||
|
|
@ -309,6 +318,7 @@ class ClientV2Test(unittest.TestCase):
|
|||
|
||||
self.client.finalize_order(self.orderr, datetime.datetime(9999, 9, 9))
|
||||
assert self.net.post.call_count == 6
|
||||
assert mock_sleep.call_args_list == [((1,),), ((50,),), ((1,),)]
|
||||
|
||||
def test_finalize_order_otherErrorCode(self):
|
||||
post = mock.MagicMock()
|
||||
|
|
|
|||
|
|
@ -253,9 +253,10 @@ class ClientV2:
|
|||
:returns: finalized order (with certificate)
|
||||
:rtype: messages.OrderResource
|
||||
"""
|
||||
|
||||
sleep_seconds: float = 1
|
||||
while datetime.datetime.now() < deadline:
|
||||
time.sleep(1)
|
||||
if sleep_seconds > 0:
|
||||
time.sleep(sleep_seconds)
|
||||
response = self._post_as_get(orderr.uri)
|
||||
body = messages.Order.from_json(response.json())
|
||||
if body.status == messages.STATUS_INVALID:
|
||||
|
|
@ -271,6 +272,7 @@ class ClientV2:
|
|||
# fulfilled, and is awaiting finalization. Submit a finalization
|
||||
# request.
|
||||
self.begin_finalization(orderr)
|
||||
sleep_seconds = 1
|
||||
elif body.status == messages.STATUS_VALID and body.certificate is not None:
|
||||
# "valid": The server has issued the certificate and provisioned its
|
||||
# URL to the "certificate" field of the order. Download the
|
||||
|
|
@ -282,6 +284,14 @@ class ClientV2:
|
|||
alt_chains = [self._post_as_get(url).text for url in alt_chains_urls]
|
||||
orderr = orderr.update(alternative_fullchains_pem=alt_chains)
|
||||
return orderr
|
||||
elif body.status == messages.STATUS_PROCESSING:
|
||||
# "processing": The certificate is being issued. Send a POST-as-GET request after
|
||||
# the time given in the Retry-After header field of the response, if any.
|
||||
retry_after = self.retry_after(response, 1)
|
||||
# Whatever Retry-After the ACME server requests, the polling must not take
|
||||
# longer than the overall deadline
|
||||
retry_after = min(retry_after, deadline)
|
||||
sleep_seconds = (retry_after - datetime.datetime.now()).total_seconds()
|
||||
raise errors.TimeoutError()
|
||||
|
||||
def finalize_order(self, orderr: messages.OrderResource, deadline: datetime.datetime,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
|
|||
`ready`, and resubmits finalization request before polling for `valid` to download
|
||||
certificate. This conforms to RFC 8555 more accurately and avoids race conditions where
|
||||
all authorizations are fulfilled but order has not yet transitioned to ready state on
|
||||
the server when the finalization request is sent.
|
||||
the server when the finalization request is sent. It also respects retry-after when
|
||||
polling for finalization readiness.
|
||||
* The --preferred-profile and --required-profile flags now have their values stored in
|
||||
the renewal configuration so the same setting will be used on renewal.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue