forked from TrueCloudLab/certificates
[acme db interface] nosql authz unit tests
This commit is contained in:
parent
206909b12e
commit
f72b2ff2c2
9 changed files with 667 additions and 34 deletions
|
@ -121,9 +121,9 @@ func TestHandler_GetAuthorization(t *testing.T) {
|
|||
Type: "dns",
|
||||
Value: "example.com",
|
||||
},
|
||||
Status: "pending",
|
||||
Expires: expiry,
|
||||
Wildcard: false,
|
||||
Status: "pending",
|
||||
ExpiresAt: expiry,
|
||||
Wildcard: false,
|
||||
Challenges: []*acme.Challenge{
|
||||
{
|
||||
Type: "http-01",
|
||||
|
@ -220,7 +220,7 @@ func TestHandler_GetAuthorization(t *testing.T) {
|
|||
return &acme.Authorization{
|
||||
AccountID: "accID",
|
||||
Status: acme.StatusPending,
|
||||
Expires: time.Now().Add(-1 * time.Hour),
|
||||
ExpiresAt: time.Now().Add(-1 * time.Hour),
|
||||
}, nil
|
||||
},
|
||||
MockUpdateAuthorization: func(ctx context.Context, az *acme.Authorization) error {
|
||||
|
|
|
@ -89,14 +89,24 @@ func (h *Handler) NewOrder(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
now := clock.Now()
|
||||
expiry := now.Add(defaultOrderExpiry)
|
||||
// New order.
|
||||
o := &acme.Order{Identifiers: nor.Identifiers}
|
||||
o := &acme.Order{
|
||||
AccountID: acc.ID,
|
||||
ProvisionerID: prov.GetID(),
|
||||
Status: acme.StatusPending,
|
||||
ExpiresAt: expiry,
|
||||
Identifiers: nor.Identifiers,
|
||||
}
|
||||
|
||||
o.AuthorizationIDs = make([]string, len(o.Identifiers))
|
||||
for i, identifier := range o.Identifiers {
|
||||
az := &acme.Authorization{
|
||||
AccountID: acc.ID,
|
||||
Identifier: identifier,
|
||||
ExpiresAt: expiry,
|
||||
Status: acme.StatusPending,
|
||||
}
|
||||
if err := h.newAuthorization(ctx, az); err != nil {
|
||||
api.WriteError(w, err)
|
||||
|
@ -105,14 +115,12 @@ func (h *Handler) NewOrder(w http.ResponseWriter, r *http.Request) {
|
|||
o.AuthorizationIDs[i] = az.ID
|
||||
}
|
||||
|
||||
now := clock.Now()
|
||||
if o.NotBefore.IsZero() {
|
||||
o.NotBefore = now
|
||||
}
|
||||
if o.NotAfter.IsZero() {
|
||||
o.NotAfter = o.NotBefore.Add(prov.DefaultTLSCertDuration())
|
||||
}
|
||||
o.Expires = now.Add(defaultOrderExpiry)
|
||||
|
||||
if err := h.db.CreateOrder(ctx, o); err != nil {
|
||||
api.WriteError(w, acme.WrapErrorISE(err, "error creating order"))
|
||||
|
@ -156,6 +164,7 @@ func (h *Handler) newAuthorization(ctx context.Context, az *acme.Authorization)
|
|||
Value: az.Identifier.Value,
|
||||
Type: typ,
|
||||
Token: az.Token,
|
||||
Status: acme.StatusPending,
|
||||
}
|
||||
if err := h.db.CreateChallenge(ctx, ch); err != nil {
|
||||
return err
|
||||
|
|
|
@ -166,9 +166,9 @@ func TestHandler_GetOrder(t *testing.T) {
|
|||
Value: "*.smallstep.com",
|
||||
},
|
||||
},
|
||||
Expires: expiry,
|
||||
Status: acme.StatusInvalid,
|
||||
Error: acme.NewError(acme.ErrorMalformedType, "order has expired"),
|
||||
ExpiresAt: expiry,
|
||||
Status: acme.StatusInvalid,
|
||||
Error: acme.NewError(acme.ErrorMalformedType, "order has expired"),
|
||||
AuthorizationURLs: []string{
|
||||
"https://test.ca.smallstep.com/acme/test@acme-provisioner.com/authz/foo",
|
||||
"https://test.ca.smallstep.com/acme/test@acme-provisioner.com/authz/bar",
|
||||
|
@ -285,7 +285,7 @@ func TestHandler_GetOrder(t *testing.T) {
|
|||
return &acme.Order{
|
||||
AccountID: "accountID",
|
||||
ProvisionerID: "acme/test@acme-provisioner.com",
|
||||
Expires: clock.Now().Add(-time.Hour),
|
||||
ExpiresAt: clock.Now().Add(-time.Hour),
|
||||
Status: acme.StatusReady,
|
||||
}, nil
|
||||
},
|
||||
|
@ -311,7 +311,7 @@ func TestHandler_GetOrder(t *testing.T) {
|
|||
ID: "orderID",
|
||||
AccountID: "accountID",
|
||||
ProvisionerID: "acme/test@acme-provisioner.com",
|
||||
Expires: expiry,
|
||||
ExpiresAt: expiry,
|
||||
Status: acme.StatusReady,
|
||||
AuthorizationIDs: []string{"foo", "bar", "baz"},
|
||||
NotBefore: nbf,
|
||||
|
@ -380,7 +380,7 @@ func TestHandler_NewOrder(t *testing.T) {
|
|||
naf := nbf.Add(17 * time.Hour)
|
||||
o := acme.Order{
|
||||
ID: "orderID",
|
||||
Expires: expiry,
|
||||
ExpiresAt: expiry,
|
||||
NotBefore: nbf,
|
||||
NotAfter: naf,
|
||||
Identifiers: []acme.Identifier{
|
||||
|
@ -607,8 +607,8 @@ func TestHandler_FinalizeOrder(t *testing.T) {
|
|||
Value: "*.smallstep.com",
|
||||
},
|
||||
},
|
||||
Expires: naf,
|
||||
Status: acme.StatusValid,
|
||||
ExpiresAt: naf,
|
||||
Status: acme.StatusValid,
|
||||
AuthorizationURLs: []string{
|
||||
"https://test.ca.smallstep.com/acme/test@acme-provisioner.com/authz/foo",
|
||||
"https://test.ca.smallstep.com/acme/test@acme-provisioner.com/authz/bar",
|
||||
|
@ -788,7 +788,7 @@ func TestHandler_FinalizeOrder(t *testing.T) {
|
|||
return &acme.Order{
|
||||
AccountID: "accountID",
|
||||
ProvisionerID: "acme/test@acme-provisioner.com",
|
||||
Expires: clock.Now().Add(-time.Hour),
|
||||
ExpiresAt: clock.Now().Add(-time.Hour),
|
||||
Status: acme.StatusReady,
|
||||
}, nil
|
||||
},
|
||||
|
@ -815,7 +815,7 @@ func TestHandler_FinalizeOrder(t *testing.T) {
|
|||
ID: "orderID",
|
||||
AccountID: "accountID",
|
||||
ProvisionerID: "acme/test@acme-provisioner.com",
|
||||
Expires: naf,
|
||||
ExpiresAt: naf,
|
||||
Status: acme.StatusValid,
|
||||
AuthorizationIDs: []string{"foo", "bar", "baz"},
|
||||
NotBefore: nbf,
|
||||
|
|
|
@ -13,6 +13,7 @@ type Authorization struct {
|
|||
ExpiresAt time.Time `json:"expires"`
|
||||
Challenges []*Challenge `json:"challenges"`
|
||||
Wildcard bool `json:"wildcard"`
|
||||
Error *Error `json:"error,omitempty"`
|
||||
ID string `json:"-"`
|
||||
AccountID string `json:"-"`
|
||||
Token string `json:"-"`
|
||||
|
|
|
@ -23,6 +23,7 @@ type dbAuthz struct {
|
|||
Wildcard bool `json:"wildcard"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Error *acme.Error `json:"error"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func (ba *dbAuthz) clone() *dbAuthz {
|
||||
|
@ -35,14 +36,14 @@ func (ba *dbAuthz) clone() *dbAuthz {
|
|||
func (db *DB) getDBAuthz(ctx context.Context, id string) (*dbAuthz, error) {
|
||||
data, err := db.db.Get(authzTable, []byte(id))
|
||||
if nosql.IsErrNotFound(err) {
|
||||
return nil, errors.Wrapf(err, "authz %s not found", id)
|
||||
return nil, acme.NewError(acme.ErrorMalformedType, "authz %s not found", id)
|
||||
} else if err != nil {
|
||||
return nil, errors.Wrapf(err, "error loading authz %s", id)
|
||||
}
|
||||
|
||||
var dbaz dbAuthz
|
||||
if err = json.Unmarshal(data, &dbaz); err != nil {
|
||||
return nil, errors.Wrap(err, "error unmarshaling authz type into dbAuthz")
|
||||
return nil, errors.Wrapf(err, "error unmarshaling authz %s into dbAuthz", id)
|
||||
}
|
||||
return &dbaz, nil
|
||||
}
|
||||
|
@ -62,12 +63,15 @@ func (db *DB) GetAuthorization(ctx context.Context, id string) (*acme.Authorizat
|
|||
}
|
||||
}
|
||||
return &acme.Authorization{
|
||||
ID: dbaz.ID,
|
||||
AccountID: dbaz.AccountID,
|
||||
Identifier: dbaz.Identifier,
|
||||
Status: dbaz.Status,
|
||||
Challenges: chs,
|
||||
Wildcard: dbaz.Wildcard,
|
||||
ExpiresAt: dbaz.ExpiresAt,
|
||||
ID: dbaz.ID,
|
||||
Token: dbaz.Token,
|
||||
Error: dbaz.Error,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -89,11 +93,12 @@ func (db *DB) CreateAuthorization(ctx context.Context, az *acme.Authorization) e
|
|||
dbaz := &dbAuthz{
|
||||
ID: az.ID,
|
||||
AccountID: az.AccountID,
|
||||
Status: acme.StatusPending,
|
||||
Status: az.Status,
|
||||
CreatedAt: now,
|
||||
ExpiresAt: now.Add(defaultExpiryDuration),
|
||||
ExpiresAt: az.ExpiresAt,
|
||||
Identifier: az.Identifier,
|
||||
Challenges: chIDs,
|
||||
Token: az.Token,
|
||||
Wildcard: az.Wildcard,
|
||||
}
|
||||
|
||||
|
@ -102,9 +107,6 @@ func (db *DB) CreateAuthorization(ctx context.Context, az *acme.Authorization) e
|
|||
|
||||
// UpdateAuthorization saves an updated ACME Authorization to the database.
|
||||
func (db *DB) UpdateAuthorization(ctx context.Context, az *acme.Authorization) error {
|
||||
if len(az.ID) == 0 {
|
||||
return errors.New("id cannot be empty")
|
||||
}
|
||||
old, err := db.getDBAuthz(ctx, az.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -113,5 +115,6 @@ func (db *DB) UpdateAuthorization(ctx context.Context, az *acme.Authorization) e
|
|||
nu := old.clone()
|
||||
|
||||
nu.Status = az.Status
|
||||
nu.Error = az.Error
|
||||
return db.save(ctx, old.ID, nu, old, "authz", authzTable)
|
||||
}
|
||||
|
|
620
acme/db/nosql/authz_test.go
Normal file
620
acme/db/nosql/authz_test.go
Normal file
|
@ -0,0 +1,620 @@
|
|||
package nosql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/smallstep/assert"
|
||||
"github.com/smallstep/certificates/acme"
|
||||
"github.com/smallstep/certificates/db"
|
||||
"github.com/smallstep/nosql"
|
||||
nosqldb "github.com/smallstep/nosql/database"
|
||||
)
|
||||
|
||||
func TestDB_getDBAuthz(t *testing.T) {
|
||||
azID := "azID"
|
||||
type test struct {
|
||||
db nosql.DB
|
||||
err error
|
||||
acmeErr *acme.Error
|
||||
dbaz *dbAuthz
|
||||
}
|
||||
var tests = map[string]func(t *testing.T) test{
|
||||
"fail/not-found": func(t *testing.T) test {
|
||||
return test{
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, string(key), azID)
|
||||
|
||||
return nil, nosqldb.ErrNotFound
|
||||
},
|
||||
},
|
||||
acmeErr: acme.NewError(acme.ErrorMalformedType, "authz azID not found"),
|
||||
}
|
||||
},
|
||||
"fail/db.Get-error": func(t *testing.T) test {
|
||||
return test{
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, string(key), azID)
|
||||
|
||||
return nil, errors.New("force")
|
||||
},
|
||||
},
|
||||
err: errors.New("error loading authz azID: force"),
|
||||
}
|
||||
},
|
||||
"fail/unmarshal-error": func(t *testing.T) test {
|
||||
return test{
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, string(key), azID)
|
||||
|
||||
return []byte("foo"), nil
|
||||
},
|
||||
},
|
||||
err: errors.New("error unmarshaling authz azID into dbAuthz"),
|
||||
}
|
||||
},
|
||||
"ok": func(t *testing.T) test {
|
||||
now := clock.Now()
|
||||
dbaz := &dbAuthz{
|
||||
ID: azID,
|
||||
AccountID: "accountID",
|
||||
Identifier: acme.Identifier{
|
||||
Type: "dns",
|
||||
Value: "test.ca.smallstep.com",
|
||||
},
|
||||
Status: acme.StatusPending,
|
||||
Token: "token",
|
||||
CreatedAt: now,
|
||||
ExpiresAt: now.Add(5 * time.Minute),
|
||||
Error: acme.NewErrorISE("force"),
|
||||
Challenges: []string{"foo", "bar"},
|
||||
Wildcard: true,
|
||||
}
|
||||
b, err := json.Marshal(dbaz)
|
||||
assert.FatalError(t, err)
|
||||
return test{
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, string(key), azID)
|
||||
|
||||
return b, nil
|
||||
},
|
||||
},
|
||||
dbaz: dbaz,
|
||||
}
|
||||
},
|
||||
}
|
||||
for name, run := range tests {
|
||||
tc := run(t)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
db := DB{db: tc.db}
|
||||
if dbaz, err := db.getDBAuthz(context.Background(), azID); err != nil {
|
||||
switch k := err.(type) {
|
||||
case *acme.Error:
|
||||
if assert.NotNil(t, tc.acmeErr) {
|
||||
assert.Equals(t, k.Type, tc.acmeErr.Type)
|
||||
assert.Equals(t, k.Detail, tc.acmeErr.Detail)
|
||||
assert.Equals(t, k.Status, tc.acmeErr.Status)
|
||||
assert.Equals(t, k.Err.Error(), tc.acmeErr.Err.Error())
|
||||
assert.Equals(t, k.Detail, tc.acmeErr.Detail)
|
||||
}
|
||||
default:
|
||||
if assert.NotNil(t, tc.err) {
|
||||
assert.HasPrefix(t, err.Error(), tc.err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if assert.Nil(t, tc.err) {
|
||||
assert.Equals(t, dbaz.ID, tc.dbaz.ID)
|
||||
assert.Equals(t, dbaz.AccountID, tc.dbaz.AccountID)
|
||||
assert.Equals(t, dbaz.Identifier, tc.dbaz.Identifier)
|
||||
assert.Equals(t, dbaz.Status, tc.dbaz.Status)
|
||||
assert.Equals(t, dbaz.Token, tc.dbaz.Token)
|
||||
assert.Equals(t, dbaz.CreatedAt, tc.dbaz.CreatedAt)
|
||||
assert.Equals(t, dbaz.ExpiresAt, tc.dbaz.ExpiresAt)
|
||||
assert.Equals(t, dbaz.Error.Error(), tc.dbaz.Error.Error())
|
||||
assert.Equals(t, dbaz.Wildcard, tc.dbaz.Wildcard)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDB_GetAuthorization(t *testing.T) {
|
||||
azID := "azID"
|
||||
type test struct {
|
||||
db nosql.DB
|
||||
err error
|
||||
acmeErr *acme.Error
|
||||
dbaz *dbAuthz
|
||||
}
|
||||
var tests = map[string]func(t *testing.T) test{
|
||||
"fail/db.Get-error": func(t *testing.T) test {
|
||||
return test{
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, string(key), azID)
|
||||
|
||||
return nil, errors.New("force")
|
||||
},
|
||||
},
|
||||
err: errors.New("error loading authz azID: force"),
|
||||
}
|
||||
},
|
||||
"fail/forward-acme-error": func(t *testing.T) test {
|
||||
return test{
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, string(key), azID)
|
||||
|
||||
return nil, nosqldb.ErrNotFound
|
||||
},
|
||||
},
|
||||
acmeErr: acme.NewError(acme.ErrorMalformedType, "authz azID not found"),
|
||||
}
|
||||
},
|
||||
"fail/db.GetChallenge-error": func(t *testing.T) test {
|
||||
now := clock.Now()
|
||||
dbaz := &dbAuthz{
|
||||
ID: azID,
|
||||
AccountID: "accountID",
|
||||
Identifier: acme.Identifier{
|
||||
Type: "dns",
|
||||
Value: "test.ca.smallstep.com",
|
||||
},
|
||||
Status: acme.StatusPending,
|
||||
Token: "token",
|
||||
CreatedAt: now,
|
||||
ExpiresAt: now.Add(5 * time.Minute),
|
||||
Error: acme.NewErrorISE("force"),
|
||||
Challenges: []string{"foo", "bar"},
|
||||
Wildcard: true,
|
||||
}
|
||||
b, err := json.Marshal(dbaz)
|
||||
assert.FatalError(t, err)
|
||||
return test{
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
switch string(bucket) {
|
||||
case string(authzTable):
|
||||
assert.Equals(t, string(key), azID)
|
||||
return b, nil
|
||||
case string(challengeTable):
|
||||
assert.Equals(t, string(key), "foo")
|
||||
return nil, errors.New("force")
|
||||
default:
|
||||
assert.FatalError(t, errors.Errorf("unexpected bucket '%s'", string(bucket)))
|
||||
return nil, errors.New("force")
|
||||
}
|
||||
},
|
||||
},
|
||||
err: errors.New("error loading acme challenge foo: force"),
|
||||
}
|
||||
},
|
||||
"fail/db.GetChallenge-not-found": func(t *testing.T) test {
|
||||
now := clock.Now()
|
||||
dbaz := &dbAuthz{
|
||||
ID: azID,
|
||||
AccountID: "accountID",
|
||||
Identifier: acme.Identifier{
|
||||
Type: "dns",
|
||||
Value: "test.ca.smallstep.com",
|
||||
},
|
||||
Status: acme.StatusPending,
|
||||
Token: "token",
|
||||
CreatedAt: now,
|
||||
ExpiresAt: now.Add(5 * time.Minute),
|
||||
Error: acme.NewErrorISE("force"),
|
||||
Challenges: []string{"foo", "bar"},
|
||||
Wildcard: true,
|
||||
}
|
||||
b, err := json.Marshal(dbaz)
|
||||
assert.FatalError(t, err)
|
||||
return test{
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
switch string(bucket) {
|
||||
case string(authzTable):
|
||||
assert.Equals(t, string(key), azID)
|
||||
return b, nil
|
||||
case string(challengeTable):
|
||||
assert.Equals(t, string(key), "foo")
|
||||
return nil, nosqldb.ErrNotFound
|
||||
default:
|
||||
assert.FatalError(t, errors.Errorf("unexpected bucket '%s'", string(bucket)))
|
||||
return nil, errors.New("force")
|
||||
}
|
||||
},
|
||||
},
|
||||
acmeErr: acme.NewError(acme.ErrorMalformedType, "challenge foo not found"),
|
||||
}
|
||||
},
|
||||
"ok": func(t *testing.T) test {
|
||||
now := clock.Now()
|
||||
dbaz := &dbAuthz{
|
||||
ID: azID,
|
||||
AccountID: "accountID",
|
||||
Identifier: acme.Identifier{
|
||||
Type: "dns",
|
||||
Value: "test.ca.smallstep.com",
|
||||
},
|
||||
Status: acme.StatusPending,
|
||||
Token: "token",
|
||||
CreatedAt: now,
|
||||
ExpiresAt: now.Add(5 * time.Minute),
|
||||
Error: acme.NewErrorISE("force"),
|
||||
Challenges: []string{"foo", "bar"},
|
||||
Wildcard: true,
|
||||
}
|
||||
b, err := json.Marshal(dbaz)
|
||||
assert.FatalError(t, err)
|
||||
chCount := 0
|
||||
fooChb, err := json.Marshal(&dbChallenge{ID: "foo"})
|
||||
assert.FatalError(t, err)
|
||||
barChb, err := json.Marshal(&dbChallenge{ID: "bar"})
|
||||
assert.FatalError(t, err)
|
||||
return test{
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
switch string(bucket) {
|
||||
case string(authzTable):
|
||||
assert.Equals(t, string(key), azID)
|
||||
return b, nil
|
||||
case string(challengeTable):
|
||||
if chCount == 0 {
|
||||
chCount++
|
||||
assert.Equals(t, string(key), "foo")
|
||||
return fooChb, nil
|
||||
}
|
||||
assert.Equals(t, string(key), "bar")
|
||||
return barChb, nil
|
||||
default:
|
||||
assert.FatalError(t, errors.Errorf("unexpected bucket '%s'", string(bucket)))
|
||||
return nil, errors.New("force")
|
||||
}
|
||||
},
|
||||
},
|
||||
dbaz: dbaz,
|
||||
}
|
||||
},
|
||||
}
|
||||
for name, run := range tests {
|
||||
tc := run(t)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
db := DB{db: tc.db}
|
||||
if az, err := db.GetAuthorization(context.Background(), azID); err != nil {
|
||||
switch k := err.(type) {
|
||||
case *acme.Error:
|
||||
if assert.NotNil(t, tc.acmeErr) {
|
||||
assert.Equals(t, k.Type, tc.acmeErr.Type)
|
||||
assert.Equals(t, k.Detail, tc.acmeErr.Detail)
|
||||
assert.Equals(t, k.Status, tc.acmeErr.Status)
|
||||
assert.Equals(t, k.Err.Error(), tc.acmeErr.Err.Error())
|
||||
assert.Equals(t, k.Detail, tc.acmeErr.Detail)
|
||||
}
|
||||
default:
|
||||
if assert.NotNil(t, tc.err) {
|
||||
assert.HasPrefix(t, err.Error(), tc.err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if assert.Nil(t, tc.err) {
|
||||
assert.Equals(t, az.ID, tc.dbaz.ID)
|
||||
assert.Equals(t, az.AccountID, tc.dbaz.AccountID)
|
||||
assert.Equals(t, az.Identifier, tc.dbaz.Identifier)
|
||||
assert.Equals(t, az.Status, tc.dbaz.Status)
|
||||
assert.Equals(t, az.Token, tc.dbaz.Token)
|
||||
assert.Equals(t, az.Wildcard, tc.dbaz.Wildcard)
|
||||
assert.Equals(t, az.ExpiresAt, tc.dbaz.ExpiresAt)
|
||||
assert.Equals(t, az.Challenges, []*acme.Challenge{
|
||||
{ID: "foo"},
|
||||
{ID: "bar"},
|
||||
})
|
||||
assert.Equals(t, az.Error.Error(), tc.dbaz.Error.Error())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDB_CreateAuthorization(t *testing.T) {
|
||||
azID := "azID"
|
||||
type test struct {
|
||||
db nosql.DB
|
||||
az *acme.Authorization
|
||||
err error
|
||||
_id *string
|
||||
}
|
||||
var tests = map[string]func(t *testing.T) test{
|
||||
"fail/cmpAndSwap-error": func(t *testing.T) test {
|
||||
now := clock.Now()
|
||||
az := &acme.Authorization{
|
||||
ID: azID,
|
||||
AccountID: "accountID",
|
||||
Identifier: acme.Identifier{
|
||||
Type: "dns",
|
||||
Value: "test.ca.smallstep.com",
|
||||
},
|
||||
Status: acme.StatusPending,
|
||||
Token: "token",
|
||||
ExpiresAt: now.Add(5 * time.Minute),
|
||||
Challenges: []*acme.Challenge{
|
||||
{ID: "foo"},
|
||||
{ID: "bar"},
|
||||
},
|
||||
Wildcard: true,
|
||||
Error: acme.NewErrorISE("force"),
|
||||
}
|
||||
return test{
|
||||
db: &db.MockNoSQLDB{
|
||||
MCmpAndSwap: func(bucket, key, old, nu []byte) ([]byte, bool, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, string(key), az.ID)
|
||||
assert.Equals(t, old, nil)
|
||||
|
||||
dbaz := new(dbAuthz)
|
||||
assert.FatalError(t, json.Unmarshal(nu, dbaz))
|
||||
assert.Equals(t, dbaz.ID, string(key))
|
||||
assert.Equals(t, dbaz.AccountID, az.AccountID)
|
||||
assert.Equals(t, dbaz.Identifier, acme.Identifier{
|
||||
Type: "dns",
|
||||
Value: "test.ca.smallstep.com",
|
||||
})
|
||||
assert.Equals(t, dbaz.Status, az.Status)
|
||||
assert.Equals(t, dbaz.Token, az.Token)
|
||||
assert.Equals(t, dbaz.Challenges, []string{"foo", "bar"})
|
||||
assert.Equals(t, dbaz.Wildcard, az.Wildcard)
|
||||
assert.Equals(t, dbaz.ExpiresAt, az.ExpiresAt)
|
||||
assert.Nil(t, dbaz.Error)
|
||||
assert.True(t, clock.Now().Add(-time.Minute).Before(dbaz.CreatedAt))
|
||||
assert.True(t, clock.Now().Add(time.Minute).After(dbaz.CreatedAt))
|
||||
return nil, false, errors.New("force")
|
||||
},
|
||||
},
|
||||
az: az,
|
||||
err: errors.New("error saving acme authz: force"),
|
||||
}
|
||||
},
|
||||
"ok": func(t *testing.T) test {
|
||||
var (
|
||||
id string
|
||||
idPtr = &id
|
||||
now = clock.Now()
|
||||
az = &acme.Authorization{
|
||||
ID: azID,
|
||||
AccountID: "accountID",
|
||||
Identifier: acme.Identifier{
|
||||
Type: "dns",
|
||||
Value: "test.ca.smallstep.com",
|
||||
},
|
||||
Status: acme.StatusPending,
|
||||
Token: "token",
|
||||
ExpiresAt: now.Add(5 * time.Minute),
|
||||
Challenges: []*acme.Challenge{
|
||||
{ID: "foo"},
|
||||
{ID: "bar"},
|
||||
},
|
||||
Wildcard: true,
|
||||
Error: acme.NewErrorISE("force"),
|
||||
}
|
||||
)
|
||||
return test{
|
||||
db: &db.MockNoSQLDB{
|
||||
MCmpAndSwap: func(bucket, key, old, nu []byte) ([]byte, bool, error) {
|
||||
*idPtr = string(key)
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, string(key), az.ID)
|
||||
assert.Equals(t, old, nil)
|
||||
|
||||
dbaz := new(dbAuthz)
|
||||
assert.FatalError(t, json.Unmarshal(nu, dbaz))
|
||||
assert.Equals(t, dbaz.ID, string(key))
|
||||
assert.Equals(t, dbaz.AccountID, az.AccountID)
|
||||
assert.Equals(t, dbaz.Identifier, acme.Identifier{
|
||||
Type: "dns",
|
||||
Value: "test.ca.smallstep.com",
|
||||
})
|
||||
assert.Equals(t, dbaz.Status, az.Status)
|
||||
assert.Equals(t, dbaz.Token, az.Token)
|
||||
assert.Equals(t, dbaz.Challenges, []string{"foo", "bar"})
|
||||
assert.Equals(t, dbaz.Wildcard, az.Wildcard)
|
||||
assert.Equals(t, dbaz.ExpiresAt, az.ExpiresAt)
|
||||
assert.Nil(t, dbaz.Error)
|
||||
assert.True(t, clock.Now().Add(-time.Minute).Before(dbaz.CreatedAt))
|
||||
assert.True(t, clock.Now().Add(time.Minute).After(dbaz.CreatedAt))
|
||||
return nu, true, nil
|
||||
},
|
||||
},
|
||||
az: az,
|
||||
_id: idPtr,
|
||||
}
|
||||
},
|
||||
}
|
||||
for name, run := range tests {
|
||||
tc := run(t)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
db := DB{db: tc.db}
|
||||
if err := db.CreateAuthorization(context.Background(), tc.az); err != nil {
|
||||
if assert.NotNil(t, tc.err) {
|
||||
assert.HasPrefix(t, err.Error(), tc.err.Error())
|
||||
}
|
||||
} else {
|
||||
if assert.Nil(t, tc.err) {
|
||||
assert.Equals(t, tc.az.ID, *tc._id)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDB_UpdateAuthorization(t *testing.T) {
|
||||
azID := "azID"
|
||||
now := clock.Now()
|
||||
dbaz := &dbAuthz{
|
||||
ID: azID,
|
||||
AccountID: "accountID",
|
||||
Identifier: acme.Identifier{
|
||||
Type: "dns",
|
||||
Value: "test.ca.smallstep.com",
|
||||
},
|
||||
Status: acme.StatusPending,
|
||||
Token: "token",
|
||||
CreatedAt: now,
|
||||
ExpiresAt: now.Add(5 * time.Minute),
|
||||
Challenges: []string{"foo", "bar"},
|
||||
Wildcard: true,
|
||||
}
|
||||
b, err := json.Marshal(dbaz)
|
||||
assert.FatalError(t, err)
|
||||
type test struct {
|
||||
db nosql.DB
|
||||
az *acme.Authorization
|
||||
err error
|
||||
}
|
||||
var tests = map[string]func(t *testing.T) test{
|
||||
"fail/db.Get-error": func(t *testing.T) test {
|
||||
return test{
|
||||
az: &acme.Authorization{
|
||||
ID: azID,
|
||||
},
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, string(key), azID)
|
||||
|
||||
return nil, errors.New("force")
|
||||
},
|
||||
},
|
||||
err: errors.New("error loading authz azID: force"),
|
||||
}
|
||||
},
|
||||
"fail/db.CmpAndSwap-error": func(t *testing.T) test {
|
||||
updAz := &acme.Authorization{
|
||||
ID: azID,
|
||||
Status: acme.StatusValid,
|
||||
Error: acme.NewError(acme.ErrorMalformedType, "malformed"),
|
||||
}
|
||||
return test{
|
||||
az: updAz,
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, string(key), azID)
|
||||
|
||||
return b, nil
|
||||
},
|
||||
MCmpAndSwap: func(bucket, key, old, nu []byte) ([]byte, bool, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, old, b)
|
||||
|
||||
dbOld := new(dbAuthz)
|
||||
assert.FatalError(t, json.Unmarshal(old, dbOld))
|
||||
assert.Equals(t, dbaz, dbOld)
|
||||
|
||||
dbNew := new(dbAuthz)
|
||||
assert.FatalError(t, json.Unmarshal(nu, dbNew))
|
||||
assert.Equals(t, dbNew.ID, dbaz.ID)
|
||||
assert.Equals(t, dbNew.AccountID, dbaz.AccountID)
|
||||
assert.Equals(t, dbNew.Identifier, dbaz.Identifier)
|
||||
assert.Equals(t, dbNew.Status, acme.StatusValid)
|
||||
assert.Equals(t, dbNew.Token, dbaz.Token)
|
||||
assert.Equals(t, dbNew.Challenges, dbaz.Challenges)
|
||||
assert.Equals(t, dbNew.Wildcard, dbaz.Wildcard)
|
||||
assert.Equals(t, dbNew.CreatedAt, dbaz.CreatedAt)
|
||||
assert.Equals(t, dbNew.ExpiresAt, dbaz.ExpiresAt)
|
||||
assert.Equals(t, dbNew.Error.Error(), acme.NewError(acme.ErrorMalformedType, "malformed").Error())
|
||||
return nil, false, errors.New("force")
|
||||
},
|
||||
},
|
||||
err: errors.New("error saving acme authz: force"),
|
||||
}
|
||||
},
|
||||
"ok": func(t *testing.T) test {
|
||||
updAz := &acme.Authorization{
|
||||
ID: azID,
|
||||
AccountID: dbaz.AccountID,
|
||||
Status: acme.StatusValid,
|
||||
Identifier: dbaz.Identifier,
|
||||
Challenges: []*acme.Challenge{
|
||||
{ID: "foo"},
|
||||
{ID: "bar"},
|
||||
},
|
||||
Token: dbaz.Token,
|
||||
Wildcard: dbaz.Wildcard,
|
||||
ExpiresAt: dbaz.ExpiresAt,
|
||||
Error: acme.NewError(acme.ErrorMalformedType, "malformed"),
|
||||
}
|
||||
return test{
|
||||
az: updAz,
|
||||
db: &db.MockNoSQLDB{
|
||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, string(key), azID)
|
||||
|
||||
return b, nil
|
||||
},
|
||||
MCmpAndSwap: func(bucket, key, old, nu []byte) ([]byte, bool, error) {
|
||||
assert.Equals(t, bucket, authzTable)
|
||||
assert.Equals(t, old, b)
|
||||
|
||||
dbOld := new(dbAuthz)
|
||||
assert.FatalError(t, json.Unmarshal(old, dbOld))
|
||||
assert.Equals(t, dbaz, dbOld)
|
||||
|
||||
dbNew := new(dbAuthz)
|
||||
assert.FatalError(t, json.Unmarshal(nu, dbNew))
|
||||
assert.Equals(t, dbNew.ID, dbaz.ID)
|
||||
assert.Equals(t, dbNew.AccountID, dbaz.AccountID)
|
||||
assert.Equals(t, dbNew.Identifier, dbaz.Identifier)
|
||||
assert.Equals(t, dbNew.Status, acme.StatusValid)
|
||||
assert.Equals(t, dbNew.Token, dbaz.Token)
|
||||
assert.Equals(t, dbNew.Challenges, dbaz.Challenges)
|
||||
assert.Equals(t, dbNew.Wildcard, dbaz.Wildcard)
|
||||
assert.Equals(t, dbNew.CreatedAt, dbaz.CreatedAt)
|
||||
assert.Equals(t, dbNew.ExpiresAt, dbaz.ExpiresAt)
|
||||
assert.Equals(t, dbNew.Error.Error(), acme.NewError(acme.ErrorMalformedType, "malformed").Error())
|
||||
return nu, true, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
for name, run := range tests {
|
||||
tc := run(t)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
db := DB{db: tc.db}
|
||||
if err := db.UpdateAuthorization(context.Background(), tc.az); err != nil {
|
||||
if assert.NotNil(t, tc.err) {
|
||||
assert.HasPrefix(t, err.Error(), tc.err.Error())
|
||||
}
|
||||
} else {
|
||||
if assert.Nil(t, tc.err) {
|
||||
assert.Equals(t, tc.az.ID, dbaz.ID)
|
||||
assert.Equals(t, tc.az.AccountID, dbaz.AccountID)
|
||||
assert.Equals(t, tc.az.Identifier, dbaz.Identifier)
|
||||
assert.Equals(t, tc.az.Status, acme.StatusValid)
|
||||
assert.Equals(t, tc.az.Wildcard, dbaz.Wildcard)
|
||||
assert.Equals(t, tc.az.Token, dbaz.Token)
|
||||
assert.Equals(t, tc.az.ExpiresAt, dbaz.ExpiresAt)
|
||||
assert.Equals(t, tc.az.Challenges, []*acme.Challenge{
|
||||
{ID: "foo"},
|
||||
{ID: "bar"},
|
||||
})
|
||||
assert.Equals(t, tc.az.Error.Error(), acme.NewError(acme.ErrorMalformedType, "malformed").Error())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -58,7 +58,7 @@ func (db *DB) GetOrder(ctx context.Context, id string) (*acme.Order, error) {
|
|||
|
||||
o := &acme.Order{
|
||||
Status: dbo.Status,
|
||||
Expires: dbo.Expires,
|
||||
ExpiresAt: dbo.Expires,
|
||||
Identifiers: dbo.Identifiers,
|
||||
NotBefore: dbo.NotBefore,
|
||||
NotAfter: dbo.NotAfter,
|
||||
|
@ -86,7 +86,7 @@ func (db *DB) CreateOrder(ctx context.Context, o *acme.Order) error {
|
|||
ProvisionerID: o.ProvisionerID,
|
||||
Created: now,
|
||||
Status: acme.StatusPending,
|
||||
Expires: o.Expires,
|
||||
Expires: o.ExpiresAt,
|
||||
Identifiers: o.Identifiers,
|
||||
NotBefore: o.NotBefore,
|
||||
NotAfter: o.NotBefore,
|
||||
|
|
|
@ -22,7 +22,7 @@ type Identifier struct {
|
|||
type Order struct {
|
||||
ID string `json:"id"`
|
||||
Status Status `json:"status"`
|
||||
Expires time.Time `json:"expires,omitempty"`
|
||||
ExpiresAt time.Time `json:"expires,omitempty"`
|
||||
Identifiers []Identifier `json:"identifiers"`
|
||||
NotBefore time.Time `json:"notBefore,omitempty"`
|
||||
NotAfter time.Time `json:"notAfter,omitempty"`
|
||||
|
@ -59,7 +59,7 @@ func (o *Order) UpdateStatus(ctx context.Context, db DB) error {
|
|||
return nil
|
||||
case StatusReady:
|
||||
// Check expiry
|
||||
if now.After(o.Expires) {
|
||||
if now.After(o.ExpiresAt) {
|
||||
o.Status = StatusInvalid
|
||||
o.Error = NewError(ErrorMalformedType, "order has expired")
|
||||
break
|
||||
|
@ -67,7 +67,7 @@ func (o *Order) UpdateStatus(ctx context.Context, db DB) error {
|
|||
return nil
|
||||
case StatusPending:
|
||||
// Check expiry
|
||||
if now.After(o.Expires) {
|
||||
if now.After(o.ExpiresAt) {
|
||||
o.Status = StatusInvalid
|
||||
o.Error = NewError(ErrorMalformedType, "order has expired")
|
||||
break
|
||||
|
|
|
@ -388,7 +388,7 @@ func TestACMEClient_NewOrder(t *testing.T) {
|
|||
assert.FatalError(t, err)
|
||||
ord := acme.Order{
|
||||
Status: "valid",
|
||||
Expires: time.Now(), // "soon"
|
||||
ExpiresAt: time.Now(), // "soon"
|
||||
FinalizeURL: "finalize-url",
|
||||
}
|
||||
ac := &ACMEClient{
|
||||
|
@ -510,7 +510,7 @@ func TestACMEClient_GetOrder(t *testing.T) {
|
|||
assert.FatalError(t, err)
|
||||
ord := acme.Order{
|
||||
Status: "valid",
|
||||
Expires: time.Now(), // "soon"
|
||||
ExpiresAt: time.Now(), // "soon"
|
||||
FinalizeURL: "finalize-url",
|
||||
}
|
||||
ac := &ACMEClient{
|
||||
|
@ -630,7 +630,7 @@ func TestACMEClient_GetAuthz(t *testing.T) {
|
|||
assert.FatalError(t, err)
|
||||
az := acme.Authorization{
|
||||
Status: "valid",
|
||||
Expires: time.Now(),
|
||||
ExpiresAt: time.Now(),
|
||||
Identifier: acme.Identifier{Type: "dns", Value: "example.com"},
|
||||
}
|
||||
ac := &ACMEClient{
|
||||
|
@ -988,7 +988,7 @@ func TestACMEClient_FinalizeOrder(t *testing.T) {
|
|||
assert.FatalError(t, err)
|
||||
ord := acme.Order{
|
||||
Status: "valid",
|
||||
Expires: time.Now(), // "soon"
|
||||
ExpiresAt: time.Now(), // "soon"
|
||||
FinalizeURL: "finalize-url",
|
||||
CertificateURL: "cert-url",
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue