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
|
// Use the default template unless no-templates are configured and email is
|
||||||
// an admin, in that case we will use the CR template.
|
// an admin, in that case we will use the CR template.
|
||||||
defaultTemplate := x509util.DefaultLeafTemplate
|
defaultTemplate := x509util.DefaultLeafTemplate
|
||||||
if !o.Options.HasTemplate() && o.IsAdmin(claims.Email) {
|
if !o.Options.GetX509Options().HasTemplate() && o.IsAdmin(claims.Email) {
|
||||||
defaultTemplate = x509util.CertificateRequestTemplate
|
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
|
// Options are a collection of custom options that can be added to
|
||||||
// each provisioner.
|
// each provisioner.
|
||||||
type Options struct {
|
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
|
// 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"`
|
||||||
|
@ -37,7 +50,7 @@ type Options 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 *Options) HasTemplate() bool {
|
func (o *X509Options) HasTemplate() bool {
|
||||||
return o != nil && (o.Template != "" || o.TemplateFile != "")
|
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
|
// 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 *Options, data x509util.TemplateData, defaultTemplate string) (CertificateOptions, error) {
|
func CustomTemplateOptions(o *Options, data x509util.TemplateData, defaultTemplate string) (CertificateOptions, error) {
|
||||||
if o != nil {
|
opts := o.GetX509Options()
|
||||||
if data == nil {
|
if data == nil {
|
||||||
data = x509util.NewTemplateData()
|
data = x509util.NewTemplateData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts != nil {
|
||||||
// Add template data if any.
|
// Add template data if any.
|
||||||
if len(o.TemplateData) > 0 {
|
if len(opts.TemplateData) > 0 {
|
||||||
if err := json.Unmarshal(o.TemplateData, &data); err != nil {
|
if err := json.Unmarshal(opts.TemplateData, &data); err != nil {
|
||||||
return nil, errors.Wrap(err, "error unmarshaling template data")
|
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 {
|
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 !opts.HasTemplate() {
|
||||||
return []x509util.Option{
|
return []x509util.Option{
|
||||||
x509util.WithTemplate(defaultTemplate, data),
|
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.
|
// Load a template from a file if Template is not defined.
|
||||||
if o.Template == "" && o.TemplateFile != "" {
|
if opts.Template == "" && opts.TemplateFile != "" {
|
||||||
return []x509util.Option{
|
return []x509util.Option{
|
||||||
x509util.WithTemplateFile(o.TemplateFile, data),
|
x509util.WithTemplateFile(opts.TemplateFile, data),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load a template from the Template fields
|
// Load a template from the Template fields
|
||||||
// 1. As a JSON in a string.
|
// 1. As a JSON in a string.
|
||||||
template := strings.TrimSpace(o.Template)
|
template := strings.TrimSpace(opts.Template)
|
||||||
if strings.HasPrefix(template, "{") {
|
if strings.HasPrefix(template, "{") {
|
||||||
return []x509util.Option{
|
return []x509util.Option{
|
||||||
x509util.WithTemplate(template, data),
|
x509util.WithTemplate(template, data),
|
||||||
|
|
|
@ -24,7 +24,29 @@ func parseCertificateRequest(t *testing.T, filename string) *x509.CertificateReq
|
||||||
return csr
|
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 {
|
type fields struct {
|
||||||
Template string
|
Template string
|
||||||
TemplateFile string
|
TemplateFile string
|
||||||
|
@ -42,7 +64,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 := &Options{
|
o := &X509Options{
|
||||||
Template: tt.fields.Template,
|
Template: tt.fields.Template,
|
||||||
TemplateFile: tt.fields.TemplateFile,
|
TemplateFile: tt.fields.TemplateFile,
|
||||||
TemplateData: tt.fields.TemplateData,
|
TemplateData: tt.fields.TemplateData,
|
||||||
|
@ -81,14 +103,14 @@ func TestTemplateOptions(t *testing.T) {
|
||||||
"keyUsage": ["digitalSignature"],
|
"keyUsage": ["digitalSignature"],
|
||||||
"extKeyUsage": ["serverAuth", "clientAuth"]
|
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||||||
}`)}, false},
|
}`)}, false},
|
||||||
{"okCustomTemplate", args{&Options{Template: x509util.DefaultIIDLeafTemplate}, data}, x509util.Options{
|
{"okCustomTemplate", args{&Options{X509: &X509Options{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{&Options{TemplateData: []byte(`{"badJSON`)}, data}, x509util.Options{}, true},
|
{"fail", args{&Options{X509: &X509Options{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) {
|
||||||
|
@ -157,27 +179,27 @@ func TestCustomTemplateOptions(t *testing.T) {
|
||||||
"keyUsage": ["digitalSignature"],
|
"keyUsage": ["digitalSignature"],
|
||||||
"extKeyUsage": ["serverAuth", "clientAuth"]
|
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||||||
}`)}, false},
|
}`)}, 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(`{
|
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{&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},
|
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},
|
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},
|
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"}`),
|
CertBuffer: bytes.NewBufferString(`{"foo": "bar"}`),
|
||||||
}, false},
|
}, 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>"}`),
|
CertBuffer: bytes.NewBufferString(`{"foo": "<no value>"}`),
|
||||||
}, false},
|
}, false},
|
||||||
{"fail", 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{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 {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
|
@ -288,7 +288,7 @@ ZYtQ9Ot36qc=
|
||||||
t.Fatal("provisioner not found")
|
t.Fatal("provisioner not found")
|
||||||
}
|
}
|
||||||
p.(*provisioner.JWK).Options = &provisioner.Options{
|
p.(*provisioner.JWK).Options = &provisioner.Options{
|
||||||
Template: `{{ fail "fail message" }}`,
|
X509: &provisioner.X509Options{Template: `{{ fail "fail message" }}`},
|
||||||
}
|
}
|
||||||
testExtraOpts, err := testAuthority.Authorize(ctx, token)
|
testExtraOpts, err := testAuthority.Authorize(ctx, token)
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
|
@ -366,12 +366,12 @@ ZYtQ9Ot36qc=
|
||||||
t.Fatal("provisioner not found")
|
t.Fatal("provisioner not found")
|
||||||
}
|
}
|
||||||
p.(*provisioner.JWK).Options = &provisioner.Options{
|
p.(*provisioner.JWK).Options = &provisioner.Options{
|
||||||
Template: `{
|
X509: &provisioner.X509Options{Template: `{
|
||||||
"subject": {{toJson .Subject}},
|
"subject": {{toJson .Subject}},
|
||||||
"dnsNames": {{ toJson .Insecure.CR.DNSNames }},
|
"dnsNames": {{ toJson .Insecure.CR.DNSNames }},
|
||||||
"keyUsage": ["digitalSignature"],
|
"keyUsage": ["digitalSignature"],
|
||||||
"extKeyUsage": ["serverAuth","clientAuth"]
|
"extKeyUsage": ["serverAuth","clientAuth"]
|
||||||
}`,
|
}`},
|
||||||
}
|
}
|
||||||
testExtraOpts, err := testAuthority.Authorize(ctx, token)
|
testExtraOpts, err := testAuthority.Authorize(ctx, token)
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
|
|
Loading…
Reference in a new issue