Rename provisioner options structs:

* provisioner.ProvisionerOptions => provisioner.Options
* provisioner.Options => provisioner.SignOptions
* provisioner.SSHOptions => provisioner.SingSSHOptions
This commit is contained in:
Mariano Cano 2020-07-22 18:24:45 -07:00
parent e0dd1bd132
commit 6c64fb3ed2
37 changed files with 405 additions and 406 deletions

View file

@ -18,7 +18,7 @@ type Provisioner interface {
AuthorizeSign(ctx context.Context, token string) ([]provisioner.SignOption, error) AuthorizeSign(ctx context.Context, token string) ([]provisioner.SignOption, error)
GetName() string GetName() string
DefaultTLSCertDuration() time.Duration DefaultTLSCertDuration() time.Duration
GetOptions() *provisioner.ProvisionerOptions GetOptions() *provisioner.Options
} }
// MockProvisioner for testing // MockProvisioner for testing
@ -28,7 +28,7 @@ type MockProvisioner struct {
MgetName func() string MgetName func() string
MauthorizeSign func(ctx context.Context, ott string) ([]provisioner.SignOption, error) MauthorizeSign func(ctx context.Context, ott string) ([]provisioner.SignOption, error)
MdefaultTLSCertDuration func() time.Duration MdefaultTLSCertDuration func() time.Duration
MgetOptions func() *provisioner.ProvisionerOptions MgetOptions func() *provisioner.Options
} }
// GetName mock // GetName mock
@ -55,11 +55,11 @@ func (m *MockProvisioner) DefaultTLSCertDuration() time.Duration {
return m.Mret1.(time.Duration) return m.Mret1.(time.Duration)
} }
func (m *MockProvisioner) GetOptions() *provisioner.ProvisionerOptions { func (m *MockProvisioner) GetOptions() *provisioner.Options {
if m.MgetOptions != nil { if m.MgetOptions != nil {
return m.MgetOptions() return m.MgetOptions()
} }
return m.Mret1.(*provisioner.ProvisionerOptions) return m.Mret1.(*provisioner.Options)
} }
// ContextKey is the key type for storing and searching for ACME request // ContextKey is the key type for storing and searching for ACME request
@ -134,7 +134,7 @@ func ProvisionerFromContext(ctx context.Context) (Provisioner, error) {
// SignAuthority is the interface implemented by a CA authority. // SignAuthority is the interface implemented by a CA authority.
type SignAuthority interface { type SignAuthority interface {
Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) Sign(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error)
LoadProvisionerByID(string) (provisioner.Interface, error) LoadProvisionerByID(string) (provisioner.Interface, error)
} }

View file

@ -338,7 +338,7 @@ func (o *order) finalize(db nosql.DB, csr *x509.CertificateRequest, auth SignAut
signOps = append(signOps, templateOptions) signOps = append(signOps, templateOptions)
// Create and store a new certificate. // Create and store a new certificate.
certChain, err := auth.Sign(csr, provisioner.Options{ certChain, err := auth.Sign(csr, provisioner.SignOptions{
NotBefore: provisioner.NewTimeDuration(o.NotBefore), NotBefore: provisioner.NewTimeDuration(o.NotBefore),
NotAfter: provisioner.NewTimeDuration(o.NotAfter), NotAfter: provisioner.NewTimeDuration(o.NotAfter),
}, signOps...) }, signOps...)

View file

@ -895,13 +895,13 @@ func TestOrderUpdateStatus(t *testing.T) {
} }
type mockSignAuth struct { type mockSignAuth struct {
sign func(csr *x509.CertificateRequest, signOpts provisioner.Options, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, error) sign func(csr *x509.CertificateRequest, signOpts provisioner.SignOptions, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, error)
loadProvisionerByID func(string) (provisioner.Interface, error) loadProvisionerByID func(string) (provisioner.Interface, error)
ret1, ret2 interface{} ret1, ret2 interface{}
err error err error
} }
func (m *mockSignAuth) Sign(csr *x509.CertificateRequest, signOpts provisioner.Options, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, error) { func (m *mockSignAuth) Sign(csr *x509.CertificateRequest, signOpts provisioner.SignOptions, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, error) {
if m.sign != nil { if m.sign != nil {
return m.sign(csr, signOpts, extraOpts...) return m.sign(csr, signOpts, extraOpts...)
} else if m.err != nil { } else if m.err != nil {
@ -1262,7 +1262,7 @@ func TestOrderFinalize(t *testing.T) {
res: clone, res: clone,
csr: csr, csr: csr,
sa: &mockSignAuth{ sa: &mockSignAuth{
sign: func(csr *x509.CertificateRequest, pops provisioner.Options, signOps ...provisioner.SignOption) ([]*x509.Certificate, error) { sign: func(csr *x509.CertificateRequest, pops provisioner.SignOptions, signOps ...provisioner.SignOption) ([]*x509.Certificate, error) {
assert.Equals(t, len(signOps), 6) assert.Equals(t, len(signOps), 6)
return []*x509.Certificate{crt, inter}, nil return []*x509.Certificate{crt, inter}, nil
}, },
@ -1311,7 +1311,7 @@ func TestOrderFinalize(t *testing.T) {
res: &clone, res: &clone,
csr: csr, csr: csr,
sa: &mockSignAuth{ sa: &mockSignAuth{
sign: func(csr *x509.CertificateRequest, pops provisioner.Options, signOps ...provisioner.SignOption) ([]*x509.Certificate, error) { sign: func(csr *x509.CertificateRequest, pops provisioner.SignOptions, signOps ...provisioner.SignOption) ([]*x509.Certificate, error) {
assert.Equals(t, len(signOps), 6) assert.Equals(t, len(signOps), 6)
return []*x509.Certificate{crt, inter}, nil return []*x509.Certificate{crt, inter}, nil
}, },
@ -1358,7 +1358,7 @@ func TestOrderFinalize(t *testing.T) {
res: &clone, res: &clone,
csr: csr, csr: csr,
sa: &mockSignAuth{ sa: &mockSignAuth{
sign: func(csr *x509.CertificateRequest, pops provisioner.Options, signOps ...provisioner.SignOption) ([]*x509.Certificate, error) { sign: func(csr *x509.CertificateRequest, pops provisioner.SignOptions, signOps ...provisioner.SignOption) ([]*x509.Certificate, error) {
assert.Equals(t, len(signOps), 6) assert.Equals(t, len(signOps), 6)
return []*x509.Certificate{crt, inter}, nil return []*x509.Certificate{crt, inter}, nil
}, },

View file

@ -34,7 +34,7 @@ type Authority interface {
AuthorizeSign(ott string) ([]provisioner.SignOption, error) AuthorizeSign(ott string) ([]provisioner.SignOption, error)
GetTLSOptions() *tlsutil.TLSOptions GetTLSOptions() *tlsutil.TLSOptions
Root(shasum string) (*x509.Certificate, error) Root(shasum string) (*x509.Certificate, error)
Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) Sign(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error)
Renew(peer *x509.Certificate) ([]*x509.Certificate, error) Renew(peer *x509.Certificate) ([]*x509.Certificate, error)
Rekey(peer *x509.Certificate, pk crypto.PublicKey) ([]*x509.Certificate, error) Rekey(peer *x509.Certificate, pk crypto.PublicKey) ([]*x509.Certificate, error)
LoadProvisionerByCertificate(*x509.Certificate) (provisioner.Interface, error) LoadProvisionerByCertificate(*x509.Certificate) (provisioner.Interface, error)

View file

@ -550,7 +550,7 @@ type mockAuthority struct {
authorizeSign func(ott string) ([]provisioner.SignOption, error) authorizeSign func(ott string) ([]provisioner.SignOption, error)
getTLSOptions func() *tlsutil.TLSOptions getTLSOptions func() *tlsutil.TLSOptions
root func(shasum string) (*x509.Certificate, error) root func(shasum string) (*x509.Certificate, error)
sign func(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) sign func(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error)
renew func(cert *x509.Certificate) ([]*x509.Certificate, error) renew func(cert *x509.Certificate) ([]*x509.Certificate, error)
rekey func(oldCert *x509.Certificate, pk crypto.PublicKey) ([]*x509.Certificate, error) rekey func(oldCert *x509.Certificate, pk crypto.PublicKey) ([]*x509.Certificate, error)
loadProvisionerByCertificate func(cert *x509.Certificate) (provisioner.Interface, error) loadProvisionerByCertificate func(cert *x509.Certificate) (provisioner.Interface, error)
@ -560,7 +560,7 @@ type mockAuthority struct {
getEncryptedKey func(kid string) (string, error) getEncryptedKey func(kid string) (string, error)
getRoots func() ([]*x509.Certificate, error) getRoots func() ([]*x509.Certificate, error)
getFederation func() ([]*x509.Certificate, error) getFederation func() ([]*x509.Certificate, error)
signSSH func(ctx context.Context, key ssh.PublicKey, opts provisioner.SSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) signSSH func(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error)
signSSHAddUser func(ctx context.Context, key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error) signSSHAddUser func(ctx context.Context, key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error)
renewSSH func(ctx context.Context, cert *ssh.Certificate) (*ssh.Certificate, error) renewSSH func(ctx context.Context, cert *ssh.Certificate) (*ssh.Certificate, error)
rekeySSH func(ctx context.Context, cert *ssh.Certificate, key ssh.PublicKey, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) rekeySSH func(ctx context.Context, cert *ssh.Certificate, key ssh.PublicKey, signOpts ...provisioner.SignOption) (*ssh.Certificate, error)
@ -599,7 +599,7 @@ func (m *mockAuthority) Root(shasum string) (*x509.Certificate, error) {
return m.ret1.(*x509.Certificate), m.err return m.ret1.(*x509.Certificate), m.err
} }
func (m *mockAuthority) Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) { func (m *mockAuthority) Sign(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) {
if m.sign != nil { if m.sign != nil {
return m.sign(cr, opts, signOpts...) return m.sign(cr, opts, signOpts...)
} }
@ -669,7 +669,7 @@ func (m *mockAuthority) GetFederation() ([]*x509.Certificate, error) {
return m.ret1.([]*x509.Certificate), m.err return m.ret1.([]*x509.Certificate), m.err
} }
func (m *mockAuthority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) { func (m *mockAuthority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) {
if m.signSSH != nil { if m.signSSH != nil {
return m.signSSH(ctx, key, opts, signOpts...) return m.signSSH(ctx, key, opts, signOpts...)
} }

View file

@ -60,7 +60,7 @@ func (h *caHandler) Sign(w http.ResponseWriter, r *http.Request) {
return return
} }
opts := provisioner.Options{ opts := provisioner.SignOptions{
NotBefore: body.NotBefore, NotBefore: body.NotBefore,
NotAfter: body.NotAfter, NotAfter: body.NotAfter,
TemplateData: body.TemplateData, TemplateData: body.TemplateData,

View file

@ -19,7 +19,7 @@ import (
// SSHAuthority is the interface implemented by a SSH CA authority. // SSHAuthority is the interface implemented by a SSH CA authority.
type SSHAuthority interface { type SSHAuthority interface {
SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error)
RenewSSH(ctx context.Context, cert *ssh.Certificate) (*ssh.Certificate, error) RenewSSH(ctx context.Context, cert *ssh.Certificate) (*ssh.Certificate, error)
RekeySSH(ctx context.Context, cert *ssh.Certificate, key ssh.PublicKey, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) RekeySSH(ctx context.Context, cert *ssh.Certificate, key ssh.PublicKey, signOpts ...provisioner.SignOption) (*ssh.Certificate, error)
SignSSHAddUser(ctx context.Context, key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error) SignSSHAddUser(ctx context.Context, key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error)
@ -274,7 +274,7 @@ func (h *caHandler) SSHSign(w http.ResponseWriter, r *http.Request) {
} }
} }
opts := provisioner.SSHOptions{ opts := provisioner.SignSSHOptions{
CertType: body.CertType, CertType: body.CertType,
KeyID: body.KeyID, KeyID: body.KeyID,
Principals: body.Principals, Principals: body.Principals,
@ -322,7 +322,7 @@ func (h *caHandler) SSHSign(w http.ResponseWriter, r *http.Request) {
NotAfter: time.Unix(int64(cert.ValidBefore), 0), NotAfter: time.Unix(int64(cert.ValidBefore), 0),
}) })
certChain, err := h.Authority.Sign(cr, provisioner.Options{}, signOpts...) certChain, err := h.Authority.Sign(cr, provisioner.SignOptions{}, signOpts...)
if err != nil { if err != nil {
WriteError(w, errs.ForbiddenErr(err)) WriteError(w, errs.ForbiddenErr(err))
return return

View file

@ -319,13 +319,13 @@ func Test_caHandler_SSHSign(t *testing.T) {
authorizeSign: func(ott string) ([]provisioner.SignOption, error) { authorizeSign: func(ott string) ([]provisioner.SignOption, error) {
return []provisioner.SignOption{}, tt.authErr return []provisioner.SignOption{}, tt.authErr
}, },
signSSH: func(ctx context.Context, key ssh.PublicKey, opts provisioner.SSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) { signSSH: func(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) {
return tt.signCert, tt.signErr return tt.signCert, tt.signErr
}, },
signSSHAddUser: func(ctx context.Context, key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error) { signSSHAddUser: func(ctx context.Context, key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error) {
return tt.addUserCert, tt.addUserErr return tt.addUserCert, tt.addUserErr
}, },
sign: func(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) { sign: func(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) {
return tt.tlsSignCerts, tt.tlsSignErr return tt.tlsSignCerts, tt.tlsSignErr
}, },
}).(*caHandler) }).(*caHandler)

View file

@ -283,7 +283,7 @@ func TestNewEmbedded_Sign(t *testing.T) {
csr, err := x509.ParseCertificateRequest(cr) csr, err := x509.ParseCertificateRequest(cr)
assert.FatalError(t, err) assert.FatalError(t, err)
cert, err := a.Sign(csr, provisioner.Options{}) cert, err := a.Sign(csr, provisioner.SignOptions{})
assert.FatalError(t, err) assert.FatalError(t, err)
assert.Equals(t, []string{"foo.bar.zar"}, cert[0].DNSNames) assert.Equals(t, []string{"foo.bar.zar"}, cert[0].DNSNames)
assert.Equals(t, crt, cert[1]) assert.Equals(t, crt, cert[1])

View file

@ -830,17 +830,17 @@ func TestAuthority_authorizeRenew(t *testing.T) {
} }
func generateSimpleSSHUserToken(iss, aud string, jwk *jose.JSONWebKey) (string, error) { func generateSimpleSSHUserToken(iss, aud string, jwk *jose.JSONWebKey) (string, error) {
return generateSSHToken("subject@localhost", iss, aud, time.Now(), &provisioner.SSHOptions{ return generateSSHToken("subject@localhost", iss, aud, time.Now(), &provisioner.SignSSHOptions{
CertType: "user", CertType: "user",
Principals: []string{"name"}, Principals: []string{"name"},
}, jwk) }, jwk)
} }
type stepPayload struct { type stepPayload struct {
SSH *provisioner.SSHOptions `json:"ssh,omitempty"` SSH *provisioner.SignSSHOptions `json:"ssh,omitempty"`
} }
func generateSSHToken(sub, iss, aud string, iat time.Time, sshOpts *provisioner.SSHOptions, jwk *jose.JSONWebKey) (string, error) { func generateSSHToken(sub, iss, aud string, iat time.Time, sshOpts *provisioner.SignSSHOptions, jwk *jose.JSONWebKey) (string, error) {
sig, err := jose.NewSigner( sig, err := jose.NewSigner(
jose.SigningKey{Algorithm: jose.ES256, Key: jwk.Key}, jose.SigningKey{Algorithm: jose.ES256, Key: jwk.Key},
new(jose.SignerOptions).WithType("JWT").WithHeader("kid", jwk.KeyID), new(jose.SignerOptions).WithType("JWT").WithHeader("kid", jwk.KeyID),

View file

@ -13,11 +13,11 @@ import (
// provisioning flow. // provisioning flow.
type ACME struct { type ACME struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
ForceCN bool `json:"forceCN,omitempty"` ForceCN bool `json:"forceCN,omitempty"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *ProvisionerOptions `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
claimer *Claimer claimer *Claimer
} }
@ -47,7 +47,7 @@ func (p *ACME) GetEncryptedKey() (string, string, bool) {
} }
// GetOptions returns the configured provisioner options. // GetOptions returns the configured provisioner options.
func (p *ACME) GetOptions() *ProvisionerOptions { func (p *ACME) GetOptions() *Options {
return p.Options return p.Options
} }

View file

@ -126,14 +126,14 @@ type awsInstanceIdentityDocument struct {
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
type AWS struct { type AWS struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
Accounts []string `json:"accounts"` Accounts []string `json:"accounts"`
DisableCustomSANs bool `json:"disableCustomSANs"` DisableCustomSANs bool `json:"disableCustomSANs"`
DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"` DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"`
InstanceAge Duration `json:"instanceAge,omitempty"` InstanceAge Duration `json:"instanceAge,omitempty"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *ProvisionerOptions `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
claimer *Claimer claimer *Claimer
config *awsConfig config *awsConfig
audiences Audiences audiences Audiences
@ -483,7 +483,7 @@ func (p *AWS) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
} }
// Default to cert type to host // Default to cert type to host
defaults := SSHOptions{ defaults := SignSSHOptions{
CertType: SSHHostCert, CertType: SSHHostCert,
Principals: principals, Principals: principals,
} }

View file

@ -647,51 +647,51 @@ func TestAWS_AuthorizeSSHSign(t *testing.T) {
assert.FatalError(t, err) assert.FatalError(t, err)
hostDuration := p1.claimer.DefaultHostSSHCertDuration() hostDuration := p1.claimer.DefaultHostSSHCertDuration()
expectedHostOptions := &SSHOptions{ expectedHostOptions := &SignSSHOptions{
CertType: "host", Principals: []string{"127.0.0.1", "ip-127-0-0-1.us-west-1.compute.internal"}, CertType: "host", Principals: []string{"127.0.0.1", "ip-127-0-0-1.us-west-1.compute.internal"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
expectedHostOptionsIP := &SSHOptions{ expectedHostOptionsIP := &SignSSHOptions{
CertType: "host", Principals: []string{"127.0.0.1"}, CertType: "host", Principals: []string{"127.0.0.1"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
expectedHostOptionsHostname := &SSHOptions{ expectedHostOptionsHostname := &SignSSHOptions{
CertType: "host", Principals: []string{"ip-127-0-0-1.us-west-1.compute.internal"}, CertType: "host", Principals: []string{"ip-127-0-0-1.us-west-1.compute.internal"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
expectedCustomOptions := &SSHOptions{ expectedCustomOptions := &SignSSHOptions{
CertType: "host", Principals: []string{"foo.local"}, CertType: "host", Principals: []string{"foo.local"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
type args struct { type args struct {
token string token string
sshOpts SSHOptions sshOpts SignSSHOptions
key interface{} key interface{}
} }
tests := []struct { tests := []struct {
name string name string
aws *AWS aws *AWS
args args args args
expected *SSHOptions expected *SignSSHOptions
code int code int
wantErr bool wantErr bool
wantSignErr bool wantSignErr bool
}{ }{
{"ok", p1, args{t1, SSHOptions{}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok", p1, args{t1, SignSSHOptions{}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-rsa2048", p1, args{t1, SSHOptions{}, rsa2048.Public()}, expectedHostOptions, http.StatusOK, false, false}, {"ok-rsa2048", p1, args{t1, SignSSHOptions{}, rsa2048.Public()}, expectedHostOptions, http.StatusOK, false, false},
{"ok-type", p1, args{t1, SSHOptions{CertType: "host"}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok-type", p1, args{t1, SignSSHOptions{CertType: "host"}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-principals", p1, args{t1, SSHOptions{Principals: []string{"127.0.0.1", "ip-127-0-0-1.us-west-1.compute.internal"}}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok-principals", p1, args{t1, SignSSHOptions{Principals: []string{"127.0.0.1", "ip-127-0-0-1.us-west-1.compute.internal"}}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-principal-ip", p1, args{t1, SSHOptions{Principals: []string{"127.0.0.1"}}, pub}, expectedHostOptionsIP, http.StatusOK, false, false}, {"ok-principal-ip", p1, args{t1, SignSSHOptions{Principals: []string{"127.0.0.1"}}, pub}, expectedHostOptionsIP, http.StatusOK, false, false},
{"ok-principal-hostname", p1, args{t1, SSHOptions{Principals: []string{"ip-127-0-0-1.us-west-1.compute.internal"}}, pub}, expectedHostOptionsHostname, http.StatusOK, false, false}, {"ok-principal-hostname", p1, args{t1, SignSSHOptions{Principals: []string{"ip-127-0-0-1.us-west-1.compute.internal"}}, pub}, expectedHostOptionsHostname, http.StatusOK, false, false},
{"ok-options", p1, args{t1, SSHOptions{CertType: "host", Principals: []string{"127.0.0.1", "ip-127-0-0-1.us-west-1.compute.internal"}}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok-options", p1, args{t1, SignSSHOptions{CertType: "host", Principals: []string{"127.0.0.1", "ip-127-0-0-1.us-west-1.compute.internal"}}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-custom", p2, args{t2, SSHOptions{Principals: []string{"foo.local"}}, pub}, expectedCustomOptions, http.StatusOK, false, false}, {"ok-custom", p2, args{t2, SignSSHOptions{Principals: []string{"foo.local"}}, pub}, expectedCustomOptions, http.StatusOK, false, false},
{"fail-rsa1024", p1, args{t1, SSHOptions{}, rsa1024.Public()}, expectedHostOptions, http.StatusOK, false, true}, {"fail-rsa1024", p1, args{t1, SignSSHOptions{}, rsa1024.Public()}, expectedHostOptions, http.StatusOK, false, true},
{"fail-type", p1, args{t1, SSHOptions{CertType: "user"}, pub}, nil, http.StatusOK, false, true}, {"fail-type", p1, args{t1, SignSSHOptions{CertType: "user"}, pub}, nil, http.StatusOK, false, true},
{"fail-principal", p1, args{t1, SSHOptions{Principals: []string{"smallstep.com"}}, pub}, nil, http.StatusOK, false, true}, {"fail-principal", p1, args{t1, SignSSHOptions{Principals: []string{"smallstep.com"}}, pub}, nil, http.StatusOK, false, true},
{"fail-extra-principal", p1, args{t1, SSHOptions{Principals: []string{"127.0.0.1", "ip-127-0-0-1.us-west-1.compute.internal", "smallstep.com"}}, pub}, nil, http.StatusOK, false, true}, {"fail-extra-principal", p1, args{t1, SignSSHOptions{Principals: []string{"127.0.0.1", "ip-127-0-0-1.us-west-1.compute.internal", "smallstep.com"}}, pub}, nil, http.StatusOK, false, true},
{"fail-sshCA-disabled", p3, args{"foo", SSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false}, {"fail-sshCA-disabled", p3, args{"foo", SignSSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false},
{"fail-invalid-token", p1, args{"foo", SSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false}, {"fail-invalid-token", p1, args{"foo", SignSSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View file

@ -83,15 +83,15 @@ type azurePayload struct {
// and https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service // and https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service
type Azure struct { type Azure struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
TenantID string `json:"tenantID"` TenantID string `json:"tenantID"`
ResourceGroups []string `json:"resourceGroups"` ResourceGroups []string `json:"resourceGroups"`
Audience string `json:"audience,omitempty"` Audience string `json:"audience,omitempty"`
DisableCustomSANs bool `json:"disableCustomSANs"` DisableCustomSANs bool `json:"disableCustomSANs"`
DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"` DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *ProvisionerOptions `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
claimer *Claimer claimer *Claimer
config *azureConfig config *azureConfig
oidcConfig openIDConfiguration oidcConfig openIDConfiguration
@ -350,7 +350,7 @@ func (p *Azure) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOptio
} }
// Default to host + known hostnames // Default to host + known hostnames
defaults := SSHOptions{ defaults := SignSSHOptions{
CertType: SSHHostCert, CertType: SSHHostCert,
Principals: principals, Principals: principals,
} }

View file

@ -571,41 +571,41 @@ func TestAzure_AuthorizeSSHSign(t *testing.T) {
assert.FatalError(t, err) assert.FatalError(t, err)
hostDuration := p1.claimer.DefaultHostSSHCertDuration() hostDuration := p1.claimer.DefaultHostSSHCertDuration()
expectedHostOptions := &SSHOptions{ expectedHostOptions := &SignSSHOptions{
CertType: "host", Principals: []string{"virtualMachine"}, CertType: "host", Principals: []string{"virtualMachine"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
expectedCustomOptions := &SSHOptions{ expectedCustomOptions := &SignSSHOptions{
CertType: "host", Principals: []string{"foo.bar"}, CertType: "host", Principals: []string{"foo.bar"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
type args struct { type args struct {
token string token string
sshOpts SSHOptions sshOpts SignSSHOptions
key interface{} key interface{}
} }
tests := []struct { tests := []struct {
name string name string
azure *Azure azure *Azure
args args args args
expected *SSHOptions expected *SignSSHOptions
code int code int
wantErr bool wantErr bool
wantSignErr bool wantSignErr bool
}{ }{
{"ok", p1, args{t1, SSHOptions{}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok", p1, args{t1, SignSSHOptions{}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-rsa2048", p1, args{t1, SSHOptions{}, rsa2048.Public()}, expectedHostOptions, http.StatusOK, false, false}, {"ok-rsa2048", p1, args{t1, SignSSHOptions{}, rsa2048.Public()}, expectedHostOptions, http.StatusOK, false, false},
{"ok-type", p1, args{t1, SSHOptions{CertType: "host"}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok-type", p1, args{t1, SignSSHOptions{CertType: "host"}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-principals", p1, args{t1, SSHOptions{Principals: []string{"virtualMachine"}}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok-principals", p1, args{t1, SignSSHOptions{Principals: []string{"virtualMachine"}}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-options", p1, args{t1, SSHOptions{CertType: "host", Principals: []string{"virtualMachine"}}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok-options", p1, args{t1, SignSSHOptions{CertType: "host", Principals: []string{"virtualMachine"}}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-custom", p2, args{t2, SSHOptions{Principals: []string{"foo.bar"}}, pub}, expectedCustomOptions, http.StatusOK, false, false}, {"ok-custom", p2, args{t2, SignSSHOptions{Principals: []string{"foo.bar"}}, pub}, expectedCustomOptions, http.StatusOK, false, false},
{"fail-rsa1024", p1, args{t1, SSHOptions{}, rsa1024.Public()}, expectedHostOptions, http.StatusOK, false, true}, {"fail-rsa1024", p1, args{t1, SignSSHOptions{}, rsa1024.Public()}, expectedHostOptions, http.StatusOK, false, true},
{"fail-type", p1, args{t1, SSHOptions{CertType: "user"}, pub}, nil, http.StatusOK, false, true}, {"fail-type", p1, args{t1, SignSSHOptions{CertType: "user"}, pub}, nil, http.StatusOK, false, true},
{"fail-principal", p1, args{t1, SSHOptions{Principals: []string{"smallstep.com"}}, pub}, nil, http.StatusOK, false, true}, {"fail-principal", p1, args{t1, SignSSHOptions{Principals: []string{"smallstep.com"}}, pub}, nil, http.StatusOK, false, true},
{"fail-extra-principal", p1, args{t1, SSHOptions{Principals: []string{"virtualMachine", "smallstep.com"}}, pub}, nil, http.StatusOK, false, true}, {"fail-extra-principal", p1, args{t1, SignSSHOptions{Principals: []string{"virtualMachine", "smallstep.com"}}, pub}, nil, http.StatusOK, false, true},
{"fail-sshCA-disabled", p3, args{"foo", SSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false}, {"fail-sshCA-disabled", p3, args{"foo", SignSSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false},
{"fail-invalid-token", p1, args{"foo", SSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false}, {"fail-invalid-token", p1, args{"foo", SignSSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View file

@ -77,15 +77,15 @@ func newGCPConfig() *gcpConfig {
// https://cloud.google.com/compute/docs/instances/verifying-instance-identity // https://cloud.google.com/compute/docs/instances/verifying-instance-identity
type GCP struct { type GCP struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
ServiceAccounts []string `json:"serviceAccounts"` ServiceAccounts []string `json:"serviceAccounts"`
ProjectIDs []string `json:"projectIDs"` ProjectIDs []string `json:"projectIDs"`
DisableCustomSANs bool `json:"disableCustomSANs"` DisableCustomSANs bool `json:"disableCustomSANs"`
DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"` DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"`
InstanceAge Duration `json:"instanceAge,omitempty"` InstanceAge Duration `json:"instanceAge,omitempty"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *ProvisionerOptions `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
claimer *Claimer claimer *Claimer
config *gcpConfig config *gcpConfig
keyStore *keyStore keyStore *keyStore
@ -394,7 +394,7 @@ func (p *GCP) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
} }
// Default to host + known hostnames // Default to host + known hostnames
defaults := SSHOptions{ defaults := SignSSHOptions{
CertType: SSHHostCert, CertType: SSHHostCert,
Principals: principals, Principals: principals,
} }

View file

@ -623,51 +623,51 @@ func TestGCP_AuthorizeSSHSign(t *testing.T) {
assert.FatalError(t, err) assert.FatalError(t, err)
hostDuration := p1.claimer.DefaultHostSSHCertDuration() hostDuration := p1.claimer.DefaultHostSSHCertDuration()
expectedHostOptions := &SSHOptions{ expectedHostOptions := &SignSSHOptions{
CertType: "host", Principals: []string{"instance-name.c.project-id.internal", "instance-name.zone.c.project-id.internal"}, CertType: "host", Principals: []string{"instance-name.c.project-id.internal", "instance-name.zone.c.project-id.internal"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
expectedHostOptionsPrincipal1 := &SSHOptions{ expectedHostOptionsPrincipal1 := &SignSSHOptions{
CertType: "host", Principals: []string{"instance-name.c.project-id.internal"}, CertType: "host", Principals: []string{"instance-name.c.project-id.internal"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
expectedHostOptionsPrincipal2 := &SSHOptions{ expectedHostOptionsPrincipal2 := &SignSSHOptions{
CertType: "host", Principals: []string{"instance-name.zone.c.project-id.internal"}, CertType: "host", Principals: []string{"instance-name.zone.c.project-id.internal"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
expectedCustomOptions := &SSHOptions{ expectedCustomOptions := &SignSSHOptions{
CertType: "host", Principals: []string{"foo.bar", "bar.foo"}, CertType: "host", Principals: []string{"foo.bar", "bar.foo"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
type args struct { type args struct {
token string token string
sshOpts SSHOptions sshOpts SignSSHOptions
key interface{} key interface{}
} }
tests := []struct { tests := []struct {
name string name string
gcp *GCP gcp *GCP
args args args args
expected *SSHOptions expected *SignSSHOptions
code int code int
wantErr bool wantErr bool
wantSignErr bool wantSignErr bool
}{ }{
{"ok", p1, args{t1, SSHOptions{}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok", p1, args{t1, SignSSHOptions{}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-rsa2048", p1, args{t1, SSHOptions{}, rsa2048.Public()}, expectedHostOptions, http.StatusOK, false, false}, {"ok-rsa2048", p1, args{t1, SignSSHOptions{}, rsa2048.Public()}, expectedHostOptions, http.StatusOK, false, false},
{"ok-type", p1, args{t1, SSHOptions{CertType: "host"}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok-type", p1, args{t1, SignSSHOptions{CertType: "host"}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-principals", p1, args{t1, SSHOptions{Principals: []string{"instance-name.c.project-id.internal", "instance-name.zone.c.project-id.internal"}}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok-principals", p1, args{t1, SignSSHOptions{Principals: []string{"instance-name.c.project-id.internal", "instance-name.zone.c.project-id.internal"}}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-principal1", p1, args{t1, SSHOptions{Principals: []string{"instance-name.c.project-id.internal"}}, pub}, expectedHostOptionsPrincipal1, http.StatusOK, false, false}, {"ok-principal1", p1, args{t1, SignSSHOptions{Principals: []string{"instance-name.c.project-id.internal"}}, pub}, expectedHostOptionsPrincipal1, http.StatusOK, false, false},
{"ok-principal2", p1, args{t1, SSHOptions{Principals: []string{"instance-name.zone.c.project-id.internal"}}, pub}, expectedHostOptionsPrincipal2, http.StatusOK, false, false}, {"ok-principal2", p1, args{t1, SignSSHOptions{Principals: []string{"instance-name.zone.c.project-id.internal"}}, pub}, expectedHostOptionsPrincipal2, http.StatusOK, false, false},
{"ok-options", p1, args{t1, SSHOptions{CertType: "host", Principals: []string{"instance-name.c.project-id.internal", "instance-name.zone.c.project-id.internal"}}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"ok-options", p1, args{t1, SignSSHOptions{CertType: "host", Principals: []string{"instance-name.c.project-id.internal", "instance-name.zone.c.project-id.internal"}}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"ok-custom", p2, args{t2, SSHOptions{Principals: []string{"foo.bar", "bar.foo"}}, pub}, expectedCustomOptions, http.StatusOK, false, false}, {"ok-custom", p2, args{t2, SignSSHOptions{Principals: []string{"foo.bar", "bar.foo"}}, pub}, expectedCustomOptions, http.StatusOK, false, false},
{"fail-rsa1024", p1, args{t1, SSHOptions{}, rsa1024.Public()}, expectedHostOptions, http.StatusOK, false, true}, {"fail-rsa1024", p1, args{t1, SignSSHOptions{}, rsa1024.Public()}, expectedHostOptions, http.StatusOK, false, true},
{"fail-type", p1, args{t1, SSHOptions{CertType: "user"}, pub}, nil, http.StatusOK, false, true}, {"fail-type", p1, args{t1, SignSSHOptions{CertType: "user"}, pub}, nil, http.StatusOK, false, true},
{"fail-principal", p1, args{t1, SSHOptions{Principals: []string{"smallstep.com"}}, pub}, nil, http.StatusOK, false, true}, {"fail-principal", p1, args{t1, SignSSHOptions{Principals: []string{"smallstep.com"}}, pub}, nil, http.StatusOK, false, true},
{"fail-extra-principal", p1, args{t1, SSHOptions{Principals: []string{"instance-name.c.project-id.internal", "instance-name.zone.c.project-id.internal", "smallstep.com"}}, pub}, nil, http.StatusOK, false, true}, {"fail-extra-principal", p1, args{t1, SignSSHOptions{Principals: []string{"instance-name.c.project-id.internal", "instance-name.zone.c.project-id.internal", "smallstep.com"}}, pub}, nil, http.StatusOK, false, true},
{"fail-sshCA-disabled", p3, args{"foo", SSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false}, {"fail-sshCA-disabled", p3, args{"foo", SignSSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false},
{"fail-invalid-token", p1, args{"foo", SSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false}, {"fail-invalid-token", p1, args{"foo", SignSSHOptions{}, pub}, expectedHostOptions, http.StatusUnauthorized, true, false},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View file

@ -20,19 +20,19 @@ type jwtPayload struct {
} }
type stepPayload struct { type stepPayload struct {
SSH *SSHOptions `json:"ssh,omitempty"` SSH *SignSSHOptions `json:"ssh,omitempty"`
} }
// JWK is the default provisioner, an entity that can sign tokens necessary for // JWK is the default provisioner, an entity that can sign tokens necessary for
// signature requests. // signature requests.
type JWK struct { type JWK struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
Key *jose.JSONWebKey `json:"key"` Key *jose.JSONWebKey `json:"key"`
EncryptedKey string `json:"encryptedKey,omitempty"` EncryptedKey string `json:"encryptedKey,omitempty"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *ProvisionerOptions `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
claimer *Claimer claimer *Claimer
audiences Audiences audiences Audiences
} }

View file

@ -404,41 +404,41 @@ func TestJWK_AuthorizeSSHSign(t *testing.T) {
userDuration := p1.claimer.DefaultUserSSHCertDuration() userDuration := p1.claimer.DefaultUserSSHCertDuration()
hostDuration := p1.claimer.DefaultHostSSHCertDuration() hostDuration := p1.claimer.DefaultHostSSHCertDuration()
expectedUserOptions := &SSHOptions{ expectedUserOptions := &SignSSHOptions{
CertType: "user", Principals: []string{"name"}, CertType: "user", Principals: []string{"name"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration)),
} }
expectedHostOptions := &SSHOptions{ expectedHostOptions := &SignSSHOptions{
CertType: "host", Principals: []string{"smallstep.com"}, CertType: "host", Principals: []string{"smallstep.com"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
type args struct { type args struct {
token string token string
sshOpts SSHOptions sshOpts SignSSHOptions
key interface{} key interface{}
} }
tests := []struct { tests := []struct {
name string name string
prov *JWK prov *JWK
args args args args
expected *SSHOptions expected *SignSSHOptions
code int code int
wantErr bool wantErr bool
wantSignErr bool wantSignErr bool
}{ }{
{"user", p1, args{t1, SSHOptions{}, pub}, expectedUserOptions, http.StatusOK, false, false}, {"user", p1, args{t1, SignSSHOptions{}, pub}, expectedUserOptions, http.StatusOK, false, false},
{"user-rsa2048", p1, args{t1, SSHOptions{}, rsa2048.Public()}, expectedUserOptions, http.StatusOK, false, false}, {"user-rsa2048", p1, args{t1, SignSSHOptions{}, rsa2048.Public()}, expectedUserOptions, http.StatusOK, false, false},
{"user-type", p1, args{t1, SSHOptions{CertType: "user"}, pub}, expectedUserOptions, http.StatusOK, false, false}, {"user-type", p1, args{t1, SignSSHOptions{CertType: "user"}, pub}, expectedUserOptions, http.StatusOK, false, false},
{"user-principals", p1, args{t1, SSHOptions{Principals: []string{"name"}}, pub}, expectedUserOptions, http.StatusOK, false, false}, {"user-principals", p1, args{t1, SignSSHOptions{Principals: []string{"name"}}, pub}, expectedUserOptions, http.StatusOK, false, false},
{"user-options", p1, args{t1, SSHOptions{CertType: "user", Principals: []string{"name"}}, pub}, expectedUserOptions, http.StatusOK, false, false}, {"user-options", p1, args{t1, SignSSHOptions{CertType: "user", Principals: []string{"name"}}, pub}, expectedUserOptions, http.StatusOK, false, false},
{"host", p1, args{t2, SSHOptions{}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"host", p1, args{t2, SignSSHOptions{}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"host-type", p1, args{t2, SSHOptions{CertType: "host"}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"host-type", p1, args{t2, SignSSHOptions{CertType: "host"}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"host-principals", p1, args{t2, SSHOptions{Principals: []string{"smallstep.com"}}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"host-principals", p1, args{t2, SignSSHOptions{Principals: []string{"smallstep.com"}}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"host-options", p1, args{t2, SSHOptions{CertType: "host", Principals: []string{"smallstep.com"}}, pub}, expectedHostOptions, http.StatusOK, false, false}, {"host-options", p1, args{t2, SignSSHOptions{CertType: "host", Principals: []string{"smallstep.com"}}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"fail-sshCA-disabled", p2, args{"foo", SSHOptions{}, pub}, expectedUserOptions, http.StatusUnauthorized, true, false}, {"fail-sshCA-disabled", p2, args{"foo", SignSSHOptions{}, pub}, expectedUserOptions, http.StatusUnauthorized, true, false},
{"fail-signature", p1, args{failSig, SSHOptions{}, pub}, nil, http.StatusUnauthorized, true, false}, {"fail-signature", p1, args{failSig, SignSSHOptions{}, pub}, nil, http.StatusUnauthorized, true, false},
{"rail-rsa1024", p1, args{t1, SSHOptions{}, rsa1024.Public()}, expectedUserOptions, http.StatusOK, false, true}, {"rail-rsa1024", p1, args{t1, SignSSHOptions{}, rsa1024.Public()}, expectedUserOptions, http.StatusOK, false, true},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -487,72 +487,72 @@ func TestJWK_AuthorizeSign_SSHOptions(t *testing.T) {
userDuration := p1.claimer.DefaultUserSSHCertDuration() userDuration := p1.claimer.DefaultUserSSHCertDuration()
hostDuration := p1.claimer.DefaultHostSSHCertDuration() hostDuration := p1.claimer.DefaultHostSSHCertDuration()
expectedUserOptions := &SSHOptions{ expectedUserOptions := &SignSSHOptions{
CertType: "user", Principals: []string{"name"}, CertType: "user", Principals: []string{"name"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration)),
} }
expectedHostOptions := &SSHOptions{ expectedHostOptions := &SignSSHOptions{
CertType: "host", Principals: []string{"smallstep.com"}, CertType: "host", Principals: []string{"smallstep.com"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
type args struct { type args struct {
sub, iss, aud string sub, iss, aud string
iat time.Time iat time.Time
tokSSHOpts *SSHOptions tokSSHOpts *SignSSHOptions
userSSHOpts *SSHOptions userSSHOpts *SignSSHOptions
jwk *jose.JSONWebKey jwk *jose.JSONWebKey
} }
tests := []struct { tests := []struct {
name string name string
prov *JWK prov *JWK
args args args args
expected *SSHOptions expected *SignSSHOptions
wantErr bool wantErr bool
wantSignErr bool wantSignErr bool
}{ }{
{"ok-user", p1, args{sub, iss, aud, iat, &SSHOptions{CertType: "user", Principals: []string{"name"}}, &SSHOptions{}, jwk}, expectedUserOptions, false, false}, {"ok-user", p1, args{sub, iss, aud, iat, &SignSSHOptions{CertType: "user", Principals: []string{"name"}}, &SignSSHOptions{}, jwk}, expectedUserOptions, false, false},
{"ok-host", p1, args{sub, iss, aud, iat, &SSHOptions{CertType: "host", Principals: []string{"smallstep.com"}}, &SSHOptions{}, jwk}, expectedHostOptions, false, false}, {"ok-host", p1, args{sub, iss, aud, iat, &SignSSHOptions{CertType: "host", Principals: []string{"smallstep.com"}}, &SignSSHOptions{}, jwk}, expectedHostOptions, false, false},
{"ok-user-opts", p1, args{sub, iss, aud, iat, &SSHOptions{}, &SSHOptions{CertType: "user", Principals: []string{"name"}}, jwk}, expectedUserOptions, false, false}, {"ok-user-opts", p1, args{sub, iss, aud, iat, &SignSSHOptions{}, &SignSSHOptions{CertType: "user", Principals: []string{"name"}}, jwk}, expectedUserOptions, false, false},
{"ok-host-opts", p1, args{sub, iss, aud, iat, &SSHOptions{}, &SSHOptions{CertType: "host", Principals: []string{"smallstep.com"}}, jwk}, expectedHostOptions, false, false}, {"ok-host-opts", p1, args{sub, iss, aud, iat, &SignSSHOptions{}, &SignSSHOptions{CertType: "host", Principals: []string{"smallstep.com"}}, jwk}, expectedHostOptions, false, false},
{"ok-user-mixed", p1, args{sub, iss, aud, iat, &SSHOptions{CertType: "user"}, &SSHOptions{Principals: []string{"name"}}, jwk}, expectedUserOptions, false, false}, {"ok-user-mixed", p1, args{sub, iss, aud, iat, &SignSSHOptions{CertType: "user"}, &SignSSHOptions{Principals: []string{"name"}}, jwk}, expectedUserOptions, false, false},
{"ok-host-mixed", p1, args{sub, iss, aud, iat, &SSHOptions{Principals: []string{"smallstep.com"}}, &SSHOptions{CertType: "host"}, jwk}, expectedHostOptions, false, false}, {"ok-host-mixed", p1, args{sub, iss, aud, iat, &SignSSHOptions{Principals: []string{"smallstep.com"}}, &SignSSHOptions{CertType: "host"}, jwk}, expectedHostOptions, false, false},
{"ok-user-validAfter", p1, args{sub, iss, aud, iat, &SSHOptions{ {"ok-user-validAfter", p1, args{sub, iss, aud, iat, &SignSSHOptions{
CertType: "user", Principals: []string{"name"}, CertType: "user", Principals: []string{"name"},
}, &SSHOptions{ }, &SignSSHOptions{
ValidAfter: NewTimeDuration(tm.Add(-time.Hour)), ValidAfter: NewTimeDuration(tm.Add(-time.Hour)),
}, jwk}, &SSHOptions{ }, jwk}, &SignSSHOptions{
CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm.Add(-time.Hour)), ValidBefore: NewTimeDuration(tm.Add(userDuration - time.Hour)), CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm.Add(-time.Hour)), ValidBefore: NewTimeDuration(tm.Add(userDuration - time.Hour)),
}, false, false}, }, false, false},
{"ok-user-validBefore", p1, args{sub, iss, aud, iat, &SSHOptions{ {"ok-user-validBefore", p1, args{sub, iss, aud, iat, &SignSSHOptions{
CertType: "user", Principals: []string{"name"}, CertType: "user", Principals: []string{"name"},
}, &SSHOptions{ }, &SignSSHOptions{
ValidBefore: NewTimeDuration(tm.Add(time.Hour)), ValidBefore: NewTimeDuration(tm.Add(time.Hour)),
}, jwk}, &SSHOptions{ }, jwk}, &SignSSHOptions{
CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(time.Hour)), CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(time.Hour)),
}, false, false}, }, false, false},
{"ok-user-validAfter-validBefore", p1, args{sub, iss, aud, iat, &SSHOptions{ {"ok-user-validAfter-validBefore", p1, args{sub, iss, aud, iat, &SignSSHOptions{
CertType: "user", Principals: []string{"name"}, CertType: "user", Principals: []string{"name"},
}, &SSHOptions{ }, &SignSSHOptions{
ValidAfter: NewTimeDuration(tm.Add(10 * time.Minute)), ValidBefore: NewTimeDuration(tm.Add(time.Hour)), ValidAfter: NewTimeDuration(tm.Add(10 * time.Minute)), ValidBefore: NewTimeDuration(tm.Add(time.Hour)),
}, jwk}, &SSHOptions{ }, jwk}, &SignSSHOptions{
CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm.Add(10 * time.Minute)), ValidBefore: NewTimeDuration(tm.Add(time.Hour)), CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm.Add(10 * time.Minute)), ValidBefore: NewTimeDuration(tm.Add(time.Hour)),
}, false, false}, }, false, false},
{"ok-user-match", p1, args{sub, iss, aud, iat, &SSHOptions{ {"ok-user-match", p1, args{sub, iss, aud, iat, &SignSSHOptions{
CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(1 * time.Hour)), CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(1 * time.Hour)),
}, &SSHOptions{ }, &SignSSHOptions{
CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(1 * time.Hour)), CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(1 * time.Hour)),
}, jwk}, &SSHOptions{ }, jwk}, &SignSSHOptions{
CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(time.Hour)), CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(time.Hour)),
}, false, false}, }, false, false},
{"fail-certType", p1, args{sub, iss, aud, iat, &SSHOptions{CertType: "user", Principals: []string{"name"}}, &SSHOptions{CertType: "host"}, jwk}, nil, false, true}, {"fail-certType", p1, args{sub, iss, aud, iat, &SignSSHOptions{CertType: "user", Principals: []string{"name"}}, &SignSSHOptions{CertType: "host"}, jwk}, nil, false, true},
{"fail-principals", p1, args{sub, iss, aud, iat, &SSHOptions{CertType: "user", Principals: []string{"name"}}, &SSHOptions{Principals: []string{"root"}}, jwk}, nil, false, true}, {"fail-principals", p1, args{sub, iss, aud, iat, &SignSSHOptions{CertType: "user", Principals: []string{"name"}}, &SignSSHOptions{Principals: []string{"root"}}, jwk}, nil, false, true},
{"fail-validAfter", p1, args{sub, iss, aud, iat, &SSHOptions{CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm)}, &SSHOptions{ValidAfter: NewTimeDuration(tm.Add(time.Hour))}, jwk}, nil, false, true}, {"fail-validAfter", p1, args{sub, iss, aud, iat, &SignSSHOptions{CertType: "user", Principals: []string{"name"}, ValidAfter: NewTimeDuration(tm)}, &SignSSHOptions{ValidAfter: NewTimeDuration(tm.Add(time.Hour))}, jwk}, nil, false, true},
{"fail-validBefore", p1, args{sub, iss, aud, iat, &SSHOptions{CertType: "user", Principals: []string{"name"}, ValidBefore: NewTimeDuration(tm.Add(time.Hour))}, &SSHOptions{ValidBefore: NewTimeDuration(tm.Add(10 * time.Hour))}, jwk}, nil, false, true}, {"fail-validBefore", p1, args{sub, iss, aud, iat, &SignSSHOptions{CertType: "user", Principals: []string{"name"}, ValidBefore: NewTimeDuration(tm.Add(time.Hour))}, &SignSSHOptions{ValidBefore: NewTimeDuration(tm.Add(10 * time.Hour))}, jwk}, nil, false, true},
{"fail-subject", p1, args{"", iss, aud, iat, &SSHOptions{CertType: "user", Principals: []string{"name"}}, &SSHOptions{}, jwk}, nil, true, false}, {"fail-subject", p1, args{"", iss, aud, iat, &SignSSHOptions{CertType: "user", Principals: []string{"name"}}, &SignSSHOptions{}, jwk}, nil, true, false},
{"fail-issuer", p1, args{sub, "invalid", aud, iat, &SSHOptions{CertType: "user", Principals: []string{"name"}}, &SSHOptions{}, jwk}, nil, true, false}, {"fail-issuer", p1, args{sub, "invalid", aud, iat, &SignSSHOptions{CertType: "user", Principals: []string{"name"}}, &SignSSHOptions{}, jwk}, nil, true, false},
{"fail-audience", p1, args{sub, iss, "invalid", iat, &SSHOptions{CertType: "user", Principals: []string{"name"}}, &SSHOptions{}, jwk}, nil, true, false}, {"fail-audience", p1, args{sub, iss, "invalid", iat, &SignSSHOptions{CertType: "user", Principals: []string{"name"}}, &SignSSHOptions{}, jwk}, nil, true, false},
{"fail-expired", p1, args{sub, iss, aud, iat.Add(-6 * time.Minute), &SSHOptions{CertType: "user", Principals: []string{"name"}}, &SSHOptions{}, jwk}, nil, true, false}, {"fail-expired", p1, args{sub, iss, aud, iat.Add(-6 * time.Minute), &SignSSHOptions{CertType: "user", Principals: []string{"name"}}, &SignSSHOptions{}, jwk}, nil, true, false},
{"fail-notBefore", p1, args{sub, iss, aud, iat.Add(5 * time.Minute), &SSHOptions{CertType: "user", Principals: []string{"name"}}, &SSHOptions{}, jwk}, nil, true, false}, {"fail-notBefore", p1, args{sub, iss, aud, iat.Add(5 * time.Minute), &SignSSHOptions{CertType: "user", Principals: []string{"name"}}, &SignSSHOptions{}, jwk}, nil, true, false},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -561,7 +561,7 @@ func TestJWK_AuthorizeSign_SSHOptions(t *testing.T) {
if got, err := tt.prov.AuthorizeSSHSign(context.Background(), token); (err != nil) != tt.wantErr { if got, err := tt.prov.AuthorizeSSHSign(context.Background(), token); (err != nil) != tt.wantErr {
t.Errorf("JWK.AuthorizeSSHSign() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("JWK.AuthorizeSSHSign() error = %v, wantErr %v", err, tt.wantErr)
} else if !tt.wantErr && assert.NotNil(t, got) { } else if !tt.wantErr && assert.NotNil(t, got) {
var opts SSHOptions var opts SignSSHOptions
if tt.args.userSSHOpts != nil { if tt.args.userSSHOpts != nil {
opts = *tt.args.userSSHOpts opts = *tt.args.userSSHOpts
} }

View file

@ -41,11 +41,11 @@ type k8sSAPayload struct {
// entity trusted to make signature requests. // entity trusted to make signature requests.
type K8sSA struct { type K8sSA struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
PubKeys []byte `json:"publicKeys,omitempty"` PubKeys []byte `json:"publicKeys,omitempty"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *ProvisionerOptions `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
claimer *Claimer claimer *Claimer
audiences Audiences audiences Audiences
//kauthn kauthn.AuthenticationV1Interface //kauthn kauthn.AuthenticationV1Interface

View file

@ -53,18 +53,18 @@ type openIDPayload struct {
// ClientSecret is mandatory, but it can be an empty string. // ClientSecret is mandatory, but it can be an empty string.
type OIDC struct { type OIDC struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
ClientID string `json:"clientID"` ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"` ClientSecret string `json:"clientSecret"`
ConfigurationEndpoint string `json:"configurationEndpoint"` ConfigurationEndpoint string `json:"configurationEndpoint"`
TenantID string `json:"tenantID,omitempty"` TenantID string `json:"tenantID,omitempty"`
Admins []string `json:"admins,omitempty"` Admins []string `json:"admins,omitempty"`
Domains []string `json:"domains,omitempty"` Domains []string `json:"domains,omitempty"`
Groups []string `json:"groups,omitempty"` Groups []string `json:"groups,omitempty"`
ListenAddress string `json:"listenAddress,omitempty"` ListenAddress string `json:"listenAddress,omitempty"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *ProvisionerOptions `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
configuration openIDConfiguration configuration openIDConfiguration
keyStore *keyStore keyStore *keyStore
claimer *Claimer claimer *Claimer
@ -380,7 +380,7 @@ func (o *OIDC) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "oidc.AuthorizeSSHSign") return nil, errs.Wrap(http.StatusInternalServerError, err, "oidc.AuthorizeSSHSign")
} }
defaults := SSHOptions{ defaults := SignSSHOptions{
CertType: SSHUserCert, CertType: SSHUserCert,
Principals: iden.Usernames, Principals: iden.Usernames,
} }

View file

@ -534,64 +534,64 @@ func TestOIDC_AuthorizeSSHSign(t *testing.T) {
userDuration := p1.claimer.DefaultUserSSHCertDuration() userDuration := p1.claimer.DefaultUserSSHCertDuration()
hostDuration := p1.claimer.DefaultHostSSHCertDuration() hostDuration := p1.claimer.DefaultHostSSHCertDuration()
expectedUserOptions := &SSHOptions{ expectedUserOptions := &SignSSHOptions{
CertType: "user", Principals: []string{"name", "name@smallstep.com"}, CertType: "user", Principals: []string{"name", "name@smallstep.com"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration)),
} }
expectedAdminOptions := &SSHOptions{ expectedAdminOptions := &SignSSHOptions{
CertType: "user", Principals: []string{"root", "root@example.com"}, CertType: "user", Principals: []string{"root", "root@example.com"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration)),
} }
expectedHostOptions := &SSHOptions{ expectedHostOptions := &SignSSHOptions{
CertType: "host", Principals: []string{"smallstep.com"}, CertType: "host", Principals: []string{"smallstep.com"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)), ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(hostDuration)),
} }
type args struct { type args struct {
token string token string
sshOpts SSHOptions sshOpts SignSSHOptions
key interface{} key interface{}
} }
tests := []struct { tests := []struct {
name string name string
prov *OIDC prov *OIDC
args args args args
expected *SSHOptions expected *SignSSHOptions
code int code int
wantErr bool wantErr bool
wantSignErr bool wantSignErr bool
}{ }{
{"ok", p1, args{t1, SSHOptions{}, pub}, expectedUserOptions, http.StatusOK, false, false}, {"ok", p1, args{t1, SignSSHOptions{}, pub}, expectedUserOptions, http.StatusOK, false, false},
{"ok-rsa2048", p1, args{t1, SSHOptions{}, rsa2048.Public()}, expectedUserOptions, http.StatusOK, false, false}, {"ok-rsa2048", p1, args{t1, SignSSHOptions{}, rsa2048.Public()}, expectedUserOptions, http.StatusOK, false, false},
{"ok-user", p1, args{t1, SSHOptions{CertType: "user"}, pub}, expectedUserOptions, http.StatusOK, false, false}, {"ok-user", p1, args{t1, SignSSHOptions{CertType: "user"}, pub}, expectedUserOptions, http.StatusOK, false, false},
{"ok-principals", p1, args{t1, SSHOptions{Principals: []string{"name"}}, pub}, {"ok-principals", p1, args{t1, SignSSHOptions{Principals: []string{"name"}}, pub},
&SSHOptions{CertType: "user", Principals: []string{"name"}, &SignSSHOptions{CertType: "user", Principals: []string{"name"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false},
{"ok-principals-getIdentity", p4, args{okGetIdentityToken, SSHOptions{Principals: []string{"mariano"}}, pub}, {"ok-principals-getIdentity", p4, args{okGetIdentityToken, SignSSHOptions{Principals: []string{"mariano"}}, pub},
&SSHOptions{CertType: "user", Principals: []string{"mariano"}, &SignSSHOptions{CertType: "user", Principals: []string{"mariano"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false},
{"ok-emptyPrincipals-getIdentity", p4, args{okGetIdentityToken, SSHOptions{}, pub}, {"ok-emptyPrincipals-getIdentity", p4, args{okGetIdentityToken, SignSSHOptions{}, pub},
&SSHOptions{CertType: "user", Principals: []string{"max", "mariano"}, &SignSSHOptions{CertType: "user", Principals: []string{"max", "mariano"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false},
{"ok-options", p1, args{t1, SSHOptions{CertType: "user", Principals: []string{"name"}}, pub}, {"ok-options", p1, args{t1, SignSSHOptions{CertType: "user", Principals: []string{"name"}}, pub},
&SSHOptions{CertType: "user", Principals: []string{"name"}, &SignSSHOptions{CertType: "user", Principals: []string{"name"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false},
{"admin", p3, args{okAdmin, SSHOptions{}, pub}, expectedAdminOptions, http.StatusOK, false, false}, {"admin", p3, args{okAdmin, SignSSHOptions{}, pub}, expectedAdminOptions, http.StatusOK, false, false},
{"admin-user", p3, args{okAdmin, SSHOptions{CertType: "user"}, pub}, expectedAdminOptions, http.StatusOK, false, false}, {"admin-user", p3, args{okAdmin, SignSSHOptions{CertType: "user"}, pub}, expectedAdminOptions, http.StatusOK, false, false},
{"admin-principals", p3, args{okAdmin, SSHOptions{Principals: []string{"root"}}, pub}, {"admin-principals", p3, args{okAdmin, SignSSHOptions{Principals: []string{"root"}}, pub},
&SSHOptions{CertType: "user", Principals: []string{"root"}, &SignSSHOptions{CertType: "user", Principals: []string{"root"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false},
{"admin-options", p3, args{okAdmin, SSHOptions{CertType: "user", Principals: []string{"name"}}, pub}, {"admin-options", p3, args{okAdmin, SignSSHOptions{CertType: "user", Principals: []string{"name"}}, pub},
&SSHOptions{CertType: "user", Principals: []string{"name"}, &SignSSHOptions{CertType: "user", Principals: []string{"name"},
ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false}, ValidAfter: NewTimeDuration(tm), ValidBefore: NewTimeDuration(tm.Add(userDuration))}, http.StatusOK, false, false},
{"admin-host", p3, args{okAdmin, SSHOptions{CertType: "host", Principals: []string{"smallstep.com"}}, pub}, {"admin-host", p3, args{okAdmin, SignSSHOptions{CertType: "host", Principals: []string{"smallstep.com"}}, pub},
expectedHostOptions, http.StatusOK, false, false}, expectedHostOptions, http.StatusOK, false, false},
{"fail-rsa1024", p1, args{t1, SSHOptions{}, rsa1024.Public()}, expectedUserOptions, http.StatusOK, false, true}, {"fail-rsa1024", p1, args{t1, SignSSHOptions{}, rsa1024.Public()}, expectedUserOptions, http.StatusOK, false, true},
{"fail-user-host", p1, args{t1, SSHOptions{CertType: "host"}, pub}, nil, http.StatusOK, false, true}, {"fail-user-host", p1, args{t1, SignSSHOptions{CertType: "host"}, pub}, nil, http.StatusOK, false, true},
{"fail-user-principals", p1, args{t1, SSHOptions{Principals: []string{"root"}}, pub}, nil, http.StatusOK, false, true}, {"fail-user-principals", p1, args{t1, SignSSHOptions{Principals: []string{"root"}}, pub}, nil, http.StatusOK, false, true},
{"fail-email", p3, args{failEmail, SSHOptions{}, pub}, nil, http.StatusUnauthorized, true, false}, {"fail-email", p3, args{failEmail, SignSSHOptions{}, pub}, nil, http.StatusUnauthorized, true, false},
{"fail-getIdentity", p5, args{failGetIdentityToken, SSHOptions{}, pub}, nil, http.StatusInternalServerError, true, false}, {"fail-getIdentity", p5, args{failGetIdentityToken, SignSSHOptions{}, pub}, nil, http.StatusInternalServerError, true, false},
{"fail-sshCA-disabled", p6, args{"foo", SSHOptions{}, pub}, nil, http.StatusUnauthorized, true, false}, {"fail-sshCA-disabled", p6, args{"foo", SignSSHOptions{}, pub}, nil, http.StatusUnauthorized, true, false},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View file

@ -12,19 +12,18 @@ import (
// CertificateOptions is an interface that returns a list of options passed when // CertificateOptions is an interface that returns a list of options passed when
// creating a new certificate. // creating a new certificate.
type CertificateOptions interface { type CertificateOptions interface {
Options(Options) []x509util.Option Options(SignOptions) []x509util.Option
} }
type certificateOptionsFunc func(Options) []x509util.Option type certificateOptionsFunc func(SignOptions) []x509util.Option
func (fn certificateOptionsFunc) Options(so Options) []x509util.Option { func (fn certificateOptionsFunc) Options(so SignOptions) []x509util.Option {
return fn(so) return fn(so)
} }
// ProvisionerOptions are a collection of custom options that can be added to // Options are a collection of custom options that can be added to
// each provisioner. // each provisioner.
// nolint:golint type Options struct {
type ProvisionerOptions struct {
// Template contains a X.509 certificate template. It can be a JSON template // Template contains a X.509 certificate template. It can be a JSON template
// escaped in a string or it can be also encoded in base64. // escaped in a string or it can be also encoded in base64.
Template string `json:"template"` Template string `json:"template"`
@ -38,7 +37,7 @@ type ProvisionerOptions struct {
} }
// HasTemplate returns true if a template is defined in the provisioner options. // HasTemplate returns true if a template is defined in the provisioner options.
func (o *ProvisionerOptions) HasTemplate() bool { func (o *Options) HasTemplate() bool {
return o != nil && (o.Template != "" || o.TemplateFile != "") return o != nil && (o.Template != "" || o.TemplateFile != "")
} }
@ -46,7 +45,7 @@ func (o *ProvisionerOptions) HasTemplate() bool {
// defined in the ProvisionerOptions, the provisioner generated data, and the // defined in the ProvisionerOptions, the provisioner generated data, and the
// user data provided in the request. If no template has been provided, // user data provided in the request. If no template has been provided,
// x509util.DefaultLeafTemplate will be used. // x509util.DefaultLeafTemplate will be used.
func TemplateOptions(o *ProvisionerOptions, data x509util.TemplateData) (CertificateOptions, error) { func TemplateOptions(o *Options, data x509util.TemplateData) (CertificateOptions, error) {
return CustomTemplateOptions(o, data, x509util.DefaultLeafTemplate) return CustomTemplateOptions(o, data, x509util.DefaultLeafTemplate)
} }
@ -54,7 +53,7 @@ func TemplateOptions(o *ProvisionerOptions, data x509util.TemplateData) (Certifi
// defined in the ProvisionerOptions, the provisioner generated data and the // defined in the ProvisionerOptions, the provisioner generated data and the
// user data provided in the request. If no template has been provided in the // user data provided in the request. If no template has been provided in the
// ProvisionerOptions, the given template will be used. // ProvisionerOptions, the given template will be used.
func CustomTemplateOptions(o *ProvisionerOptions, data x509util.TemplateData, defaultTemplate string) (CertificateOptions, error) { func CustomTemplateOptions(o *Options, data x509util.TemplateData, defaultTemplate string) (CertificateOptions, error) {
if o != nil { if o != nil {
if data == nil { if data == nil {
data = x509util.NewTemplateData() data = x509util.NewTemplateData()
@ -68,7 +67,7 @@ func CustomTemplateOptions(o *ProvisionerOptions, data x509util.TemplateData, de
} }
} }
return certificateOptionsFunc(func(so Options) []x509util.Option { return certificateOptionsFunc(func(so SignOptions) []x509util.Option {
// We're not provided user data without custom templates. // We're not provided user data without custom templates.
if !o.HasTemplate() { if !o.HasTemplate() {
return []x509util.Option{ return []x509util.Option{

View file

@ -42,7 +42,7 @@ func TestProvisionerOptions_HasTemplate(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
o := &ProvisionerOptions{ o := &Options{
Template: tt.fields.Template, Template: tt.fields.Template,
TemplateFile: tt.fields.TemplateFile, TemplateFile: tt.fields.TemplateFile,
TemplateData: tt.fields.TemplateData, TemplateData: tt.fields.TemplateData,
@ -65,7 +65,7 @@ func TestTemplateOptions(t *testing.T) {
}, },
} }
type args struct { type args struct {
o *ProvisionerOptions o *Options
data x509util.TemplateData data x509util.TemplateData
} }
tests := []struct { tests := []struct {
@ -81,14 +81,14 @@ func TestTemplateOptions(t *testing.T) {
"keyUsage": ["digitalSignature"], "keyUsage": ["digitalSignature"],
"extKeyUsage": ["serverAuth", "clientAuth"] "extKeyUsage": ["serverAuth", "clientAuth"]
}`)}, false}, }`)}, false},
{"okCustomTemplate", args{&ProvisionerOptions{Template: x509util.DefaultIIDLeafTemplate}, data}, x509util.Options{ {"okCustomTemplate", args{&Options{Template: x509util.DefaultIIDLeafTemplate}, data}, x509util.Options{
CertBuffer: bytes.NewBufferString(`{ CertBuffer: bytes.NewBufferString(`{
"subject": {"commonName":"foo"}, "subject": {"commonName":"foo"},
"sans": [{"type":"dns","value":"foo.com"}], "sans": [{"type":"dns","value":"foo.com"}],
"keyUsage": ["digitalSignature"], "keyUsage": ["digitalSignature"],
"extKeyUsage": ["serverAuth", "clientAuth"] "extKeyUsage": ["serverAuth", "clientAuth"]
}`)}, false}, }`)}, false},
{"fail", args{&ProvisionerOptions{TemplateData: []byte(`{"badJSON`)}, data}, x509util.Options{}, true}, {"fail", args{&Options{TemplateData: []byte(`{"badJSON`)}, data}, x509util.Options{}, true},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -99,7 +99,7 @@ func TestTemplateOptions(t *testing.T) {
} }
var opts x509util.Options var opts x509util.Options
if cof != nil { if cof != nil {
for _, fn := range cof.Options(Options{}) { for _, fn := range cof.Options(SignOptions{}) {
if err := fn(csr, &opts); err != nil { if err := fn(csr, &opts); err != nil {
t.Errorf("x509util.Options() error = %v", err) t.Errorf("x509util.Options() error = %v", err)
return return
@ -125,10 +125,10 @@ func TestCustomTemplateOptions(t *testing.T) {
}, },
} }
type args struct { type args struct {
o *ProvisionerOptions o *Options
data x509util.TemplateData data x509util.TemplateData
defaultTemplate string defaultTemplate string
userOptions Options userOptions SignOptions
} }
tests := []struct { tests := []struct {
name string name string
@ -136,48 +136,48 @@ func TestCustomTemplateOptions(t *testing.T) {
want x509util.Options want x509util.Options
wantErr bool wantErr bool
}{ }{
{"ok", args{nil, data, x509util.DefaultLeafTemplate, Options{}}, x509util.Options{ {"ok", args{nil, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
CertBuffer: bytes.NewBufferString(`{ CertBuffer: bytes.NewBufferString(`{
"subject": {"commonName":"foobar"}, "subject": {"commonName":"foobar"},
"sans": [{"type":"dns","value":"foo.com"}], "sans": [{"type":"dns","value":"foo.com"}],
"keyUsage": ["digitalSignature"], "keyUsage": ["digitalSignature"],
"extKeyUsage": ["serverAuth", "clientAuth"] "extKeyUsage": ["serverAuth", "clientAuth"]
}`)}, false}, }`)}, false},
{"okIID", args{nil, data, x509util.DefaultIIDLeafTemplate, Options{}}, x509util.Options{ {"okIID", args{nil, data, x509util.DefaultIIDLeafTemplate, SignOptions{}}, x509util.Options{
CertBuffer: bytes.NewBufferString(`{ CertBuffer: bytes.NewBufferString(`{
"subject": {"commonName":"foo"}, "subject": {"commonName":"foo"},
"sans": [{"type":"dns","value":"foo.com"}], "sans": [{"type":"dns","value":"foo.com"}],
"keyUsage": ["digitalSignature"], "keyUsage": ["digitalSignature"],
"extKeyUsage": ["serverAuth", "clientAuth"] "extKeyUsage": ["serverAuth", "clientAuth"]
}`)}, false}, }`)}, false},
{"okNoData", args{&ProvisionerOptions{}, nil, x509util.DefaultLeafTemplate, Options{}}, x509util.Options{ {"okNoData", args{&Options{}, nil, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
CertBuffer: bytes.NewBufferString(`{ CertBuffer: bytes.NewBufferString(`{
"subject": null, "subject": null,
"sans": null, "sans": null,
"keyUsage": ["digitalSignature"], "keyUsage": ["digitalSignature"],
"extKeyUsage": ["serverAuth", "clientAuth"] "extKeyUsage": ["serverAuth", "clientAuth"]
}`)}, false}, }`)}, false},
{"okTemplateData", args{&ProvisionerOptions{TemplateData: []byte(`{"foo":"bar"}`)}, data, x509util.DefaultLeafTemplate, Options{}}, x509util.Options{ {"okTemplateData", args{&Options{TemplateData: []byte(`{"foo":"bar"}`)}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
CertBuffer: bytes.NewBufferString(`{ CertBuffer: bytes.NewBufferString(`{
"subject": {"commonName":"foobar"}, "subject": {"commonName":"foobar"},
"sans": [{"type":"dns","value":"foo.com"}], "sans": [{"type":"dns","value":"foo.com"}],
"keyUsage": ["digitalSignature"], "keyUsage": ["digitalSignature"],
"extKeyUsage": ["serverAuth", "clientAuth"] "extKeyUsage": ["serverAuth", "clientAuth"]
}`)}, false}, }`)}, false},
{"okTemplate", args{&ProvisionerOptions{Template: "{{ toJson .Insecure.CR }}"}, data, x509util.DefaultLeafTemplate, Options{}}, x509util.Options{ {"okTemplate", args{&Options{Template: "{{ toJson .Insecure.CR }}"}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
CertBuffer: bytes.NewBufferString(csrCertificate)}, false}, CertBuffer: bytes.NewBufferString(csrCertificate)}, false},
{"okFile", args{&ProvisionerOptions{TemplateFile: "./testdata/templates/cr.tpl"}, data, x509util.DefaultLeafTemplate, Options{}}, x509util.Options{ {"okFile", args{&Options{TemplateFile: "./testdata/templates/cr.tpl"}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
CertBuffer: bytes.NewBufferString(csrCertificate)}, false}, CertBuffer: bytes.NewBufferString(csrCertificate)}, false},
{"okBase64", args{&ProvisionerOptions{Template: "e3sgdG9Kc29uIC5JbnNlY3VyZS5DUiB9fQ=="}, data, x509util.DefaultLeafTemplate, Options{}}, x509util.Options{ {"okBase64", args{&Options{Template: "e3sgdG9Kc29uIC5JbnNlY3VyZS5DUiB9fQ=="}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
CertBuffer: bytes.NewBufferString(csrCertificate)}, false}, CertBuffer: bytes.NewBufferString(csrCertificate)}, false},
{"okUserOptions", args{&ProvisionerOptions{Template: `{"foo": "{{.Insecure.User.foo}}"}`}, data, x509util.DefaultLeafTemplate, Options{TemplateData: []byte(`{"foo":"bar"}`)}}, x509util.Options{ {"okUserOptions", args{&Options{Template: `{"foo": "{{.Insecure.User.foo}}"}`}, data, x509util.DefaultLeafTemplate, SignOptions{TemplateData: []byte(`{"foo":"bar"}`)}}, x509util.Options{
CertBuffer: bytes.NewBufferString(`{"foo": "bar"}`), CertBuffer: bytes.NewBufferString(`{"foo": "bar"}`),
}, false}, }, false},
{"okBadUserOptions", args{&ProvisionerOptions{Template: `{"foo": "{{.Insecure.User.foo}}"}`}, data, x509util.DefaultLeafTemplate, Options{TemplateData: []byte(`{"badJSON"}`)}}, x509util.Options{ {"okBadUserOptions", args{&Options{Template: `{"foo": "{{.Insecure.User.foo}}"}`}, data, x509util.DefaultLeafTemplate, SignOptions{TemplateData: []byte(`{"badJSON"}`)}}, x509util.Options{
CertBuffer: bytes.NewBufferString(`{"foo": "<no value>"}`), CertBuffer: bytes.NewBufferString(`{"foo": "<no value>"}`),
}, false}, }, false},
{"fail", args{&ProvisionerOptions{TemplateData: []byte(`{"badJSON`)}, data, x509util.DefaultLeafTemplate, Options{}}, x509util.Options{}, true}, {"fail", args{&Options{TemplateData: []byte(`{"badJSON`)}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{}, true},
{"failTemplateData", args{&ProvisionerOptions{TemplateData: []byte(`{"badJSON}`)}, data, x509util.DefaultLeafTemplate, Options{}}, x509util.Options{}, true}, {"failTemplateData", args{&Options{TemplateData: []byte(`{"badJSON}`)}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{}, true},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View file

@ -20,9 +20,9 @@ import (
// DefaultCertValidity is the default validity for a certificate if none is specified. // DefaultCertValidity is the default validity for a certificate if none is specified.
const DefaultCertValidity = 24 * time.Hour const DefaultCertValidity = 24 * time.Hour
// Options contains the options that can be passed to the Sign method. Backdate // SignOptions contains the options that can be passed to the Sign method. Backdate
// is automatically filled and can only be configured in the CA. // is automatically filled and can only be configured in the CA.
type Options struct { type SignOptions struct {
NotAfter TimeDuration `json:"notAfter"` NotAfter TimeDuration `json:"notAfter"`
NotBefore TimeDuration `json:"notBefore"` NotBefore TimeDuration `json:"notBefore"`
TemplateData json.RawMessage `json:"templateData"` TemplateData json.RawMessage `json:"templateData"`
@ -35,7 +35,7 @@ type SignOption interface{}
// CertificateValidator is an interface used to validate a given X.509 certificate. // CertificateValidator is an interface used to validate a given X.509 certificate.
type CertificateValidator interface { type CertificateValidator interface {
Valid(cert *x509.Certificate, opts Options) error Valid(cert *x509.Certificate, opts SignOptions) error
} }
// CertificateRequestValidator is an interface used to validate a given X.509 certificate request. // CertificateRequestValidator is an interface used to validate a given X.509 certificate request.
@ -47,7 +47,7 @@ type CertificateRequestValidator interface {
// Types implementing this interface will be validated with a // Types implementing this interface will be validated with a
// CertificateValidator. // CertificateValidator.
type CertificateModifier interface { type CertificateModifier interface {
Modify(cert *x509.Certificate, opts Options) error Modify(cert *x509.Certificate, opts SignOptions) error
} }
// CertificateEnforcer is an interface used to modify a given X.509 certificate. // CertificateEnforcer is an interface used to modify a given X.509 certificate.
@ -59,10 +59,10 @@ type CertificateEnforcer interface {
// CertificateModifierFunc allows to create simple certificate modifiers just // CertificateModifierFunc allows to create simple certificate modifiers just
// with a function. // with a function.
type CertificateModifierFunc func(cert *x509.Certificate, opts Options) error type CertificateModifierFunc func(cert *x509.Certificate, opts SignOptions) error
// Modify implements CertificateModifier and just calls the defined function. // Modify implements CertificateModifier and just calls the defined function.
func (fn CertificateModifierFunc) Modify(cert *x509.Certificate, opts Options) error { func (fn CertificateModifierFunc) Modify(cert *x509.Certificate, opts SignOptions) error {
return fn(cert, opts) return fn(cert, opts)
} }
@ -270,7 +270,7 @@ func (eee ExtraExtsEnforcer) Enforce(cert *x509.Certificate) error {
// duration. // duration.
type profileDefaultDuration time.Duration type profileDefaultDuration time.Duration
func (v profileDefaultDuration) Modify(cert *x509.Certificate, so Options) error { func (v profileDefaultDuration) Modify(cert *x509.Certificate, so SignOptions) error {
var backdate time.Duration var backdate time.Duration
notBefore := so.NotBefore.Time() notBefore := so.NotBefore.Time()
if notBefore.IsZero() { if notBefore.IsZero() {
@ -301,7 +301,7 @@ type profileLimitDuration struct {
// Option returns an x509util option that limits the validity period of a // Option returns an x509util option that limits the validity period of a
// certificate to one that is superficially imposed. // certificate to one that is superficially imposed.
func (v profileLimitDuration) Modify(cert *x509.Certificate, so Options) error { func (v profileLimitDuration) Modify(cert *x509.Certificate, so SignOptions) error {
var backdate time.Duration var backdate time.Duration
notBefore := so.NotBefore.Time() notBefore := so.NotBefore.Time()
if notBefore.IsZero() { if notBefore.IsZero() {
@ -347,7 +347,7 @@ func newValidityValidator(min, max time.Duration) *validityValidator {
// Valid validates the certificate validity settings (notBefore/notAfter) and // Valid validates the certificate validity settings (notBefore/notAfter) and
// and total duration. // and total duration.
func (v *validityValidator) Valid(cert *x509.Certificate, o Options) error { func (v *validityValidator) Valid(cert *x509.Certificate, o SignOptions) error {
var ( var (
na = cert.NotAfter.Truncate(time.Second) na = cert.NotAfter.Truncate(time.Second)
nb = cert.NotBefore.Truncate(time.Second) nb = cert.NotBefore.Truncate(time.Second)
@ -397,7 +397,7 @@ func newForceCNOption(forceCN bool) *forceCNOption {
return &forceCNOption{forceCN} return &forceCNOption{forceCN}
} }
func (o *forceCNOption) Modify(cert *x509.Certificate, _ Options) error { func (o *forceCNOption) Modify(cert *x509.Certificate, _ SignOptions) error {
if !o.ForceCN { if !o.ForceCN {
// Forcing CN is disabled, do nothing to certificate // Forcing CN is disabled, do nothing to certificate
return nil return nil
@ -430,7 +430,7 @@ func newProvisionerExtensionOption(typ Type, name, credentialID string, keyValue
} }
} }
func (o *provisionerExtensionOption) Modify(cert *x509.Certificate, _ Options) error { func (o *provisionerExtensionOption) Modify(cert *x509.Certificate, _ SignOptions) error {
ext, err := createProvisionerExtension(o.Type, o.Name, o.CredentialID, o.KeyValuePairs...) ext, err := createProvisionerExtension(o.Type, o.Name, o.CredentialID, o.KeyValuePairs...)
if err != nil { if err != nil {
return err return err

View file

@ -399,7 +399,7 @@ func Test_ExtraExtsEnforcer_Enforce(t *testing.T) {
func Test_validityValidator_Valid(t *testing.T) { func Test_validityValidator_Valid(t *testing.T) {
type test struct { type test struct {
cert *x509.Certificate cert *x509.Certificate
opts Options opts SignOptions
vv *validityValidator vv *validityValidator
err error err error
} }
@ -408,7 +408,7 @@ func Test_validityValidator_Valid(t *testing.T) {
return test{ return test{
vv: &validityValidator{5 * time.Minute, 24 * time.Hour}, vv: &validityValidator{5 * time.Minute, 24 * time.Hour},
cert: &x509.Certificate{NotAfter: time.Now().Add(-5 * time.Minute)}, cert: &x509.Certificate{NotAfter: time.Now().Add(-5 * time.Minute)},
opts: Options{}, opts: SignOptions{},
err: errors.New("notAfter cannot be in the past"), err: errors.New("notAfter cannot be in the past"),
} }
}, },
@ -417,7 +417,7 @@ func Test_validityValidator_Valid(t *testing.T) {
vv: &validityValidator{5 * time.Minute, 24 * time.Hour}, vv: &validityValidator{5 * time.Minute, 24 * time.Hour},
cert: &x509.Certificate{NotBefore: time.Now().Add(10 * time.Minute), cert: &x509.Certificate{NotBefore: time.Now().Add(10 * time.Minute),
NotAfter: time.Now().Add(5 * time.Minute)}, NotAfter: time.Now().Add(5 * time.Minute)},
opts: Options{}, opts: SignOptions{},
err: errors.New("notAfter cannot be before notBefore"), err: errors.New("notAfter cannot be before notBefore"),
} }
}, },
@ -427,7 +427,7 @@ func Test_validityValidator_Valid(t *testing.T) {
vv: &validityValidator{5 * time.Minute, 24 * time.Hour}, vv: &validityValidator{5 * time.Minute, 24 * time.Hour},
cert: &x509.Certificate{NotBefore: n, cert: &x509.Certificate{NotBefore: n,
NotAfter: n.Add(3 * time.Minute)}, NotAfter: n.Add(3 * time.Minute)},
opts: Options{}, opts: SignOptions{},
err: errors.New("is less than the authorized minimum certificate duration of "), err: errors.New("is less than the authorized minimum certificate duration of "),
} }
}, },
@ -437,7 +437,7 @@ func Test_validityValidator_Valid(t *testing.T) {
vv: &validityValidator{5 * time.Minute, 24 * time.Hour}, vv: &validityValidator{5 * time.Minute, 24 * time.Hour},
cert: &x509.Certificate{NotBefore: n, cert: &x509.Certificate{NotBefore: n,
NotAfter: n.Add(5 * time.Minute)}, NotAfter: n.Add(5 * time.Minute)},
opts: Options{}, opts: SignOptions{},
} }
}, },
"fail/duration-too-great": func() test { "fail/duration-too-great": func() test {
@ -464,7 +464,7 @@ func Test_validityValidator_Valid(t *testing.T) {
return test{ return test{
vv: &validityValidator{5 * time.Minute, 24 * time.Hour}, vv: &validityValidator{5 * time.Minute, 24 * time.Hour},
cert: cert, cert: cert,
opts: Options{Backdate: time.Second}, opts: SignOptions{Backdate: time.Second},
} }
}, },
"ok/duration-exact-max-with-backdate": func() test { "ok/duration-exact-max-with-backdate": func() test {
@ -475,7 +475,7 @@ func Test_validityValidator_Valid(t *testing.T) {
return test{ return test{
vv: &validityValidator{5 * time.Minute, 24 * time.Hour}, vv: &validityValidator{5 * time.Minute, 24 * time.Hour},
cert: cert, cert: cert,
opts: Options{Backdate: backdate}, opts: SignOptions{Backdate: backdate},
} }
}, },
} }
@ -496,7 +496,7 @@ func Test_validityValidator_Valid(t *testing.T) {
func Test_forceCN_Option(t *testing.T) { func Test_forceCN_Option(t *testing.T) {
type test struct { type test struct {
so Options so SignOptions
fcn forceCNOption fcn forceCNOption
cert *x509.Certificate cert *x509.Certificate
valid func(*x509.Certificate) valid func(*x509.Certificate)
@ -507,7 +507,7 @@ func Test_forceCN_Option(t *testing.T) {
"ok/CN-not-forced": func() test { "ok/CN-not-forced": func() test {
return test{ return test{
fcn: forceCNOption{false}, fcn: forceCNOption{false},
so: Options{}, so: SignOptions{},
cert: &x509.Certificate{ cert: &x509.Certificate{
Subject: pkix.Name{}, Subject: pkix.Name{},
DNSNames: []string{"acme.example.com", "step.example.com"}, DNSNames: []string{"acme.example.com", "step.example.com"},
@ -520,7 +520,7 @@ func Test_forceCN_Option(t *testing.T) {
"ok/CN-forced-and-set": func() test { "ok/CN-forced-and-set": func() test {
return test{ return test{
fcn: forceCNOption{true}, fcn: forceCNOption{true},
so: Options{}, so: SignOptions{},
cert: &x509.Certificate{ cert: &x509.Certificate{
Subject: pkix.Name{ Subject: pkix.Name{
CommonName: "Some Common Name", CommonName: "Some Common Name",
@ -535,7 +535,7 @@ func Test_forceCN_Option(t *testing.T) {
"ok/CN-forced-and-not-set": func() test { "ok/CN-forced-and-not-set": func() test {
return test{ return test{
fcn: forceCNOption{true}, fcn: forceCNOption{true},
so: Options{}, so: SignOptions{},
cert: &x509.Certificate{ cert: &x509.Certificate{
Subject: pkix.Name{}, Subject: pkix.Name{},
DNSNames: []string{"acme.example.com", "step.example.com"}, DNSNames: []string{"acme.example.com", "step.example.com"},
@ -548,7 +548,7 @@ func Test_forceCN_Option(t *testing.T) {
"fail/CN-forced-and-empty-DNSNames": func() test { "fail/CN-forced-and-empty-DNSNames": func() test {
return test{ return test{
fcn: forceCNOption{true}, fcn: forceCNOption{true},
so: Options{}, so: SignOptions{},
cert: &x509.Certificate{ cert: &x509.Certificate{
Subject: pkix.Name{}, Subject: pkix.Name{},
DNSNames: []string{}, DNSNames: []string{},
@ -576,7 +576,7 @@ func Test_forceCN_Option(t *testing.T) {
func Test_profileDefaultDuration_Option(t *testing.T) { func Test_profileDefaultDuration_Option(t *testing.T) {
type test struct { type test struct {
so Options so SignOptions
pdd profileDefaultDuration pdd profileDefaultDuration
cert *x509.Certificate cert *x509.Certificate
valid func(*x509.Certificate) valid func(*x509.Certificate)
@ -585,7 +585,7 @@ func Test_profileDefaultDuration_Option(t *testing.T) {
"ok/notBefore-notAfter-duration-empty": func() test { "ok/notBefore-notAfter-duration-empty": func() test {
return test{ return test{
pdd: profileDefaultDuration(0), pdd: profileDefaultDuration(0),
so: Options{}, so: SignOptions{},
cert: new(x509.Certificate), cert: new(x509.Certificate),
valid: func(cert *x509.Certificate) { valid: func(cert *x509.Certificate) {
n := now() n := now()
@ -601,7 +601,7 @@ func Test_profileDefaultDuration_Option(t *testing.T) {
nb := time.Now().Add(5 * time.Minute).UTC() nb := time.Now().Add(5 * time.Minute).UTC()
return test{ return test{
pdd: profileDefaultDuration(0), pdd: profileDefaultDuration(0),
so: Options{NotBefore: NewTimeDuration(nb)}, so: SignOptions{NotBefore: NewTimeDuration(nb)},
cert: new(x509.Certificate), cert: new(x509.Certificate),
valid: func(cert *x509.Certificate) { valid: func(cert *x509.Certificate) {
assert.Equals(t, cert.NotBefore, nb) assert.Equals(t, cert.NotBefore, nb)
@ -613,7 +613,7 @@ func Test_profileDefaultDuration_Option(t *testing.T) {
d := 4 * time.Hour d := 4 * time.Hour
return test{ return test{
pdd: profileDefaultDuration(d), pdd: profileDefaultDuration(d),
so: Options{Backdate: time.Second}, so: SignOptions{Backdate: time.Second},
cert: new(x509.Certificate), cert: new(x509.Certificate),
valid: func(cert *x509.Certificate) { valid: func(cert *x509.Certificate) {
n := now() n := now()
@ -629,7 +629,7 @@ func Test_profileDefaultDuration_Option(t *testing.T) {
na := now().Add(10 * time.Minute).UTC() na := now().Add(10 * time.Minute).UTC()
return test{ return test{
pdd: profileDefaultDuration(0), pdd: profileDefaultDuration(0),
so: Options{NotAfter: NewTimeDuration(na)}, so: SignOptions{NotAfter: NewTimeDuration(na)},
cert: new(x509.Certificate), cert: new(x509.Certificate),
valid: func(cert *x509.Certificate) { valid: func(cert *x509.Certificate) {
n := now() n := now()
@ -646,7 +646,7 @@ func Test_profileDefaultDuration_Option(t *testing.T) {
d := 4 * time.Hour d := 4 * time.Hour
return test{ return test{
pdd: profileDefaultDuration(d), pdd: profileDefaultDuration(d),
so: Options{NotBefore: NewTimeDuration(nb), NotAfter: NewTimeDuration(na)}, so: SignOptions{NotBefore: NewTimeDuration(nb), NotAfter: NewTimeDuration(na)},
cert: new(x509.Certificate), cert: new(x509.Certificate),
valid: func(cert *x509.Certificate) { valid: func(cert *x509.Certificate) {
assert.Equals(t, cert.NotBefore, nb) assert.Equals(t, cert.NotBefore, nb)
@ -698,7 +698,7 @@ func Test_newProvisionerExtension_Option(t *testing.T) {
for name, run := range tests { for name, run := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
tt := run() tt := run()
assert.FatalError(t, newProvisionerExtensionOption(TypeJWK, "foo", "bar", "baz", "zap").Modify(tt.cert, Options{})) assert.FatalError(t, newProvisionerExtensionOption(TypeJWK, "foo", "bar", "baz", "zap").Modify(tt.cert, SignOptions{}))
tt.valid(tt.cert) tt.valid(tt.cert)
}) })
} }
@ -710,7 +710,7 @@ func Test_profileLimitDuration_Option(t *testing.T) {
type test struct { type test struct {
pld profileLimitDuration pld profileLimitDuration
so Options so SignOptions
cert *x509.Certificate cert *x509.Certificate
valid func(*x509.Certificate) valid func(*x509.Certificate)
err error err error
@ -721,7 +721,7 @@ func Test_profileLimitDuration_Option(t *testing.T) {
assert.FatalError(t, err) assert.FatalError(t, err)
return test{ return test{
pld: profileLimitDuration{def: 4 * time.Hour, notBefore: n.Add(8 * time.Hour)}, pld: profileLimitDuration{def: 4 * time.Hour, notBefore: n.Add(8 * time.Hour)},
so: Options{NotBefore: d}, so: SignOptions{NotBefore: d},
cert: new(x509.Certificate), cert: new(x509.Certificate),
err: errors.New("requested certificate notBefore ("), err: errors.New("requested certificate notBefore ("),
} }
@ -731,7 +731,7 @@ func Test_profileLimitDuration_Option(t *testing.T) {
assert.FatalError(t, err) assert.FatalError(t, err)
return test{ return test{
pld: profileLimitDuration{def: 4 * time.Hour, notAfter: n.Add(6 * time.Hour)}, pld: profileLimitDuration{def: 4 * time.Hour, notAfter: n.Add(6 * time.Hour)},
so: Options{NotBefore: NewTimeDuration(n.Add(3 * time.Hour)), NotAfter: d}, so: SignOptions{NotBefore: NewTimeDuration(n.Add(3 * time.Hour)), NotAfter: d},
cert: new(x509.Certificate), cert: new(x509.Certificate),
err: errors.New("requested certificate notAfter ("), err: errors.New("requested certificate notAfter ("),
} }
@ -741,7 +741,7 @@ func Test_profileLimitDuration_Option(t *testing.T) {
assert.FatalError(t, err) assert.FatalError(t, err)
return test{ return test{
pld: profileLimitDuration{def: 4 * time.Hour, notAfter: n.Add(6 * time.Hour)}, pld: profileLimitDuration{def: 4 * time.Hour, notAfter: n.Add(6 * time.Hour)},
so: Options{NotBefore: NewTimeDuration(n.Add(3 * time.Hour)), NotAfter: d, Backdate: 1 * time.Minute}, so: SignOptions{NotBefore: NewTimeDuration(n.Add(3 * time.Hour)), NotAfter: d, Backdate: 1 * time.Minute},
cert: new(x509.Certificate), cert: new(x509.Certificate),
valid: func(cert *x509.Certificate) { valid: func(cert *x509.Certificate) {
assert.Equals(t, cert.NotBefore, n.Add(3*time.Hour)) assert.Equals(t, cert.NotBefore, n.Add(3*time.Hour))
@ -752,7 +752,7 @@ func Test_profileLimitDuration_Option(t *testing.T) {
"ok/valid-notAfter-nil-limit-over-default": func() test { "ok/valid-notAfter-nil-limit-over-default": func() test {
return test{ return test{
pld: profileLimitDuration{def: 1 * time.Hour, notAfter: n.Add(6 * time.Hour)}, pld: profileLimitDuration{def: 1 * time.Hour, notAfter: n.Add(6 * time.Hour)},
so: Options{NotBefore: NewTimeDuration(n.Add(3 * time.Hour)), Backdate: 1 * time.Minute}, so: SignOptions{NotBefore: NewTimeDuration(n.Add(3 * time.Hour)), Backdate: 1 * time.Minute},
cert: new(x509.Certificate), cert: new(x509.Certificate),
valid: func(cert *x509.Certificate) { valid: func(cert *x509.Certificate) {
assert.Equals(t, cert.NotBefore, n.Add(3*time.Hour)) assert.Equals(t, cert.NotBefore, n.Add(3*time.Hour))
@ -763,7 +763,7 @@ func Test_profileLimitDuration_Option(t *testing.T) {
"ok/valid-notAfter-nil-limit-under-default": func() test { "ok/valid-notAfter-nil-limit-under-default": func() test {
return test{ return test{
pld: profileLimitDuration{def: 4 * time.Hour, notAfter: n.Add(6 * time.Hour)}, pld: profileLimitDuration{def: 4 * time.Hour, notAfter: n.Add(6 * time.Hour)},
so: Options{NotBefore: NewTimeDuration(n.Add(3 * time.Hour)), Backdate: 1 * time.Minute}, so: SignOptions{NotBefore: NewTimeDuration(n.Add(3 * time.Hour)), Backdate: 1 * time.Minute},
cert: new(x509.Certificate), cert: new(x509.Certificate),
valid: func(cert *x509.Certificate) { valid: func(cert *x509.Certificate) {
assert.Equals(t, cert.NotBefore, n.Add(3*time.Hour)) assert.Equals(t, cert.NotBefore, n.Add(3*time.Hour))
@ -774,7 +774,7 @@ func Test_profileLimitDuration_Option(t *testing.T) {
"ok/over-limit-with-backdate": func() test { "ok/over-limit-with-backdate": func() test {
return test{ return test{
pld: profileLimitDuration{def: 24 * time.Hour, notAfter: n.Add(6 * time.Hour)}, pld: profileLimitDuration{def: 24 * time.Hour, notAfter: n.Add(6 * time.Hour)},
so: Options{Backdate: 1 * time.Minute}, so: SignOptions{Backdate: 1 * time.Minute},
cert: new(x509.Certificate), cert: new(x509.Certificate),
valid: func(cert *x509.Certificate) { valid: func(cert *x509.Certificate) {
assert.Equals(t, cert.NotBefore, n.Add(-time.Minute)) assert.Equals(t, cert.NotBefore, n.Add(-time.Minute))
@ -785,7 +785,7 @@ func Test_profileLimitDuration_Option(t *testing.T) {
"ok/under-limit-with-backdate": func() test { "ok/under-limit-with-backdate": func() test {
return test{ return test{
pld: profileLimitDuration{def: 24 * time.Hour, notAfter: n.Add(30 * time.Hour)}, pld: profileLimitDuration{def: 24 * time.Hour, notAfter: n.Add(30 * time.Hour)},
so: Options{Backdate: 1 * time.Minute}, so: SignOptions{Backdate: 1 * time.Minute},
cert: new(x509.Certificate), cert: new(x509.Certificate),
valid: func(cert *x509.Certificate) { valid: func(cert *x509.Certificate) {
assert.Equals(t, cert.NotBefore, n.Add(-time.Minute)) assert.Equals(t, cert.NotBefore, n.Add(-time.Minute))

View file

@ -30,20 +30,20 @@ type SSHCertModifier interface {
// to modify the SSH certificate. // to modify the SSH certificate.
type SSHCertOptionModifier interface { type SSHCertOptionModifier interface {
SignOption SignOption
Option(o SSHOptions) SSHCertModifier Option(o SignSSHOptions) SSHCertModifier
} }
// SSHCertValidator is the interface used to validate an SSH certificate. // SSHCertValidator is the interface used to validate an SSH certificate.
type SSHCertValidator interface { type SSHCertValidator interface {
SignOption SignOption
Valid(cert *ssh.Certificate, opts SSHOptions) error Valid(cert *ssh.Certificate, opts SignSSHOptions) error
} }
// SSHCertOptionsValidator is the interface used to validate the custom // SSHCertOptionsValidator is the interface used to validate the custom
// options used to modify the SSH certificate. // options used to modify the SSH certificate.
type SSHCertOptionsValidator interface { type SSHCertOptionsValidator interface {
SignOption SignOption
Valid(got SSHOptions) error Valid(got SignSSHOptions) error
} }
// sshModifierFunc is an adapter to allow the use of ordinary functions as SSH // sshModifierFunc is an adapter to allow the use of ordinary functions as SSH
@ -54,8 +54,8 @@ func (f sshModifierFunc) Modify(cert *ssh.Certificate) error {
return f(cert) return f(cert)
} }
// SSHOptions contains the options that can be passed to the SignSSH method. // SignSSHOptions contains the options that can be passed to the SignSSH method.
type SSHOptions struct { type SignSSHOptions struct {
CertType string `json:"certType"` CertType string `json:"certType"`
KeyID string `json:"keyID"` KeyID string `json:"keyID"`
Principals []string `json:"principals"` Principals []string `json:"principals"`
@ -65,12 +65,12 @@ type SSHOptions struct {
} }
// Type returns the uint32 representation of the CertType. // Type returns the uint32 representation of the CertType.
func (o SSHOptions) Type() uint32 { func (o SignSSHOptions) Type() uint32 {
return sshCertTypeUInt32(o.CertType) return sshCertTypeUInt32(o.CertType)
} }
// Modify implements SSHCertModifier and sets the SSHOption in the ssh.Certificate. // Modify implements SSHCertModifier and sets the SSHOption in the ssh.Certificate.
func (o SSHOptions) Modify(cert *ssh.Certificate) error { func (o SignSSHOptions) Modify(cert *ssh.Certificate) error {
switch o.CertType { switch o.CertType {
case "": // ignore case "": // ignore
case SSHUserCert: case SSHUserCert:
@ -100,7 +100,7 @@ func (o SSHOptions) Modify(cert *ssh.Certificate) error {
// match compares two SSHOptions and return an error if they don't match. It // match compares two SSHOptions and return an error if they don't match. It
// ignores zero values. // ignores zero values.
func (o SSHOptions) match(got SSHOptions) error { func (o SignSSHOptions) match(got SignSSHOptions) error {
if o.CertType != "" && got.CertType != "" && o.CertType != got.CertType { if o.CertType != "" && got.CertType != "" && o.CertType != got.CertType {
return errors.Errorf("ssh certificate type does not match - got %v, want %v", got.CertType, o.CertType) return errors.Errorf("ssh certificate type does not match - got %v, want %v", got.CertType, o.CertType)
} }
@ -165,7 +165,7 @@ func (m sshCertValidBeforeModifier) Modify(cert *ssh.Certificate) error {
// sshCertDefaultsModifier implements a SSHCertModifier that // sshCertDefaultsModifier implements a SSHCertModifier that
// modifies the certificate with the given options if they are not set. // modifies the certificate with the given options if they are not set.
type sshCertDefaultsModifier SSHOptions type sshCertDefaultsModifier SignSSHOptions
// Modify implements the SSHCertModifier interface. // Modify implements the SSHCertModifier interface.
func (m sshCertDefaultsModifier) Modify(cert *ssh.Certificate) error { func (m sshCertDefaultsModifier) Modify(cert *ssh.Certificate) error {
@ -215,7 +215,7 @@ type sshDefaultDuration struct {
*Claimer *Claimer
} }
func (m *sshDefaultDuration) Option(o SSHOptions) SSHCertModifier { func (m *sshDefaultDuration) Option(o SignSSHOptions) SSHCertModifier {
return sshModifierFunc(func(cert *ssh.Certificate) error { return sshModifierFunc(func(cert *ssh.Certificate) error {
d, err := m.DefaultSSHCertDuration(cert.CertType) d, err := m.DefaultSSHCertDuration(cert.CertType)
if err != nil { if err != nil {
@ -248,7 +248,7 @@ type sshLimitDuration struct {
NotAfter time.Time NotAfter time.Time
} }
func (m *sshLimitDuration) Option(o SSHOptions) SSHCertModifier { func (m *sshLimitDuration) Option(o SignSSHOptions) SSHCertModifier {
if m.NotAfter.IsZero() { if m.NotAfter.IsZero() {
defaultDuration := &sshDefaultDuration{m.Claimer} defaultDuration := &sshDefaultDuration{m.Claimer}
return defaultDuration.Option(o) return defaultDuration.Option(o)
@ -297,12 +297,12 @@ func (m *sshLimitDuration) Option(o SSHOptions) SSHCertModifier {
// sshCertOptionsValidator validates the user SSHOptions with the ones // sshCertOptionsValidator validates the user SSHOptions with the ones
// usually present in the token. // usually present in the token.
type sshCertOptionsValidator SSHOptions type sshCertOptionsValidator SignSSHOptions
// Valid implements SSHCertOptionsValidator and returns nil if both // Valid implements SSHCertOptionsValidator and returns nil if both
// SSHOptions match. // SSHOptions match.
func (v sshCertOptionsValidator) Valid(got SSHOptions) error { func (v sshCertOptionsValidator) Valid(got SignSSHOptions) error {
want := SSHOptions(v) want := SignSSHOptions(v)
return want.match(got) return want.match(got)
} }
@ -310,7 +310,7 @@ type sshCertValidityValidator struct {
*Claimer *Claimer
} }
func (v *sshCertValidityValidator) Valid(cert *ssh.Certificate, opts SSHOptions) error { func (v *sshCertValidityValidator) Valid(cert *ssh.Certificate, opts SignSSHOptions) error {
switch { switch {
case cert.ValidAfter == 0: case cert.ValidAfter == 0:
return errors.New("ssh certificate validAfter cannot be 0") return errors.New("ssh certificate validAfter cannot be 0")
@ -355,7 +355,7 @@ func (v *sshCertValidityValidator) Valid(cert *ssh.Certificate, opts SSHOptions)
type sshCertDefaultValidator struct{} type sshCertDefaultValidator struct{}
// Valid returns an error if the given certificate does not contain the necessary fields. // Valid returns an error if the given certificate does not contain the necessary fields.
func (v *sshCertDefaultValidator) Valid(cert *ssh.Certificate, o SSHOptions) error { func (v *sshCertDefaultValidator) Valid(cert *ssh.Certificate, o SignSSHOptions) error {
switch { switch {
case len(cert.Nonce) == 0: case len(cert.Nonce) == 0:
return errors.New("ssh certificate nonce cannot be empty") return errors.New("ssh certificate nonce cannot be empty")
@ -390,7 +390,7 @@ func (v *sshCertDefaultValidator) Valid(cert *ssh.Certificate, o SSHOptions) err
type sshDefaultPublicKeyValidator struct{} type sshDefaultPublicKeyValidator struct{}
// Valid checks that certificate request common name matches the one configured. // Valid checks that certificate request common name matches the one configured.
func (v sshDefaultPublicKeyValidator) Valid(cert *ssh.Certificate, o SSHOptions) error { func (v sshDefaultPublicKeyValidator) Valid(cert *ssh.Certificate, o SignSSHOptions) error {
if cert.Key == nil { if cert.Key == nil {
return errors.New("ssh certificate key cannot be nil") return errors.New("ssh certificate key cannot be nil")
} }
@ -420,7 +420,7 @@ func (v sshDefaultPublicKeyValidator) Valid(cert *ssh.Certificate, o SSHOptions)
type sshCertKeyIDValidator string type sshCertKeyIDValidator string
// Valid returns an error if the given certificate does not contain the necessary fields. // Valid returns an error if the given certificate does not contain the necessary fields.
func (v sshCertKeyIDValidator) Valid(cert *ssh.Certificate, o SSHOptions) error { func (v sshCertKeyIDValidator) Valid(cert *ssh.Certificate, o SignSSHOptions) error {
if string(v) != cert.KeyId { if string(v) != cert.KeyId {
return errors.Errorf("invalid ssh certificate KeyId; want %s, but got %s", string(v), cert.KeyId) return errors.Errorf("invalid ssh certificate KeyId; want %s, but got %s", string(v), cert.KeyId)
} }

View file

@ -28,7 +28,7 @@ func TestSSHOptions_Type(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
o := SSHOptions{ o := SignSSHOptions{
CertType: tt.fields.CertType, CertType: tt.fields.CertType,
} }
if got := o.Type(); got != tt.want { if got := o.Type(); got != tt.want {
@ -40,7 +40,7 @@ func TestSSHOptions_Type(t *testing.T) {
func TestSSHOptions_Modify(t *testing.T) { func TestSSHOptions_Modify(t *testing.T) {
type test struct { type test struct {
so *SSHOptions so *SignSSHOptions
cert *ssh.Certificate cert *ssh.Certificate
valid func(*ssh.Certificate) valid func(*ssh.Certificate)
err error err error
@ -48,21 +48,21 @@ func TestSSHOptions_Modify(t *testing.T) {
tests := map[string](func() test){ tests := map[string](func() test){
"fail/unexpected-cert-type": func() test { "fail/unexpected-cert-type": func() test {
return test{ return test{
so: &SSHOptions{CertType: "foo"}, so: &SignSSHOptions{CertType: "foo"},
cert: new(ssh.Certificate), cert: new(ssh.Certificate),
err: errors.Errorf("ssh certificate has an unknown type - foo"), err: errors.Errorf("ssh certificate has an unknown type - foo"),
} }
}, },
"fail/validAfter-greater-validBefore": func() test { "fail/validAfter-greater-validBefore": func() test {
return test{ return test{
so: &SSHOptions{CertType: "user"}, so: &SignSSHOptions{CertType: "user"},
cert: &ssh.Certificate{ValidAfter: uint64(15), ValidBefore: uint64(10)}, cert: &ssh.Certificate{ValidAfter: uint64(15), ValidBefore: uint64(10)},
err: errors.Errorf("ssh certificate valid after cannot be greater than valid before"), err: errors.Errorf("ssh certificate valid after cannot be greater than valid before"),
} }
}, },
"ok/user-cert": func() test { "ok/user-cert": func() test {
return test{ return test{
so: &SSHOptions{CertType: "user"}, so: &SignSSHOptions{CertType: "user"},
cert: new(ssh.Certificate), cert: new(ssh.Certificate),
valid: func(cert *ssh.Certificate) { valid: func(cert *ssh.Certificate) {
assert.Equals(t, cert.CertType, uint32(ssh.UserCert)) assert.Equals(t, cert.CertType, uint32(ssh.UserCert))
@ -71,7 +71,7 @@ func TestSSHOptions_Modify(t *testing.T) {
}, },
"ok/host-cert": func() test { "ok/host-cert": func() test {
return test{ return test{
so: &SSHOptions{CertType: "host"}, so: &SignSSHOptions{CertType: "host"},
cert: new(ssh.Certificate), cert: new(ssh.Certificate),
valid: func(cert *ssh.Certificate) { valid: func(cert *ssh.Certificate) {
assert.Equals(t, cert.CertType, uint32(ssh.HostCert)) assert.Equals(t, cert.CertType, uint32(ssh.HostCert))
@ -81,7 +81,7 @@ func TestSSHOptions_Modify(t *testing.T) {
"ok": func() test { "ok": func() test {
va := time.Now().Add(5 * time.Minute) va := time.Now().Add(5 * time.Minute)
vb := time.Now().Add(1 * time.Hour) vb := time.Now().Add(1 * time.Hour)
so := &SSHOptions{CertType: "host", KeyID: "foo", Principals: []string{"foo", "bar"}, so := &SignSSHOptions{CertType: "host", KeyID: "foo", Principals: []string{"foo", "bar"},
ValidAfter: NewTimeDuration(va), ValidBefore: NewTimeDuration(vb)} ValidAfter: NewTimeDuration(va), ValidBefore: NewTimeDuration(vb)}
return test{ return test{
so: so, so: so,
@ -114,43 +114,43 @@ func TestSSHOptions_Modify(t *testing.T) {
func TestSSHOptions_Match(t *testing.T) { func TestSSHOptions_Match(t *testing.T) {
type test struct { type test struct {
so SSHOptions so SignSSHOptions
cmp SSHOptions cmp SignSSHOptions
err error err error
} }
tests := map[string](func() test){ tests := map[string](func() test){
"fail/cert-type": func() test { "fail/cert-type": func() test {
return test{ return test{
so: SSHOptions{CertType: "foo"}, so: SignSSHOptions{CertType: "foo"},
cmp: SSHOptions{CertType: "bar"}, cmp: SignSSHOptions{CertType: "bar"},
err: errors.Errorf("ssh certificate type does not match - got bar, want foo"), err: errors.Errorf("ssh certificate type does not match - got bar, want foo"),
} }
}, },
"fail/pricipals": func() test { "fail/pricipals": func() test {
return test{ return test{
so: SSHOptions{Principals: []string{"foo"}}, so: SignSSHOptions{Principals: []string{"foo"}},
cmp: SSHOptions{Principals: []string{"bar"}}, cmp: SignSSHOptions{Principals: []string{"bar"}},
err: errors.Errorf("ssh certificate principals does not match - got [bar], want [foo]"), err: errors.Errorf("ssh certificate principals does not match - got [bar], want [foo]"),
} }
}, },
"fail/validAfter": func() test { "fail/validAfter": func() test {
return test{ return test{
so: SSHOptions{ValidAfter: NewTimeDuration(time.Now().Add(1 * time.Minute))}, so: SignSSHOptions{ValidAfter: NewTimeDuration(time.Now().Add(1 * time.Minute))},
cmp: SSHOptions{ValidAfter: NewTimeDuration(time.Now().Add(5 * time.Minute))}, cmp: SignSSHOptions{ValidAfter: NewTimeDuration(time.Now().Add(5 * time.Minute))},
err: errors.Errorf("ssh certificate valid after does not match"), err: errors.Errorf("ssh certificate valid after does not match"),
} }
}, },
"fail/validBefore": func() test { "fail/validBefore": func() test {
return test{ return test{
so: SSHOptions{ValidBefore: NewTimeDuration(time.Now().Add(1 * time.Minute))}, so: SignSSHOptions{ValidBefore: NewTimeDuration(time.Now().Add(1 * time.Minute))},
cmp: SSHOptions{ValidBefore: NewTimeDuration(time.Now().Add(5 * time.Minute))}, cmp: SignSSHOptions{ValidBefore: NewTimeDuration(time.Now().Add(5 * time.Minute))},
err: errors.Errorf("ssh certificate valid before does not match"), err: errors.Errorf("ssh certificate valid before does not match"),
} }
}, },
"ok/original-empty": func() test { "ok/original-empty": func() test {
return test{ return test{
so: SSHOptions{}, so: SignSSHOptions{},
cmp: SSHOptions{ cmp: SignSSHOptions{
CertType: "foo", CertType: "foo",
Principals: []string{"foo"}, Principals: []string{"foo"},
ValidAfter: NewTimeDuration(time.Now().Add(1 * time.Minute)), ValidAfter: NewTimeDuration(time.Now().Add(1 * time.Minute)),
@ -160,8 +160,8 @@ func TestSSHOptions_Match(t *testing.T) {
}, },
"ok/cmp-empty": func() test { "ok/cmp-empty": func() test {
return test{ return test{
cmp: SSHOptions{}, cmp: SignSSHOptions{},
so: SSHOptions{ so: SignSSHOptions{
CertType: "foo", CertType: "foo",
Principals: []string{"foo"}, Principals: []string{"foo"},
ValidAfter: NewTimeDuration(time.Now().Add(1 * time.Minute)), ValidAfter: NewTimeDuration(time.Now().Add(1 * time.Minute)),
@ -174,13 +174,13 @@ func TestSSHOptions_Match(t *testing.T) {
va := NewTimeDuration(n.Add(1 * time.Minute)) va := NewTimeDuration(n.Add(1 * time.Minute))
vb := NewTimeDuration(n.Add(5 * time.Minute)) vb := NewTimeDuration(n.Add(5 * time.Minute))
return test{ return test{
cmp: SSHOptions{ cmp: SignSSHOptions{
CertType: "foo", CertType: "foo",
Principals: []string{"foo"}, Principals: []string{"foo"},
ValidAfter: va, ValidAfter: va,
ValidBefore: vb, ValidBefore: vb,
}, },
so: SSHOptions{ so: SignSSHOptions{
CertType: "foo", CertType: "foo",
Principals: []string{"foo"}, Principals: []string{"foo"},
ValidAfter: va, ValidAfter: va,
@ -330,7 +330,7 @@ func Test_sshCertDefaultsModifier_Modify(t *testing.T) {
n := time.Now() n := time.Now()
va := NewTimeDuration(n.Add(1 * time.Minute)) va := NewTimeDuration(n.Add(1 * time.Minute))
vb := NewTimeDuration(n.Add(5 * time.Minute)) vb := NewTimeDuration(n.Add(5 * time.Minute))
so := SSHOptions{ so := SignSSHOptions{
Principals: []string{"foo", "bar"}, Principals: []string{"foo", "bar"},
CertType: "host", CertType: "host",
ValidAfter: va, ValidAfter: va,
@ -349,7 +349,7 @@ func Test_sshCertDefaultsModifier_Modify(t *testing.T) {
}, },
"ok/no-changes": func() test { "ok/no-changes": func() test {
n := time.Now() n := time.Now()
so := SSHOptions{ so := SignSSHOptions{
Principals: []string{"foo", "bar"}, Principals: []string{"foo", "bar"},
CertType: "host", CertType: "host",
ValidAfter: NewTimeDuration(n.Add(15 * time.Minute)), ValidAfter: NewTimeDuration(n.Add(15 * time.Minute)),
@ -659,7 +659,7 @@ func Test_sshCertDefaultValidator_Valid(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if err := v.Valid(tt.cert, SSHOptions{}); err != nil { if err := v.Valid(tt.cert, SignSSHOptions{}); err != nil {
if assert.NotNil(t, tt.err) { if assert.NotNil(t, tt.err) {
assert.HasPrefix(t, err.Error(), tt.err.Error()) assert.HasPrefix(t, err.Error(), tt.err.Error())
} }
@ -678,31 +678,31 @@ func Test_sshCertValidityValidator(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
cert *ssh.Certificate cert *ssh.Certificate
opts SSHOptions opts SignSSHOptions
err error err error
}{ }{
{ {
"fail/validAfter-0", "fail/validAfter-0",
&ssh.Certificate{CertType: ssh.UserCert}, &ssh.Certificate{CertType: ssh.UserCert},
SSHOptions{}, SignSSHOptions{},
errors.New("ssh certificate validAfter cannot be 0"), errors.New("ssh certificate validAfter cannot be 0"),
}, },
{ {
"fail/validBefore-in-past", "fail/validBefore-in-past",
&ssh.Certificate{CertType: ssh.UserCert, ValidAfter: uint64(now().Unix()), ValidBefore: uint64(now().Add(-time.Minute).Unix())}, &ssh.Certificate{CertType: ssh.UserCert, ValidAfter: uint64(now().Unix()), ValidBefore: uint64(now().Add(-time.Minute).Unix())},
SSHOptions{}, SignSSHOptions{},
errors.New("ssh certificate validBefore cannot be in the past"), errors.New("ssh certificate validBefore cannot be in the past"),
}, },
{ {
"fail/validBefore-before-validAfter", "fail/validBefore-before-validAfter",
&ssh.Certificate{CertType: ssh.UserCert, ValidAfter: uint64(now().Add(5 * time.Minute).Unix()), ValidBefore: uint64(now().Add(3 * time.Minute).Unix())}, &ssh.Certificate{CertType: ssh.UserCert, ValidAfter: uint64(now().Add(5 * time.Minute).Unix()), ValidBefore: uint64(now().Add(3 * time.Minute).Unix())},
SSHOptions{}, SignSSHOptions{},
errors.New("ssh certificate validBefore cannot be before validAfter"), errors.New("ssh certificate validBefore cannot be before validAfter"),
}, },
{ {
"fail/cert-type-not-set", "fail/cert-type-not-set",
&ssh.Certificate{ValidAfter: uint64(now().Unix()), ValidBefore: uint64(now().Add(10 * time.Minute).Unix())}, &ssh.Certificate{ValidAfter: uint64(now().Unix()), ValidBefore: uint64(now().Add(10 * time.Minute).Unix())},
SSHOptions{}, SignSSHOptions{},
errors.New("ssh certificate type has not been set"), errors.New("ssh certificate type has not been set"),
}, },
{ {
@ -712,7 +712,7 @@ func Test_sshCertValidityValidator(t *testing.T) {
ValidAfter: uint64(now().Unix()), ValidAfter: uint64(now().Unix()),
ValidBefore: uint64(now().Add(10 * time.Minute).Unix()), ValidBefore: uint64(now().Add(10 * time.Minute).Unix()),
}, },
SSHOptions{}, SignSSHOptions{},
errors.New("unknown ssh certificate type 3"), errors.New("unknown ssh certificate type 3"),
}, },
{ {
@ -722,7 +722,7 @@ func Test_sshCertValidityValidator(t *testing.T) {
ValidAfter: uint64(n.Unix()), ValidAfter: uint64(n.Unix()),
ValidBefore: uint64(n.Add(4 * time.Minute).Unix()), ValidBefore: uint64(n.Add(4 * time.Minute).Unix()),
}, },
SSHOptions{Backdate: time.Second}, SignSSHOptions{Backdate: time.Second},
errors.New("requested duration of 4m0s is less than minimum accepted duration for selected provisioner of 5m0s"), errors.New("requested duration of 4m0s is less than minimum accepted duration for selected provisioner of 5m0s"),
}, },
{ {
@ -732,7 +732,7 @@ func Test_sshCertValidityValidator(t *testing.T) {
ValidAfter: uint64(n.Unix()), ValidAfter: uint64(n.Unix()),
ValidBefore: uint64(n.Add(5 * time.Minute).Unix()), ValidBefore: uint64(n.Add(5 * time.Minute).Unix()),
}, },
SSHOptions{Backdate: time.Second}, SignSSHOptions{Backdate: time.Second},
nil, nil,
}, },
{ {
@ -742,7 +742,7 @@ func Test_sshCertValidityValidator(t *testing.T) {
ValidAfter: uint64(n.Unix()), ValidAfter: uint64(n.Unix()),
ValidBefore: uint64(n.Add(48 * time.Hour).Unix()), ValidBefore: uint64(n.Add(48 * time.Hour).Unix()),
}, },
SSHOptions{Backdate: time.Second}, SignSSHOptions{Backdate: time.Second},
errors.New("requested duration of 48h0m0s is greater than maximum accepted duration for selected provisioner of 24h0m1s"), errors.New("requested duration of 48h0m0s is greater than maximum accepted duration for selected provisioner of 24h0m1s"),
}, },
{ {
@ -752,7 +752,7 @@ func Test_sshCertValidityValidator(t *testing.T) {
ValidAfter: uint64(n.Unix()), ValidAfter: uint64(n.Unix()),
ValidBefore: uint64(n.Add(24*time.Hour + time.Second).Unix()), ValidBefore: uint64(n.Add(24*time.Hour + time.Second).Unix()),
}, },
SSHOptions{Backdate: time.Second}, SignSSHOptions{Backdate: time.Second},
nil, nil,
}, },
{ {
@ -762,7 +762,7 @@ func Test_sshCertValidityValidator(t *testing.T) {
ValidAfter: uint64(now().Unix()), ValidAfter: uint64(now().Unix()),
ValidBefore: uint64(now().Add(8 * time.Hour).Unix()), ValidBefore: uint64(now().Add(8 * time.Hour).Unix()),
}, },
SSHOptions{Backdate: time.Second}, SignSSHOptions{Backdate: time.Second},
nil, nil,
}, },
} }
@ -908,7 +908,7 @@ func Test_sshValidityModifier(t *testing.T) {
for name, run := range tests { for name, run := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
tt := run() tt := run()
if err := tt.svm.Option(SSHOptions{}).Modify(tt.cert); err != nil { if err := tt.svm.Option(SignSSHOptions{}).Modify(tt.cert); err != nil {
if assert.NotNil(t, tt.err) { if assert.NotNil(t, tt.err) {
assert.HasPrefix(t, err.Error(), tt.err.Error()) assert.HasPrefix(t, err.Error(), tt.err.Error())
} }
@ -962,7 +962,7 @@ func Test_sshDefaultDuration_Option(t *testing.T) {
Claimer *Claimer Claimer *Claimer
} }
type args struct { type args struct {
o SSHOptions o SignSSHOptions
cert *ssh.Certificate cert *ssh.Certificate
} }
tests := []struct { tests := []struct {
@ -972,26 +972,26 @@ func Test_sshDefaultDuration_Option(t *testing.T) {
want *ssh.Certificate want *ssh.Certificate
wantErr bool wantErr bool
}{ }{
{"user", fields{newClaimer(nil)}, args{SSHOptions{}, &ssh.Certificate{CertType: ssh.UserCert}}, {"user", fields{newClaimer(nil)}, args{SignSSHOptions{}, &ssh.Certificate{CertType: ssh.UserCert}},
&ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(0), ValidBefore: unix(16 * time.Hour)}, false}, &ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(0), ValidBefore: unix(16 * time.Hour)}, false},
{"host", fields{newClaimer(nil)}, args{SSHOptions{}, &ssh.Certificate{CertType: ssh.HostCert}}, {"host", fields{newClaimer(nil)}, args{SignSSHOptions{}, &ssh.Certificate{CertType: ssh.HostCert}},
&ssh.Certificate{CertType: ssh.HostCert, ValidAfter: unix(0), ValidBefore: unix(30 * 24 * time.Hour)}, false}, &ssh.Certificate{CertType: ssh.HostCert, ValidAfter: unix(0), ValidBefore: unix(30 * 24 * time.Hour)}, false},
{"user claim", fields{newClaimer(&Claims{DefaultUserSSHDur: &Duration{1 * time.Hour}})}, args{SSHOptions{}, &ssh.Certificate{CertType: ssh.UserCert}}, {"user claim", fields{newClaimer(&Claims{DefaultUserSSHDur: &Duration{1 * time.Hour}})}, args{SignSSHOptions{}, &ssh.Certificate{CertType: ssh.UserCert}},
&ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(0), ValidBefore: unix(1 * time.Hour)}, false}, &ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(0), ValidBefore: unix(1 * time.Hour)}, false},
{"host claim", fields{newClaimer(&Claims{DefaultHostSSHDur: &Duration{1 * time.Hour}})}, args{SSHOptions{}, &ssh.Certificate{CertType: ssh.HostCert}}, {"host claim", fields{newClaimer(&Claims{DefaultHostSSHDur: &Duration{1 * time.Hour}})}, args{SignSSHOptions{}, &ssh.Certificate{CertType: ssh.HostCert}},
&ssh.Certificate{CertType: ssh.HostCert, ValidAfter: unix(0), ValidBefore: unix(1 * time.Hour)}, false}, &ssh.Certificate{CertType: ssh.HostCert, ValidAfter: unix(0), ValidBefore: unix(1 * time.Hour)}, false},
{"user backdate", fields{newClaimer(nil)}, args{SSHOptions{Backdate: 1 * time.Minute}, &ssh.Certificate{CertType: ssh.UserCert}}, {"user backdate", fields{newClaimer(nil)}, args{SignSSHOptions{Backdate: 1 * time.Minute}, &ssh.Certificate{CertType: ssh.UserCert}},
&ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(-1 * time.Minute), ValidBefore: unix(16 * time.Hour)}, false}, &ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(-1 * time.Minute), ValidBefore: unix(16 * time.Hour)}, false},
{"host backdate", fields{newClaimer(nil)}, args{SSHOptions{Backdate: 1 * time.Minute}, &ssh.Certificate{CertType: ssh.HostCert}}, {"host backdate", fields{newClaimer(nil)}, args{SignSSHOptions{Backdate: 1 * time.Minute}, &ssh.Certificate{CertType: ssh.HostCert}},
&ssh.Certificate{CertType: ssh.HostCert, ValidAfter: unix(-1 * time.Minute), ValidBefore: unix(30 * 24 * time.Hour)}, false}, &ssh.Certificate{CertType: ssh.HostCert, ValidAfter: unix(-1 * time.Minute), ValidBefore: unix(30 * 24 * time.Hour)}, false},
{"user validAfter", fields{newClaimer(nil)}, args{SSHOptions{Backdate: 1 * time.Minute}, &ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(1 * time.Hour)}}, {"user validAfter", fields{newClaimer(nil)}, args{SignSSHOptions{Backdate: 1 * time.Minute}, &ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(1 * time.Hour)}},
&ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(time.Hour), ValidBefore: unix(17 * time.Hour)}, false}, &ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(time.Hour), ValidBefore: unix(17 * time.Hour)}, false},
{"user validBefore", fields{newClaimer(nil)}, args{SSHOptions{Backdate: 1 * time.Minute}, &ssh.Certificate{CertType: ssh.UserCert, ValidBefore: unix(1 * time.Hour)}}, {"user validBefore", fields{newClaimer(nil)}, args{SignSSHOptions{Backdate: 1 * time.Minute}, &ssh.Certificate{CertType: ssh.UserCert, ValidBefore: unix(1 * time.Hour)}},
&ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(-1 * time.Minute), ValidBefore: unix(time.Hour)}, false}, &ssh.Certificate{CertType: ssh.UserCert, ValidAfter: unix(-1 * time.Minute), ValidBefore: unix(time.Hour)}, false},
{"host validAfter validBefore", fields{newClaimer(nil)}, args{SSHOptions{Backdate: 1 * time.Minute}, &ssh.Certificate{CertType: ssh.HostCert, ValidAfter: unix(1 * time.Minute), ValidBefore: unix(2 * time.Minute)}}, {"host validAfter validBefore", fields{newClaimer(nil)}, args{SignSSHOptions{Backdate: 1 * time.Minute}, &ssh.Certificate{CertType: ssh.HostCert, ValidAfter: unix(1 * time.Minute), ValidBefore: unix(2 * time.Minute)}},
&ssh.Certificate{CertType: ssh.HostCert, ValidAfter: unix(1 * time.Minute), ValidBefore: unix(2 * time.Minute)}, false}, &ssh.Certificate{CertType: ssh.HostCert, ValidAfter: unix(1 * time.Minute), ValidBefore: unix(2 * time.Minute)}, false},
{"fail zero", fields{newClaimer(nil)}, args{SSHOptions{}, &ssh.Certificate{}}, &ssh.Certificate{}, true}, {"fail zero", fields{newClaimer(nil)}, args{SignSSHOptions{}, &ssh.Certificate{}}, &ssh.Certificate{}, true},
{"fail type", fields{newClaimer(nil)}, args{SSHOptions{}, &ssh.Certificate{CertType: 3}}, &ssh.Certificate{CertType: 3}, true}, {"fail type", fields{newClaimer(nil)}, args{SignSSHOptions{}, &ssh.Certificate{CertType: 3}}, &ssh.Certificate{CertType: 3}, true},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -1015,7 +1015,7 @@ func Test_sshLimitDuration_Option(t *testing.T) {
NotAfter time.Time NotAfter time.Time
} }
type args struct { type args struct {
o SSHOptions o SignSSHOptions
} }
tests := []struct { tests := []struct {
name string name string

View file

@ -10,7 +10,7 @@ import (
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
func validateSSHCertificate(cert *ssh.Certificate, opts *SSHOptions) error { func validateSSHCertificate(cert *ssh.Certificate, opts *SignSSHOptions) error {
switch { switch {
case cert == nil: case cert == nil:
return fmt.Errorf("certificate is nil") return fmt.Errorf("certificate is nil")
@ -39,7 +39,7 @@ func validateSSHCertificate(cert *ssh.Certificate, opts *SSHOptions) error {
} }
} }
func signSSHCertificate(key crypto.PublicKey, opts SSHOptions, signOpts []SignOption, signKey crypto.Signer) (*ssh.Certificate, error) { func signSSHCertificate(key crypto.PublicKey, opts SignSSHOptions, signOpts []SignOption, signKey crypto.Signer) (*ssh.Certificate, error) {
pub, err := ssh.NewPublicKey(key) pub, err := ssh.NewPublicKey(key)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -713,20 +713,20 @@ func generateK8sSAToken(jwk *jose.JSONWebKey, claims *k8sSAPayload, tokOpts ...t
} }
func generateSimpleSSHUserToken(iss, aud string, jwk *jose.JSONWebKey) (string, error) { func generateSimpleSSHUserToken(iss, aud string, jwk *jose.JSONWebKey) (string, error) {
return generateSSHToken("subject@localhost", iss, aud, time.Now(), &SSHOptions{ return generateSSHToken("subject@localhost", iss, aud, time.Now(), &SignSSHOptions{
CertType: "user", CertType: "user",
Principals: []string{"name"}, Principals: []string{"name"},
}, jwk) }, jwk)
} }
func generateSimpleSSHHostToken(iss, aud string, jwk *jose.JSONWebKey) (string, error) { func generateSimpleSSHHostToken(iss, aud string, jwk *jose.JSONWebKey) (string, error) {
return generateSSHToken("subject@localhost", iss, aud, time.Now(), &SSHOptions{ return generateSSHToken("subject@localhost", iss, aud, time.Now(), &SignSSHOptions{
CertType: "host", CertType: "host",
Principals: []string{"smallstep.com"}, Principals: []string{"smallstep.com"},
}, jwk) }, jwk)
} }
func generateSSHToken(sub, iss, aud string, iat time.Time, sshOpts *SSHOptions, jwk *jose.JSONWebKey) (string, error) { func generateSSHToken(sub, iss, aud string, iat time.Time, sshOpts *SignSSHOptions, jwk *jose.JSONWebKey) (string, error) {
sig, err := jose.NewSigner( sig, err := jose.NewSigner(
jose.SigningKey{Algorithm: jose.ES256, Key: jwk.Key}, jose.SigningKey{Algorithm: jose.ES256, Key: jwk.Key},
new(jose.SignerOptions).WithType("JWT").WithHeader("kid", jwk.KeyID), new(jose.SignerOptions).WithType("JWT").WithHeader("kid", jwk.KeyID),

View file

@ -25,11 +25,11 @@ type x5cPayload struct {
// signature requests. // signature requests.
type X5C struct { type X5C struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
Roots []byte `json:"roots"` Roots []byte `json:"roots"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *ProvisionerOptions `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
claimer *Claimer claimer *Claimer
audiences Audiences audiences Audiences
rootPool *x509.CertPool rootPool *x509.CertPool

View file

@ -696,7 +696,7 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) {
Expiry: jose.NewNumericDate(now.Add(5 * time.Minute)), Expiry: jose.NewNumericDate(now.Add(5 * time.Minute)),
Audience: []string{testAudiences.SSHSign[0]}, Audience: []string{testAudiences.SSHSign[0]},
}, },
Step: &stepPayload{SSH: &SSHOptions{ Step: &stepPayload{SSH: &SignSSHOptions{
CertType: SSHHostCert, CertType: SSHHostCert,
Principals: []string{"max", "mariano", "alan"}, Principals: []string{"max", "mariano", "alan"},
ValidAfter: TimeDuration{d: 5 * time.Minute}, ValidAfter: TimeDuration{d: 5 * time.Minute},
@ -728,7 +728,7 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) {
Expiry: jose.NewNumericDate(now.Add(5 * time.Minute)), Expiry: jose.NewNumericDate(now.Add(5 * time.Minute)),
Audience: []string{testAudiences.SSHSign[0]}, Audience: []string{testAudiences.SSHSign[0]},
}, },
Step: &stepPayload{SSH: &SSHOptions{}}, Step: &stepPayload{SSH: &SignSSHOptions{}},
} }
tok, err := generateX5CSSHToken(x5cJWK, claims, withX5CHdr(x5cCerts)) tok, err := generateX5CSSHToken(x5cJWK, claims, withX5CHdr(x5cCerts))
assert.FatalError(t, err) assert.FatalError(t, err)
@ -759,7 +759,7 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) {
case sshCertOptionsValidator: case sshCertOptionsValidator:
tc.claims.Step.SSH.ValidAfter.t = time.Time{} tc.claims.Step.SSH.ValidAfter.t = time.Time{}
tc.claims.Step.SSH.ValidBefore.t = time.Time{} tc.claims.Step.SSH.ValidBefore.t = time.Time{}
assert.Equals(t, SSHOptions(v), *tc.claims.Step.SSH) assert.Equals(t, SignSSHOptions(v), *tc.claims.Step.SSH)
case sshCertKeyIDModifier: case sshCertKeyIDModifier:
assert.Equals(t, string(v), "foo") assert.Equals(t, string(v), "foo")
case sshCertTypeModifier: case sshCertTypeModifier:
@ -771,7 +771,7 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) {
case sshCertValidBeforeModifier: case sshCertValidBeforeModifier:
assert.Equals(t, int64(v), tc.claims.Step.SSH.ValidBefore.RelativeTime(nw).Unix()) assert.Equals(t, int64(v), tc.claims.Step.SSH.ValidBefore.RelativeTime(nw).Unix())
case sshCertDefaultsModifier: case sshCertDefaultsModifier:
assert.Equals(t, SSHOptions(v), SSHOptions{CertType: SSHUserCert}) assert.Equals(t, SignSSHOptions(v), SignSSHOptions{CertType: SSHUserCert})
case *sshLimitDuration: case *sshLimitDuration:
assert.Equals(t, v.Claimer, tc.p.claimer) assert.Equals(t, v.Claimer, tc.p.claimer)
assert.Equals(t, v.NotAfter, x5cCerts[0].NotAfter) assert.Equals(t, v.NotAfter, x5cCerts[0].NotAfter)

View file

@ -204,7 +204,7 @@ func (a *Authority) GetSSHBastion(ctx context.Context, user string, hostname str
} }
// SignSSH creates a signed SSH certificate with the given public key and options. // SignSSH creates a signed SSH certificate with the given public key and options.
func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) { func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) {
var mods []provisioner.SSHCertModifier var mods []provisioner.SSHCertModifier
var validators []provisioner.SSHCertValidator var validators []provisioner.SSHCertValidator
@ -453,7 +453,7 @@ func (a *Authority) RekeySSH(ctx context.Context, oldCert *ssh.Certificate, pub
// Apply validators from provisioner. // Apply validators from provisioner.
for _, v := range validators { for _, v := range validators {
if err := v.Valid(cert, provisioner.SSHOptions{Backdate: backdate}); err != nil { if err := v.Valid(cert, provisioner.SignSSHOptions{Backdate: backdate}); err != nil {
return nil, errs.Wrap(http.StatusForbidden, err, "rekeySSH") return nil, errs.Wrap(http.StatusForbidden, err, "rekeySSH")
} }
} }

View file

@ -62,7 +62,7 @@ func (m sshTestCertModifier) Modify(cert *ssh.Certificate) error {
type sshTestCertValidator string type sshTestCertValidator string
func (v sshTestCertValidator) Valid(crt *ssh.Certificate, opts provisioner.SSHOptions) error { func (v sshTestCertValidator) Valid(crt *ssh.Certificate, opts provisioner.SignSSHOptions) error {
if v == "" { if v == "" {
return nil return nil
} }
@ -71,7 +71,7 @@ func (v sshTestCertValidator) Valid(crt *ssh.Certificate, opts provisioner.SSHOp
type sshTestOptionsValidator string type sshTestOptionsValidator string
func (v sshTestOptionsValidator) Valid(opts provisioner.SSHOptions) error { func (v sshTestOptionsValidator) Valid(opts provisioner.SignSSHOptions) error {
if v == "" { if v == "" {
return nil return nil
} }
@ -80,7 +80,7 @@ func (v sshTestOptionsValidator) Valid(opts provisioner.SSHOptions) error {
type sshTestOptionsModifier string type sshTestOptionsModifier string
func (m sshTestOptionsModifier) Option(opts provisioner.SSHOptions) provisioner.SSHCertModifier { func (m sshTestOptionsModifier) Option(opts provisioner.SignSSHOptions) provisioner.SSHCertModifier {
return sshTestCertModifier(string(m)) return sshTestCertModifier(string(m))
} }
@ -109,7 +109,7 @@ func TestAuthority_SignSSH(t *testing.T) {
} }
type args struct { type args struct {
key ssh.PublicKey key ssh.PublicKey
opts provisioner.SSHOptions opts provisioner.SignSSHOptions
signOpts []provisioner.SignOption signOpts []provisioner.SignOption
} }
type want struct { type want struct {
@ -125,27 +125,27 @@ func TestAuthority_SignSSH(t *testing.T) {
want want want want
wantErr bool wantErr bool
}{ }{
{"ok-user", fields{signer, signer}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{userOptions}}, want{CertType: ssh.UserCert}, false}, {"ok-user", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userOptions}}, want{CertType: ssh.UserCert}, false},
{"ok-host", fields{signer, signer}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{hostOptions}}, want{CertType: ssh.HostCert}, false}, {"ok-host", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{hostOptions}}, want{CertType: ssh.HostCert}, false},
{"ok-opts-type-user", fields{signer, signer}, args{pub, provisioner.SSHOptions{CertType: "user"}, []provisioner.SignOption{}}, want{CertType: ssh.UserCert}, false}, {"ok-opts-type-user", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "user"}, []provisioner.SignOption{}}, want{CertType: ssh.UserCert}, false},
{"ok-opts-type-host", fields{signer, signer}, args{pub, provisioner.SSHOptions{CertType: "host"}, []provisioner.SignOption{}}, want{CertType: ssh.HostCert}, false}, {"ok-opts-type-host", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "host"}, []provisioner.SignOption{}}, want{CertType: ssh.HostCert}, false},
{"ok-opts-principals", fields{signer, signer}, args{pub, provisioner.SSHOptions{CertType: "user", Principals: []string{"user"}}, []provisioner.SignOption{}}, want{CertType: ssh.UserCert, Principals: []string{"user"}}, false}, {"ok-opts-principals", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "user", Principals: []string{"user"}}, []provisioner.SignOption{}}, want{CertType: ssh.UserCert, Principals: []string{"user"}}, false},
{"ok-opts-principals", fields{signer, signer}, args{pub, provisioner.SSHOptions{CertType: "host", Principals: []string{"foo.test.com", "bar.test.com"}}, []provisioner.SignOption{}}, want{CertType: ssh.HostCert, Principals: []string{"foo.test.com", "bar.test.com"}}, false}, {"ok-opts-principals", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "host", Principals: []string{"foo.test.com", "bar.test.com"}}, []provisioner.SignOption{}}, want{CertType: ssh.HostCert, Principals: []string{"foo.test.com", "bar.test.com"}}, false},
{"ok-opts-valid-after", fields{signer, signer}, args{pub, provisioner.SSHOptions{CertType: "user", ValidAfter: provisioner.NewTimeDuration(now)}, []provisioner.SignOption{}}, want{CertType: ssh.UserCert, ValidAfter: uint64(now.Unix())}, false}, {"ok-opts-valid-after", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "user", ValidAfter: provisioner.NewTimeDuration(now)}, []provisioner.SignOption{}}, want{CertType: ssh.UserCert, ValidAfter: uint64(now.Unix())}, false},
{"ok-opts-valid-before", fields{signer, signer}, args{pub, provisioner.SSHOptions{CertType: "host", ValidBefore: provisioner.NewTimeDuration(now)}, []provisioner.SignOption{}}, want{CertType: ssh.HostCert, ValidBefore: uint64(now.Unix())}, false}, {"ok-opts-valid-before", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "host", ValidBefore: provisioner.NewTimeDuration(now)}, []provisioner.SignOption{}}, want{CertType: ssh.HostCert, ValidBefore: uint64(now.Unix())}, false},
{"ok-cert-validator", fields{signer, signer}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{userOptions, sshTestCertValidator("")}}, want{CertType: ssh.UserCert}, false}, {"ok-cert-validator", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userOptions, sshTestCertValidator("")}}, want{CertType: ssh.UserCert}, false},
{"ok-cert-modifier", fields{signer, signer}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{userOptions, sshTestCertModifier("")}}, want{CertType: ssh.UserCert}, false}, {"ok-cert-modifier", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userOptions, sshTestCertModifier("")}}, want{CertType: ssh.UserCert}, false},
{"ok-opts-validator", fields{signer, signer}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{userOptions, sshTestOptionsValidator("")}}, want{CertType: ssh.UserCert}, false}, {"ok-opts-validator", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userOptions, sshTestOptionsValidator("")}}, want{CertType: ssh.UserCert}, false},
{"ok-opts-modifier", fields{signer, signer}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{userOptions, sshTestOptionsModifier("")}}, want{CertType: ssh.UserCert}, false}, {"ok-opts-modifier", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userOptions, sshTestOptionsModifier("")}}, want{CertType: ssh.UserCert}, false},
{"fail-opts-type", fields{signer, signer}, args{pub, provisioner.SSHOptions{CertType: "foo"}, []provisioner.SignOption{}}, want{}, true}, {"fail-opts-type", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "foo"}, []provisioner.SignOption{}}, want{}, true},
{"fail-cert-validator", fields{signer, signer}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{userOptions, sshTestCertValidator("an error")}}, want{}, true}, {"fail-cert-validator", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userOptions, sshTestCertValidator("an error")}}, want{}, true},
{"fail-cert-modifier", fields{signer, signer}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{userOptions, sshTestCertModifier("an error")}}, want{}, true}, {"fail-cert-modifier", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userOptions, sshTestCertModifier("an error")}}, want{}, true},
{"fail-opts-validator", fields{signer, signer}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{userOptions, sshTestOptionsValidator("an error")}}, want{}, true}, {"fail-opts-validator", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userOptions, sshTestOptionsValidator("an error")}}, want{}, true},
{"fail-opts-modifier", fields{signer, signer}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{userOptions, sshTestOptionsModifier("an error")}}, want{}, true}, {"fail-opts-modifier", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userOptions, sshTestOptionsModifier("an error")}}, want{}, true},
{"fail-bad-sign-options", fields{signer, signer}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{userOptions, "wrong type"}}, want{}, true}, {"fail-bad-sign-options", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userOptions, "wrong type"}}, want{}, true},
{"fail-no-user-key", fields{nil, signer}, args{pub, provisioner.SSHOptions{CertType: "user"}, []provisioner.SignOption{}}, want{}, true}, {"fail-no-user-key", fields{nil, signer}, args{pub, provisioner.SignSSHOptions{CertType: "user"}, []provisioner.SignOption{}}, want{}, true},
{"fail-no-host-key", fields{signer, nil}, args{pub, provisioner.SSHOptions{CertType: "host"}, []provisioner.SignOption{}}, want{}, true}, {"fail-no-host-key", fields{signer, nil}, args{pub, provisioner.SignSSHOptions{CertType: "host"}, []provisioner.SignOption{}}, want{}, true},
{"fail-bad-type", fields{signer, nil}, args{pub, provisioner.SSHOptions{}, []provisioner.SignOption{sshTestModifier{CertType: 0}}}, want{}, true}, {"fail-bad-type", fields{signer, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{sshTestModifier{CertType: 0}}}, want{}, true},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View file

@ -32,7 +32,7 @@ var oidAuthorityKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 35}
var oidSubjectKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 14} var oidSubjectKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 14}
func withDefaultASN1DN(def *x509legacy.ASN1DN) provisioner.CertificateModifierFunc { func withDefaultASN1DN(def *x509legacy.ASN1DN) provisioner.CertificateModifierFunc {
return func(crt *x509.Certificate, opts provisioner.Options) error { return func(crt *x509.Certificate, opts provisioner.SignOptions) error {
if def == nil { if def == nil {
return errors.New("default ASN1DN template cannot be nil") return errors.New("default ASN1DN template cannot be nil")
} }
@ -61,7 +61,7 @@ func withDefaultASN1DN(def *x509legacy.ASN1DN) provisioner.CertificateModifierFu
} }
// Sign creates a signed certificate from a certificate signing request. // Sign creates a signed certificate from a certificate signing request.
func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Options, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, error) { func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.SignOptions, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, error) {
var ( var (
certOptions []x509util.Option certOptions []x509util.Option
certValidators []provisioner.CertificateValidator certValidators []provisioner.CertificateValidator

View file

@ -132,7 +132,7 @@ func TestAuthority_Sign(t *testing.T) {
} }
nb := time.Now() nb := time.Now()
signOpts := provisioner.Options{ signOpts := provisioner.SignOptions{
NotBefore: provisioner.NewTimeDuration(nb), NotBefore: provisioner.NewTimeDuration(nb),
NotAfter: provisioner.NewTimeDuration(nb.Add(time.Minute * 5)), NotAfter: provisioner.NewTimeDuration(nb.Add(time.Minute * 5)),
} }
@ -150,7 +150,7 @@ func TestAuthority_Sign(t *testing.T) {
type signTest struct { type signTest struct {
auth *Authority auth *Authority
csr *x509.CertificateRequest csr *x509.CertificateRequest
signOpts provisioner.Options signOpts provisioner.SignOptions
extraOpts []provisioner.SignOption extraOpts []provisioner.SignOption
notBefore time.Time notBefore time.Time
notAfter time.Time notAfter time.Time
@ -210,7 +210,7 @@ func TestAuthority_Sign(t *testing.T) {
}, },
"fail provisioner duration claim": func(t *testing.T) *signTest { "fail provisioner duration claim": func(t *testing.T) *signTest {
csr := getCSR(t, priv) csr := getCSR(t, priv)
_signOpts := provisioner.Options{ _signOpts := provisioner.SignOptions{
NotBefore: provisioner.NewTimeDuration(nb), NotBefore: provisioner.NewTimeDuration(nb),
NotAfter: provisioner.NewTimeDuration(nb.Add(time.Hour * 25)), NotAfter: provisioner.NewTimeDuration(nb.Add(time.Hour * 25)),
} }
@ -429,14 +429,14 @@ func TestAuthority_Renew(t *testing.T) {
certModToWithOptions := func(m provisioner.CertificateModifierFunc) x509util.WithOption { certModToWithOptions := func(m provisioner.CertificateModifierFunc) x509util.WithOption {
return func(p x509util.Profile) error { return func(p x509util.Profile) error {
crt := p.Subject() crt := p.Subject()
return m.Modify(crt, provisioner.Options{}) return m.Modify(crt, provisioner.SignOptions{})
} }
} }
now := time.Now().UTC() now := time.Now().UTC()
nb1 := now.Add(-time.Minute * 7) nb1 := now.Add(-time.Minute * 7)
na1 := now na1 := now
so := &provisioner.Options{ so := &provisioner.SignOptions{
NotBefore: provisioner.NewTimeDuration(nb1), NotBefore: provisioner.NewTimeDuration(nb1),
NotAfter: provisioner.NewTimeDuration(na1), NotAfter: provisioner.NewTimeDuration(na1),
} }
@ -656,14 +656,14 @@ func TestAuthority_Rekey(t *testing.T) {
certModToWithOptions := func(m provisioner.CertificateModifierFunc) x509util.WithOption { certModToWithOptions := func(m provisioner.CertificateModifierFunc) x509util.WithOption {
return func(p x509util.Profile) error { return func(p x509util.Profile) error {
crt := p.Subject() crt := p.Subject()
return m.Modify(crt, provisioner.Options{}) return m.Modify(crt, provisioner.SignOptions{})
} }
} }
now := time.Now().UTC() now := time.Now().UTC()
nb1 := now.Add(-time.Minute * 7) nb1 := now.Add(-time.Minute * 7)
na1 := now na1 := now
so := &provisioner.Options{ so := &provisioner.SignOptions{
NotBefore: provisioner.NewTimeDuration(nb1), NotBefore: provisioner.NewTimeDuration(nb1),
NotAfter: provisioner.NewTimeDuration(na1), NotAfter: provisioner.NewTimeDuration(na1),
} }

View file

@ -133,7 +133,7 @@ func (p *Provisioner) SSHToken(certType, keyID string, principals []string) (str
token.WithIssuer(p.name), token.WithIssuer(p.name),
token.WithAudience(p.sshAudience), token.WithAudience(p.sshAudience),
token.WithValidity(notBefore, notAfter), token.WithValidity(notBefore, notAfter),
token.WithSSH(provisioner.SSHOptions{ token.WithSSH(provisioner.SignSSHOptions{
CertType: certType, CertType: certType,
Principals: principals, Principals: principals,
KeyID: keyID, KeyID: keyID,