You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
smallstep-certificates/cas/stepcas/jwk_issuer_test.go

251 lines
6.2 KiB
Go

package stepcas
import (
"net/url"
"reflect"
"testing"
"time"
"go.step.sm/crypto/jose"
)
func Test_jwkIssuer_SignToken(t *testing.T) {
caURL, err := url.Parse("https://ca.smallstep.com")
if err != nil {
t.Fatal(err)
}
signer, err := newJWKSignerFromEncryptedKey(testKeyID, testEncryptedJWKKey, testPassword)
if err != nil {
t.Fatal(err)
}
type fields struct {
caURL *url.URL
issuer string
signer jose.Signer
}
type args struct {
subject string
sans []string
info *raInfo
}
type stepClaims struct {
RA *raInfo `json:"ra"`
}
type claims struct {
Aud jose.Audience `json:"aud"`
Sub string `json:"sub"`
Sans []string `json:"sans"`
Step stepClaims `json:"step"`
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{"ok", fields{caURL, "ra@doe.org", signer}, args{"doe", []string{"doe.org"}, nil}, false},
{"ok ra", fields{caURL, "ra@doe.org", signer}, args{"doe", []string{"doe.org"}, &raInfo{
AuthorityID: "authority-id", ProvisionerID: "provisioner-id", ProvisionerType: "provisioner-type",
}}, false},
{"ok ra endpoint id", fields{caURL, "ra@doe.org", signer}, args{"doe", []string{"doe.org"}, &raInfo{
AuthorityID: "authority-id", EndpointID: "endpoint-id",
}}, false},
{"fail", fields{caURL, "ra@doe.org", &mockErrSigner{}}, args{"doe", []string{"doe.org"}, nil}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
i := &jwkIssuer{
caURL: tt.fields.caURL,
issuer: tt.fields.issuer,
signer: tt.fields.signer,
}
got, err := i.SignToken(tt.args.subject, tt.args.sans, tt.args.info)
if (err != nil) != tt.wantErr {
t.Errorf("jwkIssuer.SignToken() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr {
jwt, err := jose.ParseSigned(got)
if err != nil {
t.Errorf("jose.ParseSigned() error = %v", err)
}
var c claims
want := claims{
Aud: jose.Audience{tt.fields.caURL.String() + "/1.0/sign"},
Sub: tt.args.subject,
Sans: tt.args.sans,
}
if tt.args.info != nil {
want.Step.RA = tt.args.info
}
if err := jwt.Claims(testX5CKey.Public(), &c); err != nil {
t.Log(got)
t.Errorf("jwt.Claims() error = %v", err)
}
if !reflect.DeepEqual(c, want) {
t.Errorf("jwt.Claims() claims = %#v, want %#v", c, want)
}
}
})
}
}
func Test_jwkIssuer_RevokeToken(t *testing.T) {
caURL, err := url.Parse("https://ca.smallstep.com")
if err != nil {
t.Fatal(err)
}
signer, err := newJWKSignerFromEncryptedKey(testKeyID, testEncryptedJWKKey, testPassword)
if err != nil {
t.Fatal(err)
}
type fields struct {
caURL *url.URL
issuer string
signer jose.Signer
}
type args struct {
subject string
}
type claims struct {
Aud jose.Audience `json:"aud"`
Sub string `json:"sub"`
Sans []string `json:"sans"`
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{"ok", fields{caURL, "ra@doe.org", signer}, args{"doe"}, false},
{"ok", fields{caURL, "ra@doe.org", &mockErrSigner{}}, args{"doe"}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
i := &jwkIssuer{
caURL: tt.fields.caURL,
issuer: tt.fields.issuer,
signer: tt.fields.signer,
}
got, err := i.RevokeToken(tt.args.subject)
if (err != nil) != tt.wantErr {
t.Errorf("jwkIssuer.RevokeToken() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr {
jwt, err := jose.ParseSigned(got)
if err != nil {
t.Errorf("jose.ParseSigned() error = %v", err)
}
var c claims
want := claims{
Aud: []string{tt.fields.caURL.String() + "/1.0/revoke"},
Sub: tt.args.subject,
}
if err := jwt.Claims(testX5CKey.Public(), &c); err != nil {
t.Errorf("jwt.Claims() error = %v", err)
}
if !reflect.DeepEqual(c, want) {
t.Errorf("jwt.Claims() claims = %#v, want %#v", c, want)
}
}
})
}
}
func Test_jwkIssuer_Lifetime(t *testing.T) {
caURL, err := url.Parse("https://ca.smallstep.com")
if err != nil {
t.Fatal(err)
}
signer, err := newJWKSignerFromEncryptedKey(testKeyID, testEncryptedJWKKey, testPassword)
if err != nil {
t.Fatal(err)
}
type fields struct {
caURL *url.URL
issuer string
signer jose.Signer
}
type args struct {
d time.Duration
}
tests := []struct {
name string
fields fields
args args
want time.Duration
}{
{"ok", fields{caURL, "ra@smallstep.com", signer}, args{time.Second}, time.Second},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
i := &jwkIssuer{
caURL: tt.fields.caURL,
issuer: tt.fields.issuer,
signer: tt.fields.signer,
}
if got := i.Lifetime(tt.args.d); got != tt.want {
t.Errorf("jwkIssuer.Lifetime() = %v, want %v", got, tt.want)
}
})
}
}
func Test_newJWKSignerFromEncryptedKey(t *testing.T) {
encrypt := func(plaintext string) string {
recipient := jose.Recipient{
Algorithm: jose.PBES2_HS256_A128KW,
Key: testPassword,
PBES2Count: jose.PBKDF2Iterations,
PBES2Salt: []byte{0x01, 0x02},
}
opts := new(jose.EncrypterOptions)
opts.WithContentType(jose.ContentType("jwk+json"))
encrypter, err := jose.NewEncrypter(jose.DefaultEncAlgorithm, recipient, opts)
if err != nil {
t.Fatal(err)
}
jwe, err := encrypter.Encrypt([]byte(plaintext))
if err != nil {
t.Fatal(err)
}
ret, err := jwe.CompactSerialize()
if err != nil {
t.Fatal(err)
}
return ret
}
type args struct {
kid string
key string
password string
}
tests := []struct {
name string
args args
wantErr bool
}{
{"ok", args{testKeyID, testEncryptedJWKKey, testPassword}, false},
{"fail decrypt", args{testKeyID, testEncryptedJWKKey, "bad-password"}, true},
{"fail unmarshal", args{testKeyID, encrypt(`{not a json}`), testPassword}, true},
{"fail not signer", args{testKeyID, encrypt(`{"kty":"oct","k":"password"}`), testPassword}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := newJWKSignerFromEncryptedKey(tt.args.kid, tt.args.key, tt.args.password)
if (err != nil) != tt.wantErr {
t.Errorf("newJWKSignerFromEncryptedKey() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}