2021-05-03 19:48:20 +00:00
|
|
|
package ca
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"path"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/smallstep/certificates/authority/mgmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
// MgmtClient implements an HTTP client for the CA server.
|
|
|
|
type MgmtClient struct {
|
|
|
|
client *uaClient
|
|
|
|
endpoint *url.URL
|
|
|
|
retryFunc RetryFunc
|
|
|
|
opts []ClientOption
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewMgmtClient creates a new MgmtClient with the given endpoint and options.
|
|
|
|
func NewMgmtClient(endpoint string, opts ...ClientOption) (*MgmtClient, error) {
|
|
|
|
u, err := parseEndpoint(endpoint)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// Retrieve transport from options.
|
|
|
|
o := new(clientOptions)
|
|
|
|
if err := o.apply(opts); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
tr, err := o.getTransport(endpoint)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &MgmtClient{
|
|
|
|
client: newClient(tr),
|
|
|
|
endpoint: u,
|
|
|
|
retryFunc: o.retryFunc,
|
|
|
|
opts: opts,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *MgmtClient) retryOnError(r *http.Response) bool {
|
|
|
|
if c.retryFunc != nil {
|
|
|
|
if c.retryFunc(r.StatusCode) {
|
|
|
|
o := new(clientOptions)
|
|
|
|
if err := o.apply(c.opts); err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
tr, err := o.getTransport(c.endpoint.String())
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
r.Body.Close()
|
|
|
|
c.client.SetTransport(tr)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-05-07 00:03:12 +00:00
|
|
|
// GetAdmin performs the GET /mgmt/admin/{id} request to the CA.
|
2021-05-03 19:48:20 +00:00
|
|
|
func (c *MgmtClient) GetAdmin(id string) (*mgmt.Admin, error) {
|
|
|
|
var retried bool
|
2021-05-07 00:03:12 +00:00
|
|
|
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/mgmt/admin", id)})
|
2021-05-03 19:48:20 +00:00
|
|
|
retry:
|
|
|
|
resp, err := c.client.Get(u.String())
|
|
|
|
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, readError(resp.Body)
|
|
|
|
}
|
|
|
|
var adm = new(mgmt.Admin)
|
|
|
|
if err := readJSON(resp.Body, adm); err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error reading %s", u)
|
|
|
|
}
|
|
|
|
return adm, nil
|
|
|
|
}
|
|
|
|
|
2021-05-07 00:03:12 +00:00
|
|
|
// GetAdmins performs the GET /mgmt/admins request to the CA.
|
2021-05-03 19:48:20 +00:00
|
|
|
func (c *MgmtClient) GetAdmins() ([]*mgmt.Admin, error) {
|
|
|
|
var retried bool
|
2021-05-07 00:03:12 +00:00
|
|
|
u := c.endpoint.ResolveReference(&url.URL{Path: "/mgmt/admins"})
|
2021-05-03 19:48:20 +00:00
|
|
|
retry:
|
|
|
|
resp, err := c.client.Get(u.String())
|
|
|
|
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, readError(resp.Body)
|
|
|
|
}
|
|
|
|
var admins = new([]*mgmt.Admin)
|
|
|
|
if err := readJSON(resp.Body, admins); err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error reading %s", u)
|
|
|
|
}
|
|
|
|
return *admins, nil
|
|
|
|
}
|
2021-05-11 22:25:37 +00:00
|
|
|
|
|
|
|
// GetProvisioners performs the GET /mgmt/provisioners request to the CA.
|
|
|
|
func (c *MgmtClient) GetProvisioners() ([]*mgmt.Provisioner, error) {
|
|
|
|
var retried bool
|
|
|
|
u := c.endpoint.ResolveReference(&url.URL{Path: "/mgmt/provisioners"})
|
|
|
|
retry:
|
|
|
|
resp, err := c.client.Get(u.String())
|
|
|
|
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, readError(resp.Body)
|
|
|
|
}
|
|
|
|
var provs = new([]*mgmt.Provisioner)
|
|
|
|
if err := readJSON(resp.Body, provs); err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error reading %s", u)
|
|
|
|
}
|
|
|
|
return *provs, nil
|
|
|
|
}
|