forked from TrueCloudLab/certificates
Improve policy errors returned to client
This commit is contained in:
parent
a3c51881c7
commit
3fa96ebf13
4 changed files with 161 additions and 35 deletions
|
@ -10,14 +10,17 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
|
||||||
|
"go.step.sm/crypto/randutil"
|
||||||
|
"go.step.sm/crypto/sshutil"
|
||||||
|
|
||||||
"github.com/smallstep/certificates/authority/config"
|
"github.com/smallstep/certificates/authority/config"
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
"github.com/smallstep/certificates/db"
|
"github.com/smallstep/certificates/db"
|
||||||
"github.com/smallstep/certificates/errs"
|
"github.com/smallstep/certificates/errs"
|
||||||
|
policy "github.com/smallstep/certificates/policy"
|
||||||
"github.com/smallstep/certificates/templates"
|
"github.com/smallstep/certificates/templates"
|
||||||
"go.step.sm/crypto/randutil"
|
|
||||||
"go.step.sm/crypto/sshutil"
|
|
||||||
"golang.org/x/crypto/ssh"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -252,6 +255,12 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi
|
||||||
if a.sshUserPolicy != nil {
|
if a.sshUserPolicy != nil {
|
||||||
allowed, err := a.sshUserPolicy.IsSSHCertificateAllowed(certTpl)
|
allowed, err := a.sshUserPolicy.IsSSHCertificateAllowed(certTpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
var pe *policy.NamePolicyError
|
||||||
|
if errors.As(err, &pe) && pe.Reason == policy.NotAuthorizedForThisName {
|
||||||
|
return nil, errs.ApplyOptions(
|
||||||
|
errs.ForbiddenErr(errors.New("authority not allowed to sign"), "authority.SignSSH: %s", err.Error()),
|
||||||
|
)
|
||||||
|
}
|
||||||
return nil, errs.InternalServerErr(err,
|
return nil, errs.InternalServerErr(err,
|
||||||
errs.WithMessage("authority.SignSSH: error creating ssh user certificate"),
|
errs.WithMessage("authority.SignSSH: error creating ssh user certificate"),
|
||||||
)
|
)
|
||||||
|
@ -269,6 +278,13 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi
|
||||||
if a.sshHostPolicy != nil {
|
if a.sshHostPolicy != nil {
|
||||||
allowed, err := a.sshHostPolicy.IsSSHCertificateAllowed(certTpl)
|
allowed, err := a.sshHostPolicy.IsSSHCertificateAllowed(certTpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
var pe *policy.NamePolicyError
|
||||||
|
if errors.As(err, &pe) && pe.Reason == policy.NotAuthorizedForThisName {
|
||||||
|
return nil, errs.ApplyOptions(
|
||||||
|
// TODO: show which names were not allowed; they are in the err
|
||||||
|
errs.ForbiddenErr(errors.New("authority not allowed to sign"), "authority.SignSSH: %s", err.Error()),
|
||||||
|
)
|
||||||
|
}
|
||||||
return nil, errs.InternalServerErr(err,
|
return nil, errs.InternalServerErr(err,
|
||||||
errs.WithMessage("authority.SignSSH: error creating ssh host certificate"),
|
errs.WithMessage("authority.SignSSH: error creating ssh host certificate"),
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
|
|
||||||
"github.com/smallstep/assert"
|
"github.com/smallstep/assert"
|
||||||
"github.com/smallstep/certificates/api/render"
|
"github.com/smallstep/certificates/api/render"
|
||||||
|
"github.com/smallstep/certificates/authority/policy"
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
"github.com/smallstep/certificates/db"
|
"github.com/smallstep/certificates/db"
|
||||||
"github.com/smallstep/certificates/templates"
|
"github.com/smallstep/certificates/templates"
|
||||||
|
@ -159,6 +160,14 @@ func TestAuthority_SignSSH(t *testing.T) {
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
hostTemplateWithHosts, err := provisioner.TemplateSSHOptions(nil, sshutil.CreateTemplateData(sshutil.HostCert, "key-id", []string{"foo.test.com", "bar.test.com"}))
|
hostTemplateWithHosts, err := provisioner.TemplateSSHOptions(nil, sshutil.CreateTemplateData(sshutil.HostCert, "key-id", []string{"foo.test.com", "bar.test.com"}))
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
|
userTemplateWithRoot, err := provisioner.TemplateSSHOptions(nil, sshutil.CreateTemplateData(sshutil.UserCert, "key-id", []string{"root"}))
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
hostTemplateWithExampleDotCom, err := provisioner.TemplateSSHOptions(nil, sshutil.CreateTemplateData(sshutil.HostCert, "key-id", []string{"example.com"}))
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
badUserTemplate, err := provisioner.TemplateSSHOptions(nil, sshutil.CreateTemplateData(sshutil.UserCert, "key-id", []string{"127.0.0.1"}))
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
badHostTemplate, err := provisioner.TemplateSSHOptions(nil, sshutil.CreateTemplateData(sshutil.HostCert, "key-id", []string{"host...local"}))
|
||||||
|
assert.FatalError(t, err)
|
||||||
userCustomTemplate, err := provisioner.TemplateSSHOptions(&provisioner.Options{
|
userCustomTemplate, err := provisioner.TemplateSSHOptions(&provisioner.Options{
|
||||||
SSH: &provisioner.SSHOptions{Template: `{
|
SSH: &provisioner.SSHOptions{Template: `{
|
||||||
"type": "{{ .Type }}",
|
"type": "{{ .Type }}",
|
||||||
|
@ -182,11 +191,30 @@ func TestAuthority_SignSSH(t *testing.T) {
|
||||||
}, sshutil.CreateTemplateData(sshutil.UserCert, "key-id", []string{"user"}))
|
}, sshutil.CreateTemplateData(sshutil.UserCert, "key-id", []string{"user"}))
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
|
|
||||||
|
policyOptions := &policy.SSHPolicyOptions{
|
||||||
|
User: &policy.SSHUserCertificateOptions{
|
||||||
|
AllowedNames: &policy.SSHNameOptions{
|
||||||
|
Principals: []string{"user"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Host: &policy.SSHHostCertificateOptions{
|
||||||
|
AllowedNames: &policy.SSHNameOptions{
|
||||||
|
DNSDomains: []string{"*.test.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
userPolicy, err := policy.NewSSHUserPolicyEngine(policyOptions)
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
hostPolicy, err := policy.NewSSHHostPolicyEngine(policyOptions)
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
type fields struct {
|
type fields struct {
|
||||||
sshCAUserCertSignKey ssh.Signer
|
sshCAUserCertSignKey ssh.Signer
|
||||||
sshCAHostCertSignKey ssh.Signer
|
sshCAHostCertSignKey ssh.Signer
|
||||||
|
sshUserPolicy policy.UserPolicy
|
||||||
|
sshHostPolicy policy.HostPolicy
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
key ssh.PublicKey
|
key ssh.PublicKey
|
||||||
|
@ -206,39 +234,49 @@ func TestAuthority_SignSSH(t *testing.T) {
|
||||||
want want
|
want want
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok-user", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions}}, want{CertType: ssh.UserCert}, false},
|
{"ok-user", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions}}, want{CertType: ssh.UserCert}, false},
|
||||||
{"ok-host", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{hostTemplate, hostOptions}}, want{CertType: ssh.HostCert}, false},
|
{"ok-host", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{hostTemplate, hostOptions}}, want{CertType: ssh.HostCert}, false},
|
||||||
{"ok-user-only", fields{signer, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions}}, want{CertType: ssh.UserCert}, false},
|
{"ok-user-only", fields{signer, nil, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions}}, want{CertType: ssh.UserCert}, false},
|
||||||
{"ok-host-only", fields{nil, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{hostTemplate, hostOptions}}, want{CertType: ssh.HostCert}, false},
|
{"ok-host-only", fields{nil, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{hostTemplate, hostOptions}}, want{CertType: ssh.HostCert}, false},
|
||||||
{"ok-opts-type-user", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "user"}, []provisioner.SignOption{userTemplate}}, want{CertType: ssh.UserCert}, false},
|
{"ok-opts-type-user", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{CertType: "user"}, []provisioner.SignOption{userTemplate}}, want{CertType: ssh.UserCert}, false},
|
||||||
{"ok-opts-type-host", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "host"}, []provisioner.SignOption{hostTemplate}}, want{CertType: ssh.HostCert}, false},
|
{"ok-opts-type-host", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{CertType: "host"}, []provisioner.SignOption{hostTemplate}}, want{CertType: ssh.HostCert}, false},
|
||||||
{"ok-opts-principals", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "user", Principals: []string{"user"}}, []provisioner.SignOption{userTemplateWithUser}}, want{CertType: ssh.UserCert, Principals: []string{"user"}}, false},
|
{"ok-opts-principals", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{CertType: "user", Principals: []string{"user"}}, []provisioner.SignOption{userTemplateWithUser}}, want{CertType: ssh.UserCert, Principals: []string{"user"}}, false},
|
||||||
{"ok-opts-principals", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "host", Principals: []string{"foo.test.com", "bar.test.com"}}, []provisioner.SignOption{hostTemplateWithHosts}}, want{CertType: ssh.HostCert, Principals: []string{"foo.test.com", "bar.test.com"}}, false},
|
{"ok-opts-principals", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{CertType: "host", Principals: []string{"foo.test.com", "bar.test.com"}}, []provisioner.SignOption{hostTemplateWithHosts}}, want{CertType: ssh.HostCert, Principals: []string{"foo.test.com", "bar.test.com"}}, false},
|
||||||
{"ok-opts-valid-after", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "user", ValidAfter: provisioner.NewTimeDuration(now)}, []provisioner.SignOption{userTemplate}}, want{CertType: ssh.UserCert, ValidAfter: uint64(now.Unix())}, false},
|
{"ok-opts-valid-after", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{CertType: "user", ValidAfter: provisioner.NewTimeDuration(now)}, []provisioner.SignOption{userTemplate}}, want{CertType: ssh.UserCert, ValidAfter: uint64(now.Unix())}, false},
|
||||||
{"ok-opts-valid-before", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "host", ValidBefore: provisioner.NewTimeDuration(now)}, []provisioner.SignOption{hostTemplate}}, want{CertType: ssh.HostCert, ValidBefore: uint64(now.Unix())}, false},
|
{"ok-opts-valid-before", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{CertType: "host", ValidBefore: provisioner.NewTimeDuration(now)}, []provisioner.SignOption{hostTemplate}}, want{CertType: ssh.HostCert, ValidBefore: uint64(now.Unix())}, false},
|
||||||
{"ok-cert-validator", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestCertValidator("")}}, want{CertType: ssh.UserCert}, false},
|
{"ok-cert-validator", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestCertValidator("")}}, want{CertType: ssh.UserCert}, false},
|
||||||
{"ok-cert-modifier", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestCertModifier("")}}, want{CertType: ssh.UserCert}, false},
|
{"ok-cert-modifier", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestCertModifier("")}}, want{CertType: ssh.UserCert}, false},
|
||||||
{"ok-opts-validator", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestOptionsValidator("")}}, want{CertType: ssh.UserCert}, false},
|
{"ok-opts-validator", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestOptionsValidator("")}}, want{CertType: ssh.UserCert}, false},
|
||||||
{"ok-opts-modifier", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestOptionsModifier("")}}, want{CertType: ssh.UserCert}, false},
|
{"ok-opts-modifier", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestOptionsModifier("")}}, want{CertType: ssh.UserCert}, false},
|
||||||
{"ok-custom-template", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userCustomTemplate, userOptions}}, want{CertType: ssh.UserCert, Principals: []string{"user", "admin"}}, false},
|
{"ok-custom-template", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userCustomTemplate, userOptions}}, want{CertType: ssh.UserCert, Principals: []string{"user", "admin"}}, false},
|
||||||
{"fail-opts-type", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "foo"}, []provisioner.SignOption{userTemplate}}, want{}, true},
|
{"ok-user-policy", fields{signer, signer, userPolicy, nil}, args{pub, provisioner.SignSSHOptions{CertType: "user", Principals: []string{"user"}}, []provisioner.SignOption{userTemplateWithUser}}, want{CertType: ssh.UserCert, Principals: []string{"user"}}, false},
|
||||||
{"fail-cert-validator", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestCertValidator("an error")}}, want{}, true},
|
{"ok-host-policy", fields{signer, signer, nil, hostPolicy}, args{pub, provisioner.SignSSHOptions{CertType: "host", Principals: []string{"foo.test.com", "bar.test.com"}}, []provisioner.SignOption{hostTemplateWithHosts}}, want{CertType: ssh.HostCert, Principals: []string{"foo.test.com", "bar.test.com"}}, false},
|
||||||
{"fail-cert-modifier", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestCertModifier("an error")}}, want{}, true},
|
{"fail-opts-type", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{CertType: "foo"}, []provisioner.SignOption{userTemplate}}, want{}, true},
|
||||||
{"fail-opts-validator", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestOptionsValidator("an error")}}, want{}, true},
|
{"fail-cert-validator", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestCertValidator("an error")}}, want{}, true},
|
||||||
{"fail-opts-modifier", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestOptionsModifier("an error")}}, want{}, true},
|
{"fail-cert-modifier", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestCertModifier("an error")}}, want{}, true},
|
||||||
{"fail-bad-sign-options", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, "wrong type"}}, want{}, true},
|
{"fail-opts-validator", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestOptionsValidator("an error")}}, want{}, true},
|
||||||
{"fail-no-user-key", fields{nil, signer}, args{pub, provisioner.SignSSHOptions{CertType: "user"}, []provisioner.SignOption{userTemplate}}, want{}, true},
|
{"fail-opts-modifier", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, sshTestOptionsModifier("an error")}}, want{}, true},
|
||||||
{"fail-no-host-key", fields{signer, nil}, args{pub, provisioner.SignSSHOptions{CertType: "host"}, []provisioner.SignOption{hostTemplate}}, want{}, true},
|
{"fail-bad-sign-options", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions, "wrong type"}}, want{}, true},
|
||||||
{"fail-bad-type", fields{signer, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, sshTestModifier{CertType: 100}}}, want{}, true},
|
{"fail-no-user-key", fields{nil, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{CertType: "user"}, []provisioner.SignOption{userTemplate}}, want{}, true},
|
||||||
{"fail-custom-template", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userFailTemplate, userOptions}}, want{}, true},
|
{"fail-no-host-key", fields{signer, nil, nil, nil}, args{pub, provisioner.SignSSHOptions{CertType: "host"}, []provisioner.SignOption{hostTemplate}}, want{}, true},
|
||||||
{"fail-custom-template-syntax-error-file", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userJSONSyntaxErrorTemplateFile, userOptions}}, want{}, true},
|
{"fail-bad-type", fields{signer, nil, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, sshTestModifier{CertType: 100}}}, want{}, true},
|
||||||
{"fail-custom-template-syntax-value-file", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userJSONValueErrorTemplateFile, userOptions}}, want{}, true},
|
{"fail-custom-template", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userFailTemplate, userOptions}}, want{}, true},
|
||||||
|
{"fail-custom-template-syntax-error-file", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userJSONSyntaxErrorTemplateFile, userOptions}}, want{}, true},
|
||||||
|
{"fail-custom-template-syntax-value-file", fields{signer, signer, nil, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userJSONValueErrorTemplateFile, userOptions}}, want{}, true},
|
||||||
|
{"fail-user-policy", fields{signer, signer, userPolicy, nil}, args{pub, provisioner.SignSSHOptions{CertType: "user", Principals: []string{"root"}}, []provisioner.SignOption{userTemplateWithRoot}}, want{}, true},
|
||||||
|
{"fail-user-policy-with-host-cert", fields{signer, signer, userPolicy, nil}, args{pub, provisioner.SignSSHOptions{CertType: "host", Principals: []string{"foo.test.com"}}, []provisioner.SignOption{hostTemplateWithExampleDotCom}}, want{}, true},
|
||||||
|
{"fail-user-policy-with-bad-user", fields{signer, signer, userPolicy, nil}, args{pub, provisioner.SignSSHOptions{CertType: "user", Principals: []string{"user"}}, []provisioner.SignOption{badUserTemplate}}, want{}, true},
|
||||||
|
{"fail-host-policy", fields{signer, signer, nil, hostPolicy}, args{pub, provisioner.SignSSHOptions{CertType: "host", Principals: []string{"example.com"}}, []provisioner.SignOption{hostTemplateWithExampleDotCom}}, want{}, true},
|
||||||
|
{"fail-host-policy-with-user-cert", fields{signer, signer, nil, hostPolicy}, args{pub, provisioner.SignSSHOptions{CertType: "user", Principals: []string{"user"}}, []provisioner.SignOption{userTemplateWithUser}}, want{}, true},
|
||||||
|
{"fail-host-policy-with-bad-host", fields{signer, signer, nil, hostPolicy}, args{pub, provisioner.SignSSHOptions{CertType: "host", Principals: []string{"example.com"}}, []provisioner.SignOption{badHostTemplate}}, 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) {
|
||||||
a := testAuthority(t)
|
a := testAuthority(t)
|
||||||
a.sshCAUserCertSignKey = tt.fields.sshCAUserCertSignKey
|
a.sshCAUserCertSignKey = tt.fields.sshCAUserCertSignKey
|
||||||
a.sshCAHostCertSignKey = tt.fields.sshCAHostCertSignKey
|
a.sshCAHostCertSignKey = tt.fields.sshCAHostCertSignKey
|
||||||
|
a.sshUserPolicy = tt.fields.sshUserPolicy
|
||||||
|
a.sshHostPolicy = tt.fields.sshHostPolicy
|
||||||
|
|
||||||
got, err := a.SignSSH(context.Background(), tt.args.key, tt.args.opts, tt.args.signOpts...)
|
got, err := a.SignSSH(context.Background(), tt.args.key, tt.args.opts, tt.args.signOpts...)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
|
|
|
@ -16,16 +16,19 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
|
||||||
|
"go.step.sm/crypto/jose"
|
||||||
|
"go.step.sm/crypto/keyutil"
|
||||||
|
"go.step.sm/crypto/pemutil"
|
||||||
|
"go.step.sm/crypto/x509util"
|
||||||
|
|
||||||
"github.com/smallstep/certificates/authority/config"
|
"github.com/smallstep/certificates/authority/config"
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
casapi "github.com/smallstep/certificates/cas/apiv1"
|
casapi "github.com/smallstep/certificates/cas/apiv1"
|
||||||
"github.com/smallstep/certificates/db"
|
"github.com/smallstep/certificates/db"
|
||||||
"github.com/smallstep/certificates/errs"
|
"github.com/smallstep/certificates/errs"
|
||||||
"go.step.sm/crypto/jose"
|
"github.com/smallstep/certificates/policy"
|
||||||
"go.step.sm/crypto/keyutil"
|
|
||||||
"go.step.sm/crypto/pemutil"
|
|
||||||
"go.step.sm/crypto/x509util"
|
|
||||||
"golang.org/x/crypto/ssh"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetTLSOptions returns the tls options configured.
|
// GetTLSOptions returns the tls options configured.
|
||||||
|
@ -199,6 +202,13 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Sign
|
||||||
// Check if authority is allowed to sign the certificate
|
// Check if authority is allowed to sign the certificate
|
||||||
var allowedToSign bool
|
var allowedToSign bool
|
||||||
if allowedToSign, err = a.isAllowedToSign(leaf); err != nil {
|
if allowedToSign, err = a.isAllowedToSign(leaf); err != nil {
|
||||||
|
var pe *policy.NamePolicyError
|
||||||
|
if errors.As(err, &pe) && pe.Reason == policy.NotAuthorizedForThisName {
|
||||||
|
return nil, errs.ApplyOptions(
|
||||||
|
errs.ForbiddenErr(errors.New("authority not allowed to sign"), err.Error()),
|
||||||
|
opts...,
|
||||||
|
)
|
||||||
|
}
|
||||||
return nil, errs.InternalServerErr(err,
|
return nil, errs.InternalServerErr(err,
|
||||||
errs.WithKeyVal("csr", csr),
|
errs.WithKeyVal("csr", csr),
|
||||||
errs.WithKeyVal("signOptions", signOpts),
|
errs.WithKeyVal("signOptions", signOpts),
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
|
|
||||||
"github.com/smallstep/assert"
|
"github.com/smallstep/assert"
|
||||||
"github.com/smallstep/certificates/api/render"
|
"github.com/smallstep/certificates/api/render"
|
||||||
|
"github.com/smallstep/certificates/authority/policy"
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
"github.com/smallstep/certificates/cas/softcas"
|
"github.com/smallstep/certificates/cas/softcas"
|
||||||
"github.com/smallstep/certificates/db"
|
"github.com/smallstep/certificates/db"
|
||||||
|
@ -511,6 +512,37 @@ ZYtQ9Ot36qc=
|
||||||
code: http.StatusForbidden,
|
code: http.StatusForbidden,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fail with policy": func(t *testing.T) *signTest {
|
||||||
|
csr := getCSR(t, priv)
|
||||||
|
aa := testAuthority(t)
|
||||||
|
aa.config.AuthorityConfig.Template = a.config.AuthorityConfig.Template
|
||||||
|
aa.db = &db.MockAuthDB{
|
||||||
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
||||||
|
fmt.Println(crt.Subject)
|
||||||
|
assert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
policyOptions := &policy.X509PolicyOptions{
|
||||||
|
DeniedNames: &policy.X509NameOptions{
|
||||||
|
DNSDomains: []string{"test.smallstep.com"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
engine, err := policy.NewX509PolicyEngine(policyOptions)
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
aa.x509Policy = engine
|
||||||
|
return &signTest{
|
||||||
|
auth: aa,
|
||||||
|
csr: csr,
|
||||||
|
extraOpts: extraOpts,
|
||||||
|
signOpts: signOpts,
|
||||||
|
notBefore: signOpts.NotBefore.Time().Truncate(time.Second),
|
||||||
|
notAfter: signOpts.NotAfter.Time().Truncate(time.Second),
|
||||||
|
extensionsCount: 6,
|
||||||
|
err: errors.New("authority not allowed to sign"),
|
||||||
|
code: http.StatusForbidden,
|
||||||
|
}
|
||||||
|
},
|
||||||
"ok": func(t *testing.T) *signTest {
|
"ok": func(t *testing.T) *signTest {
|
||||||
csr := getCSR(t, priv)
|
csr := getCSR(t, priv)
|
||||||
_a := testAuthority(t)
|
_a := testAuthority(t)
|
||||||
|
@ -653,6 +685,36 @@ ZYtQ9Ot36qc=
|
||||||
extensionsCount: 7,
|
extensionsCount: 7,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ok with policy": func(t *testing.T) *signTest {
|
||||||
|
csr := getCSR(t, priv)
|
||||||
|
aa := testAuthority(t)
|
||||||
|
aa.config.AuthorityConfig.Template = a.config.AuthorityConfig.Template
|
||||||
|
aa.db = &db.MockAuthDB{
|
||||||
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
||||||
|
fmt.Println(crt.Subject)
|
||||||
|
assert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
policyOptions := &policy.X509PolicyOptions{
|
||||||
|
AllowedNames: &policy.X509NameOptions{
|
||||||
|
DNSDomains: []string{"*.smallstep.com"},
|
||||||
|
},
|
||||||
|
DisableSubjectCommonNameVerification: true, // allows "smallstep test"
|
||||||
|
}
|
||||||
|
engine, err := policy.NewX509PolicyEngine(policyOptions)
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
aa.x509Policy = engine
|
||||||
|
return &signTest{
|
||||||
|
auth: aa,
|
||||||
|
csr: csr,
|
||||||
|
extraOpts: extraOpts,
|
||||||
|
signOpts: signOpts,
|
||||||
|
notBefore: signOpts.NotBefore.Time().Truncate(time.Second),
|
||||||
|
notAfter: signOpts.NotAfter.Time().Truncate(time.Second),
|
||||||
|
extensionsCount: 6,
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, genTestCase := range tests {
|
for name, genTestCase := range tests {
|
||||||
|
|
Loading…
Reference in a new issue