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
|
||||
type CreateExternalAccountKeyRequest struct {
|
||||
Provisioner string `json:"provisioner"`
|
||||
Reference string `json:"reference"`
|
||||
Reference string `json:"reference"`
|
||||
}
|
||||
|
||||
// Validate validates a new ACME EAB Key request body.
|
||||
func (r *CreateExternalAccountKeyRequest) Validate() error {
|
||||
if r.Provisioner == "" {
|
||||
return admin.NewError(admin.ErrorBadRequestType, "provisioner name cannot be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -33,11 +29,26 @@ type GetExternalAccountKeysResponse struct {
|
|||
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
|
||||
// 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) {
|
||||
var (
|
||||
p provisioner.Interface
|
||||
|
@ -78,22 +89,12 @@ func (h *Handler) CreateExternalAccountKey(w http.ResponseWriter, r *http.Reques
|
|||
return
|
||||
}
|
||||
|
||||
provisioner := body.Provisioner
|
||||
provisioner := chi.URLParam(r, "prov")
|
||||
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 != "" {
|
||||
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 {
|
||||
err := admin.NewError(admin.ErrorBadRequestType, "an ACME EAB key for provisioner %s with reference %s already exists", provisioner, reference)
|
||||
err.Status = 409
|
||||
|
@ -123,17 +124,6 @@ func (h *Handler) DeleteExternalAccountKey(w http.ResponseWriter, r *http.Reques
|
|||
provisioner := chi.URLParam(r, "prov")
|
||||
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 {
|
||||
api.WriteError(w, admin.WrapErrorISE(err, "error deleting ACME EAB Key %s", keyID))
|
||||
return
|
||||
|
@ -147,17 +137,6 @@ func (h *Handler) GetExternalAccountKeys(w http.ResponseWriter, r *http.Request)
|
|||
prov := chi.URLParam(r, "prov")
|
||||
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
|
||||
// cursor, limit, err := api.ParseCursor(r)
|
||||
// if err != nil {
|
||||
|
@ -169,6 +148,7 @@ func (h *Handler) GetExternalAccountKeys(w http.ResponseWriter, r *http.Request)
|
|||
var (
|
||||
key *acme.ExternalAccountKey
|
||||
keys []*acme.ExternalAccountKey
|
||||
err error
|
||||
)
|
||||
if 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))
|
||||
}
|
||||
|
||||
requireEABEnabled := func(next nextHTTP) nextHTTP {
|
||||
return h.requireEABEnabled(next)
|
||||
}
|
||||
|
||||
// Provisioners
|
||||
r.MethodFunc("GET", "/provisioners/{name}", authnz(h.GetProvisioner))
|
||||
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))
|
||||
|
||||
// ACME External Account Binding Keys
|
||||
r.MethodFunc("GET", "/acme/eab/{prov}/{ref}", authnz(h.GetExternalAccountKeys))
|
||||
r.MethodFunc("GET", "/acme/eab/{prov}", authnz(h.GetExternalAccountKeys))
|
||||
r.MethodFunc("POST", "/acme/eab", authnz(h.CreateExternalAccountKey))
|
||||
r.MethodFunc("DELETE", "/acme/eab/{prov}/{id}", authnz(h.DeleteExternalAccountKey))
|
||||
r.MethodFunc("GET", "/acme/eab/{prov}/{ref}", authnz(requireEABEnabled(h.GetExternalAccountKeys)))
|
||||
r.MethodFunc("GET", "/acme/eab/{prov}", authnz(requireEABEnabled(h.GetExternalAccountKeys)))
|
||||
r.MethodFunc("POST", "/acme/eab/{prov}", authnz(requireEABEnabled(h.CreateExternalAccountKey)))
|
||||
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.
|
||||
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
|
||||
body, err := json.Marshal(eakRequest)
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error generating admin token")
|
||||
|
|
Loading…
Reference in a new issue