Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
dopey committed May 19, 2021
1 parent af3cf7d commit 98a6e54
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 126 deletions.
26 changes: 11 additions & 15 deletions authority/mgmt/admin.go
Expand Up @@ -4,25 +4,21 @@ import "context"

// Admin type.
type Admin struct {
ID string `json:"-"`
AuthorityID string `json:"-"`
ProvisionerID string `json:"provisionerID"`
Name string `json:"name"`
ProvisionerName string `json:"provisionerName"`
ProvisionerType string `json:"provisionerType"`
IsSuperAdmin bool `json:"isSuperAdmin"`
Status StatusType `json:"status"`
ID string `json:"id"`
AuthorityID string `json:"-"`
ProvisionerID string `json:"provisionerID"`
Name string `json:"name"`
IsSuperAdmin bool `json:"isSuperAdmin"`
Status StatusType `json:"status"`
}

// CreateAdmin builds and stores an admin type in the DB.
func CreateAdmin(ctx context.Context, db DB, name string, prov *Provisioner, isSuperAdmin bool) (*Admin, error) {
func CreateAdmin(ctx context.Context, db DB, name string, provID string, isSuperAdmin bool) (*Admin, error) {
adm := &Admin{
Name: name,
ProvisionerID: prov.ID,
ProvisionerName: prov.Name,
ProvisionerType: prov.Type,
IsSuperAdmin: isSuperAdmin,
Status: StatusActive,
Name: name,
ProvisionerID: provID,
IsSuperAdmin: isSuperAdmin,
Status: StatusActive,
}
if err := db.CreateAdmin(ctx, adm); err != nil {
return nil, WrapErrorISE(err, "error creating admin")
Expand Down
40 changes: 24 additions & 16 deletions authority/mgmt/api/provisioner.go
@@ -1,6 +1,7 @@
package api

import (
"fmt"
"net/http"

"github.com/go-chi/chi"
Expand All @@ -10,12 +11,14 @@ import (

// CreateProvisionerRequest represents the body for a CreateProvisioner request.
type CreateProvisionerRequest struct {
Type string `json:"type"`
Name string `json:"name"`
Claims *mgmt.Claims `json:"claims"`
Details interface{} `json:"details"`
X509Template string `json:"x509Template"`
SSHTemplate string `json:"sshTemplate"`
Type string `json:"type"`
Name string `json:"name"`
Claims *mgmt.Claims `json:"claims"`
Details interface{} `json:"details"`
X509Template string `json:"x509Template"`
X509TemplateData []byte `json:"x509TemplateData"`
SSHTemplate string `json:"sshTemplate"`
SSHTemplateData []byte `json:"sshTemplateData"`
}

// Validate validates a new-provisioner request body.
Expand All @@ -25,10 +28,12 @@ func (car *CreateProvisionerRequest) Validate() error {

// UpdateProvisionerRequest represents the body for a UpdateProvisioner request.
type UpdateProvisionerRequest struct {
Claims *mgmt.Claims `json:"claims"`
Details interface{} `json:"details"`
X509Template string `json:"x509Template"`
SSHTemplate string `json:"sshTemplate"`
Claims *mgmt.Claims `json:"claims"`
Details interface{} `json:"details"`
X509Template string `json:"x509Template"`
X509TemplateData []byte `json:"x509TemplateData"`
SSHTemplate string `json:"sshTemplate"`
SSHTemplateData []byte `json:"sshTemplateData"`
}

// Validate validates a new-provisioner request body.
Expand Down Expand Up @@ -58,6 +63,7 @@ func (h *Handler) GetProvisioners(w http.ResponseWriter, r *http.Request) {
api.WriteError(w, err)
return
}
fmt.Printf("provs = %+v\n", provs)
api.JSON(w, provs)
}

Expand All @@ -75,12 +81,14 @@ func (h *Handler) CreateProvisioner(w http.ResponseWriter, r *http.Request) {
}

prov := &mgmt.Provisioner{
Type: body.Type,
Name: body.Name,
Claims: body.Claims,
Details: body.Details,
X509Template: body.X509Template,
SSHTemplate: body.SSHTemplate,
Type: body.Type,
Name: body.Name,
Claims: body.Claims,
Details: body.Details,
X509Template: body.X509Template,
X509TemplateData: body.X509TemplateData,
SSHTemplate: body.SSHTemplate,
SSHTemplateData: body.SSHTemplateData,
}
if err := h.db.CreateProvisioner(ctx, prov); err != nil {
api.WriteError(w, err)
Expand Down
14 changes: 13 additions & 1 deletion authority/mgmt/config.go
Expand Up @@ -2,6 +2,7 @@ package mgmt

import (
"context"
"fmt"

"github.com/pkg/errors"
"github.com/smallstep/certificates/authority/config"
Expand All @@ -24,6 +25,17 @@ const (
StatusDeleted
)

func (st StatusType) String() string {
switch st {
case StatusActive:
return "active"
case StatusDeleted:
return "deleted"
default:
return fmt.Sprintf("status %d not found", st)
}
}

// Claims encapsulates all x509 and ssh claims applied to the authority
// configuration. E.g. maxTLSCertDuration, defaultSSHCertDuration, etc.
type Claims struct {
Expand Down Expand Up @@ -111,7 +123,7 @@ func CreateAuthority(ctx context.Context, db DB, options ...AuthorityOption) (*A
return nil, WrapErrorISE(err, "error creating first provisioner")
}

admin, err := CreateAdmin(ctx, db, "Change Me", prov, true)
admin, err := CreateAdmin(ctx, db, "Change Me", prov.ID, true)
if err != nil {
// TODO should we try to clean up?
return nil, WrapErrorISE(err, "error creating first provisioner")
Expand Down
8 changes: 1 addition & 7 deletions authority/mgmt/db/nosql/admin.go
Expand Up @@ -63,19 +63,13 @@ func (db *DB) GetAdmin(ctx context.Context, id string) (*mgmt.Admin, error) {
return nil, err
}
if adm.Status == mgmt.StatusDeleted {
return nil, mgmt.NewError(mgmt.ErrorDeletedType, "admin %s is deleted")
return nil, mgmt.NewError(mgmt.ErrorDeletedType, "admin %s is deleted", adm.ID)
}
if adm.AuthorityID != db.authorityID {
return nil, mgmt.NewError(mgmt.ErrorAuthorityMismatchType,
"admin %s is not owned by authority %s", adm.ID, db.authorityID)
}

prov, err := db.GetProvisioner(ctx, adm.ProvisionerID)
if err != nil {
return nil, err
}
adm.ProvisionerName = prov.Name
adm.ProvisionerType = prov.Type
return adm, nil
}

Expand Down
115 changes: 99 additions & 16 deletions authority/mgmt/db/nosql/provisioner.go
Expand Up @@ -3,6 +3,7 @@ package nosql
import (
"context"
"encoding/json"
"fmt"
"time"

"github.com/pkg/errors"
Expand All @@ -12,16 +13,18 @@ import (

// dbProvisioner is the database representation of a Provisioner type.
type dbProvisioner struct {
ID string `json:"id"`
AuthorityID string `json:"authorityID"`
Type string `json:"type"`
Name string `json:"name"`
Claims *mgmt.Claims `json:"claims"`
Details interface{} `json:"details"`
X509Template string `json:"x509Template"`
SSHTemplate string `json:"sshTemplate"`
CreatedAt time.Time `json:"createdAt"`
DeletedAt time.Time `json:"deletedAt"`
ID string `json:"id"`
AuthorityID string `json:"authorityID"`
Type string `json:"type"`
Name string `json:"name"`
Claims *mgmt.Claims `json:"claims"`
Details []byte `json:"details"`
X509Template string `json:"x509Template"`
X509TemplateData []byte `json:"x509TemplateData"`
SSHTemplate string `json:"sshTemplate"`
SSHTemplateData []byte `json:"sshTemplateData"`
CreatedAt time.Time `json:"createdAt"`
DeletedAt time.Time `json:"deletedAt"`
}

func (dbp *dbProvisioner) clone() *dbProvisioner {
Expand Down Expand Up @@ -84,19 +87,36 @@ func unmarshalDBProvisioner(data []byte, id string) (*dbProvisioner, error) {
return dbp, nil
}

type detailsType struct {
Type mgmt.ProvisionerType
}

func unmarshalProvisioner(data []byte, id string) (*mgmt.Provisioner, error) {
dbp, err := unmarshalDBProvisioner(data, id)
if err != nil {
return nil, err
}

dt := new(detailsType)
if err := json.Unmarshal(dbp.Details, dt); err != nil {
return nil, mgmt.WrapErrorISE(err, "error unmarshaling details to detailsType for provisioner %s", id)
}
details, err := unmarshalDetails(dt.Type, dbp.Details)
if err != nil {
return nil, err
}

prov := &mgmt.Provisioner{
ID: dbp.ID,
Type: dbp.Type,
Name: dbp.Name,
Claims: dbp.Claims,
X509Template: dbp.X509Template,
SSHTemplate: dbp.SSHTemplate,
ID: dbp.ID,
AuthorityID: dbp.AuthorityID,
Type: dbp.Type,
Name: dbp.Name,
Claims: dbp.Claims,
Details: details,
X509Template: dbp.X509Template,
X509TemplateData: dbp.X509TemplateData,
SSHTemplate: dbp.SSHTemplate,
SSHTemplateData: dbp.SSHTemplateData,
}
if !dbp.DeletedAt.IsZero() {
prov.Status = mgmt.StatusDeleted
Expand Down Expand Up @@ -172,3 +192,66 @@ func (db *DB) UpdateProvisioner(ctx context.Context, prov *mgmt.Provisioner) err

return db.save(ctx, old.ID, nu, old, "provisioner", authorityProvisionersTable)
}

func unmarshalDetails(typ ProvisionerType, details []byte) (interface{}, error) {
if !s.Valid {
return nil, nil
}
var v isProvisionerDetails_Data
switch typ {
case ProvisionerTypeJWK:
p := new(ProvisionerDetailsJWK)
if err := json.Unmarshal([]byte(s.String), p); err != nil {
return nil, err
}
if p.JWK.Key.Key == nil {
key, err := LoadKey(ctx, db, p.JWK.Key.Id.Id)
if err != nil {
return nil, err
}
p.JWK.Key = key
}
return &ProvisionerDetails{Data: p}, nil
case ProvisionerType_OIDC:
v = new(ProvisionerDetails_OIDC)
case ProvisionerType_GCP:
v = new(ProvisionerDetails_GCP)
case ProvisionerType_AWS:
v = new(ProvisionerDetails_AWS)
case ProvisionerType_AZURE:
v = new(ProvisionerDetails_Azure)
case ProvisionerType_ACME:
v = new(ProvisionerDetails_ACME)
case ProvisionerType_X5C:
p := new(ProvisionerDetails_X5C)
if err := json.Unmarshal([]byte(s.String), p); err != nil {
return nil, err
}
for _, k := range p.X5C.GetRoots() {
if err := k.Select(ctx, db, k.Id.Id); err != nil {
return nil, err
}
}
return &ProvisionerDetails{Data: p}, nil
case ProvisionerType_K8SSA:
p := new(ProvisionerDetails_K8SSA)
if err := json.Unmarshal([]byte(s.String), p); err != nil {
return nil, err
}
for _, k := range p.K8SSA.GetPublicKeys() {
if err := k.Select(ctx, db, k.Id.Id); err != nil {
return nil, err
}
}
return &ProvisionerDetails{Data: p}, nil
case ProvisionerType_SSHPOP:
v = new(ProvisionerDetails_SSHPOP)
default:
return nil, fmt.Errorf("unsupported provisioner type %s", typ)
}

if err := json.Unmarshal([]byte(s.String), v); err != nil {
return nil, err
}
return &ProvisionerDetails{Data: v}, nil
}

0 comments on commit 98a6e54

Please sign in to comment.