forked from TrueCloudLab/certificates
326 lines
8.5 KiB
Go
326 lines
8.5 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi"
|
|
|
|
"go.step.sm/linkedca"
|
|
|
|
"github.com/smallstep/certificates/api"
|
|
"github.com/smallstep/certificates/authority/admin"
|
|
"github.com/smallstep/certificates/authority/provisioner"
|
|
)
|
|
|
|
type policyAdminResponderInterface interface {
|
|
GetAuthorityPolicy(w http.ResponseWriter, r *http.Request)
|
|
CreateAuthorityPolicy(w http.ResponseWriter, r *http.Request)
|
|
UpdateAuthorityPolicy(w http.ResponseWriter, r *http.Request)
|
|
DeleteAuthorityPolicy(w http.ResponseWriter, r *http.Request)
|
|
GetProvisionerPolicy(w http.ResponseWriter, r *http.Request)
|
|
CreateProvisionerPolicy(w http.ResponseWriter, r *http.Request)
|
|
UpdateProvisionerPolicy(w http.ResponseWriter, r *http.Request)
|
|
DeleteProvisionerPolicy(w http.ResponseWriter, r *http.Request)
|
|
GetACMEAccountPolicy(w http.ResponseWriter, r *http.Request)
|
|
CreateACMEAccountPolicy(w http.ResponseWriter, r *http.Request)
|
|
UpdateACMEAccountPolicy(w http.ResponseWriter, r *http.Request)
|
|
DeleteACMEAccountPolicy(w http.ResponseWriter, r *http.Request)
|
|
}
|
|
|
|
// PolicyAdminResponder is responsible for writing ACME admin responses
|
|
type PolicyAdminResponder struct {
|
|
auth adminAuthority
|
|
adminDB admin.DB
|
|
}
|
|
|
|
// NewACMEAdminResponder returns a new ACMEAdminResponder
|
|
func NewPolicyAdminResponder(auth adminAuthority, adminDB admin.DB) *PolicyAdminResponder {
|
|
return &PolicyAdminResponder{
|
|
auth: auth,
|
|
adminDB: adminDB,
|
|
}
|
|
}
|
|
|
|
// GetAuthorityPolicy handles the GET /admin/authority/policy request
|
|
func (par *PolicyAdminResponder) GetAuthorityPolicy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
policy, err := par.auth.GetAuthorityPolicy(r.Context())
|
|
if ae, ok := err.(*admin.Error); ok {
|
|
if !ae.IsType(admin.ErrorNotFoundType) {
|
|
api.WriteError(w, admin.WrapErrorISE(ae, "error retrieving authority policy"))
|
|
return
|
|
}
|
|
}
|
|
|
|
if policy == nil {
|
|
api.JSONNotFound(w)
|
|
return
|
|
}
|
|
|
|
api.ProtoJSONStatus(w, policy, http.StatusOK)
|
|
}
|
|
|
|
// CreateAuthorityPolicy handles the POST /admin/authority/policy request
|
|
func (par *PolicyAdminResponder) CreateAuthorityPolicy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
policy, err := par.auth.GetAuthorityPolicy(ctx)
|
|
|
|
shouldWriteError := false
|
|
if ae, ok := err.(*admin.Error); ok {
|
|
shouldWriteError = !ae.IsType(admin.ErrorNotFoundType)
|
|
}
|
|
|
|
if shouldWriteError {
|
|
api.WriteError(w, admin.WrapErrorISE(err, "error retrieving authority policy"))
|
|
return
|
|
}
|
|
|
|
if policy != nil {
|
|
adminErr := admin.NewError(admin.ErrorBadRequestType, "authority already has a policy")
|
|
adminErr.Status = http.StatusConflict
|
|
api.WriteError(w, adminErr)
|
|
return
|
|
}
|
|
|
|
var newPolicy = new(linkedca.Policy)
|
|
if !api.ReadProtoJSONWithCheck(w, r.Body, newPolicy) {
|
|
return
|
|
}
|
|
|
|
adm := linkedca.AdminFromContext(ctx)
|
|
|
|
var createdPolicy *linkedca.Policy
|
|
if createdPolicy, err = par.auth.CreateAuthorityPolicy(ctx, adm, newPolicy); err != nil {
|
|
api.WriteError(w, admin.WrapError(admin.ErrorBadRequestType, err, "error storing authority policy"))
|
|
return
|
|
}
|
|
|
|
api.JSONStatus(w, createdPolicy, http.StatusCreated)
|
|
}
|
|
|
|
// UpdateAuthorityPolicy handles the PUT /admin/authority/policy request
|
|
func (par *PolicyAdminResponder) UpdateAuthorityPolicy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
policy, err := par.auth.GetAuthorityPolicy(ctx)
|
|
|
|
shouldWriteError := false
|
|
if ae, ok := err.(*admin.Error); ok {
|
|
shouldWriteError = !ae.IsType(admin.ErrorNotFoundType)
|
|
}
|
|
|
|
if shouldWriteError {
|
|
api.WriteError(w, admin.WrapErrorISE(err, "error retrieving authority policy"))
|
|
return
|
|
}
|
|
|
|
if policy == nil {
|
|
api.JSONNotFound(w)
|
|
return
|
|
}
|
|
|
|
var newPolicy = new(linkedca.Policy)
|
|
if err := api.ReadProtoJSON(r.Body, newPolicy); err != nil {
|
|
api.WriteError(w, err)
|
|
return
|
|
}
|
|
|
|
adm := linkedca.AdminFromContext(ctx)
|
|
|
|
var updatedPolicy *linkedca.Policy
|
|
if updatedPolicy, err = par.auth.UpdateAuthorityPolicy(ctx, adm, newPolicy); err != nil {
|
|
api.WriteError(w, admin.WrapError(admin.ErrorBadRequestType, err, "error updating authority policy"))
|
|
return
|
|
}
|
|
|
|
api.ProtoJSONStatus(w, updatedPolicy, http.StatusOK)
|
|
}
|
|
|
|
// DeleteAuthorityPolicy handles the DELETE /admin/authority/policy request
|
|
func (par *PolicyAdminResponder) DeleteAuthorityPolicy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
policy, err := par.auth.GetAuthorityPolicy(ctx)
|
|
|
|
if ae, ok := err.(*admin.Error); ok {
|
|
if !ae.IsType(admin.ErrorNotFoundType) {
|
|
api.WriteError(w, admin.WrapErrorISE(ae, "error retrieving authority policy"))
|
|
return
|
|
}
|
|
}
|
|
|
|
if policy == nil {
|
|
api.JSONNotFound(w)
|
|
return
|
|
}
|
|
|
|
err = par.auth.RemoveAuthorityPolicy(ctx)
|
|
if err != nil {
|
|
api.WriteError(w, admin.WrapErrorISE(err, "error deleting authority policy"))
|
|
return
|
|
}
|
|
|
|
api.JSONStatus(w, DeleteResponse{Status: "ok"}, http.StatusOK)
|
|
}
|
|
|
|
// GetProvisionerPolicy handles the GET /admin/provisioners/{name}/policy request
|
|
func (par *PolicyAdminResponder) GetProvisionerPolicy(w http.ResponseWriter, r *http.Request) {
|
|
// TODO: move getting provisioner to middleware?
|
|
ctx := r.Context()
|
|
name := chi.URLParam(r, "name")
|
|
var (
|
|
p provisioner.Interface
|
|
err error
|
|
)
|
|
if p, err = par.auth.LoadProvisionerByName(name); err != nil {
|
|
api.WriteError(w, admin.WrapErrorISE(err, "error loading provisioner %s", name))
|
|
return
|
|
}
|
|
|
|
prov, err := par.adminDB.GetProvisioner(ctx, p.GetID())
|
|
if err != nil {
|
|
api.WriteError(w, err)
|
|
return
|
|
}
|
|
|
|
policy := prov.GetPolicy()
|
|
if policy == nil {
|
|
api.JSONNotFound(w)
|
|
return
|
|
}
|
|
|
|
api.ProtoJSONStatus(w, policy, http.StatusOK)
|
|
}
|
|
|
|
// CreateProvisionerPolicy handles the POST /admin/provisioners/{name}/policy request
|
|
func (par *PolicyAdminResponder) CreateProvisionerPolicy(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
name := chi.URLParam(r, "name")
|
|
var (
|
|
p provisioner.Interface
|
|
err error
|
|
)
|
|
if p, err = par.auth.LoadProvisionerByName(name); err != nil {
|
|
api.WriteError(w, admin.WrapErrorISE(err, "error loading provisioner %s", name))
|
|
return
|
|
}
|
|
|
|
prov, err := par.adminDB.GetProvisioner(ctx, p.GetID())
|
|
if err != nil {
|
|
api.WriteError(w, err)
|
|
return
|
|
}
|
|
|
|
policy := prov.GetPolicy()
|
|
if policy != nil {
|
|
adminErr := admin.NewError(admin.ErrorBadRequestType, "provisioner %s already has a policy", name)
|
|
adminErr.Status = http.StatusConflict
|
|
api.WriteError(w, adminErr)
|
|
}
|
|
|
|
var newPolicy = new(linkedca.Policy)
|
|
if err := api.ReadProtoJSON(r.Body, newPolicy); err != nil {
|
|
api.WriteError(w, err)
|
|
return
|
|
}
|
|
|
|
prov.Policy = newPolicy
|
|
|
|
err = par.auth.UpdateProvisioner(ctx, prov)
|
|
if err != nil {
|
|
api.WriteError(w, err)
|
|
return
|
|
}
|
|
|
|
api.ProtoJSONStatus(w, newPolicy, http.StatusCreated)
|
|
}
|
|
|
|
// UpdateProvisionerPolicy handles the PUT /admin/provisioners/{name}/policy request
|
|
func (par *PolicyAdminResponder) UpdateProvisionerPolicy(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
name := chi.URLParam(r, "name")
|
|
var (
|
|
p provisioner.Interface
|
|
err error
|
|
)
|
|
if p, err = par.auth.LoadProvisionerByName(name); err != nil {
|
|
api.WriteError(w, admin.WrapErrorISE(err, "error loading provisioner %s", name))
|
|
return
|
|
}
|
|
|
|
prov, err := par.adminDB.GetProvisioner(ctx, p.GetID())
|
|
if err != nil {
|
|
api.WriteError(w, err)
|
|
return
|
|
}
|
|
|
|
var policy = new(linkedca.Policy)
|
|
if err := api.ReadProtoJSON(r.Body, policy); err != nil {
|
|
api.WriteError(w, err)
|
|
return
|
|
}
|
|
|
|
prov.Policy = policy
|
|
err = par.auth.UpdateProvisioner(ctx, prov)
|
|
if err != nil {
|
|
api.WriteError(w, err)
|
|
return
|
|
}
|
|
|
|
api.ProtoJSONStatus(w, policy, http.StatusOK)
|
|
}
|
|
|
|
// DeleteProvisionerPolicy ...
|
|
func (par *PolicyAdminResponder) DeleteProvisionerPolicy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
name := chi.URLParam(r, "name")
|
|
var (
|
|
p provisioner.Interface
|
|
err error
|
|
)
|
|
if p, err = par.auth.LoadProvisionerByName(name); err != nil {
|
|
api.WriteError(w, admin.WrapErrorISE(err, "error loading provisioner %s", name))
|
|
return
|
|
}
|
|
|
|
prov, err := par.adminDB.GetProvisioner(ctx, p.GetID())
|
|
if err != nil {
|
|
api.WriteError(w, err)
|
|
return
|
|
}
|
|
|
|
if prov.Policy == nil {
|
|
api.JSONNotFound(w)
|
|
return
|
|
}
|
|
|
|
// remove the policy
|
|
prov.Policy = nil
|
|
|
|
err = par.auth.UpdateProvisioner(ctx, prov)
|
|
if err != nil {
|
|
api.WriteError(w, err)
|
|
return
|
|
}
|
|
|
|
api.JSON(w, &DeleteResponse{Status: "ok"})
|
|
}
|
|
|
|
// GetACMEAccountPolicy ...
|
|
func (par *PolicyAdminResponder) GetACMEAccountPolicy(w http.ResponseWriter, r *http.Request) {
|
|
api.JSON(w, "ok")
|
|
}
|
|
|
|
func (par *PolicyAdminResponder) CreateACMEAccountPolicy(w http.ResponseWriter, r *http.Request) {
|
|
api.JSON(w, "ok")
|
|
}
|
|
|
|
func (par *PolicyAdminResponder) UpdateACMEAccountPolicy(w http.ResponseWriter, r *http.Request) {
|
|
api.JSON(w, "ok")
|
|
}
|
|
|
|
func (par *PolicyAdminResponder) DeleteACMEAccountPolicy(w http.ResponseWriter, r *http.Request) {
|
|
api.JSON(w, "ok")
|
|
}
|