This commit is contained in:
max furman 2021-05-20 16:02:20 -07:00
parent 5929244fda
commit d8d5d7332b
3 changed files with 102 additions and 56 deletions

View file

@ -32,20 +32,20 @@ func NewHandler(auth *authority.Authority) api.RouterHandler {
// Route traffic and implement the Router interface. // Route traffic and implement the Router interface.
func (h *Handler) Route(r api.Router) { func (h *Handler) Route(r api.Router) {
// Provisioners // Provisioners
r.MethodFunc("GET", "/provisioner/{name}", h.GetProvisioner) r.MethodFunc("GET", "/provisioners/{name}", h.GetProvisioner)
r.MethodFunc("GET", "/provisioners", h.GetProvisioners) r.MethodFunc("GET", "/provisioners", h.GetProvisioners)
r.MethodFunc("POST", "/provisioner", h.CreateProvisioner) r.MethodFunc("POST", "/provisioners", h.CreateProvisioner)
r.MethodFunc("PUT", "/provisioner/{name}", h.UpdateProvisioner) r.MethodFunc("PUT", "/provisioners/{name}", h.UpdateProvisioner)
r.MethodFunc("DELETE", "/provisioner/{name}", h.DeleteProvisioner) r.MethodFunc("DELETE", "/provisioners/{name}", h.DeleteProvisioner)
// Admins // Admins
r.MethodFunc("GET", "/admin/{id}", h.GetAdmin) r.MethodFunc("GET", "/admins/{id}", h.GetAdmin)
r.MethodFunc("GET", "/admins", h.GetAdmins) r.MethodFunc("GET", "/admins", h.GetAdmins)
r.MethodFunc("POST", "/admin", h.CreateAdmin) r.MethodFunc("POST", "/admins", h.CreateAdmin)
r.MethodFunc("PATCH", "/admin/{id}", h.UpdateAdmin) r.MethodFunc("PATCH", "/admins/{id}", h.UpdateAdmin)
r.MethodFunc("DELETE", "/admin/{id}", h.DeleteAdmin) r.MethodFunc("DELETE", "/admins/{id}", h.DeleteAdmin)
// AuthConfig // AuthConfig
r.MethodFunc("GET", "/authconfig/{id}", h.GetAuthConfig) r.MethodFunc("GET", "/authconfigs/{id}", h.GetAuthConfig)
r.MethodFunc("PUT", "/authconfig/{id}", h.UpdateAuthConfig) r.MethodFunc("PUT", "/authconfigs/{id}", h.UpdateAuthConfig)
} }

View file

@ -58,6 +58,20 @@ func WithPassword(pass string) func(*ProvisionerCtx) {
} }
} }
type unmarshalProvisioner struct {
ID string `json:"-"`
AuthorityID string `json:"-"`
Type string `json:"type"`
Name string `json:"name"`
Claims *Claims `json:"claims"`
Details json.RawMessage `json:"details"`
X509Template string `json:"x509Template"`
X509TemplateData []byte `json:"x509TemplateData"`
SSHTemplate string `json:"sshTemplate"`
SSHTemplateData []byte `json:"sshTemplateData"`
Status status.Type `json:"status"`
}
// Provisioner type. // Provisioner type.
type Provisioner struct { type Provisioner struct {
ID string `json:"-"` ID string `json:"-"`
@ -73,6 +87,38 @@ type Provisioner struct {
Status status.Type `json:"status"` Status status.Type `json:"status"`
} }
type typ struct {
Type ProvisionerType `json:"type"`
}
// UnmarshalJSON implements the Unmarshal interface.
func (p *Provisioner) UnmarshalJSON(b []byte) error {
var (
err error
up = new(unmarshalProvisioner)
)
if err = json.Unmarshal(b, up); err != nil {
return WrapErrorISE(err, "error unmarshaling provisioner to intermediate type")
}
p.Details, err = UnmarshalProvisionerDetails(up.Details)
if err = json.Unmarshal(b, up); err != nil {
return WrapErrorISE(err, "error unmarshaling provisioner details")
}
p.ID = up.ID
p.AuthorityID = up.AuthorityID
p.Type = up.Type
p.Name = up.Name
p.Claims = up.Claims
p.X509Template = up.X509Template
p.X509TemplateData = up.X509TemplateData
p.SSHTemplate = up.SSHTemplate
p.SSHTemplateData = up.SSHTemplateData
p.Status = up.Status
return nil
}
func (p *Provisioner) GetOptions() *provisioner.Options { func (p *Provisioner) GetOptions() *provisioner.Options {
return &provisioner.Options{ return &provisioner.Options{
X509: &provisioner.X509Options{ X509: &provisioner.X509Options{
@ -415,7 +461,7 @@ type detailsType struct {
Type ProvisionerType Type ProvisionerType
} }
func UnmarshalProvisionerDetails(data []byte) (ProvisionerDetails, error) { func UnmarshalProvisionerDetails(data json.RawMessage) (ProvisionerDetails, error) {
dt := new(detailsType) dt := new(detailsType)
if err := json.Unmarshal(data, dt); err != nil { if err := json.Unmarshal(data, dt); err != nil {
return nil, WrapErrorISE(err, "error unmarshaling provisioner details") return nil, WrapErrorISE(err, "error unmarshaling provisioner details")

View file

@ -16,16 +16,16 @@ import (
"github.com/smallstep/certificates/errs" "github.com/smallstep/certificates/errs"
) )
// MgmtClient implements an HTTP client for the CA server. // AdminClient implements an HTTP client for the CA server.
type MgmtClient struct { type AdminClient struct {
client *uaClient client *uaClient
endpoint *url.URL endpoint *url.URL
retryFunc RetryFunc retryFunc RetryFunc
opts []ClientOption opts []ClientOption
} }
// NewMgmtClient creates a new MgmtClient with the given endpoint and options. // NewAdminClient creates a new AdminClient with the given endpoint and options.
func NewMgmtClient(endpoint string, opts ...ClientOption) (*MgmtClient, error) { func NewAdminClient(endpoint string, opts ...ClientOption) (*AdminClient, error) {
u, err := parseEndpoint(endpoint) u, err := parseEndpoint(endpoint)
if err != nil { if err != nil {
return nil, err return nil, err
@ -40,7 +40,7 @@ func NewMgmtClient(endpoint string, opts ...ClientOption) (*MgmtClient, error) {
return nil, err return nil, err
} }
return &MgmtClient{ return &AdminClient{
client: newClient(tr), client: newClient(tr),
endpoint: u, endpoint: u,
retryFunc: o.retryFunc, retryFunc: o.retryFunc,
@ -48,7 +48,7 @@ func NewMgmtClient(endpoint string, opts ...ClientOption) (*MgmtClient, error) {
}, nil }, nil
} }
func (c *MgmtClient) retryOnError(r *http.Response) bool { func (c *AdminClient) retryOnError(r *http.Response) bool {
if c.retryFunc != nil { if c.retryFunc != nil {
if c.retryFunc(r.StatusCode) { if c.retryFunc(r.StatusCode) {
o := new(clientOptions) o := new(clientOptions)
@ -67,10 +67,10 @@ func (c *MgmtClient) retryOnError(r *http.Response) bool {
return false return false
} }
// GetAdmin performs the GET /mgmt/admin/{id} request to the CA. // GetAdmin performs the GET /admin/admin/{id} request to the CA.
func (c *MgmtClient) GetAdmin(id string) (*mgmt.Admin, error) { func (c *AdminClient) GetAdmin(id string) (*mgmt.Admin, error) {
var retried bool var retried bool
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/mgmt/admin", id)}) u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/admin", id)})
retry: retry:
resp, err := c.client.Get(u.String()) resp, err := c.client.Get(u.String())
if err != nil { if err != nil {
@ -81,7 +81,7 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return nil, readMgmtError(resp.Body) return nil, readAdminError(resp.Body)
} }
var adm = new(mgmt.Admin) var adm = new(mgmt.Admin)
if err := readJSON(resp.Body, adm); err != nil { if err := readJSON(resp.Body, adm); err != nil {
@ -135,7 +135,7 @@ func WithAdminLimit(limit int) AdminOption {
} }
// GetAdmins performs the GET /admin/admins request to the CA. // GetAdmins performs the GET /admin/admins request to the CA.
func (c *MgmtClient) GetAdmins(opts ...AdminOption) (*mgmtAPI.GetAdminsResponse, error) { func (c *AdminClient) GetAdmins(opts ...AdminOption) (*mgmtAPI.GetAdminsResponse, error) {
var retried bool var retried bool
o := new(adminOptions) o := new(adminOptions)
if err := o.apply(opts); err != nil { if err := o.apply(opts); err != nil {
@ -155,7 +155,7 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return nil, readMgmtError(resp.Body) return nil, readAdminError(resp.Body)
} }
var body = new(mgmtAPI.GetAdminsResponse) var body = new(mgmtAPI.GetAdminsResponse)
if err := readJSON(resp.Body, body); err != nil { if err := readJSON(resp.Body, body); err != nil {
@ -164,14 +164,14 @@ retry:
return body, nil return body, nil
} }
// CreateAdmin performs the POST /admin/admin request to the CA. // CreateAdmin performs the POST /admin/admins request to the CA.
func (c *MgmtClient) CreateAdmin(req *mgmtAPI.CreateAdminRequest) (*mgmt.Admin, error) { func (c *AdminClient) CreateAdmin(req *mgmtAPI.CreateAdminRequest) (*mgmt.Admin, error) {
var retried bool var retried bool
body, err := json.Marshal(req) body, err := json.Marshal(req)
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request") return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request")
} }
u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/admin"}) u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/admins"})
retry: retry:
resp, err := c.client.Post(u.String(), "application/json", bytes.NewReader(body)) resp, err := c.client.Post(u.String(), "application/json", bytes.NewReader(body))
if err != nil { if err != nil {
@ -182,7 +182,7 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return nil, readMgmtError(resp.Body) return nil, readAdminError(resp.Body)
} }
var adm = new(mgmt.Admin) var adm = new(mgmt.Admin)
if err := readJSON(resp.Body, adm); err != nil { if err := readJSON(resp.Body, adm); err != nil {
@ -191,10 +191,10 @@ retry:
return adm, nil return adm, nil
} }
// RemoveAdmin performs the DELETE /admin/admin/{id} request to the CA. // RemoveAdmin performs the DELETE /admin/admins/{id} request to the CA.
func (c *MgmtClient) RemoveAdmin(id string) error { func (c *AdminClient) RemoveAdmin(id string) error {
var retried bool var retried bool
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/admin", id)}) u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/admins", id)})
req, err := http.NewRequest("DELETE", u.String(), nil) req, err := http.NewRequest("DELETE", u.String(), nil)
if err != nil { if err != nil {
return errors.Wrapf(err, "create DELETE %s request failed", u) return errors.Wrapf(err, "create DELETE %s request failed", u)
@ -209,19 +209,19 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return readMgmtError(resp.Body) return readAdminError(resp.Body)
} }
return nil return nil
} }
// UpdateAdmin performs the PUT /admin/admin/{id} request to the CA. // UpdateAdmin performs the PUT /admin/admins/{id} request to the CA.
func (c *MgmtClient) UpdateAdmin(id string, uar *mgmtAPI.UpdateAdminRequest) (*admin.Admin, error) { func (c *AdminClient) UpdateAdmin(id string, uar *mgmtAPI.UpdateAdminRequest) (*admin.Admin, error) {
var retried bool var retried bool
body, err := json.Marshal(uar) body, err := json.Marshal(uar)
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request") return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request")
} }
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/admin", id)}) u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/admins", id)})
req, err := http.NewRequest("PATCH", u.String(), bytes.NewReader(body)) req, err := http.NewRequest("PATCH", u.String(), bytes.NewReader(body))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "create PUT %s request failed", u) return nil, errors.Wrapf(err, "create PUT %s request failed", u)
@ -236,7 +236,7 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return nil, readMgmtError(resp.Body) return nil, readAdminError(resp.Body)
} }
var adm = new(admin.Admin) var adm = new(admin.Admin)
if err := readJSON(resp.Body, adm); err != nil { if err := readJSON(resp.Body, adm); err != nil {
@ -245,10 +245,10 @@ retry:
return adm, nil return adm, nil
} }
// GetProvisioner performs the GET /admin/provisioner/{name} request to the CA. // GetProvisioner performs the GET /admin/provisioners/{name} request to the CA.
func (c *MgmtClient) GetProvisioner(name string) (*mgmt.Provisioner, error) { func (c *AdminClient) GetProvisioner(name string) (*mgmt.Provisioner, error) {
var retried bool var retried bool
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioner", name)}) u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioners", name)})
retry: retry:
resp, err := c.client.Get(u.String()) resp, err := c.client.Get(u.String())
if err != nil { if err != nil {
@ -259,7 +259,7 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return nil, readMgmtError(resp.Body) return nil, readAdminError(resp.Body)
} }
var prov = new(mgmt.Provisioner) var prov = new(mgmt.Provisioner)
if err := readJSON(resp.Body, prov); err != nil { if err := readJSON(resp.Body, prov); err != nil {
@ -269,7 +269,7 @@ retry:
} }
// GetProvisioners performs the GET /admin/provisioners request to the CA. // GetProvisioners performs the GET /admin/provisioners request to the CA.
func (c *MgmtClient) GetProvisioners() ([]*mgmt.Provisioner, error) { func (c *AdminClient) GetProvisioners() ([]*mgmt.Provisioner, error) {
var retried bool var retried bool
u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/provisioners"}) u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/provisioners"})
retry: retry:
@ -282,7 +282,7 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return nil, readMgmtError(resp.Body) return nil, readAdminError(resp.Body)
} }
var provs = new([]*mgmt.Provisioner) var provs = new([]*mgmt.Provisioner)
if err := readJSON(resp.Body, provs); err != nil { if err := readJSON(resp.Body, provs); err != nil {
@ -291,10 +291,10 @@ retry:
return *provs, nil return *provs, nil
} }
// RemoveProvisioner performs the DELETE /admin/provisioner/{name} request to the CA. // RemoveProvisioner performs the DELETE /admin/provisioners/{name} request to the CA.
func (c *MgmtClient) RemoveProvisioner(name string) error { func (c *AdminClient) RemoveProvisioner(name string) error {
var retried bool var retried bool
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioner", name)}) u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioners", name)})
req, err := http.NewRequest("DELETE", u.String(), nil) req, err := http.NewRequest("DELETE", u.String(), nil)
if err != nil { if err != nil {
return errors.Wrapf(err, "create DELETE %s request failed", u) return errors.Wrapf(err, "create DELETE %s request failed", u)
@ -309,19 +309,19 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return readMgmtError(resp.Body) return readAdminError(resp.Body)
} }
return nil return nil
} }
// CreateProvisioner performs the POST /admin/provisioner request to the CA. // CreateProvisioner performs the POST /admin/provisioners request to the CA.
func (c *MgmtClient) CreateProvisioner(req *mgmtAPI.CreateProvisionerRequest) (*mgmt.Provisioner, error) { func (c *AdminClient) CreateProvisioner(req *mgmtAPI.CreateProvisionerRequest) (*mgmt.Provisioner, error) {
var retried bool var retried bool
body, err := json.Marshal(req) body, err := json.Marshal(req)
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request") return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request")
} }
u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/provisioner"}) u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/provisioners"})
retry: retry:
resp, err := c.client.Post(u.String(), "application/json", bytes.NewReader(body)) resp, err := c.client.Post(u.String(), "application/json", bytes.NewReader(body))
if err != nil { if err != nil {
@ -332,7 +332,7 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return nil, readMgmtError(resp.Body) return nil, readAdminError(resp.Body)
} }
var prov = new(mgmt.Provisioner) var prov = new(mgmt.Provisioner)
if err := readJSON(resp.Body, prov); err != nil { if err := readJSON(resp.Body, prov); err != nil {
@ -341,14 +341,14 @@ retry:
return prov, nil return prov, nil
} }
// UpdateProvisioner performs the PUT /admin/provisioner/{id} request to the CA. // UpdateProvisioner performs the PUT /admin/provisioners/{id} request to the CA.
func (c *MgmtClient) UpdateProvisioner(id string, upr *mgmtAPI.UpdateProvisionerRequest) (*mgmt.Provisioner, error) { func (c *AdminClient) UpdateProvisioner(id string, upr *mgmtAPI.UpdateProvisionerRequest) (*mgmt.Provisioner, error) {
var retried bool var retried bool
body, err := json.Marshal(upr) body, err := json.Marshal(upr)
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request") return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request")
} }
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioner", id)}) u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioners", id)})
req, err := http.NewRequest("PUT", u.String(), bytes.NewReader(body)) req, err := http.NewRequest("PUT", u.String(), bytes.NewReader(body))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "create PUT %s request failed", u) return nil, errors.Wrapf(err, "create PUT %s request failed", u)
@ -363,7 +363,7 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return nil, readMgmtError(resp.Body) return nil, readAdminError(resp.Body)
} }
var prov = new(mgmt.Provisioner) var prov = new(mgmt.Provisioner)
if err := readJSON(resp.Body, prov); err != nil { if err := readJSON(resp.Body, prov); err != nil {
@ -373,7 +373,7 @@ retry:
} }
// GetAuthConfig performs the GET /admin/authconfig/{id} request to the CA. // GetAuthConfig performs the GET /admin/authconfig/{id} request to the CA.
func (c *MgmtClient) GetAuthConfig(id string) (*mgmt.AuthConfig, error) { func (c *AdminClient) GetAuthConfig(id string) (*mgmt.AuthConfig, error) {
var retried bool var retried bool
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/authconfig", id)}) u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/authconfig", id)})
retry: retry:
@ -386,7 +386,7 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return nil, readMgmtError(resp.Body) return nil, readAdminError(resp.Body)
} }
var ac = new(mgmt.AuthConfig) var ac = new(mgmt.AuthConfig)
if err := readJSON(resp.Body, ac); err != nil { if err := readJSON(resp.Body, ac); err != nil {
@ -395,7 +395,7 @@ retry:
return ac, nil return ac, nil
} }
func readMgmtError(r io.ReadCloser) error { func readAdminError(r io.ReadCloser) error {
defer r.Close() defer r.Close()
mgmtErr := new(mgmt.Error) mgmtErr := new(mgmt.Error)
if err := json.NewDecoder(r).Decode(mgmtErr); err != nil { if err := json.NewDecoder(r).Decode(mgmtErr); err != nil {