forked from TrueCloudLab/certificates
Refactor ACME EAB queries
The ACME EAB keys are now also indexed by the provisioner. This solves part of the issue in which too many EAB keys may be in memory at a given time.
This commit is contained in:
parent
30859d3c83
commit
ef16febf40
10 changed files with 766 additions and 553 deletions
|
@ -46,7 +46,7 @@ func KeyToID(jwk *jose.JSONWebKey) (string, error) {
|
||||||
// ExternalAccountKey is an ACME External Account Binding key.
|
// ExternalAccountKey is an ACME External Account Binding key.
|
||||||
type ExternalAccountKey struct {
|
type ExternalAccountKey struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Provisioner string `json:"provisioner"`
|
ProvisionerID string `json:"provisionerID"`
|
||||||
Reference string `json:"reference"`
|
Reference string `json:"reference"`
|
||||||
AccountID string `json:"-"`
|
AccountID string `json:"-"`
|
||||||
KeyBytes []byte `json:"-"`
|
KeyBytes []byte `json:"-"`
|
||||||
|
|
|
@ -93,7 +93,7 @@ func TestExternalAccountKey_BindTo(t *testing.T) {
|
||||||
name: "ok",
|
name: "ok",
|
||||||
eak: &ExternalAccountKey{
|
eak: &ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: "prov",
|
ProvisionerID: "provID",
|
||||||
Reference: "ref",
|
Reference: "ref",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
},
|
},
|
||||||
|
@ -106,7 +106,7 @@ func TestExternalAccountKey_BindTo(t *testing.T) {
|
||||||
name: "fail/already-bound",
|
name: "fail/already-bound",
|
||||||
eak: &ExternalAccountKey{
|
eak: &ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: "prov",
|
ProvisionerID: "provID",
|
||||||
Reference: "ref",
|
Reference: "ref",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
AccountID: "someAccountID",
|
AccountID: "someAccountID",
|
||||||
|
|
|
@ -144,7 +144,7 @@ func (h *Handler) NewAccount(w http.ResponseWriter, r *http.Request) {
|
||||||
api.WriteError(w, err)
|
api.WriteError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := h.db.UpdateExternalAccountKey(ctx, prov.Name, eak); err != nil {
|
if err := h.db.UpdateExternalAccountKey(ctx, prov.ID, eak); err != nil {
|
||||||
api.WriteError(w, acme.WrapErrorISE(err, "error updating external account binding key"))
|
api.WriteError(w, acme.WrapErrorISE(err, "error updating external account binding key"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ func (h *Handler) validateExternalAccountBinding(ctx context.Context, nar *NewAc
|
||||||
return nil, acmeErr
|
return nil, acmeErr
|
||||||
}
|
}
|
||||||
|
|
||||||
externalAccountKey, err := h.db.GetExternalAccountKey(ctx, acmeProv.Name, keyID)
|
externalAccountKey, err := h.db.GetExternalAccountKey(ctx, acmeProv.ID, keyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(*acme.Error); ok {
|
if _, ok := err.(*acme.Error); ok {
|
||||||
return nil, acme.WrapError(acme.ErrorUnauthorizedType, err, "the field 'kid' references an unknown key")
|
return nil, acme.WrapError(acme.ErrorUnauthorizedType, err, "the field 'kid' references an unknown key")
|
||||||
|
|
|
@ -351,6 +351,7 @@ func TestHandler_NewAccount(t *testing.T) {
|
||||||
prov := newProv()
|
prov := newProv()
|
||||||
escProvName := url.PathEscape(prov.GetName())
|
escProvName := url.PathEscape(prov.GetName())
|
||||||
baseURL := &url.URL{Scheme: "https", Host: "test.ca.smallstep.com"}
|
baseURL := &url.URL{Scheme: "https", Host: "test.ca.smallstep.com"}
|
||||||
|
provID := prov.GetID()
|
||||||
|
|
||||||
type test struct {
|
type test struct {
|
||||||
db acme.DB
|
db acme.DB
|
||||||
|
@ -555,7 +556,7 @@ func TestHandler_NewAccount(t *testing.T) {
|
||||||
ctx = context.WithValue(ctx, jwsContextKey, parsedJWS)
|
ctx = context.WithValue(ctx, jwsContextKey, parsedJWS)
|
||||||
eak := &acme.ExternalAccountKey{
|
eak := &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: escProvName,
|
ProvisionerID: provID,
|
||||||
Reference: "testeak",
|
Reference: "testeak",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
|
@ -732,7 +733,7 @@ func TestHandler_NewAccount(t *testing.T) {
|
||||||
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: escProvName,
|
ProvisionerID: provID,
|
||||||
Reference: "testeak",
|
Reference: "testeak",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
|
@ -1056,6 +1057,7 @@ func TestHandler_validateExternalAccountBinding(t *testing.T) {
|
||||||
acmeProv := newACMEProv(t)
|
acmeProv := newACMEProv(t)
|
||||||
escProvName := url.PathEscape(acmeProv.GetName())
|
escProvName := url.PathEscape(acmeProv.GetName())
|
||||||
baseURL := &url.URL{Scheme: "https", Host: "test.ca.smallstep.com"}
|
baseURL := &url.URL{Scheme: "https", Host: "test.ca.smallstep.com"}
|
||||||
|
provID := acmeProv.GetID()
|
||||||
type test struct {
|
type test struct {
|
||||||
db acme.DB
|
db acme.DB
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
@ -1129,7 +1131,7 @@ func TestHandler_validateExternalAccountBinding(t *testing.T) {
|
||||||
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: escProvName,
|
ProvisionerID: provID,
|
||||||
Reference: "testeak",
|
Reference: "testeak",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
|
@ -1143,7 +1145,7 @@ func TestHandler_validateExternalAccountBinding(t *testing.T) {
|
||||||
},
|
},
|
||||||
eak: &acme.ExternalAccountKey{
|
eak: &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: escProvName,
|
ProvisionerID: provID,
|
||||||
Reference: "testeak",
|
Reference: "testeak",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
|
@ -1493,7 +1495,7 @@ func TestHandler_validateExternalAccountBinding(t *testing.T) {
|
||||||
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: escProvName,
|
ProvisionerID: provID,
|
||||||
Reference: "testeak",
|
Reference: "testeak",
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
AccountID: "some-account-id",
|
AccountID: "some-account-id",
|
||||||
|
@ -1550,7 +1552,7 @@ func TestHandler_validateExternalAccountBinding(t *testing.T) {
|
||||||
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: escProvName,
|
ProvisionerID: provID,
|
||||||
Reference: "testeak",
|
Reference: "testeak",
|
||||||
KeyBytes: []byte{1, 2, 3, 4},
|
KeyBytes: []byte{1, 2, 3, 4},
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
|
@ -1608,7 +1610,7 @@ func TestHandler_validateExternalAccountBinding(t *testing.T) {
|
||||||
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: escProvName,
|
ProvisionerID: provID,
|
||||||
Reference: "testeak",
|
Reference: "testeak",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
|
@ -1663,7 +1665,7 @@ func TestHandler_validateExternalAccountBinding(t *testing.T) {
|
||||||
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: escProvName,
|
ProvisionerID: provID,
|
||||||
Reference: "testeak",
|
Reference: "testeak",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
|
@ -1719,7 +1721,7 @@ func TestHandler_validateExternalAccountBinding(t *testing.T) {
|
||||||
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: escProvName,
|
ProvisionerID: provID,
|
||||||
Reference: "testeak",
|
Reference: "testeak",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
|
@ -1765,7 +1767,7 @@ func TestHandler_validateExternalAccountBinding(t *testing.T) {
|
||||||
assert.NotNil(t, tc.eak)
|
assert.NotNil(t, tc.eak)
|
||||||
assert.Equals(t, got.ID, tc.eak.ID)
|
assert.Equals(t, got.ID, tc.eak.ID)
|
||||||
assert.Equals(t, got.KeyBytes, tc.eak.KeyBytes)
|
assert.Equals(t, got.KeyBytes, tc.eak.KeyBytes)
|
||||||
assert.Equals(t, got.Provisioner, tc.eak.Provisioner)
|
assert.Equals(t, got.ProvisionerID, tc.eak.ProvisionerID)
|
||||||
assert.Equals(t, got.Reference, tc.eak.Reference)
|
assert.Equals(t, got.Reference, tc.eak.Reference)
|
||||||
assert.Equals(t, got.CreatedAt, tc.eak.CreatedAt)
|
assert.Equals(t, got.CreatedAt, tc.eak.CreatedAt)
|
||||||
assert.Equals(t, got.AccountID, tc.eak.AccountID)
|
assert.Equals(t, got.AccountID, tc.eak.AccountID)
|
||||||
|
|
48
acme/db.go
48
acme/db.go
|
@ -19,12 +19,12 @@ type DB interface {
|
||||||
GetAccountByKeyID(ctx context.Context, kid string) (*Account, error)
|
GetAccountByKeyID(ctx context.Context, kid string) (*Account, error)
|
||||||
UpdateAccount(ctx context.Context, acc *Account) error
|
UpdateAccount(ctx context.Context, acc *Account) error
|
||||||
|
|
||||||
CreateExternalAccountKey(ctx context.Context, provisionerName, reference string) (*ExternalAccountKey, error)
|
CreateExternalAccountKey(ctx context.Context, provisionerID, reference string) (*ExternalAccountKey, error)
|
||||||
GetExternalAccountKey(ctx context.Context, provisionerName, keyID string) (*ExternalAccountKey, error)
|
GetExternalAccountKey(ctx context.Context, provisionerID, keyID string) (*ExternalAccountKey, error)
|
||||||
GetExternalAccountKeys(ctx context.Context, provisionerName string) ([]*ExternalAccountKey, error)
|
GetExternalAccountKeys(ctx context.Context, provisionerID string) ([]*ExternalAccountKey, error)
|
||||||
GetExternalAccountKeyByReference(ctx context.Context, provisionerName, reference string) (*ExternalAccountKey, error)
|
GetExternalAccountKeyByReference(ctx context.Context, provisionerID, reference string) (*ExternalAccountKey, error)
|
||||||
DeleteExternalAccountKey(ctx context.Context, provisionerName, keyID string) error
|
DeleteExternalAccountKey(ctx context.Context, provisionerID, keyID string) error
|
||||||
UpdateExternalAccountKey(ctx context.Context, provisionerName string, eak *ExternalAccountKey) error
|
UpdateExternalAccountKey(ctx context.Context, provisionerID string, eak *ExternalAccountKey) error
|
||||||
|
|
||||||
CreateNonce(ctx context.Context) (Nonce, error)
|
CreateNonce(ctx context.Context) (Nonce, error)
|
||||||
DeleteNonce(ctx context.Context, nonce Nonce) error
|
DeleteNonce(ctx context.Context, nonce Nonce) error
|
||||||
|
@ -56,12 +56,12 @@ type MockDB struct {
|
||||||
MockGetAccountByKeyID func(ctx context.Context, kid string) (*Account, error)
|
MockGetAccountByKeyID func(ctx context.Context, kid string) (*Account, error)
|
||||||
MockUpdateAccount func(ctx context.Context, acc *Account) error
|
MockUpdateAccount func(ctx context.Context, acc *Account) error
|
||||||
|
|
||||||
MockCreateExternalAccountKey func(ctx context.Context, provisionerName, reference string) (*ExternalAccountKey, error)
|
MockCreateExternalAccountKey func(ctx context.Context, provisionerID, reference string) (*ExternalAccountKey, error)
|
||||||
MockGetExternalAccountKey func(ctx context.Context, provisionerName, keyID string) (*ExternalAccountKey, error)
|
MockGetExternalAccountKey func(ctx context.Context, provisionerID, keyID string) (*ExternalAccountKey, error)
|
||||||
MockGetExternalAccountKeys func(ctx context.Context, provisionerName string) ([]*ExternalAccountKey, error)
|
MockGetExternalAccountKeys func(ctx context.Context, provisionerID string) ([]*ExternalAccountKey, error)
|
||||||
MockGetExternalAccountKeyByReference func(ctx context.Context, provisionerName, reference string) (*ExternalAccountKey, error)
|
MockGetExternalAccountKeyByReference func(ctx context.Context, provisionerID, reference string) (*ExternalAccountKey, error)
|
||||||
MockDeleteExternalAccountKey func(ctx context.Context, provisionerName, keyID string) error
|
MockDeleteExternalAccountKey func(ctx context.Context, provisionerID, keyID string) error
|
||||||
MockUpdateExternalAccountKey func(ctx context.Context, provisionerName string, eak *ExternalAccountKey) error
|
MockUpdateExternalAccountKey func(ctx context.Context, provisionerID string, eak *ExternalAccountKey) error
|
||||||
|
|
||||||
MockCreateNonce func(ctx context.Context) (Nonce, error)
|
MockCreateNonce func(ctx context.Context) (Nonce, error)
|
||||||
MockDeleteNonce func(ctx context.Context, nonce Nonce) error
|
MockDeleteNonce func(ctx context.Context, nonce Nonce) error
|
||||||
|
@ -129,9 +129,9 @@ func (m *MockDB) UpdateAccount(ctx context.Context, acc *Account) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateExternalAccountKey mock
|
// CreateExternalAccountKey mock
|
||||||
func (m *MockDB) CreateExternalAccountKey(ctx context.Context, provisionerName, reference string) (*ExternalAccountKey, error) {
|
func (m *MockDB) CreateExternalAccountKey(ctx context.Context, provisionerID, reference string) (*ExternalAccountKey, error) {
|
||||||
if m.MockCreateExternalAccountKey != nil {
|
if m.MockCreateExternalAccountKey != nil {
|
||||||
return m.MockCreateExternalAccountKey(ctx, provisionerName, reference)
|
return m.MockCreateExternalAccountKey(ctx, provisionerID, reference)
|
||||||
} else if m.MockError != nil {
|
} else if m.MockError != nil {
|
||||||
return nil, m.MockError
|
return nil, m.MockError
|
||||||
}
|
}
|
||||||
|
@ -139,9 +139,9 @@ func (m *MockDB) CreateExternalAccountKey(ctx context.Context, provisionerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExternalAccountKey mock
|
// GetExternalAccountKey mock
|
||||||
func (m *MockDB) GetExternalAccountKey(ctx context.Context, provisionerName, keyID string) (*ExternalAccountKey, error) {
|
func (m *MockDB) GetExternalAccountKey(ctx context.Context, provisionerID, keyID string) (*ExternalAccountKey, error) {
|
||||||
if m.MockGetExternalAccountKey != nil {
|
if m.MockGetExternalAccountKey != nil {
|
||||||
return m.MockGetExternalAccountKey(ctx, provisionerName, keyID)
|
return m.MockGetExternalAccountKey(ctx, provisionerID, keyID)
|
||||||
} else if m.MockError != nil {
|
} else if m.MockError != nil {
|
||||||
return nil, m.MockError
|
return nil, m.MockError
|
||||||
}
|
}
|
||||||
|
@ -149,9 +149,9 @@ func (m *MockDB) GetExternalAccountKey(ctx context.Context, provisionerName, key
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExternalAccountKeys mock
|
// GetExternalAccountKeys mock
|
||||||
func (m *MockDB) GetExternalAccountKeys(ctx context.Context, provisionerName string) ([]*ExternalAccountKey, error) {
|
func (m *MockDB) GetExternalAccountKeys(ctx context.Context, provisionerID string) ([]*ExternalAccountKey, error) {
|
||||||
if m.MockGetExternalAccountKeys != nil {
|
if m.MockGetExternalAccountKeys != nil {
|
||||||
return m.MockGetExternalAccountKeys(ctx, provisionerName)
|
return m.MockGetExternalAccountKeys(ctx, provisionerID)
|
||||||
} else if m.MockError != nil {
|
} else if m.MockError != nil {
|
||||||
return nil, m.MockError
|
return nil, m.MockError
|
||||||
}
|
}
|
||||||
|
@ -159,9 +159,9 @@ func (m *MockDB) GetExternalAccountKeys(ctx context.Context, provisionerName str
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExternalAccountKeyByReference mock
|
// GetExternalAccountKeyByReference mock
|
||||||
func (m *MockDB) GetExternalAccountKeyByReference(ctx context.Context, provisionerName, reference string) (*ExternalAccountKey, error) {
|
func (m *MockDB) GetExternalAccountKeyByReference(ctx context.Context, provisionerID, reference string) (*ExternalAccountKey, error) {
|
||||||
if m.MockGetExternalAccountKeyByReference != nil {
|
if m.MockGetExternalAccountKeyByReference != nil {
|
||||||
return m.MockGetExternalAccountKeyByReference(ctx, provisionerName, reference)
|
return m.MockGetExternalAccountKeyByReference(ctx, provisionerID, reference)
|
||||||
} else if m.MockError != nil {
|
} else if m.MockError != nil {
|
||||||
return nil, m.MockError
|
return nil, m.MockError
|
||||||
}
|
}
|
||||||
|
@ -169,9 +169,9 @@ func (m *MockDB) GetExternalAccountKeyByReference(ctx context.Context, provision
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteExternalAccountKey mock
|
// DeleteExternalAccountKey mock
|
||||||
func (m *MockDB) DeleteExternalAccountKey(ctx context.Context, provisionerName, keyID string) error {
|
func (m *MockDB) DeleteExternalAccountKey(ctx context.Context, provisionerID, keyID string) error {
|
||||||
if m.MockDeleteExternalAccountKey != nil {
|
if m.MockDeleteExternalAccountKey != nil {
|
||||||
return m.MockDeleteExternalAccountKey(ctx, provisionerName, keyID)
|
return m.MockDeleteExternalAccountKey(ctx, provisionerID, keyID)
|
||||||
} else if m.MockError != nil {
|
} else if m.MockError != nil {
|
||||||
return m.MockError
|
return m.MockError
|
||||||
}
|
}
|
||||||
|
@ -179,9 +179,9 @@ func (m *MockDB) DeleteExternalAccountKey(ctx context.Context, provisionerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateExternalAccountKey mock
|
// UpdateExternalAccountKey mock
|
||||||
func (m *MockDB) UpdateExternalAccountKey(ctx context.Context, provisionerName string, eak *ExternalAccountKey) error {
|
func (m *MockDB) UpdateExternalAccountKey(ctx context.Context, provisionerID string, eak *ExternalAccountKey) error {
|
||||||
if m.MockUpdateExternalAccountKey != nil {
|
if m.MockUpdateExternalAccountKey != nil {
|
||||||
return m.MockUpdateExternalAccountKey(ctx, provisionerName, eak)
|
return m.MockUpdateExternalAccountKey(ctx, provisionerID, eak)
|
||||||
} else if m.MockError != nil {
|
} else if m.MockError != nil {
|
||||||
return m.MockError
|
return m.MockError
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -12,6 +13,9 @@ import (
|
||||||
"go.step.sm/crypto/jose"
|
"go.step.sm/crypto/jose"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Mutex for locking referencesByProvisioner index operations.
|
||||||
|
var referencesByProvisionerIndexMux sync.Mutex
|
||||||
|
|
||||||
// dbAccount represents an ACME account.
|
// dbAccount represents an ACME account.
|
||||||
type dbAccount struct {
|
type dbAccount struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
@ -29,7 +33,7 @@ func (dba *dbAccount) clone() *dbAccount {
|
||||||
|
|
||||||
type dbExternalAccountKey struct {
|
type dbExternalAccountKey struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Provisioner string `json:"provisioner"`
|
ProvisionerID string `json:"provisionerID"`
|
||||||
Reference string `json:"reference"`
|
Reference string `json:"reference"`
|
||||||
AccountID string `json:"accountID,omitempty"`
|
AccountID string `json:"accountID,omitempty"`
|
||||||
KeyBytes []byte `json:"key"`
|
KeyBytes []byte `json:"key"`
|
||||||
|
@ -170,7 +174,7 @@ func (db *DB) UpdateAccount(ctx context.Context, acc *acme.Account) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateExternalAccountKey creates a new External Account Binding key with a name
|
// CreateExternalAccountKey creates a new External Account Binding key with a name
|
||||||
func (db *DB) CreateExternalAccountKey(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
func (db *DB) CreateExternalAccountKey(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
keyID, err := randID()
|
keyID, err := randID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -184,7 +188,7 @@ func (db *DB) CreateExternalAccountKey(ctx context.Context, provisionerName, ref
|
||||||
|
|
||||||
dbeak := &dbExternalAccountKey{
|
dbeak := &dbExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: provisionerName,
|
ProvisionerID: provisionerID,
|
||||||
Reference: reference,
|
Reference: reference,
|
||||||
KeyBytes: random,
|
KeyBytes: random,
|
||||||
CreatedAt: clock.Now(),
|
CreatedAt: clock.Now(),
|
||||||
|
@ -194,19 +198,23 @@ func (db *DB) CreateExternalAccountKey(ctx context.Context, provisionerName, ref
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := db.addEAKID(ctx, provisionerID, dbeak.ID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if dbeak.Reference != "" {
|
if dbeak.Reference != "" {
|
||||||
dbExternalAccountKeyReference := &dbExternalAccountKeyReference{
|
dbExternalAccountKeyReference := &dbExternalAccountKeyReference{
|
||||||
Reference: dbeak.Reference,
|
Reference: dbeak.Reference,
|
||||||
ExternalAccountKeyID: dbeak.ID,
|
ExternalAccountKeyID: dbeak.ID,
|
||||||
}
|
}
|
||||||
if err := db.save(ctx, dbeak.Reference, dbExternalAccountKeyReference, nil, "external_account_key_reference", externalAccountKeysByReferenceTable); err != nil {
|
if err := db.save(ctx, referenceKey(provisionerID, dbeak.Reference), dbExternalAccountKeyReference, nil, "external_account_key_reference", externalAccountKeysByReferenceTable); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: dbeak.ID,
|
ID: dbeak.ID,
|
||||||
Provisioner: dbeak.Provisioner,
|
ProvisionerID: dbeak.ProvisionerID,
|
||||||
Reference: dbeak.Reference,
|
Reference: dbeak.Reference,
|
||||||
AccountID: dbeak.AccountID,
|
AccountID: dbeak.AccountID,
|
||||||
KeyBytes: dbeak.KeyBytes,
|
KeyBytes: dbeak.KeyBytes,
|
||||||
|
@ -216,19 +224,19 @@ func (db *DB) CreateExternalAccountKey(ctx context.Context, provisionerName, ref
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExternalAccountKey retrieves an External Account Binding key by KeyID
|
// GetExternalAccountKey retrieves an External Account Binding key by KeyID
|
||||||
func (db *DB) GetExternalAccountKey(ctx context.Context, provisionerName, keyID string) (*acme.ExternalAccountKey, error) {
|
func (db *DB) GetExternalAccountKey(ctx context.Context, provisionerID, keyID string) (*acme.ExternalAccountKey, error) {
|
||||||
dbeak, err := db.getDBExternalAccountKey(ctx, keyID)
|
dbeak, err := db.getDBExternalAccountKey(ctx, keyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if dbeak.Provisioner != provisionerName {
|
if dbeak.ProvisionerID != provisionerID {
|
||||||
return nil, acme.NewError(acme.ErrorUnauthorizedType, "name of provisioner does not match provisioner for which the EAB key was created")
|
return nil, acme.NewError(acme.ErrorUnauthorizedType, "provisioner does not match provisioner for which the EAB key was created")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: dbeak.ID,
|
ID: dbeak.ID,
|
||||||
Provisioner: dbeak.Provisioner,
|
ProvisionerID: dbeak.ProvisionerID,
|
||||||
Reference: dbeak.Reference,
|
Reference: dbeak.Reference,
|
||||||
AccountID: dbeak.AccountID,
|
AccountID: dbeak.AccountID,
|
||||||
KeyBytes: dbeak.KeyBytes,
|
KeyBytes: dbeak.KeyBytes,
|
||||||
|
@ -237,52 +245,67 @@ func (db *DB) GetExternalAccountKey(ctx context.Context, provisionerName, keyID
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) DeleteExternalAccountKey(ctx context.Context, provisionerName, keyID string) error {
|
func (db *DB) DeleteExternalAccountKey(ctx context.Context, provisionerID, keyID string) error {
|
||||||
dbeak, err := db.getDBExternalAccountKey(ctx, keyID)
|
dbeak, err := db.getDBExternalAccountKey(ctx, keyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error loading ACME EAB Key with Key ID %s", keyID)
|
return errors.Wrapf(err, "error loading ACME EAB Key with Key ID %s", keyID)
|
||||||
}
|
}
|
||||||
if dbeak.Provisioner != provisionerName {
|
|
||||||
return errors.New("name of provisioner does not match provisioner for which the EAB key was created")
|
if dbeak.ProvisionerID != provisionerID {
|
||||||
|
return errors.New("provisioner does not match provisioner for which the EAB key was created")
|
||||||
}
|
}
|
||||||
|
|
||||||
if dbeak.Reference != "" {
|
if dbeak.Reference != "" {
|
||||||
err = db.db.Del(externalAccountKeysByReferenceTable, []byte(dbeak.Reference))
|
if err := db.db.Del(externalAccountKeysByReferenceTable, []byte(referenceKey(provisionerID, dbeak.Reference))); err != nil {
|
||||||
if err != nil {
|
return errors.Wrapf(err, "error deleting ACME EAB Key reference with Key ID %s and reference %s", keyID, dbeak.Reference)
|
||||||
return errors.Wrapf(err, "error deleting ACME EAB Key Reference with Key ID %s and reference %s", keyID, dbeak.Reference)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = db.db.Del(externalAccountKeyTable, []byte(keyID)); err != nil {
|
if err := db.db.Del(externalAccountKeyTable, []byte(keyID)); err != nil {
|
||||||
return errors.Wrapf(err, "error deleting ACME EAB Key with Key ID %s", keyID)
|
return errors.Wrapf(err, "error deleting ACME EAB Key with Key ID %s", keyID)
|
||||||
}
|
}
|
||||||
|
if err := db.deleteEAKID(ctx, provisionerID, keyID); err != nil {
|
||||||
|
return errors.Wrapf(err, "error removing ACME EAB Key ID %s", keyID)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExternalAccountKeys retrieves all External Account Binding keys for a provisioner
|
// GetExternalAccountKeys retrieves all External Account Binding keys for a provisioner
|
||||||
func (db *DB) GetExternalAccountKeys(ctx context.Context, provisionerName string) ([]*acme.ExternalAccountKey, error) {
|
func (db *DB) GetExternalAccountKeys(ctx context.Context, provisionerID string) ([]*acme.ExternalAccountKey, error) {
|
||||||
|
|
||||||
// TODO: lookup by provisioner based on index
|
// TODO: mutex?
|
||||||
entries, err := db.db.List(externalAccountKeyTable)
|
|
||||||
|
var eakIDs []string
|
||||||
|
r, err := db.db.Get(externalAccountKeysByProvisionerIDTable, []byte(provisionerID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
if !nosqlDB.IsErrNotFound(err) {
|
||||||
|
return nil, errors.Wrapf(err, "error loading ACME EAB Key IDs for provisioner %s", provisionerID)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := json.Unmarshal(r, &eakIDs); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error unmarshaling ACME EAB Key IDs for provisioner %s", provisionerID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keys := []*acme.ExternalAccountKey{}
|
keys := []*acme.ExternalAccountKey{}
|
||||||
for _, entry := range entries { // entries is sorted alphabetically on the key (ID) of the EAK; no need to sort this again.
|
for _, eakID := range eakIDs {
|
||||||
dbeak := new(dbExternalAccountKey)
|
if eakID == "" {
|
||||||
if err = json.Unmarshal(entry.Value, dbeak); err != nil {
|
continue // shouldn't happen; just in case
|
||||||
return nil, errors.Wrapf(err, "error unmarshaling external account key %s into ExternalAccountKey", string(entry.Key))
|
}
|
||||||
|
eak, err := db.getDBExternalAccountKey(ctx, eakID)
|
||||||
|
if err != nil {
|
||||||
|
if !nosqlDB.IsErrNotFound(err) {
|
||||||
|
return nil, errors.Wrapf(err, "error retrieving ACME EAB Key for provisioner %s and keyID %s", provisionerID, eakID)
|
||||||
}
|
}
|
||||||
if dbeak.Provisioner != provisionerName {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
keys = append(keys, &acme.ExternalAccountKey{
|
keys = append(keys, &acme.ExternalAccountKey{
|
||||||
ID: dbeak.ID,
|
ID: eak.ID,
|
||||||
KeyBytes: dbeak.KeyBytes,
|
KeyBytes: eak.KeyBytes,
|
||||||
Provisioner: dbeak.Provisioner,
|
ProvisionerID: eak.ProvisionerID,
|
||||||
Reference: dbeak.Reference,
|
Reference: eak.Reference,
|
||||||
AccountID: dbeak.AccountID,
|
AccountID: eak.AccountID,
|
||||||
CreatedAt: dbeak.CreatedAt,
|
CreatedAt: eak.CreatedAt,
|
||||||
BoundAt: dbeak.BoundAt,
|
BoundAt: eak.BoundAt,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,11 +313,12 @@ func (db *DB) GetExternalAccountKeys(ctx context.Context, provisionerName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExternalAccountKeyByReference retrieves an External Account Binding key with unique reference
|
// GetExternalAccountKeyByReference retrieves an External Account Binding key with unique reference
|
||||||
func (db *DB) GetExternalAccountKeyByReference(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
func (db *DB) GetExternalAccountKeyByReference(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
if reference == "" {
|
if reference == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
k, err := db.db.Get(externalAccountKeysByReferenceTable, []byte(reference))
|
|
||||||
|
k, err := db.db.Get(externalAccountKeysByReferenceTable, []byte(referenceKey(provisionerID, reference)))
|
||||||
if nosqlDB.IsErrNotFound(err) {
|
if nosqlDB.IsErrNotFound(err) {
|
||||||
return nil, acme.ErrNotFound
|
return nil, acme.ErrNotFound
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -304,22 +328,31 @@ func (db *DB) GetExternalAccountKeyByReference(ctx context.Context, provisionerN
|
||||||
if err := json.Unmarshal(k, dbExternalAccountKeyReference); err != nil {
|
if err := json.Unmarshal(k, dbExternalAccountKeyReference); err != nil {
|
||||||
return nil, errors.Wrapf(err, "error unmarshaling ACME EAB key for reference %s", reference)
|
return nil, errors.Wrapf(err, "error unmarshaling ACME EAB key for reference %s", reference)
|
||||||
}
|
}
|
||||||
return db.GetExternalAccountKey(ctx, provisionerName, dbExternalAccountKeyReference.ExternalAccountKeyID)
|
|
||||||
|
return db.GetExternalAccountKey(ctx, provisionerID, dbExternalAccountKeyReference.ExternalAccountKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) UpdateExternalAccountKey(ctx context.Context, provisionerName string, eak *acme.ExternalAccountKey) error {
|
func (db *DB) UpdateExternalAccountKey(ctx context.Context, provisionerID string, eak *acme.ExternalAccountKey) error {
|
||||||
old, err := db.getDBExternalAccountKey(ctx, eak.ID)
|
old, err := db.getDBExternalAccountKey(ctx, eak.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if old.Provisioner != provisionerName {
|
if old.ProvisionerID != provisionerID {
|
||||||
return errors.New("name of provisioner does not match provisioner for which the EAB key was created")
|
return errors.New("provisioner does not match provisioner for which the EAB key was created")
|
||||||
|
}
|
||||||
|
|
||||||
|
if old.ProvisionerID != eak.ProvisionerID {
|
||||||
|
return errors.New("cannot change provisioner for an existing ACME EAB Key")
|
||||||
|
}
|
||||||
|
|
||||||
|
if old.Reference != eak.Reference {
|
||||||
|
return errors.New("cannot change reference for an existing ACME EAB Key")
|
||||||
}
|
}
|
||||||
|
|
||||||
nu := dbExternalAccountKey{
|
nu := dbExternalAccountKey{
|
||||||
ID: eak.ID,
|
ID: eak.ID,
|
||||||
Provisioner: eak.Provisioner,
|
ProvisionerID: eak.ProvisionerID,
|
||||||
Reference: eak.Reference,
|
Reference: eak.Reference,
|
||||||
AccountID: eak.AccountID,
|
AccountID: eak.AccountID,
|
||||||
KeyBytes: eak.KeyBytes,
|
KeyBytes: eak.KeyBytes,
|
||||||
|
@ -329,3 +362,105 @@ func (db *DB) UpdateExternalAccountKey(ctx context.Context, provisionerName stri
|
||||||
|
|
||||||
return db.save(ctx, nu.ID, nu, old, "external_account_key", externalAccountKeyTable)
|
return db.save(ctx, nu.ID, nu, old, "external_account_key", externalAccountKeyTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *DB) addEAKID(ctx context.Context, provisionerID, eakID string) error {
|
||||||
|
referencesByProvisionerIndexMux.Lock()
|
||||||
|
defer referencesByProvisionerIndexMux.Unlock()
|
||||||
|
|
||||||
|
var eakIDs []string
|
||||||
|
b, err := db.db.Get(externalAccountKeysByProvisionerIDTable, []byte(provisionerID))
|
||||||
|
if err != nil {
|
||||||
|
if !nosqlDB.IsErrNotFound(err) {
|
||||||
|
return errors.Wrapf(err, "error loading eakIDs for provisioner %s", provisionerID)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := json.Unmarshal(b, &eakIDs); err != nil {
|
||||||
|
return errors.Wrapf(err, "error unmarshaling eakIDs for provisioner %s", provisionerID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var newEAKIDs []string
|
||||||
|
newEAKIDs = append(newEAKIDs, eakIDs...)
|
||||||
|
newEAKIDs = append(newEAKIDs, eakID)
|
||||||
|
var (
|
||||||
|
_old interface{} = eakIDs
|
||||||
|
_new interface{} = newEAKIDs
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(eakIDs) == 0 {
|
||||||
|
_old = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.save(ctx, provisionerID, _new, _old, "externalAccountKeysByProvisionerID", externalAccountKeysByProvisionerIDTable); err != nil {
|
||||||
|
return errors.Wrapf(err, "error saving eakIDs index for provisioner %s", provisionerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) deleteEAKID(ctx context.Context, provisionerID, eakID string) error {
|
||||||
|
referencesByProvisionerIndexMux.Lock()
|
||||||
|
defer referencesByProvisionerIndexMux.Unlock()
|
||||||
|
|
||||||
|
var eakIDs []string
|
||||||
|
b, err := db.db.Get(externalAccountKeysByProvisionerIDTable, []byte(provisionerID))
|
||||||
|
if err != nil {
|
||||||
|
if !nosqlDB.IsErrNotFound(err) {
|
||||||
|
return errors.Wrapf(err, "error loading reference IDs for provisioner %s", provisionerID)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := json.Unmarshal(b, &eakIDs); err != nil {
|
||||||
|
return errors.Wrapf(err, "error unmarshaling eakIDs for provisioner %s", provisionerID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newEAKIDs := removeElement(eakIDs, eakID)
|
||||||
|
var (
|
||||||
|
_old interface{} = eakIDs
|
||||||
|
_new interface{} = newEAKIDs
|
||||||
|
)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(eakIDs) == 0:
|
||||||
|
_old = nil
|
||||||
|
case len(newEAKIDs) == 0:
|
||||||
|
_new = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.save(ctx, provisionerID, _new, _old, "externalAccountKeysByProvisionerID", externalAccountKeysByProvisionerIDTable); err != nil {
|
||||||
|
return errors.Wrapf(err, "error saving referenceIDs index for provisioner %s", provisionerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// referenceKey returns a unique key for a reference per provisioner
|
||||||
|
func referenceKey(provisionerID, reference string) string {
|
||||||
|
return provisionerID + "." + reference
|
||||||
|
}
|
||||||
|
|
||||||
|
// sliceIndex finds the index of item in slice
|
||||||
|
func sliceIndex(slice []string, item string) int {
|
||||||
|
for i := range slice {
|
||||||
|
if slice[i] == item {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeElement deletes the item if it exists in the
|
||||||
|
// slice. It returns a new slice, keeping the old one intact.
|
||||||
|
func removeElement(slice []string, item string) []string {
|
||||||
|
|
||||||
|
newSlice := make([]string, 0)
|
||||||
|
index := sliceIndex(slice, item)
|
||||||
|
if index < 0 {
|
||||||
|
newSlice = append(newSlice, slice...)
|
||||||
|
return newSlice
|
||||||
|
}
|
||||||
|
|
||||||
|
newSlice = append(newSlice, slice[:index]...)
|
||||||
|
|
||||||
|
return append(newSlice, slice[index+1:]...)
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package nosql
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -307,7 +308,7 @@ func TestDB_GetAccountByKeyID(t *testing.T) {
|
||||||
assert.Equals(t, string(key), accID)
|
assert.Equals(t, string(key), accID)
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -340,7 +341,7 @@ func TestDB_GetAccountByKeyID(t *testing.T) {
|
||||||
assert.Equals(t, string(key), accID)
|
assert.Equals(t, string(key), accID)
|
||||||
return b, nil
|
return b, nil
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -462,7 +463,7 @@ func TestDB_CreateAccount(t *testing.T) {
|
||||||
assert.True(t, dbacc.DeactivatedAt.IsZero())
|
assert.True(t, dbacc.DeactivatedAt.IsZero())
|
||||||
return nil, false, errors.New("force")
|
return nil, false, errors.New("force")
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, false, errors.New("force")
|
return nil, false, errors.New("force")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -506,7 +507,7 @@ func TestDB_CreateAccount(t *testing.T) {
|
||||||
assert.True(t, dbacc.DeactivatedAt.IsZero())
|
assert.True(t, dbacc.DeactivatedAt.IsZero())
|
||||||
return nu, true, nil
|
return nu, true, nil
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, false, errors.New("force")
|
return nil, false, errors.New("force")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -699,6 +700,7 @@ func TestDB_UpdateAccount(t *testing.T) {
|
||||||
|
|
||||||
func TestDB_getDBExternalAccountKey(t *testing.T) {
|
func TestDB_getDBExternalAccountKey(t *testing.T) {
|
||||||
keyID := "keyID"
|
keyID := "keyID"
|
||||||
|
provID := "provID"
|
||||||
type test struct {
|
type test struct {
|
||||||
db nosql.DB
|
db nosql.DB
|
||||||
err error
|
err error
|
||||||
|
@ -710,7 +712,7 @@ func TestDB_getDBExternalAccountKey(t *testing.T) {
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
dbeak := &dbExternalAccountKey{
|
dbeak := &dbExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: "prov",
|
ProvisionerID: provID,
|
||||||
Reference: "ref",
|
Reference: "ref",
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -790,7 +792,7 @@ func TestDB_getDBExternalAccountKey(t *testing.T) {
|
||||||
} else if assert.Nil(t, tc.err) {
|
} else if assert.Nil(t, tc.err) {
|
||||||
assert.Equals(t, dbeak.ID, tc.dbeak.ID)
|
assert.Equals(t, dbeak.ID, tc.dbeak.ID)
|
||||||
assert.Equals(t, dbeak.KeyBytes, tc.dbeak.KeyBytes)
|
assert.Equals(t, dbeak.KeyBytes, tc.dbeak.KeyBytes)
|
||||||
assert.Equals(t, dbeak.Provisioner, tc.dbeak.Provisioner)
|
assert.Equals(t, dbeak.ProvisionerID, tc.dbeak.ProvisionerID)
|
||||||
assert.Equals(t, dbeak.Reference, tc.dbeak.Reference)
|
assert.Equals(t, dbeak.Reference, tc.dbeak.Reference)
|
||||||
assert.Equals(t, dbeak.CreatedAt, tc.dbeak.CreatedAt)
|
assert.Equals(t, dbeak.CreatedAt, tc.dbeak.CreatedAt)
|
||||||
assert.Equals(t, dbeak.AccountID, tc.dbeak.AccountID)
|
assert.Equals(t, dbeak.AccountID, tc.dbeak.AccountID)
|
||||||
|
@ -802,7 +804,7 @@ func TestDB_getDBExternalAccountKey(t *testing.T) {
|
||||||
|
|
||||||
func TestDB_GetExternalAccountKey(t *testing.T) {
|
func TestDB_GetExternalAccountKey(t *testing.T) {
|
||||||
keyID := "keyID"
|
keyID := "keyID"
|
||||||
prov := "acmeProv"
|
provID := "provID"
|
||||||
type test struct {
|
type test struct {
|
||||||
db nosql.DB
|
db nosql.DB
|
||||||
err error
|
err error
|
||||||
|
@ -814,7 +816,7 @@ func TestDB_GetExternalAccountKey(t *testing.T) {
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
dbeak := &dbExternalAccountKey{
|
dbeak := &dbExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: "ref",
|
Reference: "ref",
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -832,7 +834,7 @@ func TestDB_GetExternalAccountKey(t *testing.T) {
|
||||||
},
|
},
|
||||||
eak: &acme.ExternalAccountKey{
|
eak: &acme.ExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: "ref",
|
Reference: "ref",
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -857,7 +859,7 @@ func TestDB_GetExternalAccountKey(t *testing.T) {
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
dbeak := &dbExternalAccountKey{
|
dbeak := &dbExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: "aDifferentProv",
|
ProvisionerID: "aDifferentProvID",
|
||||||
Reference: "ref",
|
Reference: "ref",
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -875,13 +877,13 @@ func TestDB_GetExternalAccountKey(t *testing.T) {
|
||||||
},
|
},
|
||||||
eak: &acme.ExternalAccountKey{
|
eak: &acme.ExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: "ref",
|
Reference: "ref",
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
},
|
},
|
||||||
acmeErr: acme.NewError(acme.ErrorUnauthorizedType, "name of provisioner does not match provisioner for which the EAB key was created"),
|
acmeErr: acme.NewError(acme.ErrorUnauthorizedType, "provisioner does not match provisioner for which the EAB key was created"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -889,7 +891,7 @@ func TestDB_GetExternalAccountKey(t *testing.T) {
|
||||||
tc := run(t)
|
tc := run(t)
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
d := DB{db: tc.db}
|
d := DB{db: tc.db}
|
||||||
if eak, err := d.GetExternalAccountKey(context.Background(), prov, keyID); err != nil {
|
if eak, err := d.GetExternalAccountKey(context.Background(), provID, keyID); err != nil {
|
||||||
switch k := err.(type) {
|
switch k := err.(type) {
|
||||||
case *acme.Error:
|
case *acme.Error:
|
||||||
if assert.NotNil(t, tc.acmeErr) {
|
if assert.NotNil(t, tc.acmeErr) {
|
||||||
|
@ -907,7 +909,7 @@ func TestDB_GetExternalAccountKey(t *testing.T) {
|
||||||
} else if assert.Nil(t, tc.err) {
|
} else if assert.Nil(t, tc.err) {
|
||||||
assert.Equals(t, eak.ID, tc.eak.ID)
|
assert.Equals(t, eak.ID, tc.eak.ID)
|
||||||
assert.Equals(t, eak.KeyBytes, tc.eak.KeyBytes)
|
assert.Equals(t, eak.KeyBytes, tc.eak.KeyBytes)
|
||||||
assert.Equals(t, eak.Provisioner, tc.eak.Provisioner)
|
assert.Equals(t, eak.ProvisionerID, tc.eak.ProvisionerID)
|
||||||
assert.Equals(t, eak.Reference, tc.eak.Reference)
|
assert.Equals(t, eak.Reference, tc.eak.Reference)
|
||||||
assert.Equals(t, eak.CreatedAt, tc.eak.CreatedAt)
|
assert.Equals(t, eak.CreatedAt, tc.eak.CreatedAt)
|
||||||
assert.Equals(t, eak.AccountID, tc.eak.AccountID)
|
assert.Equals(t, eak.AccountID, tc.eak.AccountID)
|
||||||
|
@ -919,7 +921,7 @@ func TestDB_GetExternalAccountKey(t *testing.T) {
|
||||||
|
|
||||||
func TestDB_GetExternalAccountKeyByReference(t *testing.T) {
|
func TestDB_GetExternalAccountKeyByReference(t *testing.T) {
|
||||||
keyID := "keyID"
|
keyID := "keyID"
|
||||||
prov := "acmeProv"
|
provID := "provID"
|
||||||
ref := "ref"
|
ref := "ref"
|
||||||
type test struct {
|
type test struct {
|
||||||
db nosql.DB
|
db nosql.DB
|
||||||
|
@ -933,7 +935,7 @@ func TestDB_GetExternalAccountKeyByReference(t *testing.T) {
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
dbeak := &dbExternalAccountKey{
|
dbeak := &dbExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -953,20 +955,20 @@ func TestDB_GetExternalAccountKeyByReference(t *testing.T) {
|
||||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||||
switch string(bucket) {
|
switch string(bucket) {
|
||||||
case string(externalAccountKeysByReferenceTable):
|
case string(externalAccountKeysByReferenceTable):
|
||||||
assert.Equals(t, string(key), ref)
|
assert.Equals(t, string(key), provID+"."+ref)
|
||||||
return dbrefBytes, nil
|
return dbrefBytes, nil
|
||||||
case string(externalAccountKeyTable):
|
case string(externalAccountKeyTable):
|
||||||
assert.Equals(t, string(key), keyID)
|
assert.Equals(t, string(key), keyID)
|
||||||
return b, nil
|
return b, nil
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
eak: &acme.ExternalAccountKey{
|
eak: &acme.ExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -988,7 +990,7 @@ func TestDB_GetExternalAccountKeyByReference(t *testing.T) {
|
||||||
db: &db.MockNoSQLDB{
|
db: &db.MockNoSQLDB{
|
||||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||||
assert.Equals(t, string(bucket), string(externalAccountKeysByReferenceTable))
|
assert.Equals(t, string(bucket), string(externalAccountKeysByReferenceTable))
|
||||||
assert.Equals(t, string(key), ref)
|
assert.Equals(t, string(key), provID+"."+ref)
|
||||||
return nil, nosqldb.ErrNotFound
|
return nil, nosqldb.ErrNotFound
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1001,7 +1003,7 @@ func TestDB_GetExternalAccountKeyByReference(t *testing.T) {
|
||||||
db: &db.MockNoSQLDB{
|
db: &db.MockNoSQLDB{
|
||||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||||
assert.Equals(t, string(bucket), string(externalAccountKeysByReferenceTable))
|
assert.Equals(t, string(bucket), string(externalAccountKeysByReferenceTable))
|
||||||
assert.Equals(t, string(key), ref)
|
assert.Equals(t, string(key), provID+"."+ref)
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1014,7 +1016,7 @@ func TestDB_GetExternalAccountKeyByReference(t *testing.T) {
|
||||||
db: &db.MockNoSQLDB{
|
db: &db.MockNoSQLDB{
|
||||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||||
assert.Equals(t, string(bucket), string(externalAccountKeysByReferenceTable))
|
assert.Equals(t, string(bucket), string(externalAccountKeysByReferenceTable))
|
||||||
assert.Equals(t, string(key), ref)
|
assert.Equals(t, string(key), provID+"."+ref)
|
||||||
return []byte{0}, nil
|
return []byte{0}, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1034,13 +1036,13 @@ func TestDB_GetExternalAccountKeyByReference(t *testing.T) {
|
||||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||||
switch string(bucket) {
|
switch string(bucket) {
|
||||||
case string(externalAccountKeysByReferenceTable):
|
case string(externalAccountKeysByReferenceTable):
|
||||||
assert.Equals(t, string(key), ref)
|
assert.Equals(t, string(key), provID+"."+ref)
|
||||||
return dbrefBytes, nil
|
return dbrefBytes, nil
|
||||||
case string(externalAccountKeyTable):
|
case string(externalAccountKeyTable):
|
||||||
assert.Equals(t, string(key), keyID)
|
assert.Equals(t, string(key), keyID)
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1053,7 +1055,7 @@ func TestDB_GetExternalAccountKeyByReference(t *testing.T) {
|
||||||
tc := run(t)
|
tc := run(t)
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
d := DB{db: tc.db}
|
d := DB{db: tc.db}
|
||||||
if eak, err := d.GetExternalAccountKeyByReference(context.Background(), prov, tc.ref); err != nil {
|
if eak, err := d.GetExternalAccountKeyByReference(context.Background(), provID, tc.ref); err != nil {
|
||||||
switch k := err.(type) {
|
switch k := err.(type) {
|
||||||
case *acme.Error:
|
case *acme.Error:
|
||||||
if assert.NotNil(t, tc.acmeErr) {
|
if assert.NotNil(t, tc.acmeErr) {
|
||||||
|
@ -1074,7 +1076,7 @@ func TestDB_GetExternalAccountKeyByReference(t *testing.T) {
|
||||||
assert.Equals(t, eak.BoundAt, tc.eak.BoundAt)
|
assert.Equals(t, eak.BoundAt, tc.eak.BoundAt)
|
||||||
assert.Equals(t, eak.CreatedAt, tc.eak.CreatedAt)
|
assert.Equals(t, eak.CreatedAt, tc.eak.CreatedAt)
|
||||||
assert.Equals(t, eak.KeyBytes, tc.eak.KeyBytes)
|
assert.Equals(t, eak.KeyBytes, tc.eak.KeyBytes)
|
||||||
assert.Equals(t, eak.Provisioner, tc.eak.Provisioner)
|
assert.Equals(t, eak.ProvisionerID, tc.eak.ProvisionerID)
|
||||||
assert.Equals(t, eak.Reference, tc.eak.Reference)
|
assert.Equals(t, eak.Reference, tc.eak.Reference)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1085,7 +1087,7 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
keyID1 := "keyID1"
|
keyID1 := "keyID1"
|
||||||
keyID2 := "keyID2"
|
keyID2 := "keyID2"
|
||||||
keyID3 := "keyID3"
|
keyID3 := "keyID3"
|
||||||
prov := "acmeProv"
|
provID := "provID"
|
||||||
ref := "ref"
|
ref := "ref"
|
||||||
type test struct {
|
type test struct {
|
||||||
db nosql.DB
|
db nosql.DB
|
||||||
|
@ -1098,7 +1100,7 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
dbeak1 := &dbExternalAccountKey{
|
dbeak1 := &dbExternalAccountKey{
|
||||||
ID: keyID1,
|
ID: keyID1,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1108,7 +1110,7 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
dbeak2 := &dbExternalAccountKey{
|
dbeak2 := &dbExternalAccountKey{
|
||||||
ID: keyID2,
|
ID: keyID2,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1118,7 +1120,7 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
dbeak3 := &dbExternalAccountKey{
|
dbeak3 := &dbExternalAccountKey{
|
||||||
ID: keyID3,
|
ID: keyID3,
|
||||||
Provisioner: "differentProvisioner",
|
ProvisionerID: "aDifferentProvID",
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1128,8 +1130,32 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
return test{
|
return test{
|
||||||
db: &db.MockNoSQLDB{
|
db: &db.MockNoSQLDB{
|
||||||
|
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||||
|
switch string(bucket) {
|
||||||
|
case string(externalAccountKeysByProvisionerIDTable):
|
||||||
|
keys := []string{keyID1, keyID2}
|
||||||
|
b, err := json.Marshal(keys)
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
return b, nil
|
||||||
|
case string(externalAccountKeyTable):
|
||||||
|
switch string(key) {
|
||||||
|
case keyID1:
|
||||||
|
return b1, nil
|
||||||
|
case keyID2:
|
||||||
|
return b2, nil
|
||||||
|
default:
|
||||||
|
assert.FatalError(t, errors.Errorf("unexpected key %s", string(key)))
|
||||||
|
return nil, errors.New("force")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
|
return nil, errors.New("force")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// TODO: remove the MList
|
||||||
MList: func(bucket []byte) ([]*nosqldb.Entry, error) {
|
MList: func(bucket []byte) ([]*nosqldb.Entry, error) {
|
||||||
assert.Equals(t, bucket, externalAccountKeyTable)
|
switch string(bucket) {
|
||||||
|
case string(externalAccountKeyTable):
|
||||||
return []*nosqldb.Entry{
|
return []*nosqldb.Entry{
|
||||||
{
|
{
|
||||||
Bucket: bucket,
|
Bucket: bucket,
|
||||||
|
@ -1147,12 +1173,27 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
Value: b3,
|
Value: b3,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
|
case string(externalAccountKeysByProvisionerIDTable):
|
||||||
|
keys := []string{keyID1, keyID2}
|
||||||
|
b, err := json.Marshal(keys)
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
return []*nosqldb.Entry{
|
||||||
|
{
|
||||||
|
Bucket: bucket,
|
||||||
|
Key: []byte(provID),
|
||||||
|
Value: b,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
default:
|
||||||
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
|
return nil, errors.New("force default")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
eaks: []*acme.ExternalAccountKey{
|
eaks: []*acme.ExternalAccountKey{
|
||||||
{
|
{
|
||||||
ID: keyID1,
|
ID: keyID1,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1160,7 +1201,7 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: keyID2,
|
ID: keyID2,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1169,33 +1210,36 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fail/db.List-error": func(t *testing.T) test {
|
"fail/db.Get-externalAccountKeysByProvisionerIDTable": func(t *testing.T) test {
|
||||||
return test{
|
return test{
|
||||||
db: &db.MockNoSQLDB{
|
db: &db.MockNoSQLDB{
|
||||||
MList: func(bucket []byte) ([]*nosqldb.Entry, error) {
|
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||||
assert.Equals(t, string(bucket), string(externalAccountKeyTable))
|
assert.Equals(t, string(bucket), string(externalAccountKeysByProvisionerIDTable))
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
err: errors.New("force"),
|
err: errors.New("error loading ACME EAB Key IDs for provisioner provID: force"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fail/unmarshal-error": func(t *testing.T) test {
|
"fail/db.getDBExternalAccountKey": func(t *testing.T) test {
|
||||||
return test{
|
return test{
|
||||||
db: &db.MockNoSQLDB{
|
db: &db.MockNoSQLDB{
|
||||||
MList: func(bucket []byte) ([]*nosqldb.Entry, error) {
|
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||||
assert.Equals(t, bucket, externalAccountKeyTable)
|
switch string(bucket) {
|
||||||
return []*nosqldb.Entry{
|
case string(externalAccountKeysByProvisionerIDTable):
|
||||||
{
|
keys := []string{keyID1, keyID2}
|
||||||
Bucket: bucket,
|
b, err := json.Marshal(keys)
|
||||||
Key: []byte(keyID1),
|
assert.FatalError(t, err)
|
||||||
Value: []byte("foo"),
|
return b, nil
|
||||||
},
|
case string(externalAccountKeyTable):
|
||||||
}, nil
|
return nil, errors.New("force")
|
||||||
|
default:
|
||||||
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
|
return nil, errors.New("force bucket")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
eaks: []*acme.ExternalAccountKey{},
|
err: errors.New("error retrieving ACME EAB Key for provisioner provID and keyID keyID1: error loading external account key keyID1: force"),
|
||||||
err: errors.Errorf("error unmarshaling external account key %s into ExternalAccountKey", keyID1),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1203,7 +1247,7 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
tc := run(t)
|
tc := run(t)
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
d := DB{db: tc.db}
|
d := DB{db: tc.db}
|
||||||
if eaks, err := d.GetExternalAccountKeys(context.Background(), prov); err != nil {
|
if eaks, err := d.GetExternalAccountKeys(context.Background(), provID); err != nil {
|
||||||
switch k := err.(type) {
|
switch k := err.(type) {
|
||||||
case *acme.Error:
|
case *acme.Error:
|
||||||
if assert.NotNil(t, tc.acmeErr) {
|
if assert.NotNil(t, tc.acmeErr) {
|
||||||
|
@ -1215,7 +1259,7 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if assert.NotNil(t, tc.err) {
|
if assert.NotNil(t, tc.err) {
|
||||||
assert.HasPrefix(t, err.Error(), tc.err.Error())
|
assert.Equals(t, tc.err.Error(), err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if assert.Nil(t, tc.err) {
|
} else if assert.Nil(t, tc.err) {
|
||||||
|
@ -1223,7 +1267,7 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
for i, eak := range eaks {
|
for i, eak := range eaks {
|
||||||
assert.Equals(t, eak.ID, tc.eaks[i].ID)
|
assert.Equals(t, eak.ID, tc.eaks[i].ID)
|
||||||
assert.Equals(t, eak.KeyBytes, tc.eaks[i].KeyBytes)
|
assert.Equals(t, eak.KeyBytes, tc.eaks[i].KeyBytes)
|
||||||
assert.Equals(t, eak.Provisioner, tc.eaks[i].Provisioner)
|
assert.Equals(t, eak.ProvisionerID, tc.eaks[i].ProvisionerID)
|
||||||
assert.Equals(t, eak.Reference, tc.eaks[i].Reference)
|
assert.Equals(t, eak.Reference, tc.eaks[i].Reference)
|
||||||
assert.Equals(t, eak.CreatedAt, tc.eaks[i].CreatedAt)
|
assert.Equals(t, eak.CreatedAt, tc.eaks[i].CreatedAt)
|
||||||
assert.Equals(t, eak.AccountID, tc.eaks[i].AccountID)
|
assert.Equals(t, eak.AccountID, tc.eaks[i].AccountID)
|
||||||
|
@ -1236,7 +1280,7 @@ func TestDB_GetExternalAccountKeys(t *testing.T) {
|
||||||
|
|
||||||
func TestDB_DeleteExternalAccountKey(t *testing.T) {
|
func TestDB_DeleteExternalAccountKey(t *testing.T) {
|
||||||
keyID := "keyID"
|
keyID := "keyID"
|
||||||
prov := "acmeProv"
|
provID := "provID"
|
||||||
ref := "ref"
|
ref := "ref"
|
||||||
type test struct {
|
type test struct {
|
||||||
db nosql.DB
|
db nosql.DB
|
||||||
|
@ -1248,7 +1292,7 @@ func TestDB_DeleteExternalAccountKey(t *testing.T) {
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
dbeak := &dbExternalAccountKey{
|
dbeak := &dbExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1267,27 +1311,46 @@ func TestDB_DeleteExternalAccountKey(t *testing.T) {
|
||||||
MGet: func(bucket, key []byte) ([]byte, error) {
|
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||||
switch string(bucket) {
|
switch string(bucket) {
|
||||||
case string(externalAccountKeysByReferenceTable):
|
case string(externalAccountKeysByReferenceTable):
|
||||||
assert.Equals(t, string(key), ref)
|
assert.Equals(t, string(key), provID+"."+ref)
|
||||||
return dbrefBytes, nil
|
return dbrefBytes, nil
|
||||||
case string(externalAccountKeyTable):
|
case string(externalAccountKeyTable):
|
||||||
assert.Equals(t, string(key), keyID)
|
assert.Equals(t, string(key), keyID)
|
||||||
return b, nil
|
return b, nil
|
||||||
|
case string(externalAccountKeysByProvisionerIDTable):
|
||||||
|
assert.Equals(t, provID, string(key))
|
||||||
|
b, err := json.Marshal([]string{keyID})
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
return b, nil
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force default")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MDel: func(bucket, key []byte) error {
|
MDel: func(bucket, key []byte) error {
|
||||||
switch string(bucket) {
|
switch string(bucket) {
|
||||||
case string(externalAccountKeysByReferenceTable):
|
case string(externalAccountKeysByReferenceTable):
|
||||||
assert.Equals(t, string(key), ref)
|
assert.Equals(t, string(key), provID+"."+ref)
|
||||||
return nil
|
return nil
|
||||||
case string(externalAccountKeyTable):
|
case string(externalAccountKeyTable):
|
||||||
assert.Equals(t, string(key), keyID)
|
assert.Equals(t, string(key), keyID)
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return errors.New("force")
|
return errors.New("force default")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MCmpAndSwap: func(bucket, key, old, new []byte) ([]byte, bool, error) {
|
||||||
|
fmt.Println(string(bucket))
|
||||||
|
switch string(bucket) {
|
||||||
|
case string(externalAccountKeysByReferenceTable):
|
||||||
|
assert.Equals(t, provID+"."+ref, string(key))
|
||||||
|
return nil, true, nil
|
||||||
|
case string(externalAccountKeysByProvisionerIDTable):
|
||||||
|
assert.Equals(t, provID, string(key))
|
||||||
|
return nil, true, nil
|
||||||
|
default:
|
||||||
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
|
return nil, false, errors.New("force default")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1302,14 +1365,14 @@ func TestDB_DeleteExternalAccountKey(t *testing.T) {
|
||||||
return nil, nosqldb.ErrNotFound
|
return nil, nosqldb.ErrNotFound
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
err: errors.New("error loading ACME EAB Key with Key ID keyID"),
|
err: errors.New("error loading ACME EAB Key with Key ID keyID: not found"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fail/non-matching-provisioner": func(t *testing.T) test {
|
"fail/non-matching-provisioner": func(t *testing.T) test {
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
dbeak := &dbExternalAccountKey{
|
dbeak := &dbExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: "differentProvisioner",
|
ProvisionerID: "aDifferentProvID",
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1325,14 +1388,14 @@ func TestDB_DeleteExternalAccountKey(t *testing.T) {
|
||||||
return b, nil
|
return b, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
err: errors.New("name of provisioner does not match provisioner for which the EAB key was created"),
|
err: errors.New("provisioner does not match provisioner for which the EAB key was created"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fail/delete-reference": func(t *testing.T) test {
|
"fail/delete-reference": func(t *testing.T) test {
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
dbeak := &dbExternalAccountKey{
|
dbeak := &dbExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1357,32 +1420,32 @@ func TestDB_DeleteExternalAccountKey(t *testing.T) {
|
||||||
assert.Equals(t, string(key), keyID)
|
assert.Equals(t, string(key), keyID)
|
||||||
return b, nil
|
return b, nil
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force default")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MDel: func(bucket, key []byte) error {
|
MDel: func(bucket, key []byte) error {
|
||||||
switch string(bucket) {
|
switch string(bucket) {
|
||||||
case string(externalAccountKeysByReferenceTable):
|
case string(externalAccountKeysByReferenceTable):
|
||||||
assert.Equals(t, string(key), ref)
|
assert.Equals(t, string(key), provID+"."+ref)
|
||||||
return errors.New("force")
|
return errors.New("force")
|
||||||
case string(externalAccountKeyTable):
|
case string(externalAccountKeyTable):
|
||||||
assert.Equals(t, string(key), keyID)
|
assert.Equals(t, string(key), keyID)
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return errors.New("force")
|
return errors.New("force default")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
err: errors.New("error deleting ACME EAB Key Reference with Key ID keyID and reference ref"),
|
err: errors.New("error deleting ACME EAB Key reference with Key ID keyID and reference ref: force"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fail/delete-eak": func(t *testing.T) test {
|
"fail/delete-eak": func(t *testing.T) test {
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
dbeak := &dbExternalAccountKey{
|
dbeak := &dbExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1407,25 +1470,25 @@ func TestDB_DeleteExternalAccountKey(t *testing.T) {
|
||||||
assert.Equals(t, string(key), keyID)
|
assert.Equals(t, string(key), keyID)
|
||||||
return b, nil
|
return b, nil
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MDel: func(bucket, key []byte) error {
|
MDel: func(bucket, key []byte) error {
|
||||||
switch string(bucket) {
|
switch string(bucket) {
|
||||||
case string(externalAccountKeysByReferenceTable):
|
case string(externalAccountKeysByReferenceTable):
|
||||||
assert.Equals(t, string(key), ref)
|
assert.Equals(t, string(key), provID+"."+ref)
|
||||||
return nil
|
return nil
|
||||||
case string(externalAccountKeyTable):
|
case string(externalAccountKeyTable):
|
||||||
assert.Equals(t, string(key), keyID)
|
assert.Equals(t, string(key), keyID)
|
||||||
return errors.New("force")
|
return errors.New("force")
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return errors.New("force")
|
return errors.New("force")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
err: errors.New("error deleting ACME EAB Key with Key ID keyID"),
|
err: errors.New("error deleting ACME EAB Key with Key ID keyID: force"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1433,7 +1496,7 @@ func TestDB_DeleteExternalAccountKey(t *testing.T) {
|
||||||
tc := run(t)
|
tc := run(t)
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
d := DB{db: tc.db}
|
d := DB{db: tc.db}
|
||||||
if err := d.DeleteExternalAccountKey(context.Background(), prov, keyID); err != nil {
|
if err := d.DeleteExternalAccountKey(context.Background(), provID, keyID); err != nil {
|
||||||
switch k := err.(type) {
|
switch k := err.(type) {
|
||||||
case *acme.Error:
|
case *acme.Error:
|
||||||
if assert.NotNil(t, tc.acmeErr) {
|
if assert.NotNil(t, tc.acmeErr) {
|
||||||
|
@ -1445,7 +1508,7 @@ func TestDB_DeleteExternalAccountKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if assert.NotNil(t, tc.err) {
|
if assert.NotNil(t, tc.err) {
|
||||||
assert.HasPrefix(t, err.Error(), tc.err.Error())
|
assert.Equals(t, err.Error(), tc.err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1457,7 +1520,7 @@ func TestDB_DeleteExternalAccountKey(t *testing.T) {
|
||||||
|
|
||||||
func TestDB_CreateExternalAccountKey(t *testing.T) {
|
func TestDB_CreateExternalAccountKey(t *testing.T) {
|
||||||
keyID := "keyID"
|
keyID := "keyID"
|
||||||
prov := "acmeProv"
|
provID := "provID"
|
||||||
ref := "ref"
|
ref := "ref"
|
||||||
type test struct {
|
type test struct {
|
||||||
db nosql.DB
|
db nosql.DB
|
||||||
|
@ -1474,29 +1537,37 @@ func TestDB_CreateExternalAccountKey(t *testing.T) {
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
eak := &acme.ExternalAccountKey{
|
eak := &acme.ExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: "ref",
|
Reference: "ref",
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
}
|
}
|
||||||
return test{
|
return test{
|
||||||
db: &db.MockNoSQLDB{
|
db: &db.MockNoSQLDB{
|
||||||
|
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||||
|
assert.Equals(t, string(bucket), string(externalAccountKeysByProvisionerIDTable))
|
||||||
|
assert.Equals(t, provID, string(key))
|
||||||
|
b, _ := json.Marshal([]string{})
|
||||||
|
return b, nil
|
||||||
|
},
|
||||||
MCmpAndSwap: func(bucket, key, old, nu []byte) ([]byte, bool, error) {
|
MCmpAndSwap: func(bucket, key, old, nu []byte) ([]byte, bool, error) {
|
||||||
|
|
||||||
switch string(bucket) {
|
switch string(bucket) {
|
||||||
|
case string(externalAccountKeysByProvisionerIDTable):
|
||||||
|
assert.Equals(t, provID, string(key))
|
||||||
|
return nu, true, nil
|
||||||
case string(externalAccountKeysByReferenceTable):
|
case string(externalAccountKeysByReferenceTable):
|
||||||
assert.Equals(t, string(key), ref)
|
assert.Equals(t, provID+"."+ref, string(key))
|
||||||
assert.Equals(t, old, nil)
|
assert.Equals(t, nil, old)
|
||||||
return nu, true, nil
|
return nu, true, nil
|
||||||
case string(externalAccountKeyTable):
|
case string(externalAccountKeyTable):
|
||||||
assert.Equals(t, old, nil)
|
assert.Equals(t, nil, old)
|
||||||
|
|
||||||
id = string(key)
|
id = string(key)
|
||||||
|
|
||||||
dbeak := new(dbExternalAccountKey)
|
dbeak := new(dbExternalAccountKey)
|
||||||
assert.FatalError(t, json.Unmarshal(nu, dbeak))
|
assert.FatalError(t, json.Unmarshal(nu, dbeak))
|
||||||
assert.Equals(t, string(key), dbeak.ID)
|
assert.Equals(t, string(key), dbeak.ID)
|
||||||
assert.Equals(t, eak.Provisioner, dbeak.Provisioner)
|
assert.Equals(t, eak.ProvisionerID, dbeak.ProvisionerID)
|
||||||
assert.Equals(t, eak.Reference, dbeak.Reference)
|
assert.Equals(t, eak.Reference, dbeak.Reference)
|
||||||
assert.Equals(t, 32, len(dbeak.KeyBytes))
|
assert.Equals(t, 32, len(dbeak.KeyBytes))
|
||||||
assert.False(t, dbeak.CreatedAt.IsZero())
|
assert.False(t, dbeak.CreatedAt.IsZero())
|
||||||
|
@ -1504,8 +1575,8 @@ func TestDB_CreateExternalAccountKey(t *testing.T) {
|
||||||
assert.True(t, dbeak.BoundAt.IsZero())
|
assert.True(t, dbeak.BoundAt.IsZero())
|
||||||
return nu, true, nil
|
return nu, true, nil
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, false, errors.New("force")
|
return nil, false, errors.New("force default")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1527,34 +1598,42 @@ func TestDB_CreateExternalAccountKey(t *testing.T) {
|
||||||
assert.Equals(t, old, nil)
|
assert.Equals(t, old, nil)
|
||||||
return nu, true, errors.New("force")
|
return nu, true, errors.New("force")
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, false, errors.New("force")
|
return nil, false, errors.New("force")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
err: errors.New("error saving acme external_account_key"),
|
err: errors.New("error saving acme external_account_key: force"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fail/externalAccountKeyReference-cmpAndSwap-error": func(t *testing.T) test {
|
"fail/externalAccountKeyReference-cmpAndSwap-error": func(t *testing.T) test {
|
||||||
return test{
|
return test{
|
||||||
db: &db.MockNoSQLDB{
|
db: &db.MockNoSQLDB{
|
||||||
|
MGet: func(bucket, key []byte) ([]byte, error) {
|
||||||
|
assert.Equals(t, string(bucket), string(externalAccountKeysByProvisionerIDTable))
|
||||||
|
assert.Equals(t, provID, string(key))
|
||||||
|
b, _ := json.Marshal([]string{})
|
||||||
|
return b, nil
|
||||||
|
},
|
||||||
MCmpAndSwap: func(bucket, key, old, nu []byte) ([]byte, bool, error) {
|
MCmpAndSwap: func(bucket, key, old, nu []byte) ([]byte, bool, error) {
|
||||||
|
|
||||||
switch string(bucket) {
|
switch string(bucket) {
|
||||||
|
case string(externalAccountKeysByProvisionerIDTable):
|
||||||
|
assert.Equals(t, provID, string(key))
|
||||||
|
return nu, true, nil
|
||||||
case string(externalAccountKeysByReferenceTable):
|
case string(externalAccountKeysByReferenceTable):
|
||||||
assert.Equals(t, string(key), ref)
|
assert.Equals(t, provID+"."+ref, string(key))
|
||||||
assert.Equals(t, old, nil)
|
assert.Equals(t, old, nil)
|
||||||
return nu, true, errors.New("force")
|
return nu, true, errors.New("force")
|
||||||
case string(externalAccountKeyTable):
|
case string(externalAccountKeyTable):
|
||||||
assert.Equals(t, old, nil)
|
assert.Equals(t, old, nil)
|
||||||
return nu, true, nil
|
return nu, true, nil
|
||||||
default:
|
default:
|
||||||
assert.FatalError(t, errors.Errorf("unrecognized bucket %s", string(bucket)))
|
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
|
||||||
return nil, false, errors.New("force")
|
return nil, false, errors.New("force")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
err: errors.New("error saving acme external_account_key"),
|
err: errors.New("error saving acme external_account_key_reference: force"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1562,14 +1641,15 @@ func TestDB_CreateExternalAccountKey(t *testing.T) {
|
||||||
tc := run(t)
|
tc := run(t)
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
d := DB{db: tc.db}
|
d := DB{db: tc.db}
|
||||||
eak, err := d.CreateExternalAccountKey(context.Background(), prov, ref)
|
eak, err := d.CreateExternalAccountKey(context.Background(), provID, ref)
|
||||||
|
fmt.Println(name, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if assert.NotNil(t, tc.err) {
|
if assert.NotNil(t, tc.err) {
|
||||||
assert.HasPrefix(t, err.Error(), tc.err.Error())
|
assert.Equals(t, err.Error(), tc.err.Error())
|
||||||
}
|
}
|
||||||
} else if assert.Nil(t, tc.err) {
|
} else if assert.Nil(t, tc.err) {
|
||||||
assert.Equals(t, *tc._id, eak.ID)
|
assert.Equals(t, *tc._id, eak.ID)
|
||||||
assert.Equals(t, prov, eak.Provisioner)
|
assert.Equals(t, provID, eak.ProvisionerID)
|
||||||
assert.Equals(t, ref, eak.Reference)
|
assert.Equals(t, ref, eak.Reference)
|
||||||
assert.Equals(t, "", eak.AccountID)
|
assert.Equals(t, "", eak.AccountID)
|
||||||
assert.False(t, eak.CreatedAt.IsZero())
|
assert.False(t, eak.CreatedAt.IsZero())
|
||||||
|
@ -1582,12 +1662,12 @@ func TestDB_CreateExternalAccountKey(t *testing.T) {
|
||||||
|
|
||||||
func TestDB_UpdateExternalAccountKey(t *testing.T) {
|
func TestDB_UpdateExternalAccountKey(t *testing.T) {
|
||||||
keyID := "keyID"
|
keyID := "keyID"
|
||||||
prov := "acmeProv"
|
provID := "provID"
|
||||||
ref := "ref"
|
ref := "ref"
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
dbeak := &dbExternalAccountKey{
|
dbeak := &dbExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1605,7 +1685,7 @@ func TestDB_UpdateExternalAccountKey(t *testing.T) {
|
||||||
"ok": func(t *testing.T) test {
|
"ok": func(t *testing.T) test {
|
||||||
eak := &acme.ExternalAccountKey{
|
eak := &acme.ExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: prov,
|
ProvisionerID: provID,
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1627,7 +1707,7 @@ func TestDB_UpdateExternalAccountKey(t *testing.T) {
|
||||||
dbNew := new(dbExternalAccountKey)
|
dbNew := new(dbExternalAccountKey)
|
||||||
assert.FatalError(t, json.Unmarshal(nu, dbNew))
|
assert.FatalError(t, json.Unmarshal(nu, dbNew))
|
||||||
assert.Equals(t, dbNew.ID, dbeak.ID)
|
assert.Equals(t, dbNew.ID, dbeak.ID)
|
||||||
assert.Equals(t, dbNew.Provisioner, dbeak.Provisioner)
|
assert.Equals(t, dbNew.ProvisionerID, dbeak.ProvisionerID)
|
||||||
assert.Equals(t, dbNew.Reference, dbeak.Reference)
|
assert.Equals(t, dbNew.Reference, dbeak.Reference)
|
||||||
assert.Equals(t, dbNew.AccountID, dbeak.AccountID)
|
assert.Equals(t, dbNew.AccountID, dbeak.AccountID)
|
||||||
assert.Equals(t, dbNew.CreatedAt, dbeak.CreatedAt)
|
assert.Equals(t, dbNew.CreatedAt, dbeak.CreatedAt)
|
||||||
|
@ -1641,7 +1721,7 @@ func TestDB_UpdateExternalAccountKey(t *testing.T) {
|
||||||
"fail/provisioner-mismatch": func(t *testing.T) test {
|
"fail/provisioner-mismatch": func(t *testing.T) test {
|
||||||
newDBEAK := &dbExternalAccountKey{
|
newDBEAK := &dbExternalAccountKey{
|
||||||
ID: keyID,
|
ID: keyID,
|
||||||
Provisioner: "differentProvisioner",
|
ProvisionerID: "aDifferentProvID",
|
||||||
Reference: ref,
|
Reference: ref,
|
||||||
AccountID: "",
|
AccountID: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
|
@ -1661,7 +1741,7 @@ func TestDB_UpdateExternalAccountKey(t *testing.T) {
|
||||||
return b, nil
|
return b, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
err: errors.New("name of provisioner does not match provisioner for which the EAB key was created"),
|
err: errors.New("provisioner does not match provisioner for which the EAB key was created"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fail/db.Get-error": func(t *testing.T) test {
|
"fail/db.Get-error": func(t *testing.T) test {
|
||||||
|
@ -1685,13 +1765,13 @@ func TestDB_UpdateExternalAccountKey(t *testing.T) {
|
||||||
tc := run(t)
|
tc := run(t)
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
d := DB{db: tc.db}
|
d := DB{db: tc.db}
|
||||||
if err := d.UpdateExternalAccountKey(context.Background(), prov, tc.eak); err != nil {
|
if err := d.UpdateExternalAccountKey(context.Background(), provID, tc.eak); err != nil {
|
||||||
if assert.NotNil(t, tc.err) {
|
if assert.NotNil(t, tc.err) {
|
||||||
assert.HasPrefix(t, err.Error(), tc.err.Error())
|
assert.HasPrefix(t, err.Error(), tc.err.Error())
|
||||||
}
|
}
|
||||||
} else if assert.Nil(t, tc.err) {
|
} else if assert.Nil(t, tc.err) {
|
||||||
assert.Equals(t, dbeak.ID, tc.eak.ID)
|
assert.Equals(t, dbeak.ID, tc.eak.ID)
|
||||||
assert.Equals(t, dbeak.Provisioner, tc.eak.Provisioner)
|
assert.Equals(t, dbeak.ProvisionerID, tc.eak.ProvisionerID)
|
||||||
assert.Equals(t, dbeak.Reference, tc.eak.Reference)
|
assert.Equals(t, dbeak.Reference, tc.eak.Reference)
|
||||||
assert.Equals(t, dbeak.AccountID, tc.eak.AccountID)
|
assert.Equals(t, dbeak.AccountID, tc.eak.AccountID)
|
||||||
assert.Equals(t, dbeak.CreatedAt, tc.eak.CreatedAt)
|
assert.Equals(t, dbeak.CreatedAt, tc.eak.CreatedAt)
|
||||||
|
|
|
@ -22,6 +22,7 @@ var (
|
||||||
certBySerialTable = []byte("acme_serial_certs_index")
|
certBySerialTable = []byte("acme_serial_certs_index")
|
||||||
externalAccountKeyTable = []byte("acme_external_account_keys")
|
externalAccountKeyTable = []byte("acme_external_account_keys")
|
||||||
externalAccountKeysByReferenceTable = []byte("acme_external_account_key_reference_index")
|
externalAccountKeysByReferenceTable = []byte("acme_external_account_key_reference_index")
|
||||||
|
externalAccountKeysByProvisionerIDTable = []byte("acme_external_account_keyID_provisionerID_index")
|
||||||
)
|
)
|
||||||
|
|
||||||
// DB is a struct that implements the AcmeDB interface.
|
// DB is a struct that implements the AcmeDB interface.
|
||||||
|
@ -33,7 +34,8 @@ type DB struct {
|
||||||
func New(db nosqlDB.DB) (*DB, error) {
|
func New(db nosqlDB.DB) (*DB, error) {
|
||||||
tables := [][]byte{accountTable, accountByKeyIDTable, authzTable,
|
tables := [][]byte{accountTable, accountByKeyIDTable, authzTable,
|
||||||
challengeTable, nonceTable, orderTable, ordersByAccountIDTable,
|
challengeTable, nonceTable, orderTable, ordersByAccountIDTable,
|
||||||
certTable, certBySerialTable, externalAccountKeyTable, externalAccountKeysByReferenceTable,
|
certTable, certBySerialTable, externalAccountKeyTable,
|
||||||
|
externalAccountKeysByReferenceTable, externalAccountKeysByProvisionerIDTable,
|
||||||
}
|
}
|
||||||
for _, b := range tables {
|
for _, b := range tables {
|
||||||
if err := db.CreateTable(b); err != nil {
|
if err := db.CreateTable(b); err != nil {
|
||||||
|
|
|
@ -15,6 +15,11 @@ import (
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// provisionerContextKey provisioner key
|
||||||
|
provisionerContextKey = ContextKey("provisioner")
|
||||||
|
)
|
||||||
|
|
||||||
// CreateExternalAccountKeyRequest is the type for POST /admin/acme/eab requests
|
// CreateExternalAccountKeyRequest is the type for POST /admin/acme/eab requests
|
||||||
type CreateExternalAccountKeyRequest struct {
|
type CreateExternalAccountKeyRequest struct {
|
||||||
Reference string `json:"reference"`
|
Reference string `json:"reference"`
|
||||||
|
@ -37,47 +42,63 @@ type GetExternalAccountKeysResponse struct {
|
||||||
// before serving requests that act on ACME EAB credentials.
|
// before serving requests that act on ACME EAB credentials.
|
||||||
func (h *Handler) requireEABEnabled(next nextHTTP) nextHTTP {
|
func (h *Handler) requireEABEnabled(next nextHTTP) nextHTTP {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
prov := chi.URLParam(r, "prov")
|
ctx := r.Context()
|
||||||
eabEnabled, err := h.provisionerHasEABEnabled(r.Context(), prov)
|
provName := chi.URLParam(r, "prov")
|
||||||
|
eabEnabled, prov, err := h.provisionerHasEABEnabled(ctx, provName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.WriteError(w, err)
|
api.WriteError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !eabEnabled {
|
if !eabEnabled {
|
||||||
api.WriteError(w, admin.NewError(admin.ErrorBadRequestType, "ACME EAB not enabled for provisioner %s", prov))
|
api.WriteError(w, admin.NewError(admin.ErrorBadRequestType, "ACME EAB not enabled for provisioner %s", prov.GetName()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
next(w, r)
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
|
next(w, r.WithContext(ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// provisionerHasEABEnabled determines if the "requireEAB" setting for an ACME
|
// provisionerHasEABEnabled determines if the "requireEAB" setting for an ACME
|
||||||
// provisioner is set to true and thus has EAB enabled.
|
// provisioner is set to true and thus has EAB enabled.
|
||||||
func (h *Handler) provisionerHasEABEnabled(ctx context.Context, provisionerName string) (bool, error) {
|
func (h *Handler) provisionerHasEABEnabled(ctx context.Context, provisionerName string) (bool, *linkedca.Provisioner, error) {
|
||||||
var (
|
var (
|
||||||
p provisioner.Interface
|
p provisioner.Interface
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if p, err = h.auth.LoadProvisionerByName(provisionerName); err != nil {
|
if p, err = h.auth.LoadProvisionerByName(provisionerName); err != nil {
|
||||||
return false, admin.WrapErrorISE(err, "error loading provisioner %s", provisionerName)
|
return false, nil, admin.WrapErrorISE(err, "error loading provisioner %s", provisionerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
prov, err := h.db.GetProvisioner(ctx, p.GetID())
|
prov, err := h.db.GetProvisioner(ctx, p.GetID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, admin.WrapErrorISE(err, "error getting provisioner with ID: %s", p.GetID())
|
return false, nil, admin.WrapErrorISE(err, "error getting provisioner with ID: %s", p.GetID())
|
||||||
}
|
}
|
||||||
|
|
||||||
details := prov.GetDetails()
|
details := prov.GetDetails()
|
||||||
if details == nil {
|
if details == nil {
|
||||||
return false, admin.NewErrorISE("error getting details for provisioner with ID: %s", p.GetID())
|
return false, nil, admin.NewErrorISE("error getting details for provisioner with ID: %s", p.GetID())
|
||||||
}
|
}
|
||||||
|
|
||||||
acmeProvisioner := details.GetACME()
|
acmeProvisioner := details.GetACME()
|
||||||
if acmeProvisioner == nil {
|
if acmeProvisioner == nil {
|
||||||
return false, admin.NewErrorISE("error getting ACME details for provisioner with ID: %s", p.GetID())
|
return false, nil, admin.NewErrorISE("error getting ACME details for provisioner with ID: %s", p.GetID())
|
||||||
}
|
}
|
||||||
|
|
||||||
return acmeProvisioner.GetRequireEab(), nil
|
return acmeProvisioner.GetRequireEab(), prov, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// provisionerFromContext searches the context for a provisioner. Returns the
|
||||||
|
// provisioner or an error.
|
||||||
|
func provisionerFromContext(ctx context.Context) (*linkedca.Provisioner, error) {
|
||||||
|
val := ctx.Value(provisionerContextKey)
|
||||||
|
if val == nil {
|
||||||
|
return nil, admin.NewErrorISE("provisioner expected in request context")
|
||||||
|
}
|
||||||
|
pval, ok := val.(*linkedca.Provisioner)
|
||||||
|
if !ok || pval == nil {
|
||||||
|
return nil, admin.NewErrorISE("provisioner in context is not a linkedca.Provisioner")
|
||||||
|
}
|
||||||
|
return pval, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateExternalAccountKey creates a new External Account Binding key
|
// CreateExternalAccountKey creates a new External Account Binding key
|
||||||
|
@ -93,12 +114,17 @@ func (h *Handler) CreateExternalAccountKey(w http.ResponseWriter, r *http.Reques
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
prov := chi.URLParam(r, "prov")
|
ctx := r.Context()
|
||||||
reference := body.Reference
|
prov, err := provisionerFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
api.WriteError(w, admin.WrapErrorISE(err, "error getting provisioner from context"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// check if a key with the reference does not exist (only when a reference was in the request)
|
// check if a key with the reference does not exist (only when a reference was in the request)
|
||||||
|
reference := body.Reference
|
||||||
if reference != "" {
|
if reference != "" {
|
||||||
k, err := h.acmeDB.GetExternalAccountKeyByReference(r.Context(), prov, reference)
|
k, err := h.acmeDB.GetExternalAccountKeyByReference(ctx, prov.GetId(), reference)
|
||||||
// retrieving an EAB key from DB results in an error if it doesn't exist, which is what we're looking for,
|
// retrieving an EAB key from DB results in an error if it doesn't exist, which is what we're looking for,
|
||||||
// but other errors can also happen. Return early if that happens; continuing if it was acme.ErrNotFound.
|
// but other errors can also happen. Return early if that happens; continuing if it was acme.ErrNotFound.
|
||||||
if shouldWriteError := err != nil && !errors.Is(err, acme.ErrNotFound); shouldWriteError {
|
if shouldWriteError := err != nil && !errors.Is(err, acme.ErrNotFound); shouldWriteError {
|
||||||
|
@ -107,7 +133,7 @@ func (h *Handler) CreateExternalAccountKey(w http.ResponseWriter, r *http.Reques
|
||||||
}
|
}
|
||||||
// if a key was found, return HTTP 409 conflict
|
// if a key was found, return HTTP 409 conflict
|
||||||
if k != nil {
|
if k != nil {
|
||||||
err := admin.NewError(admin.ErrorBadRequestType, "an ACME EAB key for provisioner %s with reference %s already exists", prov, reference)
|
err := admin.NewError(admin.ErrorBadRequestType, "an ACME EAB key for provisioner '%s' with reference '%s' already exists", prov.GetName(), reference)
|
||||||
err.Status = 409
|
err.Status = 409
|
||||||
api.WriteError(w, err)
|
api.WriteError(w, err)
|
||||||
return
|
return
|
||||||
|
@ -115,9 +141,9 @@ func (h *Handler) CreateExternalAccountKey(w http.ResponseWriter, r *http.Reques
|
||||||
// continue execution if no key was found for the reference
|
// continue execution if no key was found for the reference
|
||||||
}
|
}
|
||||||
|
|
||||||
eak, err := h.acmeDB.CreateExternalAccountKey(r.Context(), prov, reference)
|
eak, err := h.acmeDB.CreateExternalAccountKey(ctx, prov.GetId(), reference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("error creating ACME EAB key for provisioner '%s'", prov)
|
msg := fmt.Sprintf("error creating ACME EAB key for provisioner '%s'", prov.GetName())
|
||||||
if reference != "" {
|
if reference != "" {
|
||||||
msg += fmt.Sprintf(" and reference '%s'", reference)
|
msg += fmt.Sprintf(" and reference '%s'", reference)
|
||||||
}
|
}
|
||||||
|
@ -128,7 +154,7 @@ func (h *Handler) CreateExternalAccountKey(w http.ResponseWriter, r *http.Reques
|
||||||
response := &linkedca.EABKey{
|
response := &linkedca.EABKey{
|
||||||
Id: eak.ID,
|
Id: eak.ID,
|
||||||
HmacKey: eak.KeyBytes,
|
HmacKey: eak.KeyBytes,
|
||||||
Provisioner: eak.Provisioner,
|
Provisioner: prov.GetName(),
|
||||||
Reference: eak.Reference,
|
Reference: eak.Reference,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,10 +163,17 @@ func (h *Handler) CreateExternalAccountKey(w http.ResponseWriter, r *http.Reques
|
||||||
|
|
||||||
// DeleteExternalAccountKey deletes an ACME External Account Key.
|
// DeleteExternalAccountKey deletes an ACME External Account Key.
|
||||||
func (h *Handler) DeleteExternalAccountKey(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) DeleteExternalAccountKey(w http.ResponseWriter, r *http.Request) {
|
||||||
prov := chi.URLParam(r, "prov")
|
|
||||||
keyID := chi.URLParam(r, "id")
|
keyID := chi.URLParam(r, "id")
|
||||||
|
|
||||||
if err := h.acmeDB.DeleteExternalAccountKey(r.Context(), prov, keyID); err != nil {
|
ctx := r.Context()
|
||||||
|
prov, err := provisionerFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
api.WriteError(w, admin.WrapErrorISE(err, "error getting provisioner from context"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.acmeDB.DeleteExternalAccountKey(ctx, prov.GetId(), keyID); err != nil {
|
||||||
api.WriteError(w, admin.WrapErrorISE(err, "error deleting ACME EAB Key '%s'", keyID))
|
api.WriteError(w, admin.WrapErrorISE(err, "error deleting ACME EAB Key '%s'", keyID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -152,8 +185,6 @@ func (h *Handler) DeleteExternalAccountKey(w http.ResponseWriter, r *http.Reques
|
||||||
// only the ExternalAccountKey with that reference is returned. Otherwise all
|
// only the ExternalAccountKey with that reference is returned. Otherwise all
|
||||||
// ExternalAccountKeys in the system for a specific provisioner are returned.
|
// ExternalAccountKeys in the system for a specific provisioner are returned.
|
||||||
func (h *Handler) GetExternalAccountKeys(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) GetExternalAccountKeys(w http.ResponseWriter, r *http.Request) {
|
||||||
prov := chi.URLParam(r, "prov")
|
|
||||||
reference := chi.URLParam(r, "ref")
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
key *acme.ExternalAccountKey
|
key *acme.ExternalAccountKey
|
||||||
|
@ -161,8 +192,16 @@ func (h *Handler) GetExternalAccountKeys(w http.ResponseWriter, r *http.Request)
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ctx := r.Context()
|
||||||
|
prov, err := provisionerFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
api.WriteError(w, admin.WrapErrorISE(err, "error getting provisioner from context"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reference := chi.URLParam(r, "ref")
|
||||||
if reference != "" {
|
if reference != "" {
|
||||||
if key, err = h.acmeDB.GetExternalAccountKeyByReference(r.Context(), prov, reference); err != nil {
|
if key, err = h.acmeDB.GetExternalAccountKeyByReference(ctx, prov.GetId(), reference); err != nil {
|
||||||
api.WriteError(w, admin.WrapErrorISE(err, "error retrieving external account key with reference '%s'", reference))
|
api.WriteError(w, admin.WrapErrorISE(err, "error retrieving external account key with reference '%s'", reference))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -170,18 +209,19 @@ func (h *Handler) GetExternalAccountKeys(w http.ResponseWriter, r *http.Request)
|
||||||
keys = []*acme.ExternalAccountKey{key}
|
keys = []*acme.ExternalAccountKey{key}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if keys, err = h.acmeDB.GetExternalAccountKeys(r.Context(), prov); err != nil {
|
if keys, err = h.acmeDB.GetExternalAccountKeys(ctx, prov.GetId()); err != nil {
|
||||||
api.WriteError(w, admin.WrapErrorISE(err, "error retrieving external account keys"))
|
api.WriteError(w, admin.WrapErrorISE(err, "error retrieving external account keys"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
provisionerName := prov.GetName()
|
||||||
eaks := make([]*linkedca.EABKey, len(keys))
|
eaks := make([]*linkedca.EABKey, len(keys))
|
||||||
for i, k := range keys {
|
for i, k := range keys {
|
||||||
eaks[i] = &linkedca.EABKey{
|
eaks[i] = &linkedca.EABKey{
|
||||||
Id: k.ID,
|
Id: k.ID,
|
||||||
HmacKey: []byte{},
|
HmacKey: []byte{},
|
||||||
Provisioner: k.Provisioner,
|
Provisioner: provisionerName,
|
||||||
Reference: k.Reference,
|
Reference: k.Reference,
|
||||||
Account: k.AccountID,
|
Account: k.AccountID,
|
||||||
CreatedAt: timestamppb.New(k.CreatedAt),
|
CreatedAt: timestamppb.New(k.CreatedAt),
|
||||||
|
|
|
@ -368,12 +368,13 @@ func TestHandler_provisionerHasEABEnabled(t *testing.T) {
|
||||||
auth: tc.auth,
|
auth: tc.auth,
|
||||||
acmeDB: nil,
|
acmeDB: nil,
|
||||||
}
|
}
|
||||||
got, err := h.provisionerHasEABEnabled(context.TODO(), tc.provisionerName)
|
got, prov, err := h.provisionerHasEABEnabled(context.TODO(), tc.provisionerName)
|
||||||
if (err != nil) != (tc.err != nil) {
|
if (err != nil) != (tc.err != nil) {
|
||||||
t.Errorf("Handler.provisionerHasEABEnabled() error = %v, want err %v", err, tc.err)
|
t.Errorf("Handler.provisionerHasEABEnabled() error = %v, want err %v", err, tc.err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if tc.err != nil {
|
if tc.err != nil {
|
||||||
|
assert.Type(t, &linkedca.Provisioner{}, prov)
|
||||||
assert.Type(t, &admin.Error{}, err)
|
assert.Type(t, &admin.Error{}, err)
|
||||||
adminError, _ := err.(*admin.Error)
|
adminError, _ := err.(*admin.Error)
|
||||||
assert.Equals(t, tc.err.Type, adminError.Type)
|
assert.Equals(t, tc.err.Type, adminError.Type)
|
||||||
|
@ -434,6 +435,10 @@ func TestCreateExternalAccountKeyRequest_Validate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
||||||
|
prov := &linkedca.Provisioner{
|
||||||
|
Id: "provID",
|
||||||
|
Name: "provName",
|
||||||
|
}
|
||||||
type test struct {
|
type test struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
db acme.DB
|
db acme.DB
|
||||||
|
@ -487,14 +492,15 @@ func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
||||||
chiCtx := chi.NewRouteContext()
|
chiCtx := chi.NewRouteContext()
|
||||||
chiCtx.URLParams.Add("prov", "provName")
|
chiCtx.URLParams.Add("prov", "provName")
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
req := CreateExternalAccountKeyRequest{
|
req := CreateExternalAccountKeyRequest{
|
||||||
Reference: "an-external-key-reference",
|
Reference: "an-external-key-reference",
|
||||||
}
|
}
|
||||||
body, err := json.Marshal(req)
|
body, err := json.Marshal(req)
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "an-external-key-reference", reference)
|
assert.Equals(t, "an-external-key-reference", reference)
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
},
|
},
|
||||||
|
@ -517,19 +523,20 @@ func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
||||||
chiCtx := chi.NewRouteContext()
|
chiCtx := chi.NewRouteContext()
|
||||||
chiCtx.URLParams.Add("prov", "provName")
|
chiCtx.URLParams.Add("prov", "provName")
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
req := CreateExternalAccountKeyRequest{
|
req := CreateExternalAccountKeyRequest{
|
||||||
Reference: "an-external-key-reference",
|
Reference: "an-external-key-reference",
|
||||||
}
|
}
|
||||||
body, err := json.Marshal(req)
|
body, err := json.Marshal(req)
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "an-external-key-reference", reference)
|
assert.Equals(t, "an-external-key-reference", reference)
|
||||||
past := time.Now().Add(-24 * time.Hour)
|
past := time.Now().Add(-24 * time.Hour)
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: "provName",
|
ProvisionerID: "provID",
|
||||||
Reference: "an-external-key-reference",
|
Reference: "an-external-key-reference",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: past,
|
CreatedAt: past,
|
||||||
|
@ -546,7 +553,7 @@ func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
||||||
Type: admin.ErrorBadRequestType.String(),
|
Type: admin.ErrorBadRequestType.String(),
|
||||||
Status: 409,
|
Status: 409,
|
||||||
Detail: "bad request",
|
Detail: "bad request",
|
||||||
Message: "an ACME EAB key for provisioner provName with reference an-external-key-reference already exists",
|
Message: "an ACME EAB key for provisioner 'provName' with reference 'an-external-key-reference' already exists",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -554,14 +561,15 @@ func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
||||||
chiCtx := chi.NewRouteContext()
|
chiCtx := chi.NewRouteContext()
|
||||||
chiCtx.URLParams.Add("prov", "provName")
|
chiCtx.URLParams.Add("prov", "provName")
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
req := CreateExternalAccountKeyRequest{
|
req := CreateExternalAccountKeyRequest{
|
||||||
Reference: "",
|
Reference: "",
|
||||||
}
|
}
|
||||||
body, err := json.Marshal(req)
|
body, err := json.Marshal(req)
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockCreateExternalAccountKey: func(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
MockCreateExternalAccountKey: func(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "", reference)
|
assert.Equals(t, "", reference)
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
},
|
},
|
||||||
|
@ -583,19 +591,20 @@ func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
||||||
chiCtx := chi.NewRouteContext()
|
chiCtx := chi.NewRouteContext()
|
||||||
chiCtx.URLParams.Add("prov", "provName")
|
chiCtx.URLParams.Add("prov", "provName")
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
req := CreateExternalAccountKeyRequest{
|
req := CreateExternalAccountKeyRequest{
|
||||||
Reference: "an-external-key-reference",
|
Reference: "an-external-key-reference",
|
||||||
}
|
}
|
||||||
body, err := json.Marshal(req)
|
body, err := json.Marshal(req)
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "an-external-key-reference", reference)
|
assert.Equals(t, "an-external-key-reference", reference)
|
||||||
return nil, acme.ErrNotFound // simulating not found; skipping 409 conflict
|
return nil, acme.ErrNotFound // simulating not found; skipping 409 conflict
|
||||||
},
|
},
|
||||||
MockCreateExternalAccountKey: func(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
MockCreateExternalAccountKey: func(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "an-external-key-reference", reference)
|
assert.Equals(t, "an-external-key-reference", reference)
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
},
|
},
|
||||||
|
@ -617,6 +626,7 @@ func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
||||||
chiCtx := chi.NewRouteContext()
|
chiCtx := chi.NewRouteContext()
|
||||||
chiCtx.URLParams.Add("prov", "provName")
|
chiCtx.URLParams.Add("prov", "provName")
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
req := CreateExternalAccountKeyRequest{
|
req := CreateExternalAccountKeyRequest{
|
||||||
Reference: "",
|
Reference: "",
|
||||||
}
|
}
|
||||||
|
@ -624,12 +634,12 @@ func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockCreateExternalAccountKey: func(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
MockCreateExternalAccountKey: func(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "", reference)
|
assert.Equals(t, "", reference)
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: "provName",
|
ProvisionerID: "provID",
|
||||||
Reference: "",
|
Reference: "",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
|
@ -653,6 +663,7 @@ func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
||||||
chiCtx := chi.NewRouteContext()
|
chiCtx := chi.NewRouteContext()
|
||||||
chiCtx.URLParams.Add("prov", "provName")
|
chiCtx.URLParams.Add("prov", "provName")
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
req := CreateExternalAccountKeyRequest{
|
req := CreateExternalAccountKeyRequest{
|
||||||
Reference: "an-external-key-reference",
|
Reference: "an-external-key-reference",
|
||||||
}
|
}
|
||||||
|
@ -660,17 +671,17 @@ func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "an-external-key-reference", reference)
|
assert.Equals(t, "an-external-key-reference", reference)
|
||||||
return nil, acme.ErrNotFound // simulating not found; skipping 409 conflict
|
return nil, acme.ErrNotFound // simulating not found; skipping 409 conflict
|
||||||
},
|
},
|
||||||
MockCreateExternalAccountKey: func(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
MockCreateExternalAccountKey: func(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "an-external-key-reference", reference)
|
assert.Equals(t, "an-external-key-reference", reference)
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: "provName",
|
ProvisionerID: "provID",
|
||||||
Reference: "an-external-key-reference",
|
Reference: "an-external-key-reference",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
|
@ -737,6 +748,10 @@ func TestHandler_CreateExternalAccountKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandler_DeleteExternalAccountKey(t *testing.T) {
|
func TestHandler_DeleteExternalAccountKey(t *testing.T) {
|
||||||
|
prov := &linkedca.Provisioner{
|
||||||
|
Id: "provID",
|
||||||
|
Name: "provName",
|
||||||
|
}
|
||||||
type test struct {
|
type test struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
db acme.DB
|
db acme.DB
|
||||||
|
@ -749,9 +764,10 @@ func TestHandler_DeleteExternalAccountKey(t *testing.T) {
|
||||||
chiCtx.URLParams.Add("prov", "provName")
|
chiCtx.URLParams.Add("prov", "provName")
|
||||||
chiCtx.URLParams.Add("id", "keyID")
|
chiCtx.URLParams.Add("id", "keyID")
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockDeleteExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) error {
|
MockDeleteExternalAccountKey: func(ctx context.Context, provisionerID, keyID string) error {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "keyID", keyID)
|
assert.Equals(t, "keyID", keyID)
|
||||||
return errors.New("force")
|
return errors.New("force")
|
||||||
},
|
},
|
||||||
|
@ -773,9 +789,10 @@ func TestHandler_DeleteExternalAccountKey(t *testing.T) {
|
||||||
chiCtx.URLParams.Add("prov", "provName")
|
chiCtx.URLParams.Add("prov", "provName")
|
||||||
chiCtx.URLParams.Add("id", "keyID")
|
chiCtx.URLParams.Add("id", "keyID")
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockDeleteExternalAccountKey: func(ctx context.Context, provisionerName, keyID string) error {
|
MockDeleteExternalAccountKey: func(ctx context.Context, provisionerID, keyID string) error {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "keyID", keyID)
|
assert.Equals(t, "keyID", keyID)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
@ -831,6 +848,10 @@ func TestHandler_DeleteExternalAccountKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandler_GetExternalAccountKeys(t *testing.T) {
|
func TestHandler_GetExternalAccountKeys(t *testing.T) {
|
||||||
|
prov := &linkedca.Provisioner{
|
||||||
|
Id: "provID",
|
||||||
|
Name: "provName",
|
||||||
|
}
|
||||||
type test struct {
|
type test struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
db acme.DB
|
db acme.DB
|
||||||
|
@ -846,9 +867,10 @@ func TestHandler_GetExternalAccountKeys(t *testing.T) {
|
||||||
chiCtx.URLParams.Add("ref", "an-external-key-reference")
|
chiCtx.URLParams.Add("ref", "an-external-key-reference")
|
||||||
req := httptest.NewRequest("GET", "/foo", nil)
|
req := httptest.NewRequest("GET", "/foo", nil)
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "an-external-key-reference", reference)
|
assert.Equals(t, "an-external-key-reference", reference)
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
},
|
},
|
||||||
|
@ -871,9 +893,10 @@ func TestHandler_GetExternalAccountKeys(t *testing.T) {
|
||||||
chiCtx.URLParams.Add("prov", "provName")
|
chiCtx.URLParams.Add("prov", "provName")
|
||||||
req := httptest.NewRequest("GET", "/foo", nil)
|
req := httptest.NewRequest("GET", "/foo", nil)
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockGetExternalAccountKeys: func(ctx context.Context, provisionerName string) ([]*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKeys: func(ctx context.Context, provisionerID string) ([]*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -896,9 +919,10 @@ func TestHandler_GetExternalAccountKeys(t *testing.T) {
|
||||||
chiCtx.URLParams.Add("ref", "an-external-key-reference")
|
chiCtx.URLParams.Add("ref", "an-external-key-reference")
|
||||||
req := httptest.NewRequest("GET", "/foo", nil)
|
req := httptest.NewRequest("GET", "/foo", nil)
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "an-external-key-reference", reference)
|
assert.Equals(t, "an-external-key-reference", reference)
|
||||||
return nil, nil // returning nil; no key found
|
return nil, nil // returning nil; no key found
|
||||||
},
|
},
|
||||||
|
@ -920,15 +944,16 @@ func TestHandler_GetExternalAccountKeys(t *testing.T) {
|
||||||
chiCtx.URLParams.Add("ref", "an-external-key-reference")
|
chiCtx.URLParams.Add("ref", "an-external-key-reference")
|
||||||
req := httptest.NewRequest("GET", "/foo", nil)
|
req := httptest.NewRequest("GET", "/foo", nil)
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
createdAt := time.Now().Add(-24 * time.Hour)
|
createdAt := time.Now().Add(-24 * time.Hour)
|
||||||
var boundAt time.Time
|
var boundAt time.Time
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerName, reference string) (*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKeyByReference: func(ctx context.Context, provisionerID, reference string) (*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
assert.Equals(t, "an-external-key-reference", reference)
|
assert.Equals(t, "an-external-key-reference", reference)
|
||||||
return &acme.ExternalAccountKey{
|
return &acme.ExternalAccountKey{
|
||||||
ID: "eakID",
|
ID: "eakID",
|
||||||
Provisioner: "provName",
|
ProvisionerID: "provID",
|
||||||
Reference: "an-external-key-reference",
|
Reference: "an-external-key-reference",
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -958,102 +983,31 @@ func TestHandler_GetExternalAccountKeys(t *testing.T) {
|
||||||
chiCtx.URLParams.Add("prov", "provName")
|
chiCtx.URLParams.Add("prov", "provName")
|
||||||
req := httptest.NewRequest("GET", "/foo", nil)
|
req := httptest.NewRequest("GET", "/foo", nil)
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
||||||
|
ctx = context.WithValue(ctx, provisionerContextKey, prov)
|
||||||
createdAt := time.Now().Add(-24 * time.Hour)
|
createdAt := time.Now().Add(-24 * time.Hour)
|
||||||
var boundAt time.Time
|
var boundAt time.Time
|
||||||
boundAtSet := time.Now().Add(-12 * time.Hour)
|
boundAtSet := time.Now().Add(-12 * time.Hour)
|
||||||
db := &acme.MockDB{
|
db := &acme.MockDB{
|
||||||
MockGetExternalAccountKeys: func(ctx context.Context, provisionerName string) ([]*acme.ExternalAccountKey, error) {
|
MockGetExternalAccountKeys: func(ctx context.Context, provisionerID string) ([]*acme.ExternalAccountKey, error) {
|
||||||
assert.Equals(t, "provName", provisionerName)
|
assert.Equals(t, "provID", provisionerID)
|
||||||
return []*acme.ExternalAccountKey{
|
return []*acme.ExternalAccountKey{
|
||||||
{
|
{
|
||||||
ID: "eakID1",
|
ID: "eakID1",
|
||||||
Provisioner: "provName",
|
ProvisionerID: "provID",
|
||||||
Reference: "some-external-key-reference",
|
Reference: "some-external-key-reference",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "eakID2",
|
ID: "eakID2",
|
||||||
Provisioner: "provName",
|
ProvisionerID: "provID",
|
||||||
Reference: "some-other-external-key-reference",
|
Reference: "some-other-external-key-reference",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: createdAt.Add(1 * time.Hour),
|
CreatedAt: createdAt.Add(1 * time.Hour),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "eakID3",
|
ID: "eakID3",
|
||||||
Provisioner: "provName",
|
ProvisionerID: "provID",
|
||||||
Reference: "another-external-key-reference",
|
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
|
||||||
CreatedAt: createdAt,
|
|
||||||
BoundAt: boundAtSet,
|
|
||||||
AccountID: "accountID",
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return test{
|
|
||||||
ctx: ctx,
|
|
||||||
statusCode: 200,
|
|
||||||
req: req,
|
|
||||||
resp: GetExternalAccountKeysResponse{
|
|
||||||
EAKs: []*linkedca.EABKey{
|
|
||||||
{
|
|
||||||
Id: "eakID1",
|
|
||||||
Provisioner: "provName",
|
|
||||||
Reference: "some-external-key-reference",
|
|
||||||
CreatedAt: timestamppb.New(createdAt),
|
|
||||||
BoundAt: timestamppb.New(boundAt),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Id: "eakID2",
|
|
||||||
Provisioner: "provName",
|
|
||||||
Reference: "some-other-external-key-reference",
|
|
||||||
CreatedAt: timestamppb.New(createdAt.Add(1 * time.Hour)),
|
|
||||||
BoundAt: timestamppb.New(boundAt),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Id: "eakID3",
|
|
||||||
Provisioner: "provName",
|
|
||||||
Reference: "another-external-key-reference",
|
|
||||||
CreatedAt: timestamppb.New(createdAt),
|
|
||||||
BoundAt: timestamppb.New(boundAtSet),
|
|
||||||
Account: "accountID",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
db: db,
|
|
||||||
err: nil,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ok/multiple-keys-with-cursor-and-limit": func(t *testing.T) test {
|
|
||||||
chiCtx := chi.NewRouteContext()
|
|
||||||
chiCtx.URLParams.Add("prov", "provName")
|
|
||||||
req := httptest.NewRequest("GET", "/foo?cursor=eakID1&limit=10", nil)
|
|
||||||
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)
|
|
||||||
createdAt := time.Now().Add(-24 * time.Hour)
|
|
||||||
var boundAt time.Time
|
|
||||||
boundAtSet := time.Now().Add(-12 * time.Hour)
|
|
||||||
db := &acme.MockDB{
|
|
||||||
MockGetExternalAccountKeys: func(ctx context.Context, provisionerName string) ([]*acme.ExternalAccountKey, error) {
|
|
||||||
assert.Equals(t, "provName", provisionerName)
|
|
||||||
return []*acme.ExternalAccountKey{
|
|
||||||
{
|
|
||||||
ID: "eakID1",
|
|
||||||
Provisioner: "provName",
|
|
||||||
Reference: "some-external-key-reference",
|
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
|
||||||
CreatedAt: createdAt,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "eakID2",
|
|
||||||
Provisioner: "provName",
|
|
||||||
Reference: "some-other-external-key-reference",
|
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
|
||||||
CreatedAt: createdAt.Add(1 * time.Hour),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "eakID3",
|
|
||||||
Provisioner: "provName",
|
|
||||||
Reference: "another-external-key-reference",
|
Reference: "another-external-key-reference",
|
||||||
KeyBytes: []byte{1, 3, 3, 7},
|
KeyBytes: []byte{1, 3, 3, 7},
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
|
|
Loading…
Reference in a new issue