diff --git a/acme/api/handler.go b/acme/api/handler.go index 31477fca..16deeaf8 100644 --- a/acme/api/handler.go +++ b/acme/api/handler.go @@ -1,7 +1,6 @@ package api import ( - "context" "crypto/tls" "crypto/x509" "encoding/json" @@ -71,28 +70,14 @@ func NewHandler(ops HandlerOptions) api.RouterHandler { dialer := &net.Dialer{ Timeout: 30 * time.Second, } - resolver := &net.Resolver{ - // The DNS resolver can be configured for testing purposes with something - // like this: - // - // PreferGo: true, - // Dial: func(ctx context.Context, network, address string) (net.Conn, error) { - // var d net.Dialer - // return d.DialContext(ctx, "udp", "127.0.0.1:5333") - // }, - } return &Handler{ ca: ops.CA, db: ops.DB, backdate: ops.Backdate, linker: NewLinker(ops.DNS, ops.Prefix), validateChallengeOptions: &acme.ValidateChallengeOptions{ - HTTPGet: client.Get, - LookupTxt: func(name string) ([]string, error) { - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - return resolver.LookupTXT(ctx, name) - }, + HTTPGet: client.Get, + LookupTxt: net.LookupTXT, TLSDial: func(network, addr string, config *tls.Config) (*tls.Conn, error) { return tls.DialWithDialer(dialer, network, addr, config) }, diff --git a/acme/api/linker.go b/acme/api/linker.go index 9459e1bc..b6a44dfa 100644 --- a/acme/api/linker.go +++ b/acme/api/linker.go @@ -181,81 +181,3 @@ func (l *linker) LinkOrdersByAccountID(ctx context.Context, orders []string) { orders[i] = l.GetLink(ctx, OrderLinkType, true, id) } } - -// MockLinker implements the Linker interface. Only used for testing. -type MockLinker struct { - MockGetLink func(ctx context.Context, typ LinkType, abs bool, inputs ...string) string - MockGetLinkExplicit func(typ LinkType, provName string, abs bool, baseURL *url.URL, inputs ...string) string - - MockLinkOrder func(ctx context.Context, o *acme.Order) - MockLinkAccount func(ctx context.Context, o *acme.Account) - MockLinkChallenge func(ctx context.Context, o *acme.Challenge) - MockLinkAuthorization func(ctx context.Context, o *acme.Authorization) - MockLinkOrdersByAccountID func(ctx context.Context, orders []string) - - MockError error - MockRet1 interface{} -} - -// GetLink mock. -func (m *MockLinker) GetLink(ctx context.Context, typ LinkType, abs bool, inputs ...string) string { - if m.MockGetLink != nil { - return m.MockGetLink(ctx, typ, abs, inputs...) - } - - return m.MockRet1.(string) -} - -// GetLinkExplicit mock. -func (m *MockLinker) GetLinkExplicit(typ LinkType, provName string, abs bool, baseURL *url.URL, inputs ...string) string { - if m.MockGetLinkExplicit != nil { - return m.MockGetLinkExplicit(typ, provName, abs, baseURL, inputs...) - } - - return m.MockRet1.(string) -} - -// LinkOrder mock. -func (m *MockLinker) LinkOrder(ctx context.Context, o *acme.Order) { - if m.MockLinkOrder != nil { - m.MockLinkOrder(ctx, o) - return - } - return -} - -// LinkAccount mock. -func (m *MockLinker) LinkAccount(ctx context.Context, o *acme.Account) { - if m.MockLinkAccount != nil { - m.MockLinkAccount(ctx, o) - return - } - return -} - -// LinkChallenge mock. -func (m *MockLinker) LinkChallenge(ctx context.Context, o *acme.Challenge) { - if m.MockLinkChallenge != nil { - m.MockLinkChallenge(ctx, o) - return - } - return -} - -// LinkAuthorization mock. -func (m *MockLinker) LinkAuthorization(ctx context.Context, o *acme.Authorization) { - if m.MockLinkAuthorization != nil { - m.MockLinkAuthorization(ctx, o) - return - } - return -} - -// LinkOrderAccountsByID mock. -func (m *MockLinker) LinkOrderAccountsByID(ctx context.Context, orders []string) { - if m.MockLinkOrdersByAccountID != nil { - m.MockLinkOrdersByAccountID(ctx, orders) - return - } - return -} diff --git a/acme/api/order.go b/acme/api/order.go index 9f557d7f..e7a913ab 100644 --- a/acme/api/order.go +++ b/acme/api/order.go @@ -123,8 +123,10 @@ func (h *Handler) NewOrder(w http.ResponseWriter, r *http.Request) { if o.NotAfter.IsZero() { o.NotAfter = o.NotBefore.Add(prov.DefaultTLSCertDuration()) } + // If request NotBefore was empty then backdate the order.NotBefore (now) + // to avoid timing issues. if nor.NotBefore.IsZero() { - o.NotBefore.Add(-defaultOrderBackdate) + o.NotBefore = o.NotBefore.Add(-defaultOrderBackdate) } if err := h.db.CreateOrder(ctx, o); err != nil { diff --git a/acme/api/order_test.go b/acme/api/order_test.go index 62652812..597ec018 100644 --- a/acme/api/order_test.go +++ b/acme/api/order_test.go @@ -591,6 +591,7 @@ func TestHandler_NewOrder(t *testing.T) { ctx context.Context nor *NewOrderRequest statusCode int + vr func(t *testing.T, o *acme.Order) err *acme.Error } var tests = map[string]func(t *testing.T) test{ @@ -772,14 +773,130 @@ func TestHandler_NewOrder(t *testing.T) { err: acme.NewErrorISE("error creating order: force"), } }, - "ok/no-naf-nbf": func(t *testing.T) test { + "ok/multiple-authz": func(t *testing.T) test { acc := &acme.Account{ID: "accID"} - fr := &NewOrderRequest{ + nor := &NewOrderRequest{ + Identifiers: []acme.Identifier{ + {Type: "dns", Value: "zap.internal"}, + {Type: "dns", Value: "*.zar.internal"}, + }, + } + b, err := json.Marshal(nor) + assert.FatalError(t, err) + ctx := context.WithValue(context.Background(), provisionerContextKey, prov) + ctx = context.WithValue(ctx, accContextKey, acc) + ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{value: b}) + ctx = context.WithValue(ctx, baseURLContextKey, baseURL) + var ( + ch1, ch2, ch3, ch4 **acme.Challenge + az1ID, az2ID *string + chCount, azCount = 0, 0 + ) + return test{ + ctx: ctx, + statusCode: 201, + nor: nor, + db: &acme.MockDB{ + MockCreateChallenge: func(ctx context.Context, ch *acme.Challenge) error { + switch chCount { + case 0: + ch.ID = "dns" + assert.Equals(t, ch.Type, "dns-01") + assert.Equals(t, ch.Value, "zap.internal") + ch1 = &ch + case 1: + ch.ID = "http" + assert.Equals(t, ch.Type, "http-01") + assert.Equals(t, ch.Value, "zap.internal") + ch2 = &ch + case 2: + ch.ID = "tls" + assert.Equals(t, ch.Type, "tls-alpn-01") + assert.Equals(t, ch.Value, "zap.internal") + ch3 = &ch + case 3: + ch.ID = "dns" + assert.Equals(t, ch.Type, "dns-01") + assert.Equals(t, ch.Value, "zar.internal") + ch4 = &ch + default: + assert.FatalError(t, errors.New("test logic error")) + return errors.New("force") + } + chCount++ + assert.Equals(t, ch.AccountID, "accID") + assert.NotEquals(t, ch.Token, "") + assert.Equals(t, ch.Status, acme.StatusPending) + return nil + }, + MockCreateAuthorization: func(ctx context.Context, az *acme.Authorization) error { + switch azCount { + case 0: + az.ID = "az1ID" + az1ID = &az.ID + assert.Equals(t, az.Identifier, nor.Identifiers[0]) + assert.Equals(t, az.Wildcard, false) + assert.Equals(t, az.Challenges, []*acme.Challenge{*ch1, *ch2, *ch3}) + case 1: + az.ID = "az2ID" + az2ID = &az.ID + assert.Equals(t, az.Identifier, acme.Identifier{ + Type: "dns", + Value: "zar.internal", + }) + assert.Equals(t, az.Wildcard, true) + assert.Equals(t, az.Challenges, []*acme.Challenge{*ch4}) + default: + assert.FatalError(t, errors.New("test logic error")) + return errors.New("force") + } + azCount++ + assert.Equals(t, az.AccountID, "accID") + assert.NotEquals(t, az.Token, "") + assert.Equals(t, az.Status, acme.StatusPending) + return nil + }, + MockCreateOrder: func(ctx context.Context, o *acme.Order) error { + o.ID = "ordID" + assert.Equals(t, o.AccountID, "accID") + assert.Equals(t, o.ProvisionerID, prov.GetID()) + assert.Equals(t, o.Status, acme.StatusPending) + assert.Equals(t, o.Identifiers, nor.Identifiers) + assert.Equals(t, o.AuthorizationIDs, []string{*az1ID, *az2ID}) + return nil + }, + }, + vr: func(t *testing.T, o *acme.Order) { + now := clock.Now() + testBufferDur := 5 * time.Second + orderExpiry := now.Add(defaultOrderExpiry) + expNbf := now.Add(-defaultOrderBackdate) + expNaf := now.Add(prov.DefaultTLSCertDuration()) + + assert.Equals(t, o.ID, "ordID") + assert.Equals(t, o.Status, acme.StatusPending) + assert.Equals(t, o.Identifiers, nor.Identifiers) + assert.Equals(t, o.AuthorizationURLs, []string{ + "https://test.ca.smallstep.com/acme/test@acme-provisioner.com/authz/az1ID", + "https://test.ca.smallstep.com/acme/test@acme-provisioner.com/authz/az2ID", + }) + assert.True(t, o.NotBefore.Add(-testBufferDur).Before(expNbf)) + assert.True(t, o.NotBefore.Add(testBufferDur).After(expNbf)) + assert.True(t, o.NotAfter.Add(-testBufferDur).Before(expNaf)) + assert.True(t, o.NotAfter.Add(testBufferDur).After(expNaf)) + assert.True(t, o.ExpiresAt.Add(-testBufferDur).Before(orderExpiry)) + assert.True(t, o.ExpiresAt.Add(testBufferDur).After(orderExpiry)) + }, + } + }, + "ok/default-naf-nbf": func(t *testing.T) test { + acc := &acme.Account{ID: "accID"} + nor := &NewOrderRequest{ Identifiers: []acme.Identifier{ {Type: "dns", Value: "zap.internal"}, }, } - b, err := json.Marshal(fr) + b, err := json.Marshal(nor) assert.FatalError(t, err) ctx := context.WithValue(context.Background(), provisionerContextKey, prov) ctx = context.WithValue(ctx, accContextKey, acc) @@ -793,7 +910,7 @@ func TestHandler_NewOrder(t *testing.T) { return test{ ctx: ctx, statusCode: 201, - nor: fr, + nor: nor, db: &acme.MockDB{ MockCreateChallenge: func(ctx context.Context, ch *acme.Challenge) error { switch count { @@ -826,7 +943,7 @@ func TestHandler_NewOrder(t *testing.T) { assert.Equals(t, az.AccountID, "accID") assert.NotEquals(t, az.Token, "") assert.Equals(t, az.Status, acme.StatusPending) - assert.Equals(t, az.Identifier, fr.Identifiers[0]) + assert.Equals(t, az.Identifier, nor.Identifiers[0]) assert.Equals(t, az.Challenges, []*acme.Challenge{*ch1, *ch2, *ch3}) assert.Equals(t, az.Wildcard, false) return nil @@ -836,11 +953,301 @@ func TestHandler_NewOrder(t *testing.T) { assert.Equals(t, o.AccountID, "accID") assert.Equals(t, o.ProvisionerID, prov.GetID()) assert.Equals(t, o.Status, acme.StatusPending) - assert.Equals(t, o.Identifiers, fr.Identifiers) + assert.Equals(t, o.Identifiers, nor.Identifiers) assert.Equals(t, o.AuthorizationIDs, []string{*az1ID}) return nil }, }, + vr: func(t *testing.T, o *acme.Order) { + now := clock.Now() + testBufferDur := 5 * time.Second + orderExpiry := now.Add(defaultOrderExpiry) + expNbf := now.Add(-defaultOrderBackdate) + expNaf := now.Add(prov.DefaultTLSCertDuration()) + + assert.Equals(t, o.ID, "ordID") + assert.Equals(t, o.Status, acme.StatusPending) + assert.Equals(t, o.Identifiers, nor.Identifiers) + assert.Equals(t, o.AuthorizationURLs, []string{"https://test.ca.smallstep.com/acme/test@acme-provisioner.com/authz/az1ID"}) + assert.True(t, o.NotBefore.Add(-testBufferDur).Before(expNbf)) + assert.True(t, o.NotBefore.Add(testBufferDur).After(expNbf)) + assert.True(t, o.NotAfter.Add(-testBufferDur).Before(expNaf)) + assert.True(t, o.NotAfter.Add(testBufferDur).After(expNaf)) + assert.True(t, o.ExpiresAt.Add(-testBufferDur).Before(orderExpiry)) + assert.True(t, o.ExpiresAt.Add(testBufferDur).After(orderExpiry)) + }, + } + }, + "ok/nbf-no-naf": func(t *testing.T) test { + now := clock.Now() + expNbf := now.Add(10 * time.Minute) + acc := &acme.Account{ID: "accID"} + nor := &NewOrderRequest{ + Identifiers: []acme.Identifier{ + {Type: "dns", Value: "zap.internal"}, + }, + NotBefore: expNbf, + } + b, err := json.Marshal(nor) + assert.FatalError(t, err) + ctx := context.WithValue(context.Background(), provisionerContextKey, prov) + ctx = context.WithValue(ctx, accContextKey, acc) + ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{value: b}) + ctx = context.WithValue(ctx, baseURLContextKey, baseURL) + var ( + ch1, ch2, ch3 **acme.Challenge + az1ID *string + count = 0 + ) + return test{ + ctx: ctx, + statusCode: 201, + nor: nor, + db: &acme.MockDB{ + MockCreateChallenge: func(ctx context.Context, ch *acme.Challenge) error { + switch count { + case 0: + ch.ID = "dns" + assert.Equals(t, ch.Type, "dns-01") + ch1 = &ch + case 1: + ch.ID = "http" + assert.Equals(t, ch.Type, "http-01") + ch2 = &ch + case 2: + ch.ID = "tls" + assert.Equals(t, ch.Type, "tls-alpn-01") + ch3 = &ch + default: + assert.FatalError(t, errors.New("test logic error")) + return errors.New("force") + } + count++ + assert.Equals(t, ch.AccountID, "accID") + assert.NotEquals(t, ch.Token, "") + assert.Equals(t, ch.Status, acme.StatusPending) + assert.Equals(t, ch.Value, "zap.internal") + return nil + }, + MockCreateAuthorization: func(ctx context.Context, az *acme.Authorization) error { + az.ID = "az1ID" + az1ID = &az.ID + assert.Equals(t, az.AccountID, "accID") + assert.NotEquals(t, az.Token, "") + assert.Equals(t, az.Status, acme.StatusPending) + assert.Equals(t, az.Identifier, nor.Identifiers[0]) + assert.Equals(t, az.Challenges, []*acme.Challenge{*ch1, *ch2, *ch3}) + assert.Equals(t, az.Wildcard, false) + return nil + }, + MockCreateOrder: func(ctx context.Context, o *acme.Order) error { + o.ID = "ordID" + assert.Equals(t, o.AccountID, "accID") + assert.Equals(t, o.ProvisionerID, prov.GetID()) + assert.Equals(t, o.Status, acme.StatusPending) + assert.Equals(t, o.Identifiers, nor.Identifiers) + assert.Equals(t, o.AuthorizationIDs, []string{*az1ID}) + return nil + }, + }, + vr: func(t *testing.T, o *acme.Order) { + now := clock.Now() + testBufferDur := 5 * time.Second + orderExpiry := now.Add(defaultOrderExpiry) + expNaf := expNbf.Add(prov.DefaultTLSCertDuration()) + + assert.Equals(t, o.ID, "ordID") + assert.Equals(t, o.Status, acme.StatusPending) + assert.Equals(t, o.Identifiers, nor.Identifiers) + assert.Equals(t, o.AuthorizationURLs, []string{"https://test.ca.smallstep.com/acme/test@acme-provisioner.com/authz/az1ID"}) + assert.True(t, o.NotBefore.Add(-testBufferDur).Before(expNbf)) + assert.True(t, o.NotBefore.Add(testBufferDur).After(expNbf)) + assert.True(t, o.NotAfter.Add(-testBufferDur).Before(expNaf)) + assert.True(t, o.NotAfter.Add(testBufferDur).After(expNaf)) + assert.True(t, o.ExpiresAt.Add(-testBufferDur).Before(orderExpiry)) + assert.True(t, o.ExpiresAt.Add(testBufferDur).After(orderExpiry)) + }, + } + }, + "ok/naf-no-nbf": func(t *testing.T) test { + now := clock.Now() + expNaf := now.Add(15 * time.Minute) + acc := &acme.Account{ID: "accID"} + nor := &NewOrderRequest{ + Identifiers: []acme.Identifier{ + {Type: "dns", Value: "zap.internal"}, + }, + NotAfter: expNaf, + } + b, err := json.Marshal(nor) + assert.FatalError(t, err) + ctx := context.WithValue(context.Background(), provisionerContextKey, prov) + ctx = context.WithValue(ctx, accContextKey, acc) + ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{value: b}) + ctx = context.WithValue(ctx, baseURLContextKey, baseURL) + var ( + ch1, ch2, ch3 **acme.Challenge + az1ID *string + count = 0 + ) + return test{ + ctx: ctx, + statusCode: 201, + nor: nor, + db: &acme.MockDB{ + MockCreateChallenge: func(ctx context.Context, ch *acme.Challenge) error { + switch count { + case 0: + ch.ID = "dns" + assert.Equals(t, ch.Type, "dns-01") + ch1 = &ch + case 1: + ch.ID = "http" + assert.Equals(t, ch.Type, "http-01") + ch2 = &ch + case 2: + ch.ID = "tls" + assert.Equals(t, ch.Type, "tls-alpn-01") + ch3 = &ch + default: + assert.FatalError(t, errors.New("test logic error")) + return errors.New("force") + } + count++ + assert.Equals(t, ch.AccountID, "accID") + assert.NotEquals(t, ch.Token, "") + assert.Equals(t, ch.Status, acme.StatusPending) + assert.Equals(t, ch.Value, "zap.internal") + return nil + }, + MockCreateAuthorization: func(ctx context.Context, az *acme.Authorization) error { + az.ID = "az1ID" + az1ID = &az.ID + assert.Equals(t, az.AccountID, "accID") + assert.NotEquals(t, az.Token, "") + assert.Equals(t, az.Status, acme.StatusPending) + assert.Equals(t, az.Identifier, nor.Identifiers[0]) + assert.Equals(t, az.Challenges, []*acme.Challenge{*ch1, *ch2, *ch3}) + assert.Equals(t, az.Wildcard, false) + return nil + }, + MockCreateOrder: func(ctx context.Context, o *acme.Order) error { + o.ID = "ordID" + assert.Equals(t, o.AccountID, "accID") + assert.Equals(t, o.ProvisionerID, prov.GetID()) + assert.Equals(t, o.Status, acme.StatusPending) + assert.Equals(t, o.Identifiers, nor.Identifiers) + assert.Equals(t, o.AuthorizationIDs, []string{*az1ID}) + return nil + }, + }, + vr: func(t *testing.T, o *acme.Order) { + testBufferDur := 5 * time.Second + orderExpiry := now.Add(defaultOrderExpiry) + expNbf := now.Add(-defaultOrderBackdate) + + assert.Equals(t, o.ID, "ordID") + assert.Equals(t, o.Status, acme.StatusPending) + assert.Equals(t, o.Identifiers, nor.Identifiers) + assert.Equals(t, o.AuthorizationURLs, []string{"https://test.ca.smallstep.com/acme/test@acme-provisioner.com/authz/az1ID"}) + assert.True(t, o.NotBefore.Add(-testBufferDur).Before(expNbf)) + assert.True(t, o.NotBefore.Add(testBufferDur).After(expNbf)) + assert.True(t, o.NotAfter.Add(-testBufferDur).Before(expNaf)) + assert.True(t, o.NotAfter.Add(testBufferDur).After(expNaf)) + assert.True(t, o.ExpiresAt.Add(-testBufferDur).Before(orderExpiry)) + assert.True(t, o.ExpiresAt.Add(testBufferDur).After(orderExpiry)) + }, + } + }, + "ok/naf-nbf": func(t *testing.T) test { + now := clock.Now() + expNbf := now.Add(5 * time.Minute) + expNaf := now.Add(15 * time.Minute) + acc := &acme.Account{ID: "accID"} + nor := &NewOrderRequest{ + Identifiers: []acme.Identifier{ + {Type: "dns", Value: "zap.internal"}, + }, + NotBefore: expNbf, + NotAfter: expNaf, + } + b, err := json.Marshal(nor) + assert.FatalError(t, err) + ctx := context.WithValue(context.Background(), provisionerContextKey, prov) + ctx = context.WithValue(ctx, accContextKey, acc) + ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{value: b}) + ctx = context.WithValue(ctx, baseURLContextKey, baseURL) + var ( + ch1, ch2, ch3 **acme.Challenge + az1ID *string + count = 0 + ) + return test{ + ctx: ctx, + statusCode: 201, + nor: nor, + db: &acme.MockDB{ + MockCreateChallenge: func(ctx context.Context, ch *acme.Challenge) error { + switch count { + case 0: + ch.ID = "dns" + assert.Equals(t, ch.Type, "dns-01") + ch1 = &ch + case 1: + ch.ID = "http" + assert.Equals(t, ch.Type, "http-01") + ch2 = &ch + case 2: + ch.ID = "tls" + assert.Equals(t, ch.Type, "tls-alpn-01") + ch3 = &ch + default: + assert.FatalError(t, errors.New("test logic error")) + return errors.New("force") + } + count++ + assert.Equals(t, ch.AccountID, "accID") + assert.NotEquals(t, ch.Token, "") + assert.Equals(t, ch.Status, acme.StatusPending) + assert.Equals(t, ch.Value, "zap.internal") + return nil + }, + MockCreateAuthorization: func(ctx context.Context, az *acme.Authorization) error { + az.ID = "az1ID" + az1ID = &az.ID + assert.Equals(t, az.AccountID, "accID") + assert.NotEquals(t, az.Token, "") + assert.Equals(t, az.Status, acme.StatusPending) + assert.Equals(t, az.Identifier, nor.Identifiers[0]) + assert.Equals(t, az.Challenges, []*acme.Challenge{*ch1, *ch2, *ch3}) + assert.Equals(t, az.Wildcard, false) + return nil + }, + MockCreateOrder: func(ctx context.Context, o *acme.Order) error { + o.ID = "ordID" + assert.Equals(t, o.AccountID, "accID") + assert.Equals(t, o.ProvisionerID, prov.GetID()) + assert.Equals(t, o.Status, acme.StatusPending) + assert.Equals(t, o.Identifiers, nor.Identifiers) + assert.Equals(t, o.AuthorizationIDs, []string{*az1ID}) + return nil + }, + }, + vr: func(t *testing.T, o *acme.Order) { + testBufferDur := 5 * time.Second + orderExpiry := now.Add(defaultOrderExpiry) + + assert.Equals(t, o.ID, "ordID") + assert.Equals(t, o.Status, acme.StatusPending) + assert.Equals(t, o.Identifiers, nor.Identifiers) + assert.Equals(t, o.AuthorizationURLs, []string{"https://test.ca.smallstep.com/acme/test@acme-provisioner.com/authz/az1ID"}) + assert.True(t, o.NotBefore.Add(-testBufferDur).Before(expNbf)) + assert.True(t, o.NotBefore.Add(testBufferDur).After(expNbf)) + assert.True(t, o.NotAfter.Add(-testBufferDur).Before(expNaf)) + assert.True(t, o.NotAfter.Add(testBufferDur).After(expNaf)) + assert.True(t, o.ExpiresAt.Add(-testBufferDur).Before(orderExpiry)) + assert.True(t, o.ExpiresAt.Add(testBufferDur).After(orderExpiry)) + }, } }, } @@ -871,22 +1278,10 @@ func TestHandler_NewOrder(t *testing.T) { assert.Equals(t, res.Header["Content-Type"], []string{"application/problem+json"}) } else { ro := new(acme.Order) - err = json.Unmarshal(body, ro) - - now := clock.Now() - orderExpiry := now.Add(defaultOrderExpiry) - certExpiry := now.Add(prov.DefaultTLSCertDuration()) - - assert.Equals(t, ro.ID, "ordID") - assert.Equals(t, ro.Status, acme.StatusPending) - assert.Equals(t, ro.Identifiers, tc.nor.Identifiers) - assert.Equals(t, ro.AuthorizationURLs, []string{"https://test.ca.smallstep.com/acme/test@acme-provisioner.com/authz/az1ID"}) - assert.True(t, ro.NotBefore.Add(-time.Minute).Before(now)) - assert.True(t, ro.NotBefore.Add(time.Minute).After(now)) - assert.True(t, ro.NotAfter.Add(-time.Minute).Before(certExpiry)) - assert.True(t, ro.NotAfter.Add(time.Minute).After(certExpiry)) - assert.True(t, ro.ExpiresAt.Add(-time.Minute).Before(orderExpiry)) - assert.True(t, ro.ExpiresAt.Add(time.Minute).After(orderExpiry)) + assert.FatalError(t, json.Unmarshal(body, ro)) + if tc.vr != nil { + tc.vr(t, ro) + } assert.Equals(t, res.Header["Location"], []string{url}) assert.Equals(t, res.Header["Content-Type"], []string{"application/json"}) diff --git a/acme/order.go b/acme/order.go index fdc250ea..a6112362 100644 --- a/acme/order.go +++ b/acme/order.go @@ -20,22 +20,20 @@ type Identifier struct { // Order contains order metadata for the ACME protocol order type. type Order struct { - ID string `json:"id"` - Status Status `json:"status"` - ExpiresAt time.Time `json:"expires,omitempty"` - Identifiers []Identifier `json:"identifiers"` - NotBefore time.Time `json:"notBefore,omitempty"` - NotAfter time.Time `json:"notAfter,omitempty"` - Error *Error `json:"error,omitempty"` - AuthorizationIDs []string `json:"-"` - AuthorizationURLs []string `json:"authorizations"` - FinalizeURL string `json:"finalize"` - CertificateID string `json:"-"` - CertificateURL string `json:"certificate,omitempty"` - AccountID string `json:"-"` - ProvisionerID string `json:"-"` - DefaultDuration time.Duration `json:"-"` - Backdate time.Duration `json:"-"` + ID string `json:"id"` + Status Status `json:"status"` + ExpiresAt time.Time `json:"expires,omitempty"` + Identifiers []Identifier `json:"identifiers"` + NotBefore time.Time `json:"notBefore,omitempty"` + NotAfter time.Time `json:"notAfter,omitempty"` + Error *Error `json:"error,omitempty"` + AuthorizationIDs []string `json:"-"` + AuthorizationURLs []string `json:"authorizations"` + FinalizeURL string `json:"finalize"` + CertificateID string `json:"-"` + CertificateURL string `json:"certificate,omitempty"` + AccountID string `json:"-"` + ProvisionerID string `json:"-"` } // ToLog enables response logging.