diff --git a/api/api.go b/api/api.go index 4439bc04..15b82be3 100644 --- a/api/api.go +++ b/api/api.go @@ -31,7 +31,7 @@ type Authority interface { Root(shasum string) (*x509.Certificate, error) Sign(cr *x509.CertificateRequest, signOpts authority.SignOptions, extraOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) Renew(peer *x509.Certificate) (*x509.Certificate, *x509.Certificate, error) - GetProvisioners(cursor string, limit int) ([]*provisioner.Provisioner, string, error) + GetProvisioners(cursor string, limit int) (provisioner.List, string, error) GetEncryptedKey(kid string) (string, error) GetRoots() (federation []*x509.Certificate, err error) GetFederation() ([]*x509.Certificate, error) @@ -162,8 +162,8 @@ type SignRequest struct { // ProvisionersResponse is the response object that returns the list of // provisioners. type ProvisionersResponse struct { - Provisioners []*provisioner.Provisioner `json:"provisioners"` - NextCursor string `json:"nextCursor"` + Provisioners provisioner.List `json:"provisioners"` + NextCursor string `json:"nextCursor"` } // ProvisionerKeyResponse is the response object that returns the encryptoed key diff --git a/authority/config.go b/authority/config.go index 44e6b6c2..406fd437 100644 --- a/authority/config.go +++ b/authority/config.go @@ -52,10 +52,10 @@ type Config struct { // AuthConfig represents the configuration options for the authority. type AuthConfig struct { - Provisioners []*provisioner.Provisioner `json:"provisioners"` - Template *x509util.ASN1DN `json:"template,omitempty"` - Claims *provisioner.Claims `json:"claims,omitempty"` - DisableIssuedAtCheck bool `json:"disableIssuedAtCheck,omitempty"` + Provisioners provisioner.List `json:"provisioners"` + Template *x509util.ASN1DN `json:"template,omitempty"` + Claims *provisioner.Claims `json:"claims,omitempty"` + DisableIssuedAtCheck bool `json:"disableIssuedAtCheck,omitempty"` } // Validate validates the authority configuration. diff --git a/authority/provisioner/collection.go b/authority/provisioner/collection.go index 7488c7cd..8f3c1009 100644 --- a/authority/provisioner/collection.go +++ b/authority/provisioner/collection.go @@ -23,7 +23,7 @@ const DefaultProvisionersLimit = 20 const DefaultProvisionersMax = 100 type uidProvisioner struct { - provisioner *Provisioner + provisioner Interface uid string } @@ -52,12 +52,12 @@ func NewCollection(audiences []string) *Collection { } // Load a provisioner by the ID. -func (c *Collection) Load(id string) (*Provisioner, bool) { +func (c *Collection) Load(id string) (Interface, bool) { return loadProvisioner(c.byID, id) } // LoadByToken parses the token claims and loads the provisioner associated. -func (c *Collection) LoadByToken(token *jose.JSONWebToken, claims *jose.Claims) (*Provisioner, bool) { +func (c *Collection) LoadByToken(token *jose.JSONWebToken, claims *jose.Claims) (Interface, bool) { // match with server audiences if matchesAudience(claims.Audience, c.audiences) { // If matches with stored audiences it will be a JWT token (default), and @@ -82,7 +82,7 @@ func (c *Collection) LoadByToken(token *jose.JSONWebToken, claims *jose.Claims) // LoadByCertificate lookds for the provisioner extension and extracts the // proper id to load the provisioner. -func (c *Collection) LoadByCertificate(cert *x509.Certificate) (*Provisioner, bool) { +func (c *Collection) LoadByCertificate(cert *x509.Certificate) (Interface, bool) { for _, e := range cert.Extensions { if e.Id.Equal(stepOIDProvisioner) { var provisioner stepProvisionerASN1 @@ -111,7 +111,7 @@ func (c *Collection) LoadEncryptedKey(keyID string) (string, bool) { // Store adds a provisioner to the collection, it makes sure two provisioner // does not have the same ID. -func (c *Collection) Store(p *Provisioner) error { +func (c *Collection) Store(p Interface) error { // Store provisioner always in byID. ID must be unique. if _, loaded := c.byID.LoadOrStore(p.GetID(), p); loaded == true { return errors.New("cannot add multiple provisioners with the same id") @@ -142,7 +142,7 @@ func (c *Collection) Store(p *Provisioner) error { } // Find implements pagination on a list of sorted provisioners. -func (c *Collection) Find(cursor string, limit int) ([]*Provisioner, string) { +func (c *Collection) Find(cursor string, limit int) (List, string) { switch { case limit <= 0: limit = DefaultProvisionersLimit @@ -154,7 +154,7 @@ func (c *Collection) Find(cursor string, limit int) ([]*Provisioner, string) { cursor = fmt.Sprintf("%040s", cursor) i := sort.Search(n, func(i int) bool { return c.sorted[i].uid >= cursor }) - slice := []*Provisioner{} + slice := List{} for ; i < n && len(slice) < limit; i++ { slice = append(slice, c.sorted[i].provisioner) } @@ -165,12 +165,12 @@ func (c *Collection) Find(cursor string, limit int) ([]*Provisioner, string) { return slice, "" } -func loadProvisioner(m *sync.Map, key string) (*Provisioner, bool) { +func loadProvisioner(m *sync.Map, key string) (Interface, bool) { i, ok := m.Load(key) if !ok { return nil, false } - p, ok := i.(*Provisioner) + p, ok := i.(Interface) if !ok { return nil, false } @@ -179,7 +179,7 @@ func loadProvisioner(m *sync.Map, key string) (*Provisioner, bool) { // provisionerSum returns the SHA1 of the provisioners ID. From this we will // create the unique and sorted id. -func provisionerSum(p *Provisioner) ([]byte, error) { +func provisionerSum(p Interface) ([]byte, error) { sum := sha1.Sum([]byte(p.GetID())) return sum[:], nil } diff --git a/authority/provisioner/provisioner.go b/authority/provisioner/provisioner.go index 96b6ea19..74c2a13c 100644 --- a/authority/provisioner/provisioner.go +++ b/authority/provisioner/provisioner.go @@ -44,91 +44,36 @@ type provisioner struct { Type string `json:"type"` } -// Provisioner implements the provisioner.Interface on a base provisioner. It -// also implements custom marshalers and unmarshalers so different provisioners -// can be represented in a configuration type. -type Provisioner struct { - base Interface -} - -// New creates a new provisioner from the base provisioner. -func New(base Interface) *Provisioner { - return &Provisioner{ - base: base, +// List represents a list of provisioners. +type List []Interface + +// UnmarshalJSON implements json.Unmarshaler and allows to unmarshal a list of a +// interfaces into the right type. +func (l *List) UnmarshalJSON(data []byte) error { + ps := []json.RawMessage{} + if err := json.Unmarshal(data, &ps); err != nil { + return errors.Wrap(err, "error unmarshaling provisioner list") } -} - -// Base returns the base type of the provisioner. -func (p *Provisioner) Base() Interface { - return p.base -} - -// GetID returns the base provisioner unique ID. This identifier is used as the -// key in a provisioner.Collection. -func (p *Provisioner) GetID() string { - return p.base.GetID() -} - -// GetEncryptedKey returns the base provisioner encrypted key if it's defined. -func (p *Provisioner) GetEncryptedKey() (string, string, bool) { - return p.base.GetEncryptedKey() -} - -// GetName returns the name of the provisioner -func (p *Provisioner) GetName() string { - return p.base.GetName() -} - -// GetType return the provisioners type. -func (p *Provisioner) GetType() Type { - return p.base.GetType() -} -// Init initializes the base provisioner with the given claims. -func (p *Provisioner) Init(c Config) error { - return p.base.Init(c) -} - -// Authorize validates the given token on the base provisioner returning a list -// of options to validate the signing request. -func (p *Provisioner) Authorize(token string) ([]SignOption, error) { - return p.base.Authorize(token) -} - -// AuthorizeRenewal checks if the base provisioner authorizes the renewal. -func (p *Provisioner) AuthorizeRenewal(cert *x509.Certificate) error { - return p.base.AuthorizeRenewal(cert) -} - -// AuthorizeRevoke checks on the base provisioner if the given token has revoke -// access. -func (p *Provisioner) AuthorizeRevoke(token string) error { - return p.base.AuthorizeRevoke(token) -} - -// MarshalJSON implements the json.Marshaler interface on the Provisioner type. -func (p *Provisioner) MarshalJSON() ([]byte, error) { - return json.Marshal(p.base) -} - -// UnmarshalJSON implements the json.Unmarshaler interface on the Provisioner -// type. -func (p *Provisioner) UnmarshalJSON(data []byte) error { - var typ provisioner - if err := json.Unmarshal(data, &typ); err != nil { - return errors.Errorf("error unmarshaling provisioner") + for _, data := range ps { + var typ provisioner + if err := json.Unmarshal(data, &typ); err != nil { + return errors.Errorf("error unmarshaling provisioner") + } + var p Interface + switch strings.ToLower(typ.Type) { + case "jwk": + p = &JWK{} + case "oidc": + p = &OIDC{} + default: + return errors.Errorf("provisioner type %s not supported", typ.Type) + } + if err := json.Unmarshal(data, p); err != nil { + return errors.Errorf("error unmarshaling provisioner") + } + *l = append(*l, p) } - switch strings.ToLower(typ.Type) { - case "jwk": - p.base = &JWK{} - case "oidc": - p.base = &OIDC{} - default: - return errors.Errorf("provisioner type %s not supported", typ.Type) - } - if err := json.Unmarshal(data, &p.base); err != nil { - return errors.Errorf("error unmarshaling provisioner") - } return nil } diff --git a/authority/provisioners.go b/authority/provisioners.go index dcea9121..d3072d12 100644 --- a/authority/provisioners.go +++ b/authority/provisioners.go @@ -19,7 +19,7 @@ func (a *Authority) GetEncryptedKey(kid string) (string, error) { // GetProvisioners returns a map listing each provisioner and the JWK Key Set // with their public keys. -func (a *Authority) GetProvisioners(cursor string, limit int) ([]*provisioner.Provisioner, string, error) { +func (a *Authority) GetProvisioners(cursor string, limit int) (provisioner.List, string, error) { provisioners, nextCursor := a.provisioners.Find(cursor, limit) return provisioners, nextCursor, nil }