Skip to content

Commit 6a2819a

Browse files
authored
Introduce separate UpdateRegistrationContact & UpdateRegistrationKey methods in RA & SA (#7735)
Introduce separate UpdateRegistrationContact & UpdateRegistrationKey methods in RA & SA Clear contact field during DeactivateRegistration Part of #7716 Part of #5554
1 parent 84b15eb commit 6a2819a

File tree

10 files changed

+1540
-588
lines changed

10 files changed

+1540
-588
lines changed

ra/proto/ra.pb.go

Lines changed: 381 additions & 218 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ra/proto/ra.proto

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import "google/protobuf/empty.proto";
1010
service RegistrationAuthority {
1111
rpc NewRegistration(core.Registration) returns (core.Registration) {}
1212
rpc UpdateRegistration(UpdateRegistrationRequest) returns (core.Registration) {}
13+
rpc UpdateRegistrationContact(UpdateRegistrationContactRequest) returns (core.Registration) {}
14+
rpc UpdateRegistrationKey(UpdateRegistrationKeyRequest) returns (core.Registration) {}
1315
rpc PerformValidation(PerformValidationRequest) returns (core.Authorization) {}
1416
rpc DeactivateRegistration(core.Registration) returns (google.protobuf.Empty) {}
1517
rpc DeactivateAuthorization(core.Authorization) returns (google.protobuf.Empty) {}
@@ -33,6 +35,16 @@ message UpdateRegistrationRequest {
3335
core.Registration update = 2;
3436
}
3537

38+
message UpdateRegistrationContactRequest {
39+
int64 registrationID = 1;
40+
repeated string contacts = 2;
41+
}
42+
43+
message UpdateRegistrationKeyRequest {
44+
int64 registrationID = 1;
45+
bytes jwk = 2;
46+
}
47+
3648
message UpdateAuthorizationRequest {
3749
core.Authorization authz = 1;
3850
int64 challengeIndex = 2;

ra/proto/ra_grpc.pb.go

Lines changed: 76 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ra/ra.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1620,7 +1620,8 @@ func (ra *RegistrationAuthorityImpl) checkNewOrderLimits(ctx context.Context, na
16201620
// UpdateRegistration updates an existing Registration with new values. Caller
16211621
// is responsible for making sure that update.Key is only different from base.Key
16221622
// if it is being called from the WFE key change endpoint.
1623-
// TODO(#5554): Split this into separate methods for updating Contacts vs Key.
1623+
//
1624+
// Deprecated: Use UpdateRegistrationContact or UpdateRegistrationKey instead.
16241625
func (ra *RegistrationAuthorityImpl) UpdateRegistration(ctx context.Context, req *rapb.UpdateRegistrationRequest) (*corepb.Registration, error) {
16251626
// Error if the request is nil, there is no account key or IP address
16261627
if req.Base == nil || len(req.Base.Key) == 0 || len(req.Base.InitialIP) == 0 || req.Base.Id == 0 {
@@ -1659,6 +1660,46 @@ func (ra *RegistrationAuthorityImpl) UpdateRegistration(ctx context.Context, req
16591660
return update, nil
16601661
}
16611662

1663+
// UpdateRegistrationContact updates an existing Registration's contact.
1664+
// The updated contacts field may be empty.
1665+
func (ra *RegistrationAuthorityImpl) UpdateRegistrationContact(ctx context.Context, req *rapb.UpdateRegistrationContactRequest) (*corepb.Registration, error) {
1666+
if core.IsAnyNilOrZero(req.RegistrationID) {
1667+
return nil, errIncompleteGRPCRequest
1668+
}
1669+
1670+
err := ra.validateContacts(req.Contacts)
1671+
if err != nil {
1672+
return nil, fmt.Errorf("invalid contact: %w", err)
1673+
}
1674+
1675+
update, err := ra.SA.UpdateRegistrationContact(ctx, &sapb.UpdateRegistrationContactRequest{
1676+
RegistrationID: req.RegistrationID,
1677+
Contacts: req.Contacts,
1678+
})
1679+
if err != nil {
1680+
return nil, fmt.Errorf("failed to update registration contact: %w", err)
1681+
}
1682+
1683+
return update, nil
1684+
}
1685+
1686+
// UpdateRegistrationKey updates an existing Registration's key.
1687+
func (ra *RegistrationAuthorityImpl) UpdateRegistrationKey(ctx context.Context, req *rapb.UpdateRegistrationKeyRequest) (*corepb.Registration, error) {
1688+
if core.IsAnyNilOrZero(req.RegistrationID, req.Jwk) {
1689+
return nil, errIncompleteGRPCRequest
1690+
}
1691+
1692+
update, err := ra.SA.UpdateRegistrationKey(ctx, &sapb.UpdateRegistrationKeyRequest{
1693+
RegistrationID: req.RegistrationID,
1694+
Jwk: req.Jwk,
1695+
})
1696+
if err != nil {
1697+
return nil, fmt.Errorf("failed to update registration key: %w", err)
1698+
}
1699+
1700+
return update, nil
1701+
}
1702+
16621703
func contactsEqual(a []string, b []string) bool {
16631704
if len(a) != len(b) {
16641705
return false

ra/ra_test.go

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -671,10 +671,21 @@ type NoUpdateSA struct {
671671
sapb.StorageAuthorityClient
672672
}
673673

674-
func (sa NoUpdateSA) UpdateRegistration(_ context.Context, _ *corepb.Registration, _ ...grpc.CallOption) (*emptypb.Empty, error) {
674+
// Deprecated: When this function is removed, the NoUpdateSA should be moved
675+
// down to join the other mocks and tests for UpdateRegistrationContact & Key,
676+
// where it's also used.
677+
func (sa *NoUpdateSA) UpdateRegistration(_ context.Context, _ *corepb.Registration, _ ...grpc.CallOption) (*emptypb.Empty, error) {
675678
return nil, fmt.Errorf("UpdateRegistration() is mocked to always error")
676679
}
677680

681+
func (sa *NoUpdateSA) UpdateRegistrationContact(_ context.Context, _ *sapb.UpdateRegistrationContactRequest, _ ...grpc.CallOption) (*corepb.Registration, error) {
682+
return nil, fmt.Errorf("UpdateRegistrationContact() is mocked to always error")
683+
}
684+
685+
func (sa *NoUpdateSA) UpdateRegistrationKey(_ context.Context, _ *sapb.UpdateRegistrationKeyRequest, _ ...grpc.CallOption) (*corepb.Registration, error) {
686+
return nil, fmt.Errorf("UpdateRegistrationKey() is mocked to always error")
687+
}
688+
678689
func TestUpdateRegistrationSame(t *testing.T) {
679690
_, _, ra, _, cleanUp := initAuthorities(t)
680691
defer cleanUp()
@@ -4483,3 +4494,136 @@ func TestGetAuthorization(t *testing.T) {
44834494
test.AssertNotError(t, err, "should not fail")
44844495
test.AssertEquals(t, len(authz.Challenges), 0)
44854496
}
4497+
4498+
// mockSARecordingRegistration tests UpdateRegistrationContact and UpdateRegistrationKey.
4499+
type mockSARecordingRegistration struct {
4500+
sapb.StorageAuthorityClient
4501+
providedRegistrationID int64
4502+
providedContacts []string
4503+
providedJwk []byte
4504+
}
4505+
4506+
// UpdateRegistrationContact records the registration ID and updated contacts
4507+
// (optional) provided.
4508+
func (sa *mockSARecordingRegistration) UpdateRegistrationContact(ctx context.Context, req *sapb.UpdateRegistrationContactRequest, _ ...grpc.CallOption) (*corepb.Registration, error) {
4509+
sa.providedRegistrationID = req.RegistrationID
4510+
sa.providedContacts = req.Contacts
4511+
4512+
return &corepb.Registration{
4513+
Id: req.RegistrationID,
4514+
Contact: req.Contacts,
4515+
}, nil
4516+
}
4517+
4518+
// UpdateRegistrationKey records the registration ID and updated key provided.
4519+
func (sa *mockSARecordingRegistration) UpdateRegistrationKey(ctx context.Context, req *sapb.UpdateRegistrationKeyRequest, _ ...grpc.CallOption) (*corepb.Registration, error) {
4520+
sa.providedRegistrationID = req.RegistrationID
4521+
sa.providedJwk = req.Jwk
4522+
4523+
return &corepb.Registration{
4524+
Id: req.RegistrationID,
4525+
Key: req.Jwk,
4526+
}, nil
4527+
}
4528+
4529+
// TestUpdateRegistrationContact tests that the RA's UpdateRegistrationContact
4530+
// method correctly: requires a registration ID; validates the contact provided;
4531+
// does not require a contact; passes the requested registration ID and contact
4532+
// to the SA; passes the updated Registration back to the caller; and can return
4533+
// an error.
4534+
func TestUpdateRegistrationContact(t *testing.T) {
4535+
_, _, ra, _, cleanUp := initAuthorities(t)
4536+
defer cleanUp()
4537+
4538+
expectRegID := int64(1)
4539+
expectContacts := []string{"mailto:[email protected]"}
4540+
mockSA := mockSARecordingRegistration{}
4541+
ra.SA = &mockSA
4542+
4543+
_, err := ra.UpdateRegistrationContact(context.Background(), &rapb.UpdateRegistrationContactRequest{})
4544+
test.AssertError(t, err, "should not have been able to update registration contact without a registration ID")
4545+
test.AssertContains(t, err.Error(), "incomplete gRPC request message")
4546+
4547+
_, err = ra.UpdateRegistrationContact(context.Background(), &rapb.UpdateRegistrationContactRequest{
4548+
RegistrationID: expectRegID,
4549+
Contacts: []string{"tel:+44123"},
4550+
})
4551+
test.AssertError(t, err, "should not have been able to update registration contact to an invalid contact")
4552+
test.AssertContains(t, err.Error(), "invalid contact")
4553+
4554+
res, err := ra.UpdateRegistrationContact(context.Background(), &rapb.UpdateRegistrationContactRequest{
4555+
RegistrationID: expectRegID,
4556+
})
4557+
test.AssertNotError(t, err, "should have been able to update registration with a blank contact")
4558+
test.AssertEquals(t, res.Id, expectRegID)
4559+
test.AssertEquals(t, mockSA.providedRegistrationID, expectRegID)
4560+
test.AssertDeepEquals(t, res.Contact, []string(nil))
4561+
test.AssertDeepEquals(t, mockSA.providedContacts, []string(nil))
4562+
4563+
res, err = ra.UpdateRegistrationContact(context.Background(), &rapb.UpdateRegistrationContactRequest{
4564+
RegistrationID: expectRegID,
4565+
Contacts: expectContacts,
4566+
})
4567+
test.AssertNotError(t, err, "should have been able to update registration with a populated contact")
4568+
test.AssertEquals(t, res.Id, expectRegID)
4569+
test.AssertEquals(t, mockSA.providedRegistrationID, expectRegID)
4570+
test.AssertDeepEquals(t, res.Contact, expectContacts)
4571+
test.AssertDeepEquals(t, mockSA.providedContacts, expectContacts)
4572+
4573+
// Switch to a mock SA that will always error if UpdateRegistrationContact()
4574+
// is called.
4575+
ra.SA = &NoUpdateSA{}
4576+
_, err = ra.UpdateRegistrationContact(context.Background(), &rapb.UpdateRegistrationContactRequest{
4577+
RegistrationID: expectRegID,
4578+
Contacts: expectContacts,
4579+
})
4580+
test.AssertError(t, err, "should have received an error from the SA")
4581+
test.AssertContains(t, err.Error(), "failed to update registration contact")
4582+
test.AssertContains(t, err.Error(), "mocked to always error")
4583+
}
4584+
4585+
// TestUpdateRegistrationKey tests that the RA's UpdateRegistrationKey method
4586+
// correctly requires a registration ID and key, passes them to the SA, and
4587+
// passes the updated Registration back to the caller.
4588+
func TestUpdateRegistrationKey(t *testing.T) {
4589+
_, _, ra, _, cleanUp := initAuthorities(t)
4590+
defer cleanUp()
4591+
4592+
expectRegID := int64(1)
4593+
expectJwk := AccountKeyJSONA
4594+
mockSA := mockSARecordingRegistration{}
4595+
ra.SA = &mockSA
4596+
4597+
_, err := ra.UpdateRegistrationKey(context.Background(), &rapb.UpdateRegistrationKeyRequest{})
4598+
test.AssertError(t, err, "should not have been able to update registration key without a registration ID or key")
4599+
test.AssertContains(t, err.Error(), "incomplete gRPC request message")
4600+
4601+
_, err = ra.UpdateRegistrationKey(context.Background(), &rapb.UpdateRegistrationKeyRequest{RegistrationID: expectRegID})
4602+
test.AssertError(t, err, "should not have been able to update registration key without a key")
4603+
test.AssertContains(t, err.Error(), "incomplete gRPC request message")
4604+
4605+
_, err = ra.UpdateRegistrationKey(context.Background(), &rapb.UpdateRegistrationKeyRequest{Jwk: expectJwk})
4606+
test.AssertError(t, err, "should not have been able to update registration key without a registration ID")
4607+
test.AssertContains(t, err.Error(), "incomplete gRPC request message")
4608+
4609+
res, err := ra.UpdateRegistrationKey(context.Background(), &rapb.UpdateRegistrationKeyRequest{
4610+
RegistrationID: expectRegID,
4611+
Jwk: expectJwk,
4612+
})
4613+
test.AssertNotError(t, err, "should have been able to update registration key")
4614+
test.AssertEquals(t, res.Id, expectRegID)
4615+
test.AssertEquals(t, mockSA.providedRegistrationID, expectRegID)
4616+
test.AssertDeepEquals(t, res.Key, expectJwk)
4617+
test.AssertDeepEquals(t, mockSA.providedJwk, expectJwk)
4618+
4619+
// Switch to a mock SA that will always error if UpdateRegistrationKey() is
4620+
// called.
4621+
ra.SA = &NoUpdateSA{}
4622+
_, err = ra.UpdateRegistrationKey(context.Background(), &rapb.UpdateRegistrationKeyRequest{
4623+
RegistrationID: expectRegID,
4624+
Jwk: expectJwk,
4625+
})
4626+
test.AssertError(t, err, "should have received an error from the SA")
4627+
test.AssertContains(t, err.Error(), "failed to update registration key")
4628+
test.AssertContains(t, err.Error(), "mocked to always error")
4629+
}

0 commit comments

Comments
 (0)