Skip to content

Commit

Permalink
Fix race condition during ACME order finalization
Browse files Browse the repository at this point in the history
Previously when the authorization for an order completed the
ACMEChallengeProcessor would update the authorization status
and the order status after that, then the client would call
the ACMEFinalizeOrderService to finalize the order.

However, since these updates are not atomic there is a risk
that the client will detect the new authorization status then
immediately call the ACMEFinalizeOrderService before the order
status can be updated by ACMEChallengeProcessor. Since both
both ACMEFinalizeOrderService and ACMEChallengeProcessor will
read and write the same order at the same time, there could be
a race condition and the finalization could fail.

To avoid the problem the ACMEChallengeProcessor has been
modified to update the order status first before updating the
authorization status.
  • Loading branch information
frasertweedale authored and edewata committed Sep 14, 2023
1 parent 2262588 commit 2457fc3
Showing 1 changed file with 11 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,6 @@ public void finalizeValidAuthorization() throws Exception {
Date expirationTime = engine.getPolicy().getValidAuthorizationExpirationTime(currentTime);
authorization.setExpirationTime(expirationTime);

engine.updateAuthorization(account, authorization);

logger.info("Updating pending orders");

Collection<ACMEOrder> orders =
Expand All @@ -129,6 +127,10 @@ public void finalizeValidAuthorization() throws Exception {
boolean allAuthorizationsValid = true;

for (String orderAuthzID : order.getAuthzIDs()) {
if (orderAuthzID.equals(authzID)) {
// We're about to set it to valid, so treat it as such
continue;
}

ACMEAuthorization authz = engine.getAuthorization(account, orderAuthzID);
if (authz.getStatus().equals("valid")) continue;
Expand All @@ -147,6 +149,13 @@ public void finalizeValidAuthorization() throws Exception {

engine.updateOrder(account, order);
}

// We defer the LDAP update until AFTER any order transitions
// occur. This avoids a race condition where clients that eagerly
// proceed to finalization when all Authorizations are "valid"
// experience finalization failure, because the __Order__ has not yet
// transition to "ready".
engine.updateAuthorization(account, authorization);
}

public void finalizeInvalidAuthorization(ACMEError err) throws Exception {
Expand Down

0 comments on commit 2457fc3

Please sign in to comment.