SA: Support profiles associated with authorizations (#7956)

Add "certificateProfileName" to the model used to insert new authz2 rows
and to the list of column names read when retrieving rows from the
authz2 table. Add support for this column to the functions which convert
to and from authz2 model types.

Add support for the profile field to core types so that it can be
returned by the SA.

Fixes https://github.com/letsencrypt/boulder/issues/7955
This commit is contained in:
Aaron Gable 2025-01-27 14:53:30 -08:00 committed by GitHub
parent 811e6073d1
commit 86ab2ed245
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 191 additions and 95 deletions

View File

@ -317,6 +317,11 @@ type Authorization struct {
// as part of the authorization, the identifier we store in the database
// can contain an asterisk.
Wildcard bool `json:"wildcard,omitempty" db:"-"`
// CertificateProfileName is the name of the profile associated with the
// order that first resulted in the creation of this authorization. Omitted
// from API responses.
CertificateProfileName string `json:"-"`
}
// FindChallengeByStringID will look for a challenge matching the given ID inside

View File

@ -648,10 +648,11 @@ type Authorization struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
RegistrationID int64 `protobuf:"varint,3,opt,name=registrationID,proto3" json:"registrationID,omitempty"`
// Fields specified by RFC 8555, Section 7.1.4
DnsName string `protobuf:"bytes,2,opt,name=dnsName,proto3" json:"dnsName,omitempty"`
Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
Expires *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=expires,proto3" json:"expires,omitempty"`
Challenges []*Challenge `protobuf:"bytes,6,rep,name=challenges,proto3" json:"challenges,omitempty"`
DnsName string `protobuf:"bytes,2,opt,name=dnsName,proto3" json:"dnsName,omitempty"`
Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
Expires *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=expires,proto3" json:"expires,omitempty"`
Challenges []*Challenge `protobuf:"bytes,6,rep,name=challenges,proto3" json:"challenges,omitempty"`
CertificateProfileName string `protobuf:"bytes,10,opt,name=certificateProfileName,proto3" json:"certificateProfileName,omitempty"`
}
func (x *Authorization) Reset() {
@ -728,6 +729,13 @@ func (x *Authorization) GetChallenges() []*Challenge {
return nil
}
func (x *Authorization) GetCertificateProfileName() string {
if x != nil {
return x.CertificateProfileName
}
return ""
}
type Order struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -1033,7 +1041,7 @@ var file_core_proto_rawDesc = []byte{
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41,
0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28,
0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a,
0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x22, 0xf2, 0x01, 0x0a, 0x0d,
0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x22, 0xaa, 0x02, 0x0a, 0x0d,
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a,
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a,
0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18,
@ -1047,49 +1055,53 @@ var file_core_proto_rawDesc = []byte{
0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x12, 0x2f, 0x0a,
0x0a, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e,
0x67, 0x65, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x73, 0x4a, 0x04,
0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09,
0x22, 0xd9, 0x03, 0x0a, 0x05, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65,
0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01,
0x28, 0x03, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x07, 0x20, 0x01,
0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x07, 0x65, 0x78,
0x70, 0x69, 0x72, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73,
0x12, 0x1a, 0x0a, 0x08, 0x64, 0x6e, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03,
0x28, 0x09, 0x52, 0x08, 0x64, 0x6e, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x05,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c,
0x73, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2a, 0x0a, 0x10, 0x76, 0x32, 0x41, 0x75,
0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x03,
0x28, 0x03, 0x52, 0x10, 0x76, 0x32, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
0x11, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0d, 0x20,
0x67, 0x65, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x36,
0x0a, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f,
0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16,
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69,
0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07,
0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0xd9, 0x03, 0x0a, 0x05, 0x4f, 0x72, 0x64,
0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02,
0x69, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69,
0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74,
0x61, 0x74, 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74,
0x75, 0x73, 0x12, 0x34, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x18, 0x0c, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x63, 0x65, 0x72, 0x74,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61,
0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65,
0x12, 0x28, 0x0a, 0x0f, 0x62, 0x65, 0x67, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
0x69, 0x6e, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x62, 0x65, 0x67, 0x61, 0x6e,
0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04,
0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x22, 0x7a, 0x0a, 0x08,
0x43, 0x52, 0x4c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x09, 0x72, 0x65, 0x76, 0x6f,
0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x6e, 0x73, 0x4e,
0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x64, 0x6e, 0x73, 0x4e,
0x61, 0x6d, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x6c,
0x65, 0x6d, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x12, 0x2a, 0x0a, 0x10, 0x76, 0x32, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x03, 0x52, 0x10, 0x76, 0x32, 0x41, 0x75,
0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2c, 0x0a, 0x11,
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69, 0x61,
0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72,
0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64,
0x41, 0x74, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x65, 0x74, 0x73, 0x65, 0x6e, 0x63, 0x72, 0x79,
0x70, 0x74, 0x2f, 0x62, 0x6f, 0x75, 0x6c, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
0x12, 0x36, 0x0a, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50,
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09,
0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f,
0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x65, 0x67, 0x61,
0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28,
0x08, 0x52, 0x0f, 0x62, 0x65, 0x67, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69,
0x6e, 0x67, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04,
0x08, 0x0a, 0x10, 0x0b, 0x22, 0x7a, 0x0a, 0x08, 0x43, 0x52, 0x4c, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73,
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
0x12, 0x38, 0x0a, 0x09, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
0x09, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04,
0x42, 0x2b, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c,
0x65, 0x74, 0x73, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2f, 0x62, 0x6f, 0x75, 0x6c, 0x64,
0x65, 0x72, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -93,7 +93,7 @@ message Registration {
}
message Authorization {
// Next unused field number: 10
// Next unused field number: 11
reserved 5, 7, 8;
string id = 1;
int64 registrationID = 3;
@ -102,6 +102,7 @@ message Authorization {
string status = 4;
google.protobuf.Timestamp expires = 9;
repeated core.Challenge challenges = 6;
string certificateProfileName = 10;
// We do not directly represent the "wildcard" field, instead inferring it
// from the identifier value.
}

View File

@ -289,12 +289,13 @@ func AuthzToPB(authz core.Authorization) (*corepb.Authorization, error) {
}
return &corepb.Authorization{
Id: authz.ID,
DnsName: authz.Identifier.Value,
RegistrationID: authz.RegistrationID,
Status: string(authz.Status),
Expires: expires,
Challenges: challs,
Id: authz.ID,
DnsName: authz.Identifier.Value,
RegistrationID: authz.RegistrationID,
Status: string(authz.Status),
Expires: expires,
Challenges: challs,
CertificateProfileName: authz.CertificateProfileName,
}, nil
}
@ -313,12 +314,13 @@ func PBToAuthz(pb *corepb.Authorization) (core.Authorization, error) {
expires = &c
}
authz := core.Authorization{
ID: pb.Id,
Identifier: identifier.NewDNS(pb.DnsName),
RegistrationID: pb.RegistrationID,
Status: core.AcmeStatus(pb.Status),
Expires: expires,
Challenges: challs,
ID: pb.Id,
Identifier: identifier.NewDNS(pb.DnsName),
RegistrationID: pb.RegistrationID,
Status: core.AcmeStatus(pb.Status),
Expires: expires,
Challenges: challs,
CertificateProfileName: pb.CertificateProfileName,
}
return authz, nil
}

View File

@ -1,9 +0,0 @@
-- +migrate Up
-- SQL in section 'Up' is executed when this migration is applied
ALTER TABLE `authz2` ADD COLUMN `certificateProfileName` varchar(32) DEFAULT NULL;
-- +migrate Down
-- SQL section 'Down' is executed when this migration is rolled back
ALTER TABLE `authz2` DROP COLUMN `certificateProfileName`;

View File

@ -0,0 +1 @@
../../db/boulder_sa/20250115000000_AuthzProfiles.sql

View File

@ -0,0 +1,9 @@
-- +migrate Up
-- SQL in section 'Up' is executed when this migration is applied
ALTER TABLE `authz2` ADD COLUMN `certificateProfileName` varchar(32) DEFAULT NULL;
-- +migrate Down
-- SQL section 'Down' is executed when this migration is rolled back
ALTER TABLE `authz2` DROP COLUMN `certificateProfileName`;

View File

@ -480,21 +480,24 @@ func statusUint(status core.AcmeStatus) uint8 {
// authzFields is used in a variety of places in sa.go, and modifications to
// it must be carried through to every use in sa.go
const authzFields = "id, identifierType, identifierValue, registrationID, status, expires, challenges, attempted, attemptedAt, token, validationError, validationRecord"
const authzFields = "id, identifierType, identifierValue, registrationID, certificateProfileName, status, expires, challenges, attempted, attemptedAt, token, validationError, validationRecord"
// authzModel represents one row in the authz2 table. The CertificateProfileName
// column is a pointer because the column is NULL-able.
type authzModel struct {
ID int64 `db:"id"`
IdentifierType uint8 `db:"identifierType"`
IdentifierValue string `db:"identifierValue"`
RegistrationID int64 `db:"registrationID"`
Status uint8 `db:"status"`
Expires time.Time `db:"expires"`
Challenges uint8 `db:"challenges"`
Attempted *uint8 `db:"attempted"`
AttemptedAt *time.Time `db:"attemptedAt"`
Token []byte `db:"token"`
ValidationError []byte `db:"validationError"`
ValidationRecord []byte `db:"validationRecord"`
ID int64 `db:"id"`
IdentifierType uint8 `db:"identifierType"`
IdentifierValue string `db:"identifierValue"`
RegistrationID int64 `db:"registrationID"`
CertificateProfileName *string `db:"certificateProfileName"`
Status uint8 `db:"status"`
Expires time.Time `db:"expires"`
Challenges uint8 `db:"challenges"`
Attempted *uint8 `db:"attempted"`
AttemptedAt *time.Time `db:"attemptedAt"`
Token []byte `db:"token"`
ValidationError []byte `db:"validationError"`
ValidationRecord []byte `db:"validationRecord"`
}
// rehydrateHostPort mutates a validation record. If the URL in the validation
@ -627,7 +630,7 @@ func hasMultipleNonPendingChallenges(challenges []*corepb.Challenge) bool {
// newAuthzReqToModel converts an sapb.NewAuthzRequest to the authzModel storage
// representation. It hardcodes the status to "pending" because it should be
// impossible to create an authz in any other state.
func newAuthzReqToModel(authz *sapb.NewAuthzRequest) (*authzModel, error) {
func newAuthzReqToModel(authz *sapb.NewAuthzRequest, profile string) (*authzModel, error) {
am := &authzModel{
IdentifierType: identifierTypeToUint[authz.Identifier.Type],
IdentifierValue: authz.Identifier.Value,
@ -636,6 +639,10 @@ func newAuthzReqToModel(authz *sapb.NewAuthzRequest) (*authzModel, error) {
Expires: authz.Expires.AsTime(),
}
if profile != "" {
am.CertificateProfileName = &profile
}
for _, challType := range authz.ChallengeTypes {
// Set the challenge type bit in the bitmap
am.Challenges |= 1 << challTypeToUint[challType]
@ -652,6 +659,8 @@ func newAuthzReqToModel(authz *sapb.NewAuthzRequest) (*authzModel, error) {
// authzPBToModel converts a protobuf authorization representation to the
// authzModel storage representation.
// Deprecated: this function is only used as part of test setup, do not
// introduce any new uses in production code.
func authzPBToModel(authz *corepb.Authorization) (*authzModel, error) {
am := &authzModel{
IdentifierType: identifierTypeToUint[string(identifier.TypeDNS)],
@ -660,6 +669,10 @@ func authzPBToModel(authz *corepb.Authorization) (*authzModel, error) {
Status: statusToUint[core.AcmeStatus(authz.Status)],
Expires: authz.Expires.AsTime(),
}
if authz.CertificateProfileName != "" {
profile := authz.CertificateProfileName
am.CertificateProfileName = &profile
}
if authz.Id != "" {
// The v1 internal authorization objects use a string for the ID, the v2
// storage format uses a integer ID. In order to maintain compatibility we
@ -801,12 +814,18 @@ func modelToAuthzPB(am authzModel) (*corepb.Authorization, error) {
return nil, fmt.Errorf("unrecognized identifier type encoding %d", am.IdentifierType)
}
profile := ""
if am.CertificateProfileName != nil {
profile = *am.CertificateProfileName
}
pb := &corepb.Authorization{
Id: fmt.Sprintf("%d", am.ID),
Status: string(uintToStatus[am.Status]),
DnsName: am.IdentifierValue,
RegistrationID: am.RegistrationID,
Expires: timestamppb.New(am.Expires),
Id: fmt.Sprintf("%d", am.ID),
Status: string(uintToStatus[am.Status]),
DnsName: am.IdentifierValue,
RegistrationID: am.RegistrationID,
Expires: timestamppb.New(am.Expires),
CertificateProfileName: profile,
}
// Populate authorization challenge array. We do this by iterating through
// the challenge type bitmap and creating a challenge of each type if its

View File

@ -59,11 +59,12 @@ func TestAuthzModel(t *testing.T) {
now := clk.Now()
expires := now.Add(24 * time.Hour)
authzPB := &corepb.Authorization{
Id: "1",
DnsName: "example.com",
RegistrationID: 1,
Status: string(core.StatusValid),
Expires: timestamppb.New(expires),
Id: "1",
DnsName: "example.com",
RegistrationID: 1,
Status: string(core.StatusValid),
Expires: timestamppb.New(expires),
CertificateProfileName: "test",
Challenges: []*corepb.Challenge{
{
Type: string(core.ChallengeTypeHTTP01),
@ -101,6 +102,7 @@ func TestAuthzModel(t *testing.T) {
authzPB.Challenges[0].Validationrecords[0].Hostname = "example.com"
authzPB.Challenges[0].Validationrecords[0].Port = "443"
test.AssertDeepEquals(t, authzPB.Challenges, authzPBOut.Challenges)
test.AssertEquals(t, authzPBOut.CertificateProfileName, authzPB.CertificateProfileName)
now = clk.Now()
expires = now.Add(24 * time.Hour)

View File

@ -521,7 +521,7 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb
newAuthzIDs := make([]int64, 0)
if features.Get().InsertAuthzsIndividually {
for _, authz := range req.NewAuthzs {
am, err := newAuthzReqToModel(authz)
am, err := newAuthzReqToModel(authz, req.NewOrder.CertificateProfileName)
if err != nil {
return nil, err
}
@ -538,7 +538,7 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb
return nil, err
}
for _, authz := range req.NewAuthzs {
am, err := newAuthzReqToModel(authz)
am, err := newAuthzReqToModel(authz, req.NewOrder.CertificateProfileName)
if err != nil {
return nil, err
}
@ -547,6 +547,7 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb
am.IdentifierType,
am.IdentifierValue,
am.RegistrationID,
am.CertificateProfileName,
statusToUint[core.StatusPending],
am.Expires,
am.Challenges,

View File

@ -1043,6 +1043,55 @@ func TestNewOrderAndAuthzs_NewAuthzExpectedFields(t *testing.T) {
test.AssertBoxedNil(t, am.ValidationRecord, "am.ValidationRecord should be nil")
}
func TestNewOrderAndAuthzs_Profile(t *testing.T) {
sa, fc, cleanup := initSA(t)
defer cleanup()
reg := createWorkingRegistration(t, sa)
expires := fc.Now().Add(time.Hour)
// Create and order and authz while specifying a profile.
order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{
NewOrder: &sapb.NewOrderRequest{
RegistrationID: reg.Id,
Expires: timestamppb.New(expires),
DnsNames: []string{"example.com"},
CertificateProfileName: "test",
},
NewAuthzs: []*sapb.NewAuthzRequest{
{
Identifier: &corepb.Identifier{Type: "dns", Value: "example.com"},
RegistrationID: reg.Id,
Expires: timestamppb.New(expires),
ChallengeTypes: []string{string(core.ChallengeTypeHTTP01)},
Token: core.NewToken(),
},
},
})
if err != nil {
t.Fatalf("inserting order and authzs: %s", err)
}
// Retrieve the order and check that the profile is correct.
gotOrder, err := sa.GetOrder(context.Background(), &sapb.OrderRequest{Id: order.Id})
if err != nil {
t.Fatalf("retrieving inserted order: %s", err)
}
if gotOrder.CertificateProfileName != "test" {
t.Errorf("order.CertificateProfileName = %v, want %v", gotOrder.CertificateProfileName, "test")
}
// Retrieve the authz and check that the profile is correct.
// Safely get the authz for the order we created above.
gotAuthz, err := sa.GetAuthorization2(context.Background(), &sapb.AuthorizationID2{Id: order.V2Authorizations[0]})
if err != nil {
t.Fatalf("retrieving inserted authz: %s", err)
}
if gotAuthz.CertificateProfileName != "test" {
t.Errorf("authz.CertificateProfileName = %v, want %v", gotAuthz.CertificateProfileName, "test")
}
}
func BenchmarkNewOrderAndAuthzs(b *testing.B) {
for _, flag := range []bool{false, true} {
for _, numIdents := range []int{1, 2, 5, 10, 20, 50, 100} {
@ -1174,7 +1223,9 @@ func TestFinalizeOrder(t *testing.T) {
test.AssertEquals(t, updatedOrder.Status, string(core.StatusValid))
}
func TestOrder(t *testing.T) {
// TestGetOrder tests that round-tripping a simple order through
// NewOrderAndAuthzs and GetOrder has the expected result.
func TestGetOrder(t *testing.T) {
sa, fc, cleanup := initSA(t)
defer cleanup()
@ -1230,7 +1281,9 @@ func TestOrder(t *testing.T) {
test.AssertDeepEquals(t, storedOrder, expectedOrder)
}
func TestOrderWithProfile(t *testing.T) {
// TestGetOrderWithProfile tests that round-tripping a simple order through
// NewOrderAndAuthzs and GetOrder has the expected result.
func TestGetOrderWithProfile(t *testing.T) {
sa, fc, cleanup := initSA(t)
defer cleanup()