Skip to content

Commit

Permalink
SA: Support profiles associated with authorizations (#7956)
Browse files Browse the repository at this point in the history
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 #7955
  • Loading branch information
aarongable authored Jan 27, 2025
1 parent 811e607 commit 86ab2ed
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 95 deletions.
5 changes: 5 additions & 0 deletions core/objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
102 changes: 57 additions & 45 deletions core/proto/core.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion core/proto/core.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
}
Expand Down
26 changes: 14 additions & 12 deletions grpc/pb-marshalling.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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
}
Expand Down
9 changes: 0 additions & 9 deletions sa/db-next/boulder_sa/20250115000000_AuthzProfiles.sql

This file was deleted.

1 change: 1 addition & 0 deletions sa/db-next/boulder_sa/20250115000000_AuthzProfiles.sql
9 changes: 9 additions & 0 deletions sa/db/boulder_sa/20250115000000_AuthzProfiles.sql
Original file line number Diff line number Diff line change
@@ -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`;
57 changes: 38 additions & 19 deletions sa/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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]
Expand All @@ -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)],
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 86ab2ed

Please sign in to comment.