forked from TrueCloudLab/certificates
Add support for user data in templates.
This commit is contained in:
parent
a35988ff08
commit
91130b9c3f
5 changed files with 36 additions and 22 deletions
|
@ -514,7 +514,7 @@ type mockAuthority struct {
|
|||
getRoots func() ([]*x509.Certificate, error)
|
||||
getFederation func() ([]*x509.Certificate, error)
|
||||
getSSHKeys func() (*authority.SSHKeys, error)
|
||||
getSSHConfig func(typ string) ([]templates.Output, error)
|
||||
getSSHConfig func(typ string, data map[string]string) ([]templates.Output, error)
|
||||
}
|
||||
|
||||
// TODO: remove once Authorize is deprecated.
|
||||
|
@ -627,9 +627,9 @@ func (m *mockAuthority) GetSSHKeys() (*authority.SSHKeys, error) {
|
|||
return m.ret1.(*authority.SSHKeys), m.err
|
||||
}
|
||||
|
||||
func (m *mockAuthority) GetSSHConfig(typ string) ([]templates.Output, error) {
|
||||
func (m *mockAuthority) GetSSHConfig(typ string, data map[string]string) ([]templates.Output, error) {
|
||||
if m.getSSHConfig != nil {
|
||||
return m.getSSHConfig(typ)
|
||||
return m.getSSHConfig(typ, data)
|
||||
}
|
||||
return m.ret1.([]templates.Output), m.err
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ type SSHAuthority interface {
|
|||
SignSSH(key ssh.PublicKey, opts provisioner.SSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error)
|
||||
SignSSHAddUser(key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error)
|
||||
GetSSHKeys() (*authority.SSHKeys, error)
|
||||
GetSSHConfig(typ string) ([]templates.Output, error)
|
||||
GetSSHConfig(typ string, data map[string]string) ([]templates.Output, error)
|
||||
}
|
||||
|
||||
// SignSSHRequest is the request body of an SSH certificate request.
|
||||
|
@ -146,7 +146,8 @@ type Template = templates.Output
|
|||
// SSHConfigRequest is the request body used to get the SSH configuration
|
||||
// templates.
|
||||
type SSHConfigRequest struct {
|
||||
Type string `json:"type"`
|
||||
Type string `json:"type"`
|
||||
Data map[string]string `json:"data"`
|
||||
}
|
||||
|
||||
// Validate checks the values of the SSHConfigurationRequest.
|
||||
|
@ -272,7 +273,7 @@ func (h *caHandler) SSHConfig(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
ts, err := h.Authority.GetSSHConfig(body.Type)
|
||||
ts, err := h.Authority.GetSSHConfig(body.Type, body.Data)
|
||||
if err != nil {
|
||||
WriteError(w, InternalServerError(err))
|
||||
return
|
||||
|
|
|
@ -158,8 +158,8 @@ func (a *Authority) init() error {
|
|||
|
||||
// Configure protected template variables:
|
||||
if t := a.config.Templates; t != nil {
|
||||
if t.Variables == nil {
|
||||
t.Variables = make(map[string]interface{})
|
||||
if t.Data == nil {
|
||||
t.Data = make(map[string]interface{})
|
||||
}
|
||||
var vars templates.Step
|
||||
if a.config.SSH != nil {
|
||||
|
@ -170,7 +170,7 @@ func (a *Authority) init() error {
|
|||
vars.SSH.UserKey = a.sshCAUserCertSignKey.PublicKey()
|
||||
}
|
||||
}
|
||||
t.Variables["Step"] = vars
|
||||
t.Data["Step"] = vars
|
||||
}
|
||||
|
||||
// JWT numeric dates are seconds.
|
||||
|
|
|
@ -6,10 +6,9 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/smallstep/certificates/templates"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/smallstep/certificates/authority/provisioner"
|
||||
"github.com/smallstep/certificates/templates"
|
||||
"github.com/smallstep/cli/crypto/randutil"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
@ -51,7 +50,7 @@ func (a *Authority) GetSSHKeys() (*SSHKeys, error) {
|
|||
}
|
||||
|
||||
// GetSSHConfig returns rendered templates for clients (user) or servers (host).
|
||||
func (a *Authority) GetSSHConfig(typ string) ([]templates.Output, error) {
|
||||
func (a *Authority) GetSSHConfig(typ string, data map[string]string) ([]templates.Output, error) {
|
||||
if a.sshCAUserCertSignKey == nil && a.sshCAHostCertSignKey == nil {
|
||||
return nil, &apiError{
|
||||
err: errors.New("getSSHConfig: ssh is not configured"),
|
||||
|
@ -76,10 +75,23 @@ func (a *Authority) GetSSHConfig(typ string) ([]templates.Output, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Render templates.
|
||||
// Merge user and default data
|
||||
var mergedData map[string]interface{}
|
||||
|
||||
if len(data) == 0 {
|
||||
mergedData = a.config.Templates.Data
|
||||
} else {
|
||||
mergedData = make(map[string]interface{}, len(a.config.Templates.Data)+1)
|
||||
mergedData["User"] = data
|
||||
for k, v := range a.config.Templates.Data {
|
||||
mergedData[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// Render templates
|
||||
output := []templates.Output{}
|
||||
for _, t := range ts {
|
||||
o, err := t.Output(a.config.Templates.Variables)
|
||||
o, err := t.Output(mergedData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package templates
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"text/template"
|
||||
|
||||
|
@ -31,8 +30,8 @@ type Output struct {
|
|||
|
||||
// Templates is a collection of templates and variables.
|
||||
type Templates struct {
|
||||
SSH *SSHTemplates `json:"ssh,omitempty"`
|
||||
Variables map[string]interface{} `json:"variables,omitempty"`
|
||||
SSH *SSHTemplates `json:"ssh,omitempty"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// Validate returns an error if a template is not valid.
|
||||
|
@ -46,10 +45,13 @@ func (t *Templates) Validate() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// Do not allow "Step"
|
||||
if t.Variables != nil {
|
||||
if _, ok := t.Variables["Step"]; ok {
|
||||
return errors.New("templates variables cannot contain 'step' as a property")
|
||||
// Do not allow "Step" and "User"
|
||||
if t.Data != nil {
|
||||
if _, ok := t.Data["Step"]; ok {
|
||||
return errors.New("templates variables cannot contain 'Step' as a property")
|
||||
}
|
||||
if _, ok := t.Data["User"]; ok {
|
||||
return errors.New("templates variables cannot contain 'User' as a property")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -156,7 +158,6 @@ func (t *Template) Render(data interface{}) ([]byte, error) {
|
|||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
fmt.Println(data)
|
||||
if err := t.Execute(buf, data); err != nil {
|
||||
return nil, errors.Wrapf(err, "error executing %s", t.TemplatePath)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue