From b65a588d5bef26b61c40cf721312687459fc1b25 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Thu, 22 Jul 2021 22:43:21 +0200 Subject: [PATCH] Make authentication work for /admin/eak --- authority/admin/api/eak.go | 12 +++++------ authority/admin/api/handler.go | 2 +- ca/adminClient.go | 38 ++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/authority/admin/api/eak.go b/authority/admin/api/eak.go index 1e46ff31..6f785f7a 100644 --- a/authority/admin/api/eak.go +++ b/authority/admin/api/eak.go @@ -7,12 +7,12 @@ import ( "github.com/smallstep/certificates/authority/admin" ) -// CreateExternalAccountKeyRequest is the type for GET /admin/eak requests +// CreateExternalAccountKeyRequest is the type for POST /admin/eak requests type CreateExternalAccountKeyRequest struct { Name string `json:"name"` } -// CreateExternalAccountKeyResponse is the type for GET /admin/eak responses +// CreateExternalAccountKeyResponse is the type for POST /admin/eak responses type CreateExternalAccountKeyResponse struct { KeyID string `json:"keyID"` Name string `json:"name"` @@ -21,17 +21,17 @@ type CreateExternalAccountKeyResponse struct { // CreateExternalAccountKey creates a new External Account Binding key func (h *Handler) CreateExternalAccountKey(w http.ResponseWriter, r *http.Request) { - var eakRequest = new(CreateExternalAccountKeyRequest) - if err := api.ReadJSON(r.Body, eakRequest); err != nil { // TODO: rewrite into protobuf json (likely) + var body CreateExternalAccountKeyRequest + if err := api.ReadJSON(r.Body, &body); err != nil { // TODO: rewrite into protobuf json (likely) api.WriteError(w, err) return } // TODO: Validate input - eak, err := h.db.CreateExternalAccountKey(r.Context(), eakRequest.Name) + eak, err := h.db.CreateExternalAccountKey(r.Context(), body.Name) if err != nil { - api.WriteError(w, admin.WrapErrorISE(err, "error creating external account key %s", eakRequest.Name)) + api.WriteError(w, admin.WrapErrorISE(err, "error creating external account key %s", body.Name)) return } diff --git a/authority/admin/api/handler.go b/authority/admin/api/handler.go index 561db687..ba72581d 100644 --- a/authority/admin/api/handler.go +++ b/authority/admin/api/handler.go @@ -40,5 +40,5 @@ func (h *Handler) Route(r api.Router) { r.MethodFunc("DELETE", "/admins/{id}", authnz(h.DeleteAdmin)) // External Account Binding Keys - r.MethodFunc("POST", "/eak", h.CreateExternalAccountKey) // TODO: authnz + r.MethodFunc("POST", "/eak", authnz(h.CreateExternalAccountKey)) } diff --git a/ca/adminClient.go b/ca/adminClient.go index 2f3d4b5d..4aa03db2 100644 --- a/ca/adminClient.go +++ b/ca/adminClient.go @@ -12,6 +12,7 @@ import ( "time" "github.com/pkg/errors" + "github.com/smallstep/certificates/api" "github.com/smallstep/certificates/authority/admin" adminAPI "github.com/smallstep/certificates/authority/admin/api" "github.com/smallstep/certificates/authority/provisioner" @@ -558,6 +559,43 @@ retry: return nil } +// CreateExternalAccountKey performs the POST /admin/eak request to the CA. +func (c *AdminClient) CreateExternalAccountKey(eakRequest *adminAPI.CreateExternalAccountKeyRequest) (*adminAPI.CreateExternalAccountKeyResponse, error) { + var retried bool + //body, err := protojson.Marshal(req) + 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, "eak")}) + tok, err := c.generateAdminToken(u.Path) + if err != nil { + return nil, errors.Wrapf(err, "error generating admin token") + } + req, err := http.NewRequest("POST", u.String(), bytes.NewReader(body)) + if err != nil { + return nil, errors.Wrapf(err, "create POST %s request failed", u) + } + req.Header.Add("Authorization", tok) +retry: + resp, err := c.client.Do(req) + if err != nil { + return nil, errors.Wrapf(err, "client POST %s failed", u) + } + if resp.StatusCode >= 400 { + if !retried && c.retryOnError(resp) { + retried = true + goto retry + } + return nil, readAdminError(resp.Body) + } + var eakResp = new(adminAPI.CreateExternalAccountKeyResponse) + if err := api.ReadJSON(resp.Body, &eakResp); err != nil { + return nil, errors.Wrapf(err, "error reading %s", u) + } + return eakResp, nil +} + func readAdminError(r io.ReadCloser) error { defer r.Close() adminErr := new(admin.Error)