forked from TrueCloudLab/certificates
Change ACME EAB endpoint
This commit is contained in:
parent
c6bfc6eac2
commit
c6a4c4ecba
4 changed files with 65 additions and 62 deletions
|
@ -1,45 +0,0 @@
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/smallstep/certificates/api"
|
|
||||||
"github.com/smallstep/certificates/authority/admin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CreateExternalAccountKeyRequest is the type for POST /admin/eak requests
|
|
||||||
type CreateExternalAccountKeyRequest struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateExternalAccountKeyResponse is the type for POST /admin/eak responses
|
|
||||||
type CreateExternalAccountKeyResponse struct {
|
|
||||||
KeyID string `json:"keyID"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Key []byte `json:"key"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateExternalAccountKey creates a new External Account Binding key
|
|
||||||
func (h *Handler) CreateExternalAccountKey(w http.ResponseWriter, r *http.Request) {
|
|
||||||
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.acmeDB.CreateExternalAccountKey(r.Context(), body.Name)
|
|
||||||
if err != nil {
|
|
||||||
api.WriteError(w, admin.WrapErrorISE(err, "error creating external account key %s", body.Name))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
eakResponse := CreateExternalAccountKeyResponse{
|
|
||||||
KeyID: eak.ID,
|
|
||||||
Name: eak.Name,
|
|
||||||
Key: eak.KeyBytes,
|
|
||||||
}
|
|
||||||
|
|
||||||
api.JSONStatus(w, eakResponse, http.StatusCreated) // TODO: rewrite into protobuf json (likely)
|
|
||||||
}
|
|
|
@ -43,6 +43,7 @@ func (h *Handler) Route(r api.Router) {
|
||||||
r.MethodFunc("PATCH", "/admins/{id}", authnz(h.UpdateAdmin))
|
r.MethodFunc("PATCH", "/admins/{id}", authnz(h.UpdateAdmin))
|
||||||
r.MethodFunc("DELETE", "/admins/{id}", authnz(h.DeleteAdmin))
|
r.MethodFunc("DELETE", "/admins/{id}", authnz(h.DeleteAdmin))
|
||||||
|
|
||||||
// External Account Binding Keys
|
// ACME External Account Binding Keys
|
||||||
r.MethodFunc("POST", "/eak", authnz(h.CreateExternalAccountKey))
|
r.MethodFunc("GET", "/acme/eab", authnz(h.GetExternalAccountKeys))
|
||||||
|
r.MethodFunc("POST", "/acme/eab", authnz(h.CreateExternalAccountKey))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
package eak
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type ExternalAccountKey struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
AccountID string `json:"-"`
|
|
||||||
KeyBytes []byte `json:"-"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
BoundAt time.Time `json:"boundAt,omitempty"`
|
|
||||||
}
|
|
|
@ -559,15 +559,54 @@ retry:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateExternalAccountKey performs the POST /admin/eak request to the CA.
|
// GetExternalAccountKeysPaginate returns a page from the the GET /admin/acme/eab request to the CA.
|
||||||
|
func (c *AdminClient) GetExternalAccountKeysPaginate(opts ...AdminOption) (*adminAPI.GetExternalAccountKeysResponse, error) {
|
||||||
|
var retried bool
|
||||||
|
o := new(adminOptions)
|
||||||
|
if err := o.apply(opts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := c.endpoint.ResolveReference(&url.URL{
|
||||||
|
Path: "/admin/acme/eab",
|
||||||
|
RawQuery: o.rawQuery(),
|
||||||
|
})
|
||||||
|
tok, err := c.generateAdminToken(u.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error generating admin token")
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("GET", u.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "create GET %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 GET %s failed", u)
|
||||||
|
}
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
if !retried && c.retryOnError(resp) {
|
||||||
|
retried = true
|
||||||
|
goto retry
|
||||||
|
}
|
||||||
|
return nil, readAdminError(resp.Body)
|
||||||
|
}
|
||||||
|
// var body = new(GetExternalAccountKeysResponse)
|
||||||
|
// if err := readJSON(resp.Body, body); err != nil {
|
||||||
|
// return nil, errors.Wrapf(err, "error reading %s", u)
|
||||||
|
// }
|
||||||
|
// return body, nil
|
||||||
|
return nil, nil // TODO: fix correctly
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateExternalAccountKey performs the POST /admin/acme/eab request to the CA.
|
||||||
func (c *AdminClient) CreateExternalAccountKey(eakRequest *adminAPI.CreateExternalAccountKeyRequest) (*adminAPI.CreateExternalAccountKeyResponse, error) {
|
func (c *AdminClient) CreateExternalAccountKey(eakRequest *adminAPI.CreateExternalAccountKeyRequest) (*adminAPI.CreateExternalAccountKeyResponse, error) {
|
||||||
var retried bool
|
var retried bool
|
||||||
//body, err := protojson.Marshal(req)
|
|
||||||
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, "eak")})
|
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "acme/eab")})
|
||||||
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")
|
||||||
|
@ -596,7 +635,27 @@ retry:
|
||||||
return eakResp, nil
|
return eakResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetExternalAccountKeys returns all ACME EAB Keys from the GET /admin/acme/eab request to the CA.
|
||||||
|
func (c *AdminClient) GetExternalAccountKeys(opts ...AdminOption) ([]*adminAPI.CreateExternalAccountKeyResponse, error) {
|
||||||
|
var (
|
||||||
|
cursor = ""
|
||||||
|
eaks = []*adminAPI.CreateExternalAccountKeyResponse{}
|
||||||
|
)
|
||||||
|
for {
|
||||||
|
resp, err := c.GetExternalAccountKeysPaginate(WithAdminCursor(cursor), WithAdminLimit(100))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
eaks = append(eaks, resp.EAKs...)
|
||||||
|
if resp.NextCursor == "" {
|
||||||
|
return eaks, nil
|
||||||
|
}
|
||||||
|
cursor = resp.NextCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func readAdminError(r io.ReadCloser) error {
|
func readAdminError(r io.ReadCloser) error {
|
||||||
|
// TODO: not all errors can be read (i.e. 404); seems to be a bigger issue
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
adminErr := new(admin.Error)
|
adminErr := new(admin.Error)
|
||||||
if err := json.NewDecoder(r).Decode(adminErr); err != nil {
|
if err := json.NewDecoder(r).Decode(adminErr); err != nil {
|
||||||
|
|
Loading…
Reference in a new issue