certificates/authority/authorize_test.go

172 lines
5 KiB
Go
Raw Normal View History

2018-10-05 21:48:36 +00:00
package authority
import (
"net/http"
"testing"
"time"
"github.com/pkg/errors"
"github.com/smallstep/assert"
2019-03-11 23:38:48 +00:00
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/jose"
2018-10-05 21:48:36 +00:00
)
2019-03-11 23:38:48 +00:00
func generateToken(sub, iss, aud string, sans []string, iat time.Time, jwk *jose.JSONWebKey) (string, error) {
sig, err := jose.NewSigner(
jose.SigningKey{Algorithm: jose.ES256, Key: jwk.Key},
new(jose.SignerOptions).WithType("JWT").WithHeader("kid", jwk.KeyID),
)
if err != nil {
return "", err
}
id, err := randutil.ASCII(64)
if err != nil {
return "", err
}
claims := struct {
jose.Claims
SANS []string `json:"sans"`
}{
Claims: jose.Claims{
ID: id,
Subject: sub,
Issuer: iss,
IssuedAt: jose.NewNumericDate(iat),
NotBefore: jose.NewNumericDate(iat),
Expiry: jose.NewNumericDate(iat.Add(5 * time.Minute)),
Audience: []string{aud},
},
SANS: sans,
}
return jose.Signed(sig).Claims(claims).CompactSerialize()
}
2018-10-05 21:48:36 +00:00
func TestAuthorize(t *testing.T) {
a := testAuthority(t)
2019-03-11 23:38:48 +00:00
key, err := jose.ParseKey("testdata/secrets/step_cli_key_priv.jwk", jose.WithPassword([]byte("pass")))
2018-10-05 21:48:36 +00:00
assert.FatalError(t, err)
2019-03-11 23:38:48 +00:00
// Invalid keys
keyNoKid := &jose.JSONWebKey{Key: key.Key, KeyID: ""}
keyBadKid := &jose.JSONWebKey{Key: key.Key, KeyID: "foo"}
2018-10-05 21:48:36 +00:00
2019-03-12 01:15:24 +00:00
now := time.Now()
2018-10-05 21:48:36 +00:00
validIssuer := "step-cli"
validAudience := []string{"https://test.ca.smallstep.com/sign"}
2018-10-05 21:48:36 +00:00
type authorizeTest struct {
auth *Authority
ott string
err *apiError
res []interface{}
2018-10-05 21:48:36 +00:00
}
tests := map[string]func(t *testing.T) *authorizeTest{
"fail invalid ott": func(t *testing.T) *authorizeTest {
2018-10-05 21:48:36 +00:00
return &authorizeTest{
auth: a,
ott: "foo",
err: &apiError{errors.New("authorize: error parsing token"),
2018-10-05 21:48:36 +00:00
http.StatusUnauthorized, context{"ott": "foo"}},
}
},
"fail empty key id": func(t *testing.T) *authorizeTest {
2019-03-11 23:38:48 +00:00
raw, err := generateToken("test.smallstep.com", validIssuer, validAudience[0], nil, now, keyNoKid)
assert.FatalError(t, err)
return &authorizeTest{
auth: a,
ott: raw,
2019-03-09 02:05:11 +00:00
err: &apiError{errors.New("authorize: provisioner not found or invalid audience"),
http.StatusUnauthorized, context{"ott": raw}},
}
},
"fail provisioner not found": func(t *testing.T) *authorizeTest {
2019-03-11 23:38:48 +00:00
raw, err := generateToken("test.smallstep.com", validIssuer, validAudience[0], nil, now, keyBadKid)
assert.FatalError(t, err)
return &authorizeTest{
auth: a,
ott: raw,
2019-03-09 02:05:11 +00:00
err: &apiError{errors.New("authorize: provisioner not found or invalid audience"),
http.StatusUnauthorized, context{"ott": raw}},
}
},
"fail invalid issuer": func(t *testing.T) *authorizeTest {
2019-03-11 23:38:48 +00:00
raw, err := generateToken("test.smallstep.com", "invalid-issuer", validAudience[0], nil, now, key)
2018-10-05 21:48:36 +00:00
assert.FatalError(t, err)
return &authorizeTest{
auth: a,
ott: raw,
2019-03-09 02:05:11 +00:00
err: &apiError{errors.New("authorize: provisioner not found or invalid audience"),
2018-10-05 21:48:36 +00:00
http.StatusUnauthorized, context{"ott": raw}},
}
2018-10-05 21:48:36 +00:00
},
"fail empty subject": func(t *testing.T) *authorizeTest {
2019-03-11 23:38:48 +00:00
raw, err := generateToken("", validIssuer, validAudience[0], nil, now, key)
2018-10-05 21:48:36 +00:00
assert.FatalError(t, err)
return &authorizeTest{
auth: a,
ott: raw,
err: &apiError{errors.New("authorize: token subject cannot be empty"),
2018-10-05 21:48:36 +00:00
http.StatusUnauthorized, context{"ott": raw}},
}
2018-10-05 21:48:36 +00:00
},
"fail verify-sig-failure": func(t *testing.T) *authorizeTest {
2019-03-11 23:38:48 +00:00
raw, err := generateToken("test.smallstep.com", validIssuer, validAudience[0], nil, now, key)
2018-10-05 21:48:36 +00:00
assert.FatalError(t, err)
return &authorizeTest{
auth: a,
2019-03-11 23:38:48 +00:00
ott: raw + "00",
2019-03-09 02:05:11 +00:00
err: &apiError{errors.New("authorize: error parsing claims: square/go-jose: error in cryptographic primitive"),
2019-03-11 23:38:48 +00:00
http.StatusUnauthorized, context{"ott": raw + "00"}},
}
2018-10-05 21:48:36 +00:00
},
"fail token-already-used": func(t *testing.T) *authorizeTest {
2019-03-11 23:38:48 +00:00
raw, err := generateToken("test.smallstep.com", validIssuer, validAudience[0], nil, now, key)
2018-10-05 21:48:36 +00:00
assert.FatalError(t, err)
_, err = a.Authorize(raw)
assert.FatalError(t, err)
return &authorizeTest{
auth: a,
ott: raw,
2019-03-09 02:05:11 +00:00
err: &apiError{errors.New("authorize: token already used"),
2018-10-05 21:48:36 +00:00
http.StatusUnauthorized, context{"ott": raw}},
}
2018-10-05 21:48:36 +00:00
},
"ok": func(t *testing.T) *authorizeTest {
2019-03-11 23:38:48 +00:00
raw, err := generateToken("test.smallstep.com", validIssuer, validAudience[0], nil, now, key)
2018-10-05 21:48:36 +00:00
assert.FatalError(t, err)
return &authorizeTest{
auth: a,
ott: raw,
2019-03-09 02:05:11 +00:00
res: []interface{}{"1", "2", "3", "4", "5", "6"},
2018-10-05 21:48:36 +00:00
}
},
}
for name, genTestCase := range tests {
t.Run(name, func(t *testing.T) {
tc := genTestCase(t)
assert.FatalError(t, err)
crtOpts, err := tc.auth.Authorize(tc.ott)
2018-10-05 21:48:36 +00:00
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) {
assert.Equals(t, len(crtOpts), len(tc.res))
2018-10-05 21:48:36 +00:00
}
}
})
}
}