From 94ba057f014d862e77296f9c6b847aa2476917e7 Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 26 May 2021 14:55:31 -0700 Subject: [PATCH] wip --- authority/authority.go | 17 ++++--- authority/mgmt/db/nosql/provisioner.go | 2 +- authority/mgmt/provisioner.go | 8 ++- authority/provisioners.go | 1 + ca/adminClient.go | 70 ++++++++++++++++++++++---- 5 files changed, 77 insertions(+), 21 deletions(-) diff --git a/authority/authority.go b/authority/authority.go index 3e089397..6be0ea8f 100644 --- a/authority/authority.go +++ b/authority/authority.go @@ -130,6 +130,7 @@ func NewEmbedded(opts ...Option) (*Authority, error) { return a, nil } +// ReloadAuthConfig reloads dynamic fields of the AuthConfig. func (a *Authority) ReloadAuthConfig(ctx context.Context) error { provs, err := a.adminDB.GetProvisioners(ctx) if err != nil { @@ -218,14 +219,20 @@ func (a *Authority) init() error { provs, err := a.adminDB.GetProvisioners(context.Background()) if err != nil { - return err + return mgmt.WrapErrorISE(err, "error getting provisioners to initialize authority") } if len(provs) == 0 { // Create First Provisioner prov, err := mgmt.CreateFirstProvisioner(context.Background(), a.adminDB, a.config.Password) if err != nil { - return err + return mgmt.WrapErrorISE(err, "error creating first provisioner") + } + certProv, err := provisionerToCertificates(prov) + if err != nil { + return mgmt.WrapErrorISE(err, "error converting provisioner to certificates type") } + a.config.AuthorityConfig.Provisioners = []provisioner.Interface{certProv} + // Create First Admin adm := &linkedca.Admin{ ProvisionerId: prov.Id, @@ -238,13 +245,9 @@ func (a *Authority) init() error { } a.config.AuthorityConfig.Admins = []*linkedca.Admin{adm} } else { - provs, err := a.adminDB.GetProvisioners(context.Background()) - if err != nil { - return mgmt.WrapErrorISE(err, "error getting provisioners to initialize authority") - } a.config.AuthorityConfig.Provisioners, err = provisionerListToCertificates(provs) if err != nil { - return mgmt.WrapErrorISE(err, "error converting provisioner list to certificates") + return mgmt.WrapErrorISE(err, "error converting provisioner list to certificates type") } a.config.AuthorityConfig.Admins, err = a.adminDB.GetAdmins(context.Background()) if err != nil { diff --git a/authority/mgmt/db/nosql/provisioner.go b/authority/mgmt/db/nosql/provisioner.go index 1924aee3..fa5eaf2a 100644 --- a/authority/mgmt/db/nosql/provisioner.go +++ b/authority/mgmt/db/nosql/provisioner.go @@ -151,7 +151,7 @@ func (db *DB) CreateProvisioner(ctx context.Context, prov *linkedca.Provisioner) return errors.Wrap(err, "error generating random id for provisioner") } - details, err := json.Marshal(prov.Details) + details, err := json.Marshal(prov.Details.GetData()) if err != nil { return mgmt.WrapErrorISE(err, "error marshaling details when creating provisioner %s", prov.Name) } diff --git a/authority/mgmt/provisioner.go b/authority/mgmt/provisioner.go index 0386a894..2177e116 100644 --- a/authority/mgmt/provisioner.go +++ b/authority/mgmt/provisioner.go @@ -96,7 +96,7 @@ func CreateFirstProvisioner(ctx context.Context, db DB, password string) (*linke return nil, WrapErrorISE(err, "error serializing JWE") } - return &linkedca.Provisioner{ + p := &linkedca.Provisioner{ Name: "Admin JWK", Type: linkedca.Provisioner_JWK, Claims: NewDefaultClaims(), @@ -108,5 +108,9 @@ func CreateFirstProvisioner(ctx context.Context, db DB, password string) (*linke }, }, }, - }, nil + } + if err := db.CreateProvisioner(ctx, p); err != nil { + return nil, WrapErrorISE(err, "error creating provisioner") + } + return p, nil } diff --git a/authority/provisioners.go b/authority/provisioners.go index 599db4bd..48f67dc8 100644 --- a/authority/provisioners.go +++ b/authority/provisioners.go @@ -87,6 +87,7 @@ func provisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface, switch d := details.(type) { case *linkedca.ProvisionerDetails_JWK: + fmt.Printf("d = %+v\n", d) jwk := new(jose.JSONWebKey) if err := json.Unmarshal(d.JWK.PublicKey, &jwk); err != nil { return nil, err diff --git a/ca/adminClient.go b/ca/adminClient.go index 32d6339d..ad708146 100644 --- a/ca/adminClient.go +++ b/ca/adminClient.go @@ -12,6 +12,7 @@ import ( "github.com/pkg/errors" "github.com/smallstep/certificates/authority/mgmt" mgmtAPI "github.com/smallstep/certificates/authority/mgmt/api" + "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/errs" "github.com/smallstep/certificates/linkedca" ) @@ -92,7 +93,7 @@ retry: return adm, nil } -// AdminOption is the type of options passed to the Provisioner method. +// AdminOption is the type of options passed to the Admin method. type AdminOption func(o *adminOptions) error type adminOptions struct { @@ -136,8 +137,8 @@ func WithAdminLimit(limit int) AdminOption { } } -// GetAdmins performs the GET /admin/admins request to the CA. -func (c *AdminClient) GetAdmins(opts ...AdminOption) (*mgmtAPI.GetAdminsResponse, error) { +// GetAdminsPaginate returns a page from the the GET /admin/admins request to the CA. +func (c *AdminClient) GetAdminsPaginate(opts ...AdminOption) (*mgmtAPI.GetAdminsResponse, error) { var retried bool o := new(adminOptions) if err := o.apply(opts); err != nil { @@ -166,6 +167,26 @@ retry: return body, nil } +// GetAdmins returns all admins from the GET /admin/admins request to the CA. +func (c *AdminClient) GetAdmins(opts ...AdminOption) ([]*linkedca.Admin, error) { + var ( + cursor = "" + admins = []*linkedca.Admin{} + ) + for { + resp, err := c.GetAdminsPaginate(WithAdminCursor(cursor), WithAdminLimit(100)) + if err != nil { + return nil, err + } + admins = append(admins, resp.Admins...) + if resp.NextCursor == "" { + return admins, nil + } + cursor = resp.NextCursor + } + return admins, nil +} + // CreateAdmin performs the POST /admin/admins request to the CA. func (c *AdminClient) CreateAdmin(req *mgmtAPI.CreateAdminRequest) (*linkedca.Admin, error) { var retried bool @@ -247,8 +268,8 @@ retry: return adm, nil } -// GetProvisioner performs the GET /admin/provisioners/{name} request to the CA. -func (c *AdminClient) GetProvisioner(name string) (*linkedca.Provisioner, error) { +// GetProvisionerByName performs the GET /admin/provisioners/{name} request to the CA. +func (c *AdminClient) GetProvisionerByName(name string) (*linkedca.Provisioner, error) { var retried bool u := c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "provisioners", name)}) retry: @@ -270,10 +291,17 @@ retry: return prov, nil } -// GetProvisioners performs the GET /admin/provisioners request to the CA. -func (c *AdminClient) GetProvisioners() ([]*linkedca.Provisioner, error) { +// GetProvisionersPaginate performs the GET /admin/provisioners request to the CA. +func (c *AdminClient) GetProvisionersPaginate(opts ...ProvisionerOption) (*mgmtAPI.GetProvisionersResponse, error) { var retried bool - u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/provisioners"}) + o := new(provisionerOptions) + if err := o.apply(opts); err != nil { + return nil, err + } + u := c.endpoint.ResolveReference(&url.URL{ + Path: "/admin/provisioners", + RawQuery: o.rawQuery(), + }) retry: resp, err := c.client.Get(u.String()) if err != nil { @@ -286,11 +314,31 @@ retry: } return nil, readAdminError(resp.Body) } - var provs = new([]*linkedca.Provisioner) - if err := readJSON(resp.Body, provs); err != nil { + var body = new(mgmtAPI.GetProvisionersResponse) + if err := readJSON(resp.Body, body); err != nil { return nil, errors.Wrapf(err, "error reading %s", u) } - return *provs, nil + return body, nil +} + +// GetProvisioners returns all admins from the GET /admin/admins request to the CA. +func (c *AdminClient) GetProvisioners(opts ...AdminOption) (provisioner.List, error) { + var ( + cursor = "" + provs = provisioner.List{} + ) + for { + resp, err := c.GetProvisionersPaginate(WithProvisionerCursor(cursor), WithProvisionerLimit(100)) + if err != nil { + return nil, err + } + provs = append(provs, resp.Provisioners...) + if resp.NextCursor == "" { + return provs, nil + } + cursor = resp.NextCursor + } + return provs, nil } // RemoveProvisioner performs the DELETE /admin/provisioners/{name} request to the CA.