From eb5db84499a317523f49cfc990133b770150e1fa Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Wed, 29 Nov 2023 00:09:06 +1000 Subject: [PATCH] acme: implement POST-as-GET for accounts Some ACME clients POST-as-GET the account resource, expecting to receive the account object (for an existing account). In particular, mod_md does this and certificate renewal fails when it cannot read or verify the account information. The ACME protocol does not explicitly require this behaviour. But on the other hand, it is not surprising that clients assume they can do it, and it arguably is surprising if an ACME server does not provide it. So let's implement it. The change itself is trivial: when payload is empty, POST-as-GET is implied (RFC 8555 section 6.3). In this case, return the ACMEAccount object (which we already have at hand) unchanged. --- .../acme/server/ACMEAccountService.java | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEAccountService.java b/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEAccountService.java index 38db0b2c3dc..8c9f704cf5e 100644 --- a/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEAccountService.java +++ b/base/acme/src/main/java/org/dogtagpki/acme/server/ACMEAccountService.java @@ -74,33 +74,40 @@ public Response updateAccount(@PathParam("id") String accountID, JWS jws) throws engine.validateJWS(jws, header.getAlg(), account.getJWK()); String payload = new String(jws.getPayloadAsBytes(), "UTF-8"); - logger.info("Payload: " + payload); - ACMEAccount update; - try { - update = ACMEAccount.fromJSON(payload); - } catch (JsonProcessingException e) { - throw engine.createMalformedException(e.toString()); + if (payload.isEmpty()) { + logger.info("Empty payload; treating as POST-as-GET"); } - String newStatus = update.getStatus(); - if (newStatus != null) { - logger.info("New status: " + newStatus); - account.setStatus(newStatus); - } + else { + logger.info("Payload: " + payload); - String[] newContact = update.getContact(); - if (newContact != null) { - logger.info("New contact:"); - for (String c : newContact) { - logger.info("- " + c); + ACMEAccount update; + try { + update = ACMEAccount.fromJSON(payload); + } catch (JsonProcessingException e) { + throw engine.createMalformedException(e.toString()); + } + + String newStatus = update.getStatus(); + if (newStatus != null) { + logger.info("New status: " + newStatus); + account.setStatus(newStatus); + } + + String[] newContact = update.getContact(); + if (newContact != null) { + logger.info("New contact:"); + for (String c : newContact) { + logger.info("- " + c); + } + account.setContact(newContact); } - account.setContact(newContact); - } - engine.updateAccount(account); + engine.updateAccount(account); - // TODO: if account is deactivated, cancel all account's pending operations + // TODO: if account is deactivated, cancel all account's pending operations + } // RFC 8555 Section 7.1.2.1 Orders List //