Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions features/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ type Config struct {
// during certificate issuance. This flag must be set to true in the
// RA, VA, and WFE2 services for full functionality.
DNSAccount01Enabled bool

// StoreAuthzsInOrders causes the SA to write to the `authzs`
// column in NewOrder and read from it in GetOrder. It should be enabled
// after the migration to add that column has been run.
StoreAuthzsInOrders bool
}

var fMu = new(sync.RWMutex)
Expand Down
3 changes: 3 additions & 0 deletions sa/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ func initTables(dbMap *borp.DbMap) {
if !features.Get().StoreARIReplacesInOrders {
tableMap.ColMap("Replaces").SetTransient(true)
}
if !features.Get().StoreAuthzsInOrders {
tableMap.ColMap("Authzs").SetTransient(true)
}

dbMap.AddTableWithName(orderToAuthzModel{}, "orderToAuthz").SetKeys(false, "OrderID", "AuthzID")
dbMap.AddTableWithName(orderFQDNSet{}, "orderFqdnSets").SetKeys(true, "ID")
Expand Down
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 `orders` ADD COLUMN `authzs` blob DEFAULT NULL;

-- +migrate Down
-- SQL section 'Down' is executed when this migration is rolled back

ALTER TABLE `orders` DROP COLUMN `authzs`;
38 changes: 9 additions & 29 deletions sa/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"encoding/json"
"errors"
"fmt"
"google.golang.org/protobuf/proto"
"math"
"net/netip"
"net/url"
Expand Down Expand Up @@ -346,42 +347,14 @@ type orderModel struct {
BeganProcessing bool
CertificateProfileName *string
Replaces *string
Authzs []byte
}

type orderToAuthzModel struct {
OrderID int64
AuthzID int64
}

func orderToModel(order *corepb.Order) (*orderModel, error) {
// Make a local copy so we can take a reference to it below.
profile := order.CertificateProfileName
replaces := order.Replaces

om := &orderModel{
ID: order.Id,
RegistrationID: order.RegistrationID,
Expires: order.Expires.AsTime(),
Created: order.Created.AsTime(),
BeganProcessing: order.BeganProcessing,
CertificateSerial: order.CertificateSerial,
CertificateProfileName: &profile,
Replaces: &replaces,
}

if order.Error != nil {
errJSON, err := json.Marshal(order.Error)
if err != nil {
return nil, err
}
if len(errJSON) > mediumBlobSize {
return nil, fmt.Errorf("Error object is too large to store in the database")
}
om.Error = errJSON
}
return om, nil
}

func modelToOrder(om *orderModel) (*corepb.Order, error) {
profile := ""
if om.CertificateProfileName != nil {
Expand All @@ -391,6 +364,13 @@ func modelToOrder(om *orderModel) (*corepb.Order, error) {
if om.Replaces != nil {
replaces = *om.Replaces
}
if len(om.Authzs) > 0 {
var decodedAuthzs sapb.Authzs
err := proto.Unmarshal(om.Authzs, &decodedAuthzs)
if err != nil {
return nil, err
}
}
order := &corepb.Order{
Id: om.ID,
RegistrationID: om.RegistrationID,
Expand Down
20 changes: 0 additions & 20 deletions sa/model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,26 +223,6 @@ func TestModelToOrderBadJSON(t *testing.T) {
test.AssertEquals(t, string(badJSONErr.json), string(badJSON))
}

func TestOrderModelThereAndBackAgain(t *testing.T) {
clk := clock.New()
now := clk.Now()
order := &corepb.Order{
Id: 1,
RegistrationID: 2024,
Expires: timestamppb.New(now.Add(24 * time.Hour)),
Created: timestamppb.New(now),
Error: nil,
CertificateSerial: "2",
BeganProcessing: true,
CertificateProfileName: "phljny",
}
model, err := orderToModel(order)
test.AssertNotError(t, err, "orderToModelv2 should not have errored")
returnOrder, err := modelToOrder(model)
test.AssertNotError(t, err, "modelToOrderv2 should not have errored")
test.AssertDeepEquals(t, order, returnOrder)
}

// TestPopulateAttemptedFieldsBadJSON tests that populating a challenge from an
// authz2 model with an invalid validation error or an invalid validation record
// produces the expected bad JSON error.
Expand Down
127 changes: 127 additions & 0 deletions sa/proto/sadb.pb.go

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

9 changes: 9 additions & 0 deletions sa/proto/sadb.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
syntax = "proto3";

package sa;
option go_package = "github.com/letsencrypt/boulder/sa/proto";

// Used internally for storage in the DB, not for RPCs.
message Authzs {
repeated int64 authzIDs = 1;
}
42 changes: 29 additions & 13 deletions sa/sa.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/json"
"errors"
"fmt"
"google.golang.org/protobuf/proto"
"strings"
"time"

Expand All @@ -20,6 +21,7 @@ import (
corepb "github.com/letsencrypt/boulder/core/proto"
"github.com/letsencrypt/boulder/db"
berrors "github.com/letsencrypt/boulder/errors"
"github.com/letsencrypt/boulder/features"
bgrpc "github.com/letsencrypt/boulder/grpc"
"github.com/letsencrypt/boulder/identifier"
blog "github.com/letsencrypt/boulder/log"
Expand Down Expand Up @@ -477,24 +479,37 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb
newAuthzIDs = append(newAuthzIDs, am.ID)
}

// Combine the already-existing and newly-created authzs.
allAuthzIds := append(req.NewOrder.V2Authorizations, newAuthzIDs...)

// Second, insert the new order.
created := ssa.clk.Now()
var encodedAuthzs []byte
var err error
if features.Get().StoreAuthzsInOrders {
encodedAuthzs, err = proto.Marshal(&sapb.Authzs{
AuthzIDs: allAuthzIds,
})
if err != nil {
return nil, err
}
}

om := orderModel{
RegistrationID: req.NewOrder.RegistrationID,
Expires: req.NewOrder.Expires.AsTime(),
Created: created,
CertificateProfileName: &req.NewOrder.CertificateProfileName,
Replaces: &req.NewOrder.Replaces,
Authzs: encodedAuthzs,
}
err := tx.Insert(ctx, &om)
err = tx.Insert(ctx, &om)
if err != nil {
return nil, err
}
orderID := om.ID

// Third, insert all of the orderToAuthz relations.
// Have to combine the already-associated and newly-created authzs.
allAuthzIds := append(req.NewOrder.V2Authorizations, newAuthzIDs...)
inserter, err := db.NewMultiInserter("orderToAuthz2", []string{"orderID", "authzID"})
if err != nil {
return nil, err
Expand Down Expand Up @@ -612,21 +627,22 @@ func (ssa *SQLStorageAuthority) SetOrderError(ctx context.Context, req *sapb.Set
if req.Id == 0 || req.Error == nil {
return nil, errIncompleteRequest
}
_, overallError := db.WithTransaction(ctx, ssa.dbMap, func(tx db.Executor) (any, error) {
om, err := orderToModel(&corepb.Order{
Id: req.Id,
Error: req.Error,
})
if err != nil {
return nil, err
}

errJSON, err := json.Marshal(req.Error)
if err != nil {
return nil, err
}
if len(errJSON) > mediumBlobSize {
return nil, fmt.Errorf("error object is too large to store in the database")
}

_, overallError := db.WithTransaction(ctx, ssa.dbMap, func(tx db.Executor) (any, error) {
result, err := tx.ExecContext(ctx, `
UPDATE orders
SET error = ?
WHERE id = ?`,
om.Error,
om.ID)
errJSON,
req.Id)
if err != nil {
return nil, berrors.InternalServerError("error updating order error field")
}
Expand Down
Loading
Loading