Change provisioner options to have X509 as a field.

pull/312/head
Mariano Cano 4 years ago
parent a7b65f1e1e
commit 3e80f41c19

@ -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…
Cancel
Save