2022-03-15 14:51:45 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2022-04-04 11:58:16 +00:00
|
|
|
"errors"
|
2022-03-15 14:51:45 +00:00
|
|
|
"net/http"
|
|
|
|
|
2022-03-24 09:54:45 +00:00
|
|
|
"go.step.sm/linkedca"
|
2022-04-19 08:24:52 +00:00
|
|
|
"google.golang.org/protobuf/types/known/wrapperspb"
|
2022-03-24 09:54:45 +00:00
|
|
|
|
2022-04-07 12:11:53 +00:00
|
|
|
"github.com/smallstep/certificates/acme"
|
2022-03-24 12:10:49 +00:00
|
|
|
"github.com/smallstep/certificates/api/read"
|
2022-03-30 12:50:14 +00:00
|
|
|
"github.com/smallstep/certificates/api/render"
|
2022-04-04 11:58:16 +00:00
|
|
|
"github.com/smallstep/certificates/authority"
|
2022-03-15 14:51:45 +00:00
|
|
|
"github.com/smallstep/certificates/authority/admin"
|
|
|
|
)
|
|
|
|
|
|
|
|
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 {
|
2022-04-21 14:18:55 +00:00
|
|
|
auth adminAuthority
|
|
|
|
adminDB admin.DB
|
|
|
|
acmeDB acme.DB
|
|
|
|
deploymentType string
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewACMEAdminResponder returns a new ACMEAdminResponder
|
2022-04-21 14:18:55 +00:00
|
|
|
func NewPolicyAdminResponder(auth adminAuthority, adminDB admin.DB, acmeDB acme.DB, deploymentType string) *PolicyAdminResponder {
|
2022-03-15 14:51:45 +00:00
|
|
|
return &PolicyAdminResponder{
|
2022-04-21 14:18:55 +00:00
|
|
|
auth: auth,
|
|
|
|
adminDB: adminDB,
|
|
|
|
acmeDB: acmeDB,
|
|
|
|
deploymentType: deploymentType,
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetAuthorityPolicy handles the GET /admin/authority/policy request
|
|
|
|
func (par *PolicyAdminResponder) GetAuthorityPolicy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
2022-04-21 14:18:55 +00:00
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-15 14:51:45 +00:00
|
|
|
policy, err := par.auth.GetAuthorityPolicy(r.Context())
|
2022-04-04 11:58:16 +00:00
|
|
|
if ae, ok := err.(*admin.Error); ok && !ae.IsType(admin.ErrorNotFoundType) {
|
|
|
|
render.Error(w, admin.WrapErrorISE(ae, "error retrieving authority policy"))
|
|
|
|
return
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if policy == nil {
|
2022-03-30 12:50:14 +00:00
|
|
|
render.Error(w, admin.NewError(admin.ErrorNotFoundType, "authority policy does not exist"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-30 12:50:14 +00:00
|
|
|
render.ProtoJSONStatus(w, policy, http.StatusOK)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// CreateAuthorityPolicy handles the POST /admin/authority/policy request
|
|
|
|
func (par *PolicyAdminResponder) CreateAuthorityPolicy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
2022-04-21 14:18:55 +00:00
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-15 14:51:45 +00:00
|
|
|
ctx := r.Context()
|
|
|
|
policy, err := par.auth.GetAuthorityPolicy(ctx)
|
|
|
|
|
2022-03-31 14:12:29 +00:00
|
|
|
if ae, ok := err.(*admin.Error); ok && !ae.IsType(admin.ErrorNotFoundType) {
|
2022-03-30 12:50:14 +00:00
|
|
|
render.Error(w, admin.WrapErrorISE(err, "error retrieving authority policy"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if policy != nil {
|
2022-04-21 10:14:03 +00:00
|
|
|
adminErr := admin.NewError(admin.ErrorConflictType, "authority already has a policy")
|
2022-03-30 12:50:14 +00:00
|
|
|
render.Error(w, adminErr)
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var newPolicy = new(linkedca.Policy)
|
2022-04-18 21:38:13 +00:00
|
|
|
if err := read.ProtoJSON(r.Body, newPolicy); err != nil {
|
|
|
|
render.Error(w, err)
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-19 10:09:45 +00:00
|
|
|
applyConditionalDefaults(newPolicy)
|
2022-04-19 08:24:52 +00:00
|
|
|
|
2022-04-19 11:21:37 +00:00
|
|
|
newPolicy.Deduplicate()
|
|
|
|
|
2022-03-24 09:54:45 +00:00
|
|
|
adm := linkedca.AdminFromContext(ctx)
|
2022-03-21 14:53:59 +00:00
|
|
|
|
2022-03-24 09:54:45 +00:00
|
|
|
var createdPolicy *linkedca.Policy
|
|
|
|
if createdPolicy, err = par.auth.CreateAuthorityPolicy(ctx, adm, newPolicy); err != nil {
|
2022-04-04 11:58:16 +00:00
|
|
|
var pe *authority.PolicyError
|
2022-04-04 13:31:28 +00:00
|
|
|
isPolicyError := errors.As(err, &pe)
|
2022-04-04 11:58:16 +00:00
|
|
|
|
2022-04-04 13:31:28 +00:00
|
|
|
if isPolicyError && pe.Typ == authority.AdminLockOut || pe.Typ == authority.EvaluationFailure || pe.Typ == authority.ConfigurationFailure {
|
2022-04-04 11:58:16 +00:00
|
|
|
render.Error(w, admin.WrapError(admin.ErrorBadRequestType, pe, "error storing authority policy"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
render.Error(w, admin.WrapErrorISE(err, "error storing authority policy"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-19 10:09:45 +00:00
|
|
|
render.ProtoJSONStatus(w, createdPolicy, http.StatusCreated)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateAuthorityPolicy handles the PUT /admin/authority/policy request
|
|
|
|
func (par *PolicyAdminResponder) UpdateAuthorityPolicy(w http.ResponseWriter, r *http.Request) {
|
2022-03-21 14:53:59 +00:00
|
|
|
|
2022-04-21 14:18:55 +00:00
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-21 14:53:59 +00:00
|
|
|
ctx := r.Context()
|
|
|
|
policy, err := par.auth.GetAuthorityPolicy(ctx)
|
|
|
|
|
2022-03-31 14:12:29 +00:00
|
|
|
if ae, ok := err.(*admin.Error); ok && !ae.IsType(admin.ErrorNotFoundType) {
|
2022-03-30 12:50:14 +00:00
|
|
|
render.Error(w, admin.WrapErrorISE(err, "error retrieving authority policy"))
|
2022-03-21 14:53:59 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if policy == nil {
|
2022-03-30 12:50:14 +00:00
|
|
|
render.Error(w, admin.NewError(admin.ErrorNotFoundType, "authority policy does not exist"))
|
2022-03-21 14:53:59 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var newPolicy = new(linkedca.Policy)
|
2022-04-18 21:38:13 +00:00
|
|
|
if err := read.ProtoJSON(r.Body, newPolicy); err != nil {
|
|
|
|
render.Error(w, err)
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-19 11:21:37 +00:00
|
|
|
newPolicy.Deduplicate()
|
|
|
|
|
2022-03-24 09:54:45 +00:00
|
|
|
adm := linkedca.AdminFromContext(ctx)
|
2022-03-21 14:53:59 +00:00
|
|
|
|
2022-03-24 09:54:45 +00:00
|
|
|
var updatedPolicy *linkedca.Policy
|
|
|
|
if updatedPolicy, err = par.auth.UpdateAuthorityPolicy(ctx, adm, newPolicy); err != nil {
|
2022-04-04 11:58:16 +00:00
|
|
|
var pe *authority.PolicyError
|
2022-04-04 13:31:28 +00:00
|
|
|
isPolicyError := errors.As(err, &pe)
|
|
|
|
if isPolicyError && pe.Typ == authority.AdminLockOut || pe.Typ == authority.EvaluationFailure || pe.Typ == authority.ConfigurationFailure {
|
2022-04-04 11:58:16 +00:00
|
|
|
render.Error(w, admin.WrapError(admin.ErrorBadRequestType, pe, "error updating authority policy"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
render.Error(w, admin.WrapErrorISE(err, "error updating authority policy"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-30 12:50:14 +00:00
|
|
|
render.ProtoJSONStatus(w, updatedPolicy, http.StatusOK)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteAuthorityPolicy handles the DELETE /admin/authority/policy request
|
|
|
|
func (par *PolicyAdminResponder) DeleteAuthorityPolicy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
2022-04-21 14:18:55 +00:00
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-15 14:51:45 +00:00
|
|
|
ctx := r.Context()
|
|
|
|
policy, err := par.auth.GetAuthorityPolicy(ctx)
|
|
|
|
|
2022-04-04 11:58:16 +00:00
|
|
|
if ae, ok := err.(*admin.Error); ok && !ae.IsType(admin.ErrorNotFoundType) {
|
|
|
|
render.Error(w, admin.WrapErrorISE(ae, "error retrieving authority policy"))
|
|
|
|
return
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if policy == nil {
|
2022-03-30 12:50:14 +00:00
|
|
|
render.Error(w, admin.NewError(admin.ErrorNotFoundType, "authority policy does not exist"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-07 12:11:53 +00:00
|
|
|
if err := par.auth.RemoveAuthorityPolicy(ctx); err != nil {
|
2022-03-30 12:50:14 +00:00
|
|
|
render.Error(w, admin.WrapErrorISE(err, "error deleting authority policy"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-30 12:50:14 +00:00
|
|
|
render.JSONStatus(w, DeleteResponse{Status: "ok"}, http.StatusOK)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetProvisionerPolicy handles the GET /admin/provisioners/{name}/policy request
|
|
|
|
func (par *PolicyAdminResponder) GetProvisionerPolicy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
2022-04-21 14:18:55 +00:00
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-30 12:21:39 +00:00
|
|
|
prov := linkedca.ProvisionerFromContext(r.Context())
|
2022-03-15 14:51:45 +00:00
|
|
|
|
|
|
|
policy := prov.GetPolicy()
|
|
|
|
if policy == nil {
|
2022-03-30 12:50:14 +00:00
|
|
|
render.Error(w, admin.NewError(admin.ErrorNotFoundType, "provisioner policy does not exist"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-30 12:50:14 +00:00
|
|
|
render.ProtoJSONStatus(w, policy, http.StatusOK)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// CreateProvisionerPolicy handles the POST /admin/provisioners/{name}/policy request
|
|
|
|
func (par *PolicyAdminResponder) CreateProvisionerPolicy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
2022-04-21 14:18:55 +00:00
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-30 12:21:39 +00:00
|
|
|
ctx := r.Context()
|
|
|
|
prov := linkedca.ProvisionerFromContext(ctx)
|
2022-03-15 14:51:45 +00:00
|
|
|
|
|
|
|
policy := prov.GetPolicy()
|
|
|
|
if policy != nil {
|
2022-04-21 10:14:03 +00:00
|
|
|
adminErr := admin.NewError(admin.ErrorConflictType, "provisioner %s already has a policy", prov.Name)
|
2022-03-30 12:50:14 +00:00
|
|
|
render.Error(w, adminErr)
|
2022-03-30 12:21:39 +00:00
|
|
|
return
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var newPolicy = new(linkedca.Policy)
|
2022-04-18 21:38:13 +00:00
|
|
|
if err := read.ProtoJSON(r.Body, newPolicy); err != nil {
|
|
|
|
render.Error(w, err)
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-19 10:09:45 +00:00
|
|
|
applyConditionalDefaults(newPolicy)
|
2022-04-19 08:24:52 +00:00
|
|
|
|
2022-04-19 11:21:37 +00:00
|
|
|
newPolicy.Deduplicate()
|
|
|
|
|
2022-03-15 14:51:45 +00:00
|
|
|
prov.Policy = newPolicy
|
|
|
|
|
2022-04-07 12:11:53 +00:00
|
|
|
if err := par.auth.UpdateProvisioner(ctx, prov); err != nil {
|
2022-04-04 11:58:16 +00:00
|
|
|
var pe *authority.PolicyError
|
2022-04-04 13:31:28 +00:00
|
|
|
isPolicyError := errors.As(err, &pe)
|
|
|
|
if isPolicyError && pe.Typ == authority.AdminLockOut || pe.Typ == authority.EvaluationFailure || pe.Typ == authority.ConfigurationFailure {
|
2022-04-04 11:58:16 +00:00
|
|
|
render.Error(w, admin.WrapError(admin.ErrorBadRequestType, pe, "error creating provisioner policy"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
render.Error(w, admin.WrapErrorISE(err, "error creating provisioner policy"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-30 12:50:14 +00:00
|
|
|
render.ProtoJSONStatus(w, newPolicy, http.StatusCreated)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateProvisionerPolicy handles the PUT /admin/provisioners/{name}/policy request
|
|
|
|
func (par *PolicyAdminResponder) UpdateProvisionerPolicy(w http.ResponseWriter, r *http.Request) {
|
2022-03-30 12:21:39 +00:00
|
|
|
|
2022-04-21 14:18:55 +00:00
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-15 14:51:45 +00:00
|
|
|
ctx := r.Context()
|
2022-03-30 12:21:39 +00:00
|
|
|
prov := linkedca.ProvisionerFromContext(ctx)
|
2022-03-15 14:51:45 +00:00
|
|
|
|
2022-03-30 12:21:39 +00:00
|
|
|
if prov.Policy == nil {
|
2022-03-30 12:50:14 +00:00
|
|
|
render.Error(w, admin.NewError(admin.ErrorNotFoundType, "provisioner policy does not exist"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-30 12:21:39 +00:00
|
|
|
var newPolicy = new(linkedca.Policy)
|
2022-04-18 21:38:13 +00:00
|
|
|
if err := read.ProtoJSON(r.Body, newPolicy); err != nil {
|
|
|
|
render.Error(w, err)
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-19 11:21:37 +00:00
|
|
|
newPolicy.Deduplicate()
|
|
|
|
|
2022-03-30 12:21:39 +00:00
|
|
|
prov.Policy = newPolicy
|
2022-04-07 12:11:53 +00:00
|
|
|
if err := par.auth.UpdateProvisioner(ctx, prov); err != nil {
|
2022-04-04 11:58:16 +00:00
|
|
|
var pe *authority.PolicyError
|
2022-04-04 13:31:28 +00:00
|
|
|
isPolicyError := errors.As(err, &pe)
|
|
|
|
if isPolicyError && pe.Typ == authority.AdminLockOut || pe.Typ == authority.EvaluationFailure || pe.Typ == authority.ConfigurationFailure {
|
2022-04-04 11:58:16 +00:00
|
|
|
render.Error(w, admin.WrapError(admin.ErrorBadRequestType, pe, "error updating provisioner policy"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-15 08:43:10 +00:00
|
|
|
render.Error(w, admin.WrapErrorISE(err, "error updating provisioner policy"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-30 12:50:14 +00:00
|
|
|
render.ProtoJSONStatus(w, newPolicy, http.StatusOK)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
2022-03-24 12:10:49 +00:00
|
|
|
// DeleteProvisionerPolicy handles the DELETE /admin/provisioners/{name}/policy request
|
2022-03-15 14:51:45 +00:00
|
|
|
func (par *PolicyAdminResponder) DeleteProvisionerPolicy(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
2022-04-21 14:18:55 +00:00
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-15 14:51:45 +00:00
|
|
|
ctx := r.Context()
|
2022-03-30 12:21:39 +00:00
|
|
|
prov := linkedca.ProvisionerFromContext(ctx)
|
2022-03-15 14:51:45 +00:00
|
|
|
|
|
|
|
if prov.Policy == nil {
|
2022-03-30 12:50:14 +00:00
|
|
|
render.Error(w, admin.NewError(admin.ErrorNotFoundType, "provisioner policy does not exist"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove the policy
|
|
|
|
prov.Policy = nil
|
|
|
|
|
2022-04-07 12:11:53 +00:00
|
|
|
if err := par.auth.UpdateProvisioner(ctx, prov); err != nil {
|
2022-04-04 11:58:16 +00:00
|
|
|
render.Error(w, admin.WrapErrorISE(err, "error deleting provisioner policy"))
|
2022-03-15 14:51:45 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-30 12:50:14 +00:00
|
|
|
render.JSONStatus(w, DeleteResponse{Status: "ok"}, http.StatusOK)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (par *PolicyAdminResponder) GetACMEAccountPolicy(w http.ResponseWriter, r *http.Request) {
|
2022-04-21 14:18:55 +00:00
|
|
|
|
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-07 12:11:53 +00:00
|
|
|
ctx := r.Context()
|
|
|
|
eak := linkedca.ExternalAccountKeyFromContext(ctx)
|
|
|
|
|
|
|
|
policy := eak.GetPolicy()
|
|
|
|
if policy == nil {
|
|
|
|
render.Error(w, admin.NewError(admin.ErrorNotFoundType, "ACME EAK policy does not exist"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
render.ProtoJSONStatus(w, policy, http.StatusOK)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (par *PolicyAdminResponder) CreateACMEAccountPolicy(w http.ResponseWriter, r *http.Request) {
|
2022-04-21 14:18:55 +00:00
|
|
|
|
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-07 12:11:53 +00:00
|
|
|
ctx := r.Context()
|
|
|
|
prov := linkedca.ProvisionerFromContext(ctx)
|
|
|
|
eak := linkedca.ExternalAccountKeyFromContext(ctx)
|
|
|
|
|
|
|
|
policy := eak.GetPolicy()
|
|
|
|
if policy != nil {
|
2022-04-21 10:14:03 +00:00
|
|
|
adminErr := admin.NewError(admin.ErrorConflictType, "ACME EAK %s already has a policy", eak.Id)
|
2022-04-07 12:11:53 +00:00
|
|
|
render.Error(w, adminErr)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var newPolicy = new(linkedca.Policy)
|
2022-04-18 21:38:13 +00:00
|
|
|
if err := read.ProtoJSON(r.Body, newPolicy); err != nil {
|
|
|
|
render.Error(w, err)
|
2022-04-07 12:11:53 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-19 11:21:37 +00:00
|
|
|
newPolicy.Deduplicate()
|
|
|
|
|
2022-04-07 12:11:53 +00:00
|
|
|
eak.Policy = newPolicy
|
|
|
|
|
|
|
|
acmeEAK := linkedEAKToCertificates(eak)
|
|
|
|
if err := par.acmeDB.UpdateExternalAccountKey(ctx, prov.GetId(), acmeEAK); err != nil {
|
|
|
|
render.Error(w, admin.WrapErrorISE(err, "error creating ACME EAK policy"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
render.ProtoJSONStatus(w, newPolicy, http.StatusCreated)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (par *PolicyAdminResponder) UpdateACMEAccountPolicy(w http.ResponseWriter, r *http.Request) {
|
2022-04-21 14:18:55 +00:00
|
|
|
|
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-07 12:11:53 +00:00
|
|
|
ctx := r.Context()
|
|
|
|
prov := linkedca.ProvisionerFromContext(ctx)
|
|
|
|
eak := linkedca.ExternalAccountKeyFromContext(ctx)
|
|
|
|
|
|
|
|
policy := eak.GetPolicy()
|
|
|
|
if policy == nil {
|
|
|
|
render.Error(w, admin.NewError(admin.ErrorNotFoundType, "ACME EAK policy does not exist"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var newPolicy = new(linkedca.Policy)
|
2022-04-18 21:38:13 +00:00
|
|
|
if err := read.ProtoJSON(r.Body, newPolicy); err != nil {
|
|
|
|
render.Error(w, err)
|
2022-04-07 12:11:53 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-19 11:21:37 +00:00
|
|
|
newPolicy.Deduplicate()
|
|
|
|
|
2022-04-07 12:11:53 +00:00
|
|
|
eak.Policy = newPolicy
|
|
|
|
acmeEAK := linkedEAKToCertificates(eak)
|
|
|
|
if err := par.acmeDB.UpdateExternalAccountKey(ctx, prov.GetId(), acmeEAK); err != nil {
|
|
|
|
render.Error(w, admin.WrapErrorISE(err, "error updating ACME EAK policy"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
render.ProtoJSONStatus(w, newPolicy, http.StatusOK)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (par *PolicyAdminResponder) DeleteACMEAccountPolicy(w http.ResponseWriter, r *http.Request) {
|
2022-04-21 14:18:55 +00:00
|
|
|
|
|
|
|
if err := par.blockLinkedCA(); err != nil {
|
|
|
|
render.Error(w, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-07 12:11:53 +00:00
|
|
|
ctx := r.Context()
|
|
|
|
prov := linkedca.ProvisionerFromContext(ctx)
|
|
|
|
eak := linkedca.ExternalAccountKeyFromContext(ctx)
|
|
|
|
|
|
|
|
policy := eak.GetPolicy()
|
|
|
|
if policy == nil {
|
|
|
|
render.Error(w, admin.NewError(admin.ErrorNotFoundType, "ACME EAK policy does not exist"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove the policy
|
|
|
|
eak.Policy = nil
|
|
|
|
|
|
|
|
acmeEAK := linkedEAKToCertificates(eak)
|
|
|
|
if err := par.acmeDB.UpdateExternalAccountKey(ctx, prov.GetId(), acmeEAK); err != nil {
|
|
|
|
render.Error(w, admin.WrapErrorISE(err, "error deleting ACME EAK policy"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
render.JSONStatus(w, DeleteResponse{Status: "ok"}, http.StatusOK)
|
2022-03-15 14:51:45 +00:00
|
|
|
}
|
2022-04-19 08:24:52 +00:00
|
|
|
|
2022-04-21 14:18:55 +00:00
|
|
|
// blockLinkedCA blocks all API operations on linked deployments
|
|
|
|
func (par *PolicyAdminResponder) blockLinkedCA() error {
|
|
|
|
// temporary blocking linked deployments based on string comparison (preventing import cycle)
|
|
|
|
if par.deploymentType == "linked" {
|
|
|
|
return admin.NewError(admin.ErrorNotImplementedType, "policy operations not yet supported in linked deployments")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-04-19 10:09:45 +00:00
|
|
|
// applyConditionalDefaults applies default settings in case they're not provided
|
|
|
|
// in the request body.
|
|
|
|
func applyConditionalDefaults(p *linkedca.Policy) {
|
2022-04-19 08:24:52 +00:00
|
|
|
if p.GetX509() == nil {
|
|
|
|
return
|
|
|
|
}
|
2022-04-19 12:41:36 +00:00
|
|
|
if p.GetX509().GetVerifySubjectCommonName() == nil {
|
2022-04-19 08:24:52 +00:00
|
|
|
p.X509.VerifySubjectCommonName = &wrapperspb.BoolValue{Value: true}
|
|
|
|
}
|
|
|
|
}
|