certificates/authority/mgmt/api/provisioner.go

212 lines
6.1 KiB
Go
Raw Normal View History

2021-05-03 19:48:20 +00:00
package api
import (
2021-05-11 22:25:37 +00:00
"fmt"
2021-05-03 19:48:20 +00:00
"net/http"
"github.com/go-chi/chi"
"github.com/smallstep/certificates/api"
2021-05-07 00:03:12 +00:00
"github.com/smallstep/certificates/authority/mgmt"
2021-05-18 04:07:25 +00:00
"github.com/smallstep/certificates/authority/provisioner"
2021-05-18 23:50:54 +00:00
"github.com/smallstep/certificates/authority/status"
2021-05-20 20:01:58 +00:00
"github.com/smallstep/certificates/errs"
2021-05-03 19:48:20 +00:00
)
// CreateProvisionerRequest represents the body for a CreateProvisioner request.
type CreateProvisionerRequest struct {
2021-05-11 22:25:37 +00:00
Type string `json:"type"`
Name string `json:"name"`
Claims *mgmt.Claims `json:"claims"`
2021-05-18 04:07:25 +00:00
Details []byte `json:"details"`
2021-05-11 22:25:37 +00:00
X509Template string `json:"x509Template"`
X509TemplateData []byte `json:"x509TemplateData"`
SSHTemplate string `json:"sshTemplate"`
SSHTemplateData []byte `json:"sshTemplateData"`
2021-05-03 19:48:20 +00:00
}
// Validate validates a new-provisioner request body.
2021-05-18 04:07:25 +00:00
func (cpr *CreateProvisionerRequest) Validate(c *provisioner.Collection) error {
if _, ok := c.LoadByName(cpr.Name); ok {
return mgmt.NewError(mgmt.ErrorBadRequestType, "provisioner with name %s already exists", cpr.Name)
}
2021-05-03 19:48:20 +00:00
return nil
}
2021-05-20 20:01:58 +00:00
// GetProvisionersResponse is the type for GET /admin/provisioners responses.
type GetProvisionersResponse struct {
Provisioners provisioner.List `json:"provisioners"`
NextCursor string `json:"nextCursor"`
}
2021-05-03 19:48:20 +00:00
// UpdateProvisionerRequest represents the body for a UpdateProvisioner request.
type UpdateProvisionerRequest struct {
2021-05-18 04:07:25 +00:00
Type string `json:"type"`
Name string `json:"name"`
2021-05-11 22:25:37 +00:00
Claims *mgmt.Claims `json:"claims"`
2021-05-18 04:07:25 +00:00
Details []byte `json:"details"`
2021-05-11 22:25:37 +00:00
X509Template string `json:"x509Template"`
X509TemplateData []byte `json:"x509TemplateData"`
SSHTemplate string `json:"sshTemplate"`
SSHTemplateData []byte `json:"sshTemplateData"`
2021-05-03 19:48:20 +00:00
}
2021-05-18 04:07:25 +00:00
// Validate validates a update-provisioner request body.
func (upr *UpdateProvisionerRequest) Validate(c *provisioner.Collection) error {
if _, ok := c.LoadByName(upr.Name); ok {
return mgmt.NewError(mgmt.ErrorBadRequestType, "provisioner with name %s already exists", upr.Name)
}
2021-05-03 19:48:20 +00:00
return nil
}
// GetProvisioner returns the requested provisioner, or an error.
func (h *Handler) GetProvisioner(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
2021-05-18 04:07:25 +00:00
name := chi.URLParam(r, "name")
2021-05-03 19:48:20 +00:00
2021-05-18 23:50:54 +00:00
p, ok := h.auth.GetProvisionerCollection().LoadByName(name)
if !ok {
api.WriteError(w, mgmt.NewError(mgmt.ErrorNotFoundType, "provisioner %s not found", name))
return
}
prov, err := h.db.GetProvisioner(ctx, p.GetID())
2021-05-03 19:48:20 +00:00
if err != nil {
api.WriteError(w, err)
return
}
api.JSON(w, prov)
}
// GetProvisioners returns all provisioners associated with the authority.
func (h *Handler) GetProvisioners(w http.ResponseWriter, r *http.Request) {
2021-05-20 20:01:58 +00:00
cursor, limit, err := api.ParseCursor(r)
if err != nil {
api.WriteError(w, mgmt.WrapError(mgmt.ErrorBadRequestType, err,
"error parsing cursor / limt query params"))
return
}
2021-05-03 19:48:20 +00:00
2021-05-20 20:01:58 +00:00
p, next, err := h.auth.GetProvisioners(cursor, limit)
2021-05-03 19:48:20 +00:00
if err != nil {
2021-05-20 20:01:58 +00:00
api.WriteError(w, errs.InternalServerErr(err))
2021-05-03 19:48:20 +00:00
return
}
2021-05-20 20:01:58 +00:00
api.JSON(w, &GetProvisionersResponse{
Provisioners: p,
NextCursor: next,
})
2021-05-03 19:48:20 +00:00
}
// CreateProvisioner creates a new prov.
func (h *Handler) CreateProvisioner(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
2021-05-21 20:31:41 +00:00
var prov = new(mgmt.Provisioner)
if err := api.ReadJSON(r.Body, prov); err != nil {
2021-05-03 19:48:20 +00:00
api.WriteError(w, err)
2021-05-18 04:07:25 +00:00
return
}
2021-05-21 20:31:41 +00:00
// TODO: validate
// TODO: fix this
prov.Claims = mgmt.NewDefaultClaims()
2021-05-03 19:48:20 +00:00
if err := h.db.CreateProvisioner(ctx, prov); err != nil {
api.WriteError(w, err)
return
}
api.JSONStatus(w, prov, http.StatusCreated)
2021-05-18 04:07:25 +00:00
if err := h.auth.ReloadAuthConfig(); err != nil {
fmt.Printf("err = %+v\n", err)
}
}
// DeleteProvisioner deletes a provisioner.
func (h *Handler) DeleteProvisioner(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
2021-05-21 20:31:41 +00:00
p, ok := h.auth.GetProvisionerCollection().LoadByName(name)
if !ok {
api.WriteError(w, mgmt.NewError(mgmt.ErrorNotFoundType, "provisioner %s not found", name))
return
}
2021-05-18 04:07:25 +00:00
c := h.auth.GetAdminCollection()
2021-05-21 20:31:41 +00:00
if c.SuperCount() == c.SuperCountByProvisioner(name) {
2021-05-18 04:07:25 +00:00
api.WriteError(w, mgmt.NewError(mgmt.ErrorBadRequestType,
2021-05-21 20:31:41 +00:00
"cannot remove provisioner %s because no super admins will remain", name))
2021-05-18 04:07:25 +00:00
return
}
ctx := r.Context()
2021-05-18 23:50:54 +00:00
prov, err := h.db.GetProvisioner(ctx, p.GetID())
2021-05-18 04:07:25 +00:00
if err != nil {
2021-05-18 23:50:54 +00:00
api.WriteError(w, mgmt.WrapErrorISE(err, "error loading provisioner %s from db", name))
2021-05-18 04:07:25 +00:00
return
}
2021-05-18 23:50:54 +00:00
prov.Status = status.Deleted
if err := h.db.UpdateProvisioner(ctx, prov); err != nil {
2021-05-18 04:07:25 +00:00
api.WriteError(w, mgmt.WrapErrorISE(err, "error updating provisioner %s", name))
return
}
// Delete all admins associated with the provisioner.
admins, ok := c.LoadByProvisioner(name)
if ok {
for _, adm := range admins {
if err := h.db.UpdateAdmin(ctx, &mgmt.Admin{
ID: adm.ID,
ProvisionerID: adm.ProvisionerID,
Subject: adm.Subject,
2021-05-18 23:50:54 +00:00
Type: adm.Type,
Status: status.Deleted,
2021-05-18 04:07:25 +00:00
}); err != nil {
api.WriteError(w, mgmt.WrapErrorISE(err, "error deleting admin %s, as part of provisioner %s deletion", adm.Subject, name))
return
}
}
}
api.JSON(w, &DeleteResponse{Status: "ok"})
if err := h.auth.ReloadAuthConfig(); err != nil {
fmt.Printf("err = %+v\n", err)
}
2021-05-03 19:48:20 +00:00
}
// UpdateProvisioner updates an existing prov.
func (h *Handler) UpdateProvisioner(w http.ResponseWriter, r *http.Request) {
2021-05-07 00:03:12 +00:00
/*
ctx := r.Context()
id := chi.URLParam(r, "id")
var body UpdateProvisionerRequest
if err := ReadJSON(r.Body, &body); err != nil {
api.WriteError(w, err)
return
}
if err := body.Validate(); err != nil {
api.WriteError(w, err)
return
}
if prov, err := h.db.GetProvisioner(ctx, id); err != nil {
api.WriteError(w, err)
return
}
prov.Claims = body.Claims
prov.Details = body.Provisioner
prov.X509Template = body.X509Template
prov.SSHTemplate = body.SSHTemplate
prov.Status = body.Status
if err := h.db.UpdateProvisioner(ctx, prov); err != nil {
api.WriteError(w, err)
return
}
api.JSON(w, prov)
*/
2021-05-03 19:48:20 +00:00
}