Change provisioner options to have X509 as a field.
This commit is contained in:
parent
a7b65f1e1e
commit
3e80f41c19
4 changed files with 63 additions and 27 deletions
|
@ -325,7 +325,7 @@ func (o *OIDC) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e
|
|||
// Use the default template unless no-templates are configured and email is
|
||||
// an admin, in that case we will use the CR template.
|
||||
defaultTemplate := x509util.DefaultLeafTemplate
|
||||
if !o.Options.HasTemplate() && o.IsAdmin(claims.Email) {
|
||||
if !o.Options.GetX509Options().HasTemplate() && o.IsAdmin(claims.Email) {
|
||||
defaultTemplate = x509util.CertificateRequestTemplate
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,19 @@ func (fn certificateOptionsFunc) Options(so SignOptions) []x509util.Option {
|
|||
// Options are a collection of custom options that can be added to
|
||||
// each provisioner.
|
||||
type Options struct {
|
||||
X509 *X509Options `json:"x509,omitempty"`
|
||||
}
|
||||
|
||||
// GetX509Options returns the X.509Options
|
||||
func (o *Options) GetX509Options() *X509Options {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
return o.X509
|
||||
}
|
||||
|
||||
// X509Options contains specific options for X.509 certificates.
|
||||
type X509Options struct {
|
||||
// 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.
|
||||
Template string `json:"template"`
|
||||
|
@ -37,7 +50,7 @@ type Options struct {
|
|||
}
|
||||
|
||||
// HasTemplate returns true if a template is defined in the provisioner options.
|
||||
func (o *Options) HasTemplate() bool {
|
||||
func (o *X509Options) HasTemplate() bool {
|
||||
return o != nil && (o.Template != "" || o.TemplateFile != "")
|
||||
}
|
||||
|
||||
|
@ -54,14 +67,15 @@ func TemplateOptions(o *Options, data x509util.TemplateData) (CertificateOptions
|
|||
// user data provided in the request. If no template has been provided in the
|
||||
// ProvisionerOptions, the given template will be used.
|
||||
func CustomTemplateOptions(o *Options, data x509util.TemplateData, defaultTemplate string) (CertificateOptions, error) {
|
||||
if o != nil {
|
||||
if data == nil {
|
||||
data = x509util.NewTemplateData()
|
||||
}
|
||||
opts := o.GetX509Options()
|
||||
if data == nil {
|
||||
data = x509util.NewTemplateData()
|
||||
}
|
||||
|
||||
if opts != nil {
|
||||
// Add template data if any.
|
||||
if len(o.TemplateData) > 0 {
|
||||
if err := json.Unmarshal(o.TemplateData, &data); err != nil {
|
||||
if len(opts.TemplateData) > 0 {
|
||||
if err := json.Unmarshal(opts.TemplateData, &data); err != nil {
|
||||
return nil, errors.Wrap(err, "error unmarshaling template data")
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +83,7 @@ func CustomTemplateOptions(o *Options, data x509util.TemplateData, defaultTempla
|
|||
|
||||
return certificateOptionsFunc(func(so SignOptions) []x509util.Option {
|
||||
// We're not provided user data without custom templates.
|
||||
if !o.HasTemplate() {
|
||||
if !opts.HasTemplate() {
|
||||
return []x509util.Option{
|
||||
x509util.WithTemplate(defaultTemplate, data),
|
||||
}
|
||||
|
@ -86,15 +100,15 @@ func CustomTemplateOptions(o *Options, data x509util.TemplateData, defaultTempla
|
|||
}
|
||||
|
||||
// Load a template from a file if Template is not defined.
|
||||
if o.Template == "" && o.TemplateFile != "" {
|
||||
if opts.Template == "" && opts.TemplateFile != "" {
|
||||
return []x509util.Option{
|
||||
x509util.WithTemplateFile(o.TemplateFile, data),
|
||||
x509util.WithTemplateFile(opts.TemplateFile, data),
|
||||
}
|
||||
}
|
||||
|
||||
// Load a template from the Template fields
|
||||
// 1. As a JSON in a string.
|
||||
template := strings.TrimSpace(o.Template)
|
||||
template := strings.TrimSpace(opts.Template)
|
||||
if strings.HasPrefix(template, "{") {
|
||||
return []x509util.Option{
|
||||
x509util.WithTemplate(template, data),
|
||||
|
|
|
@ -24,7 +24,29 @@ func parseCertificateRequest(t *testing.T, filename string) *x509.CertificateReq
|
|||
return csr
|
||||
}
|
||||
|
||||
func TestProvisionerOptions_HasTemplate(t *testing.T) {
|
||||
func TestOptions_GetX509Options(t *testing.T) {
|
||||
type fields struct {
|
||||
o *Options
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want *X509Options
|
||||
}{
|
||||
{"ok", fields{&Options{X509: &X509Options{Template: "foo"}}}, &X509Options{Template: "foo"}},
|
||||
{"nil", fields{&Options{}}, nil},
|
||||
{"nilOptions", fields{nil}, nil},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.fields.o.GetX509Options(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Options.GetX509Options() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvisionerX509Options_HasTemplate(t *testing.T) {
|
||||
type fields struct {
|
||||
Template string
|
||||
TemplateFile string
|
||||
|
@ -42,7 +64,7 @@ func TestProvisionerOptions_HasTemplate(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := &Options{
|
||||
o := &X509Options{
|
||||
Template: tt.fields.Template,
|
||||
TemplateFile: tt.fields.TemplateFile,
|
||||
TemplateData: tt.fields.TemplateData,
|
||||
|
@ -81,14 +103,14 @@ func TestTemplateOptions(t *testing.T) {
|
|||
"keyUsage": ["digitalSignature"],
|
||||
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||||
}`)}, false},
|
||||
{"okCustomTemplate", args{&Options{Template: x509util.DefaultIIDLeafTemplate}, data}, x509util.Options{
|
||||
{"okCustomTemplate", args{&Options{X509: &X509Options{Template: x509util.DefaultIIDLeafTemplate}}, data}, x509util.Options{
|
||||
CertBuffer: bytes.NewBufferString(`{
|
||||
"subject": {"commonName":"foo"},
|
||||
"sans": [{"type":"dns","value":"foo.com"}],
|
||||
"keyUsage": ["digitalSignature"],
|
||||
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||||
}`)}, false},
|
||||
{"fail", args{&Options{TemplateData: []byte(`{"badJSON`)}, data}, x509util.Options{}, true},
|
||||
{"fail", args{&Options{X509: &X509Options{TemplateData: []byte(`{"badJSON`)}}, data}, x509util.Options{}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -157,27 +179,27 @@ func TestCustomTemplateOptions(t *testing.T) {
|
|||
"keyUsage": ["digitalSignature"],
|
||||
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||||
}`)}, false},
|
||||
{"okTemplateData", args{&Options{TemplateData: []byte(`{"foo":"bar"}`)}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
|
||||
{"okTemplateData", args{&Options{X509: &X509Options{TemplateData: []byte(`{"foo":"bar"}`)}}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
|
||||
CertBuffer: bytes.NewBufferString(`{
|
||||
"subject": {"commonName":"foobar"},
|
||||
"sans": [{"type":"dns","value":"foo.com"}],
|
||||
"keyUsage": ["digitalSignature"],
|
||||
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||||
}`)}, false},
|
||||
{"okTemplate", args{&Options{Template: "{{ toJson .Insecure.CR }}"}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
|
||||
{"okTemplate", args{&Options{X509: &X509Options{Template: "{{ toJson .Insecure.CR }}"}}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
|
||||
CertBuffer: bytes.NewBufferString(csrCertificate)}, false},
|
||||
{"okFile", args{&Options{TemplateFile: "./testdata/templates/cr.tpl"}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
|
||||
{"okFile", args{&Options{X509: &X509Options{TemplateFile: "./testdata/templates/cr.tpl"}}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
|
||||
CertBuffer: bytes.NewBufferString(csrCertificate)}, false},
|
||||
{"okBase64", args{&Options{Template: "e3sgdG9Kc29uIC5JbnNlY3VyZS5DUiB9fQ=="}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
|
||||
{"okBase64", args{&Options{X509: &X509Options{Template: "e3sgdG9Kc29uIC5JbnNlY3VyZS5DUiB9fQ=="}}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{
|
||||
CertBuffer: bytes.NewBufferString(csrCertificate)}, false},
|
||||
{"okUserOptions", args{&Options{Template: `{"foo": "{{.Insecure.User.foo}}"}`}, data, x509util.DefaultLeafTemplate, SignOptions{TemplateData: []byte(`{"foo":"bar"}`)}}, x509util.Options{
|
||||
{"okUserOptions", args{&Options{X509: &X509Options{Template: `{"foo": "{{.Insecure.User.foo}}"}`}}, data, x509util.DefaultLeafTemplate, SignOptions{TemplateData: []byte(`{"foo":"bar"}`)}}, x509util.Options{
|
||||
CertBuffer: bytes.NewBufferString(`{"foo": "bar"}`),
|
||||
}, false},
|
||||
{"okBadUserOptions", args{&Options{Template: `{"foo": "{{.Insecure.User.foo}}"}`}, data, x509util.DefaultLeafTemplate, SignOptions{TemplateData: []byte(`{"badJSON"}`)}}, x509util.Options{
|
||||
{"okBadUserOptions", args{&Options{X509: &X509Options{Template: `{"foo": "{{.Insecure.User.foo}}"}`}}, data, x509util.DefaultLeafTemplate, SignOptions{TemplateData: []byte(`{"badJSON"}`)}}, x509util.Options{
|
||||
CertBuffer: bytes.NewBufferString(`{"foo": "<no value>"}`),
|
||||
}, false},
|
||||
{"fail", args{&Options{TemplateData: []byte(`{"badJSON`)}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{}, true},
|
||||
{"failTemplateData", args{&Options{TemplateData: []byte(`{"badJSON}`)}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{}, true},
|
||||
{"fail", args{&Options{X509: &X509Options{TemplateData: []byte(`{"badJSON`)}}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{}, true},
|
||||
{"failTemplateData", args{&Options{X509: &X509Options{TemplateData: []byte(`{"badJSON}`)}}, data, x509util.DefaultLeafTemplate, SignOptions{}}, x509util.Options{}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
@ -288,7 +288,7 @@ ZYtQ9Ot36qc=
|
|||
t.Fatal("provisioner not found")
|
||||
}
|
||||
p.(*provisioner.JWK).Options = &provisioner.Options{
|
||||
Template: `{{ fail "fail message" }}`,
|
||||
X509: &provisioner.X509Options{Template: `{{ fail "fail message" }}`},
|
||||
}
|
||||
testExtraOpts, err := testAuthority.Authorize(ctx, token)
|
||||
assert.FatalError(t, err)
|
||||
|
@ -366,12 +366,12 @@ ZYtQ9Ot36qc=
|
|||
t.Fatal("provisioner not found")
|
||||
}
|
||||
p.(*provisioner.JWK).Options = &provisioner.Options{
|
||||
Template: `{
|
||||
X509: &provisioner.X509Options{Template: `{
|
||||
"subject": {{toJson .Subject}},
|
||||
"dnsNames": {{ toJson .Insecure.CR.DNSNames }},
|
||||
"keyUsage": ["digitalSignature"],
|
||||
"extKeyUsage": ["serverAuth","clientAuth"]
|
||||
}`,
|
||||
}`},
|
||||
}
|
||||
testExtraOpts, err := testAuthority.Authorize(ctx, token)
|
||||
assert.FatalError(t, err)
|
||||
|
|
Loading…
Reference in a new issue