wfe: Use separate UpdateRegistrationContact & UpdateRegistrationKey methods (#7827)

Fixes #7716
Part of #5554
This commit is contained in:
James Renken 2024-12-13 08:41:59 -08:00 committed by GitHub
parent efaa370457
commit 62f1a26ccf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 29 additions and 64 deletions

View File

@ -48,7 +48,7 @@ func TestAccountEmailError(t *testing.T) {
longStringBuf.WriteString("@a.com")
createErrorPrefix := "Error creating new account :: "
updateErrorPrefix := "Unable to update account :: "
updateErrorPrefix := "Unable to update account :: invalid contact: "
testCases := []struct {
name string

View File

@ -1442,8 +1442,8 @@ func (wfe *WebFrontEndImpl) Account(
// updateAccount unmarshals an account update request from the provided
// requestBody to update the given registration. Important: It is assumed the
// request has already been authenticated by the caller. If the request is
// a valid update the resulting updated account is returned, otherwise a problem
// request has already been authenticated by the caller. If the request is a
// valid update the resulting updated account is returned, otherwise a problem
// is returned.
func (wfe *WebFrontEndImpl) updateAccount(
ctx context.Context,
@ -1461,56 +1461,29 @@ func (wfe *WebFrontEndImpl) updateAccount(
return nil, probs.Malformed("Error unmarshaling account")
}
// Convert existing account to corepb.Registration
basePb, err := bgrpc.RegistrationToPB(*currAcct)
if err != nil {
return nil, probs.ServerInternal("Error updating account")
}
var contacts []string
var contactsPresent bool
if accountUpdateRequest.Contact != nil {
contactsPresent = true
contacts = *accountUpdateRequest.Contact
}
// Copy over the fields from the request to the registration object used for
// the RA updates.
// Create corepb.Registration from provided account information
updatePb := &corepb.Registration{
Contact: contacts,
ContactsPresent: contactsPresent,
Status: string(accountUpdateRequest.Status),
}
// People *will* POST their full accounts to this endpoint, including
// the 'valid' status, to avoid always failing out when that happens only
// attempt to deactivate if the provided status is different from their current
// status.
//
// If a user tries to send both a deactivation request and an update to their
// contacts or subscriber agreement URL the deactivation will take place and
// return before an update would be performed.
if updatePb.Status != "" && updatePb.Status != basePb.Status {
if updatePb.Status != string(core.StatusDeactivated) {
return nil, probs.Malformed("Invalid value provided for status field")
}
_, err := wfe.ra.DeactivateRegistration(ctx, basePb)
// If a user tries to send both a deactivation request and an update to
// their contacts, the deactivation will take place and return before an
// update would be performed. Deactivation deletes the contacts field.
if accountUpdateRequest.Status == core.StatusDeactivated {
_, err = wfe.ra.DeactivateRegistration(ctx, &corepb.Registration{Id: currAcct.ID, Status: string(core.StatusDeactivated)})
if err != nil {
return nil, web.ProblemDetailsForError(err, "Unable to deactivate account")
}
currAcct.Status = core.StatusDeactivated
return currAcct, nil
}
// Account objects contain a JWK object which are merged in UpdateRegistration
// if it is different from the existing account key. Since this isn't how you
// update the key we just copy the existing one into the update object here. This
// ensures the key isn't changed and that we can cleanly serialize the update as
// JSON to send via RPC to the RA.
updatePb.Key = basePb.Key
if accountUpdateRequest.Status != core.StatusValid && accountUpdateRequest.Status != "" {
return nil, probs.Malformed("Invalid value provided for status field")
}
updatedAcct, err := wfe.ra.UpdateRegistration(ctx, &rapb.UpdateRegistrationRequest{Base: basePb, Update: updatePb})
var contacts []string
if accountUpdateRequest.Contact != nil {
contacts = *accountUpdateRequest.Contact
}
updatedAcct, err := wfe.ra.UpdateRegistrationContact(ctx, &rapb.UpdateRegistrationContactRequest{RegistrationID: currAcct.ID, Contacts: contacts})
if err != nil {
return nil, web.ProblemDetailsForError(err, "Unable to update account")
}
@ -1993,18 +1966,9 @@ func (wfe *WebFrontEndImpl) KeyRollover(
wfe.sendError(response, logEvent, web.ProblemDetailsForError(err, "Failed to lookup existing keys"), err)
return
}
// Convert account to proto for grpc
regPb, err := bgrpc.RegistrationToPB(*acct)
if err != nil {
wfe.sendError(response, logEvent, probs.ServerInternal("Error marshaling Registration to proto"), err)
return
}
// Copy new key into an empty registration to provide as the update
updatePb := &corepb.Registration{Key: newKeyBytes}
// Update the account key to the new key
updatedAcctPb, err := wfe.ra.UpdateRegistration(ctx, &rapb.UpdateRegistrationRequest{Base: regPb, Update: updatePb})
updatedAcctPb, err := wfe.ra.UpdateRegistrationKey(ctx, &rapb.UpdateRegistrationKeyRequest{RegistrationID: acct.ID, Jwk: newKeyBytes})
if err != nil {
if errors.Is(err, berrors.Duplicate) {
// It is possible that between checking for the existing key, and performing the update

View File

@ -194,11 +194,15 @@ func (ra *MockRegistrationAuthority) NewRegistration(ctx context.Context, in *co
return in, nil
}
func (ra *MockRegistrationAuthority) UpdateRegistration(ctx context.Context, in *rapb.UpdateRegistrationRequest, _ ...grpc.CallOption) (*corepb.Registration, error) {
if !bytes.Equal(in.Base.Key, in.Update.Key) {
in.Base.Key = in.Update.Key
}
return in.Base, nil
func (ra *MockRegistrationAuthority) UpdateRegistrationContact(ctx context.Context, in *rapb.UpdateRegistrationContactRequest, _ ...grpc.CallOption) (*corepb.Registration, error) {
return &corepb.Registration{
Contact: in.Contacts,
Key: []byte(test1KeyPublicJSON),
}, nil
}
func (ra *MockRegistrationAuthority) UpdateRegistrationKey(ctx context.Context, in *rapb.UpdateRegistrationKeyRequest, _ ...grpc.CallOption) (*corepb.Registration, error) {
return &corepb.Registration{Key: in.Jwk}, nil
}
func (ra *MockRegistrationAuthority) PerformValidation(context.Context, *rapb.PerformValidationRequest, ...grpc.CallOption) (*corepb.Authorization, error) {
@ -3211,10 +3215,7 @@ func TestKeyRollover(t *testing.T) {
Payload: `{"oldKey":` + test1KeyPublicJSON + `,"account":"http://localhost/acme/acct/1"}`,
ExpectedResponse: `{
"key": ` + string(newJWKJSON) + `,
"contact": [
"mailto:person@mail.com"
],
"status": "valid"
"status": ""
}`,
NewKey: newKeyPriv,
},