In #3402 we implemented order status as a function of the authorizations associated with an order, and their respective statuses.
The sa.StatusForOrder function relies on sa.getAllOrderAuthorizations to load the full authorizations for an order:
|
authzs, err := ssa.getAllOrderAuthorizations(ctx, *order.Id, *order.RegistrationID) |
statusForOrder enforces the invariant that the # of authorization IDs in the order object (populated based on the orderToAuthz join table) should always be equal to the # of authorization objects returned by sa.getAllOrderAuthorizations or an InternalServerError is produced.
We overlooked the fact that sa.getAllOrderAuthorizations has a WHERE clause that excludes expired authorizations:
Therefore, if an order has an authorization that expires, the authorization ID will remain in the orderToAuthz join table used to find the order's authorization IDs, but it will not be present in the results returned from sa.getAllOrderAuthorizations, which results in sa.statusForOrder producing an internal server error, which results in sa.GetOrder failing, which in turn makes almost all ACME v2 operations fail because they rely on fetching order details and status through sa.GetOrder.
Worse, since our order expiry is currently set distinctly from authorization expiry (See #3498) order reuse will return the broken order for subsequent newOrder requests for the same identifiers.
To fix, sa.getAllOrderAuthorizations should return expired authorizations. In sa.StatusForOrder we should mark the order's overall status as invalid when one or more authorizations are expired.
In #3402 we implemented order status as a function of the authorizations associated with an order, and their respective statuses.
The
sa.StatusForOrderfunction relies onsa.getAllOrderAuthorizationsto load the full authorizations for an order:boulder/sa/sa.go
Line 1673 in 8cf8c44
statusForOrderenforces the invariant that the # of authorization IDs in the order object (populated based on theorderToAuthzjoin table) should always be equal to the # of authorization objects returned bysa.getAllOrderAuthorizationsor anInternalServerErroris produced.We overlooked the fact that
sa.getAllOrderAuthorizationshas aWHEREclause that excludes expired authorizations:boulder/sa/sa.go
Line 1777 in 8cf8c44
Therefore, if an
orderhas an authorization that expires, the authorization ID will remain in theorderToAuthzjoin table used to find the order's authorization IDs, but it will not be present in the results returned fromsa.getAllOrderAuthorizations, which results insa.statusForOrderproducing an internal server error, which results insa.GetOrderfailing, which in turn makes almost all ACME v2 operations fail because they rely on fetching order details and status throughsa.GetOrder.Worse, since our order expiry is currently set distinctly from authorization expiry (See #3498) order reuse will return the broken order for subsequent
newOrderrequests for the same identifiers.To fix,
sa.getAllOrderAuthorizationsshould return expired authorizations. Insa.StatusForOrderwe should mark the order's overall status asinvalidwhen one or more authorizations are expired.