certificates/authority/admin/api/acme.go

122 lines
4.2 KiB
Go
Raw Normal View History

2021-07-23 13:41:24 +00:00
package api
import (
2021-09-16 21:09:24 +00:00
"context"
"fmt"
2021-07-23 13:41:24 +00:00
"net/http"
2021-08-27 12:10:00 +00:00
"github.com/go-chi/chi"
"go.step.sm/linkedca"
"github.com/smallstep/certificates/api/render"
2021-07-23 13:41:24 +00:00
"github.com/smallstep/certificates/authority/admin"
2021-09-16 21:09:24 +00:00
"github.com/smallstep/certificates/authority/provisioner"
2021-07-23 13:41:24 +00:00
)
const (
// provisionerContextKey provisioner key
provisionerContextKey = ContextKey("provisioner")
)
2021-07-23 13:41:24 +00:00
// CreateExternalAccountKeyRequest is the type for POST /admin/acme/eab requests
type CreateExternalAccountKeyRequest struct {
Reference string `json:"reference"`
2021-07-23 13:41:24 +00:00
}
2021-09-16 21:09:24 +00:00
// Validate validates a new ACME EAB Key request body.
func (r *CreateExternalAccountKeyRequest) Validate() error {
if len(r.Reference) > 256 { // an arbitrary, but sensible (IMO), limit
return fmt.Errorf("reference length %d exceeds the maximum (256)", len(r.Reference))
}
return nil
2021-07-23 13:41:24 +00:00
}
// GetExternalAccountKeysResponse is the type for GET /admin/acme/eab responses
type GetExternalAccountKeysResponse struct {
EAKs []*linkedca.EABKey `json:"eaks"`
NextCursor string `json:"nextCursor"`
2021-07-23 13:41:24 +00:00
}
// requireEABEnabled is a middleware that ensures ACME EAB is enabled
// before serving requests that act on ACME EAB credentials.
2022-04-27 18:59:32 +00:00
func requireEABEnabled(next nextHTTP) nextHTTP {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
provName := chi.URLParam(r, "provisionerName")
2022-04-27 18:59:32 +00:00
eabEnabled, prov, err := provisionerHasEABEnabled(ctx, provName)
if err != nil {
render.Error(w, err)
return
}
if !eabEnabled {
render.Error(w, admin.NewError(admin.ErrorBadRequestType, "ACME EAB not enabled for provisioner %s", prov.GetName()))
return
}
ctx = context.WithValue(ctx, provisionerContextKey, prov)
next(w, r.WithContext(ctx))
}
}
2021-09-16 21:09:24 +00:00
// provisionerHasEABEnabled determines if the "requireEAB" setting for an ACME
// provisioner is set to true and thus has EAB enabled.
2022-04-27 18:59:32 +00:00
func provisionerHasEABEnabled(ctx context.Context, provisionerName string) (bool, *linkedca.Provisioner, error) {
2021-09-16 21:09:24 +00:00
var (
p provisioner.Interface
err error
)
2022-04-27 18:59:32 +00:00
auth := mustAuthority(ctx)
db := admin.MustFromContext(ctx)
if p, err = auth.LoadProvisionerByName(provisionerName); err != nil {
return false, nil, admin.WrapErrorISE(err, "error loading provisioner %s", provisionerName)
2021-09-16 21:09:24 +00:00
}
2022-04-27 18:59:32 +00:00
prov, err := db.GetProvisioner(ctx, p.GetID())
2021-09-16 21:09:24 +00:00
if err != nil {
return false, nil, admin.WrapErrorISE(err, "error getting provisioner with ID: %s", p.GetID())
2021-09-16 21:09:24 +00:00
}
details := prov.GetDetails()
if details == nil {
return false, nil, admin.NewErrorISE("error getting details for provisioner with ID: %s", p.GetID())
2021-09-16 21:09:24 +00:00
}
2021-10-11 21:34:23 +00:00
acmeProvisioner := details.GetACME()
if acmeProvisioner == nil {
return false, nil, admin.NewErrorISE("error getting ACME details for provisioner with ID: %s", p.GetID())
2021-09-16 21:09:24 +00:00
}
return acmeProvisioner.GetRequireEab(), prov, nil
}
2022-02-08 12:26:30 +00:00
type acmeAdminResponderInterface interface {
GetExternalAccountKeys(w http.ResponseWriter, r *http.Request)
CreateExternalAccountKey(w http.ResponseWriter, r *http.Request)
DeleteExternalAccountKey(w http.ResponseWriter, r *http.Request)
2021-09-16 21:09:24 +00:00
}
2022-02-08 12:26:30 +00:00
// ACMEAdminResponder is responsible for writing ACME admin responses
type ACMEAdminResponder struct{}
2021-07-23 13:41:24 +00:00
2022-02-08 12:26:30 +00:00
// NewACMEAdminResponder returns a new ACMEAdminResponder
func NewACMEAdminResponder() *ACMEAdminResponder {
return &ACMEAdminResponder{}
2021-07-23 13:41:24 +00:00
}
2022-02-08 12:26:30 +00:00
// GetExternalAccountKeys writes the response for the EAB keys GET endpoint
func (h *ACMEAdminResponder) GetExternalAccountKeys(w http.ResponseWriter, r *http.Request) {
render.Error(w, admin.NewError(admin.ErrorNotImplementedType, "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm"))
2021-08-27 12:10:00 +00:00
}
2022-02-08 12:26:30 +00:00
// CreateExternalAccountKey writes the response for the EAB key POST endpoint
func (h *ACMEAdminResponder) CreateExternalAccountKey(w http.ResponseWriter, r *http.Request) {
render.Error(w, admin.NewError(admin.ErrorNotImplementedType, "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm"))
2022-02-08 12:26:30 +00:00
}
2021-08-27 14:58:04 +00:00
2022-02-08 12:26:30 +00:00
// DeleteExternalAccountKey writes the response for the EAB key DELETE endpoint
func (h *ACMEAdminResponder) DeleteExternalAccountKey(w http.ResponseWriter, r *http.Request) {
render.Error(w, admin.NewError(admin.ErrorNotImplementedType, "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm"))
2021-07-23 13:41:24 +00:00
}