diff --git a/wfe2/wfe.go b/wfe2/wfe.go index 351c27c02b3..ba351bcd2ab 100644 --- a/wfe2/wfe.go +++ b/wfe2/wfe.go @@ -1416,8 +1416,10 @@ func (wfe *WebFrontEndImpl) Account( return } - // If the body was not empty, then this is an account update request. - if string(body) != "" { + // An empty string means POST-as-GET (i.e. no update). A body of "{}" means + // an update of zero fields, returning the unchanged object. This was the + // recommended way to fetch the account object in ACMEv1. + if string(body) != "" && string(body) != "{}" { currAcct, prob = wfe.updateAccount(ctx, body, currAcct) if prob != nil { wfe.sendError(response, logEvent, prob, nil) diff --git a/wfe2/wfe_test.go b/wfe2/wfe_test.go index d3c243fabc4..0b524bdd44d 100644 --- a/wfe2/wfe_test.go +++ b/wfe2/wfe_test.go @@ -1569,7 +1569,6 @@ func TestNewECDSAAccount(t *testing.T) { // a populated acct object will be returned. func TestEmptyAccount(t *testing.T) { wfe, _, signer := setupWFE(t) - responseWriter := httptest.NewRecorder() // Test Key 1 is mocked in the mock StorageAuthority used in setupWFE to // return a populated account for GetRegistrationByKey when test key 1 is @@ -1578,31 +1577,66 @@ func TestEmptyAccount(t *testing.T) { _, ok := key.(*rsa.PrivateKey) test.Assert(t, ok, "Couldn't load RSA key") - payload := `{}` path := "1" signedURL := "http://localhost/1" - _, _, body := signer.byKeyID(1, key, signedURL, payload) - request := makePostRequestWithPath(path, body) - // Send an account update with the trivial body - wfe.Account( - ctx, - newRequestEvent(), - responseWriter, - request) + testCases := []struct { + Name string + Payload string + ExpectedStatus int + }{ + { + Name: "POST empty string to acct", + Payload: "", + ExpectedStatus: http.StatusOK, + }, + { + Name: "POST empty JSON object to acct", + Payload: "{}", + ExpectedStatus: http.StatusOK, + }, + { + Name: "POST invalid empty JSON string to acct", + Payload: "\"\"", + ExpectedStatus: http.StatusBadRequest, + }, + { + Name: "POST invalid empty JSON array to acct", + Payload: "[]", + ExpectedStatus: http.StatusBadRequest, + }, + } - responseBody := responseWriter.Body.String() - // There should be no error - test.AssertNotContains(t, responseBody, probs.ErrorNS) + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + responseWriter := httptest.NewRecorder() - // We should get back a populated Account - var acct core.Registration - err := json.Unmarshal([]byte(responseBody), &acct) - test.AssertNotError(t, err, "Couldn't unmarshal returned account object") - test.Assert(t, len(*acct.Contact) >= 1, "No contact field in account") - test.AssertEquals(t, (*acct.Contact)[0], "mailto:person@mail.com") - test.AssertEquals(t, acct.Agreement, "") - responseWriter.Body.Reset() + _, _, body := signer.byKeyID(1, key, signedURL, tc.Payload) + request := makePostRequestWithPath(path, body) + + // Send an account update with the trivial body + wfe.Account( + ctx, + newRequestEvent(), + responseWriter, + request) + + responseBody := responseWriter.Body.String() + test.AssertEquals(t, responseWriter.Code, tc.ExpectedStatus) + + // If success is expected, we should get back a populated Account + if tc.ExpectedStatus == http.StatusOK { + var acct core.Registration + err := json.Unmarshal([]byte(responseBody), &acct) + test.AssertNotError(t, err, "Couldn't unmarshal returned account object") + test.Assert(t, len(*acct.Contact) >= 1, "No contact field in account") + test.AssertEquals(t, (*acct.Contact)[0], "mailto:person@mail.com") + test.AssertEquals(t, acct.Agreement, "") + } + + responseWriter.Body.Reset() + }) + } } func TestNewAccount(t *testing.T) {