forked from TrueCloudLab/certificates
Refactor retrieval of provisioner into middleware
This commit is contained in:
parent
0afea2e957
commit
f34d68897a
3 changed files with 32 additions and 48 deletions
|
@ -15,15 +15,11 @@ import (
|
||||||
|
|
||||||
// CreateExternalAccountKeyRequest is the type for POST /admin/acme/eab requests
|
// CreateExternalAccountKeyRequest is the type for POST /admin/acme/eab requests
|
||||||
type CreateExternalAccountKeyRequest struct {
|
type CreateExternalAccountKeyRequest struct {
|
||||||
Provisioner string `json:"provisioner"`
|
|
||||||
Reference string `json:"reference"`
|
Reference string `json:"reference"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates a new ACME EAB Key request body.
|
// Validate validates a new ACME EAB Key request body.
|
||||||
func (r *CreateExternalAccountKeyRequest) Validate() error {
|
func (r *CreateExternalAccountKeyRequest) Validate() error {
|
||||||
if r.Provisioner == "" {
|
|
||||||
return admin.NewError(admin.ErrorBadRequestType, "provisioner name cannot be empty")
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,11 +29,26 @@ type GetExternalAccountKeysResponse struct {
|
||||||
NextCursor string `json:"nextCursor"`
|
NextCursor string `json:"nextCursor"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// requireEABEnabled is a middleware that ensures ACME EAB is enabled
|
||||||
|
// before serving requests that act on ACME EAB credentials.
|
||||||
|
func (h *Handler) requireEABEnabled(next nextHTTP) nextHTTP {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
provisioner := chi.URLParam(r, "prov")
|
||||||
|
eabEnabled, err := h.provisionerHasEABEnabled(r.Context(), provisioner)
|
||||||
|
if err != nil {
|
||||||
|
api.WriteError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !eabEnabled {
|
||||||
|
api.WriteError(w, admin.NewError(admin.ErrorBadRequestType, "ACME EAB not enabled for provisioner %s", provisioner))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// provisionerHasEABEnabled determines if the "requireEAB" setting for an ACME
|
// provisionerHasEABEnabled determines if the "requireEAB" setting for an ACME
|
||||||
// provisioner is set to true and thus has EAB enabled.
|
// provisioner is set to true and thus has EAB enabled.
|
||||||
// TODO: rewrite this into a middleware for the ACME handlers? This probably requires
|
|
||||||
// ensuring that all the ACME EAB APIs that need the middleware work the same in terms
|
|
||||||
// of specifying the provisioner; probably a bit of refactoring required.
|
|
||||||
func (h *Handler) provisionerHasEABEnabled(ctx context.Context, provisionerName string) (bool, error) {
|
func (h *Handler) provisionerHasEABEnabled(ctx context.Context, provisionerName string) (bool, error) {
|
||||||
var (
|
var (
|
||||||
p provisioner.Interface
|
p provisioner.Interface
|
||||||
|
@ -78,22 +89,12 @@ func (h *Handler) CreateExternalAccountKey(w http.ResponseWriter, r *http.Reques
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
provisioner := body.Provisioner
|
provisioner := chi.URLParam(r, "prov")
|
||||||
reference := body.Reference
|
reference := body.Reference
|
||||||
|
|
||||||
eabEnabled, err := h.provisionerHasEABEnabled(r.Context(), provisioner)
|
|
||||||
if err != nil {
|
|
||||||
api.WriteError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !eabEnabled {
|
|
||||||
api.WriteError(w, admin.NewError(admin.ErrorBadRequestType, "ACME EAB not enabled for provisioner %s", provisioner))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if reference != "" {
|
if reference != "" {
|
||||||
k, err := h.acmeDB.GetExternalAccountKeyByReference(r.Context(), provisioner, reference)
|
k, err := h.acmeDB.GetExternalAccountKeyByReference(r.Context(), provisioner, reference)
|
||||||
|
// retrieving an EAB key from DB results in error if it doesn't exist, which is what we're looking for
|
||||||
if err == nil || k != nil {
|
if err == nil || k != nil {
|
||||||
err := admin.NewError(admin.ErrorBadRequestType, "an ACME EAB key for provisioner %s with reference %s already exists", provisioner, reference)
|
err := admin.NewError(admin.ErrorBadRequestType, "an ACME EAB key for provisioner %s with reference %s already exists", provisioner, reference)
|
||||||
err.Status = 409
|
err.Status = 409
|
||||||
|
@ -123,17 +124,6 @@ func (h *Handler) DeleteExternalAccountKey(w http.ResponseWriter, r *http.Reques
|
||||||
provisioner := chi.URLParam(r, "prov")
|
provisioner := chi.URLParam(r, "prov")
|
||||||
keyID := chi.URLParam(r, "id")
|
keyID := chi.URLParam(r, "id")
|
||||||
|
|
||||||
eabEnabled, err := h.provisionerHasEABEnabled(r.Context(), provisioner)
|
|
||||||
if err != nil {
|
|
||||||
api.WriteError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !eabEnabled {
|
|
||||||
api.WriteError(w, admin.NewError(admin.ErrorBadRequestType, "ACME EAB not enabled for provisioner %s", provisioner))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := h.acmeDB.DeleteExternalAccountKey(r.Context(), provisioner, keyID); err != nil {
|
if err := h.acmeDB.DeleteExternalAccountKey(r.Context(), provisioner, keyID); err != nil {
|
||||||
api.WriteError(w, admin.WrapErrorISE(err, "error deleting ACME EAB Key %s", keyID))
|
api.WriteError(w, admin.WrapErrorISE(err, "error deleting ACME EAB Key %s", keyID))
|
||||||
return
|
return
|
||||||
|
@ -147,17 +137,6 @@ func (h *Handler) GetExternalAccountKeys(w http.ResponseWriter, r *http.Request)
|
||||||
prov := chi.URLParam(r, "prov")
|
prov := chi.URLParam(r, "prov")
|
||||||
reference := chi.URLParam(r, "ref")
|
reference := chi.URLParam(r, "ref")
|
||||||
|
|
||||||
eabEnabled, err := h.provisionerHasEABEnabled(r.Context(), prov)
|
|
||||||
if err != nil {
|
|
||||||
api.WriteError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !eabEnabled {
|
|
||||||
api.WriteError(w, admin.NewError(admin.ErrorBadRequestType, "ACME EAB not enabled for provisioner %s", prov))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: support paging properly? It'll probably leak to the DB layer, as we have to loop through all keys
|
// TODO: support paging properly? It'll probably leak to the DB layer, as we have to loop through all keys
|
||||||
// cursor, limit, err := api.ParseCursor(r)
|
// cursor, limit, err := api.ParseCursor(r)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
|
@ -169,6 +148,7 @@ func (h *Handler) GetExternalAccountKeys(w http.ResponseWriter, r *http.Request)
|
||||||
var (
|
var (
|
||||||
key *acme.ExternalAccountKey
|
key *acme.ExternalAccountKey
|
||||||
keys []*acme.ExternalAccountKey
|
keys []*acme.ExternalAccountKey
|
||||||
|
err error
|
||||||
)
|
)
|
||||||
if reference != "" {
|
if reference != "" {
|
||||||
key, err = h.acmeDB.GetExternalAccountKeyByReference(r.Context(), prov, reference)
|
key, err = h.acmeDB.GetExternalAccountKeyByReference(r.Context(), prov, reference)
|
||||||
|
|
|
@ -29,6 +29,10 @@ func (h *Handler) Route(r api.Router) {
|
||||||
return h.extractAuthorizeTokenAdmin(h.requireAPIEnabled(next))
|
return h.extractAuthorizeTokenAdmin(h.requireAPIEnabled(next))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requireEABEnabled := func(next nextHTTP) nextHTTP {
|
||||||
|
return h.requireEABEnabled(next)
|
||||||
|
}
|
||||||
|
|
||||||
// Provisioners
|
// Provisioners
|
||||||
r.MethodFunc("GET", "/provisioners/{name}", authnz(h.GetProvisioner))
|
r.MethodFunc("GET", "/provisioners/{name}", authnz(h.GetProvisioner))
|
||||||
r.MethodFunc("GET", "/provisioners", authnz(h.GetProvisioners))
|
r.MethodFunc("GET", "/provisioners", authnz(h.GetProvisioners))
|
||||||
|
@ -44,8 +48,8 @@ func (h *Handler) Route(r api.Router) {
|
||||||
r.MethodFunc("DELETE", "/admins/{id}", authnz(h.DeleteAdmin))
|
r.MethodFunc("DELETE", "/admins/{id}", authnz(h.DeleteAdmin))
|
||||||
|
|
||||||
// ACME External Account Binding Keys
|
// ACME External Account Binding Keys
|
||||||
r.MethodFunc("GET", "/acme/eab/{prov}/{ref}", authnz(h.GetExternalAccountKeys))
|
r.MethodFunc("GET", "/acme/eab/{prov}/{ref}", authnz(requireEABEnabled(h.GetExternalAccountKeys)))
|
||||||
r.MethodFunc("GET", "/acme/eab/{prov}", authnz(h.GetExternalAccountKeys))
|
r.MethodFunc("GET", "/acme/eab/{prov}", authnz(requireEABEnabled(h.GetExternalAccountKeys)))
|
||||||
r.MethodFunc("POST", "/acme/eab", authnz(h.CreateExternalAccountKey))
|
r.MethodFunc("POST", "/acme/eab/{prov}", authnz(requireEABEnabled(h.CreateExternalAccountKey)))
|
||||||
r.MethodFunc("DELETE", "/acme/eab/{prov}/{id}", authnz(h.DeleteExternalAccountKey))
|
r.MethodFunc("DELETE", "/acme/eab/{prov}/{id}", authnz(requireEABEnabled(h.DeleteExternalAccountKey)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -602,13 +602,13 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateExternalAccountKey performs the POST /admin/acme/eab request to the CA.
|
// CreateExternalAccountKey performs the POST /admin/acme/eab request to the CA.
|
||||||
func (c *AdminClient) CreateExternalAccountKey(eakRequest *adminAPI.CreateExternalAccountKeyRequest) (*linkedca.EABKey, error) {
|
func (c *AdminClient) CreateExternalAccountKey(provisionerName string, eakRequest *adminAPI.CreateExternalAccountKeyRequest) (*linkedca.EABKey, error) {
|
||||||
var retried bool
|
var retried bool
|
||||||
body, err := json.Marshal(eakRequest)
|
body, err := json.Marshal(eakRequest)
|
||||||
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(adminURLPrefix, "acme/eab")})
|
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "acme/eab/", provisionerName)})
|
||||||
tok, err := c.generateAdminToken(u.Path)
|
tok, err := c.generateAdminToken(u.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "error generating admin token")
|
return nil, errors.Wrapf(err, "error generating admin token")
|
||||||
|
|
Loading…
Reference in a new issue