diff --git a/authority/provisioners.go b/authority/provisioners.go index 93dd5263..3e609700 100644 --- a/authority/provisioners.go +++ b/authority/provisioners.go @@ -1,6 +1,7 @@ package authority import ( + "log" "net/http" "github.com/pkg/errors" @@ -30,7 +31,8 @@ func (a *Authority) GetProvisioners() (map[string]*jose.JSONWebKeySet, error) { a.provisionerIDIndex.Range(func(key, val interface{}) bool { p, ok := val.(*Provisioner) if !ok { - return false + log.Printf("authority.GetProvisioners: expected type *Provisioner, but got %T\n", val) + return true } ks, found := pks[p.Issuer] if found { diff --git a/authority/provisioners_test.go b/authority/provisioners_test.go new file mode 100644 index 00000000..9f6343dc --- /dev/null +++ b/authority/provisioners_test.go @@ -0,0 +1,135 @@ +package authority + +import ( + "net/http" + "testing" + + "github.com/pkg/errors" + "github.com/smallstep/assert" + "github.com/smallstep/cli/jose" +) + +func TestGetEncryptedKey(t *testing.T) { + type ek struct { + a *Authority + kid string + err *apiError + } + tests := map[string]func(t *testing.T) *ek{ + "ok": func(t *testing.T) *ek { + c, err := LoadConfiguration("../ca/testdata/ca.json") + assert.FatalError(t, err) + a, err := New(c) + assert.FatalError(t, err) + return &ek{ + a: a, + kid: c.AuthorityConfig.Provisioners[1].Key.KeyID, + } + }, + "fail-not-found": func(t *testing.T) *ek { + c, err := LoadConfiguration("../ca/testdata/ca.json") + assert.FatalError(t, err) + a, err := New(c) + assert.FatalError(t, err) + return &ek{ + a: a, + kid: "foo", + err: &apiError{errors.Errorf("encrypted key with kid foo was not found"), + http.StatusNotFound, context{}}, + } + }, + "fail-invalid-type-found": func(t *testing.T) *ek { + c, err := LoadConfiguration("../ca/testdata/ca.json") + assert.FatalError(t, err) + a, err := New(c) + assert.FatalError(t, err) + a.encryptedKeyIndex.Store("foo", 5) + return &ek{ + a: a, + kid: "foo", + err: &apiError{errors.Errorf("stored value is not a string"), + http.StatusInternalServerError, context{}}, + } + }, + } + + for name, genTestCase := range tests { + t.Run(name, func(t *testing.T) { + tc := genTestCase(t) + + ek, err := tc.a.GetEncryptedKey(tc.kid) + if err != nil { + if assert.NotNil(t, tc.err) { + switch v := err.(type) { + case *apiError: + assert.HasPrefix(t, v.err.Error(), tc.err.Error()) + assert.Equals(t, v.code, tc.err.code) + assert.Equals(t, v.context, tc.err.context) + default: + t.Errorf("unexpected error type: %T", v) + } + } + } else { + if assert.Nil(t, tc.err) { + val, ok := tc.a.provisionerIDIndex.Load(tc.kid) + assert.Fatal(t, ok) + p, ok := val.(*Provisioner) + assert.Fatal(t, ok) + assert.Equals(t, p.EncryptedKey, ek) + } + } + }) + } +} + +func TestGetProvisioners(t *testing.T) { + type gp struct { + a *Authority + err *apiError + } + tests := map[string]func(t *testing.T) *gp{ + "ok": func(t *testing.T) *gp { + c, err := LoadConfiguration("../ca/testdata/ca.json") + assert.FatalError(t, err) + a, err := New(c) + assert.FatalError(t, err) + return &gp{a: a} + }, + } + + for name, genTestCase := range tests { + t.Run(name, func(t *testing.T) { + tc := genTestCase(t) + + ps, err := tc.a.GetProvisioners() + if err != nil { + if assert.NotNil(t, tc.err) { + switch v := err.(type) { + case *apiError: + assert.HasPrefix(t, v.err.Error(), tc.err.Error()) + assert.Equals(t, v.code, tc.err.code) + assert.Equals(t, v.context, tc.err.context) + default: + t.Errorf("unexpected error type: %T", v) + } + } + } else { + if assert.Nil(t, tc.err) { + var cps = tc.a.config.AuthorityConfig.Provisioners + + maxks, found := ps["max"] + assert.Fatal(t, found) + assert.Equals(t, maxks.Keys, []jose.JSONWebKey{*cps[0].Key, *cps[1].Key}) + + marianoks, found := ps["mariano"] + assert.Fatal(t, found) + assert.Equals(t, marianoks.Keys, []jose.JSONWebKey{*cps[3].Key, *cps[4].Key}) + + stepcliks, found := ps["step-cli"] + assert.Fatal(t, found) + assert.Equals(t, stepcliks.Keys, []jose.JSONWebKey{*cps[2].Key}) + } + } + }) + } +}