Skip to content

Commit 4f3e5ef

Browse files
committedMay 19, 2021
wip
1 parent 5d09d04 commit 4f3e5ef

18 files changed

+276
-400
lines changed
 

‎api/api.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ func certChainToPEM(certChain []*x509.Certificate) []Certificate {
316316

317317
// Provisioners returns the list of provisioners configured in the authority.
318318
func (h *caHandler) Provisioners(w http.ResponseWriter, r *http.Request) {
319-
cursor, limit, err := parseCursor(r)
319+
cursor, limit, err := ParseCursor(r)
320320
if err != nil {
321321
WriteError(w, errs.BadRequestErr(err))
322322
return
@@ -427,7 +427,8 @@ func LogCertificate(w http.ResponseWriter, cert *x509.Certificate) {
427427
}
428428
}
429429

430-
func parseCursor(r *http.Request) (cursor string, limit int, err error) {
430+
// ParseCursor parses the cursor and limit from the request query params.
431+
func ParseCursor(r *http.Request) (cursor string, limit int, err error) {
431432
q := r.URL.Query()
432433
cursor = q.Get("cursor")
433434
if v := q.Get("limit"); len(v) > 0 {

‎authority/admin/admin.go

+18-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
package admin
22

3-
// Type specifies the type of administrator privileges the admin has.
3+
import "github.com/smallstep/certificates/authority/status"
4+
5+
// Type specifies the type of the admin. e.g. SUPER_ADMIN, REGULAR
46
type Type string
57

8+
var (
9+
// TypeSuper superadmin
10+
TypeSuper = Type("SUPER_ADMIN")
11+
// TypeRegular regular
12+
TypeRegular = Type("REGULAR")
13+
)
14+
615
// Admin type.
716
type Admin struct {
8-
ID string `json:"id"`
9-
AuthorityID string `json:"-"`
10-
Subject string `json:"subject"`
11-
ProvisionerName string `json:"provisionerName"`
12-
ProvisionerType string `json:"provisionerType"`
13-
ProvisionerID string `json:"provisionerID"`
14-
Type Type `json:"type"`
17+
ID string `json:"id"`
18+
AuthorityID string `json:"-"`
19+
Subject string `json:"subject"`
20+
ProvisionerName string `json:"provisionerName"`
21+
ProvisionerType string `json:"provisionerType"`
22+
ProvisionerID string `json:"provisionerID"`
23+
Type Type `json:"type"`
24+
Status status.Type `json:"status"`
1525
}

‎authority/admin/collection.go

+49-32
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,54 @@ package admin
22

33
import (
44
"crypto/sha1"
5+
"encoding/binary"
6+
"encoding/hex"
7+
"fmt"
8+
"sort"
9+
"strings"
510
"sync"
611

712
"github.com/pkg/errors"
8-
"go.step.sm/crypto/jose"
13+
"github.com/smallstep/certificates/authority/provisioner"
914
)
1015

11-
// DefaultProvisionersLimit is the default limit for listing provisioners.
12-
const DefaultProvisionersLimit = 20
16+
// DefaultAdminLimit is the default limit for listing provisioners.
17+
const DefaultAdminLimit = 20
1318

14-
// DefaultProvisionersMax is the maximum limit for listing provisioners.
15-
const DefaultProvisionersMax = 100
19+
// DefaultAdminMax is the maximum limit for listing provisioners.
20+
const DefaultAdminMax = 100
1621

17-
/*
18-
type uidProvisioner struct {
19-
provisioner Interface
20-
uid string
22+
type uidAdmin struct {
23+
admin *Admin
24+
uid string
2125
}
2226

23-
type provisionerSlice []uidProvisioner
24-
25-
func (p provisionerSlice) Len() int { return len(p) }
26-
func (p provisionerSlice) Less(i, j int) bool { return p[i].uid < p[j].uid }
27-
func (p provisionerSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
28-
*/
27+
type adminSlice []uidAdmin
2928

30-
// loadByTokenPayload is a payload used to extract the id used to load the
31-
// provisioner.
32-
type loadByTokenPayload struct {
33-
jose.Claims
34-
AuthorizedParty string `json:"azp"` // OIDC client id
35-
TenantID string `json:"tid"` // Microsoft Azure tenant id
36-
}
29+
func (p adminSlice) Len() int { return len(p) }
30+
func (p adminSlice) Less(i, j int) bool { return p[i].uid < p[j].uid }
31+
func (p adminSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
3732

3833
// Collection is a memory map of admins.
3934
type Collection struct {
4035
byID *sync.Map
4136
bySubProv *sync.Map
4237
byProv *sync.Map
38+
sorted adminSlice
39+
provisioners *provisioner.Collection
4340
count int
4441
countByProvisioner map[string]int
4542
}
4643

4744
// NewCollection initializes a collection of provisioners. The given list of
4845
// audiences are the audiences used by the JWT provisioner.
49-
func NewCollection() *Collection {
46+
func NewCollection(provisioners *provisioner.Collection) *Collection {
5047
return &Collection{
5148
byID: new(sync.Map),
5249
byProv: new(sync.Map),
5350
bySubProv: new(sync.Map),
5451
countByProvisioner: map[string]int{},
52+
provisioners: provisioners,
5553
}
5654
}
5755

@@ -88,12 +86,18 @@ func (c *Collection) LoadByProvisioner(provName string) ([]*Admin, bool) {
8886
// Store adds an admin to the collection and enforces the uniqueness of
8987
// admin IDs and amdin subject <-> provisioner name combos.
9088
func (c *Collection) Store(adm *Admin) error {
91-
provName := adm.ProvisionerName
89+
p, ok := c.provisioners.Load(adm.ProvisionerID)
90+
if !ok {
91+
return fmt.Errorf("provisioner %s not found", adm.ProvisionerID)
92+
}
93+
adm.ProvisionerName = p.GetName()
94+
adm.ProvisionerType = p.GetType().String()
9295
// Store admin always in byID. ID must be unique.
9396
if _, loaded := c.byID.LoadOrStore(adm.ID, adm); loaded {
9497
return errors.New("cannot add multiple admins with the same id")
9598
}
9699

100+
provName := adm.ProvisionerName
97101
// Store admin alwasy in bySubProv. Subject <-> ProvisionerName must be unique.
98102
if _, loaded := c.bySubProv.LoadOrStore(subProvNameHash(adm.Subject, provName), adm); loaded {
99103
c.byID.Delete(adm.ID)
@@ -109,6 +113,21 @@ func (c *Collection) Store(adm *Admin) error {
109113
}
110114
c.count++
111115

116+
// Store sorted admins.
117+
// Use the first 4 bytes (32bit) of the sum to insert the order
118+
// Using big endian format to get the strings sorted:
119+
// 0x00000000, 0x00000001, 0x00000002, ...
120+
bi := make([]byte, 4)
121+
_sum := sha1.Sum([]byte(adm.ID))
122+
sum := _sum[:]
123+
binary.BigEndian.PutUint32(bi, uint32(c.sorted.Len()))
124+
sum[0], sum[1], sum[2], sum[3] = bi[0], bi[1], bi[2], bi[3]
125+
c.sorted = append(c.sorted, uidAdmin{
126+
admin: adm,
127+
uid: hex.EncodeToString(sum),
128+
})
129+
sort.Sort(c.sorted)
130+
112131
return nil
113132
}
114133

@@ -125,31 +144,29 @@ func (c *Collection) CountByProvisioner(provName string) int {
125144
return 0
126145
}
127146

128-
/*
129147
// Find implements pagination on a list of sorted provisioners.
130-
func (c *Collection) Find(cursor string, limit int) (List, string) {
148+
func (c *Collection) Find(cursor string, limit int) ([]*Admin, string) {
131149
switch {
132150
case limit <= 0:
133-
limit = DefaultProvisionersLimit
134-
case limit > DefaultProvisionersMax:
135-
limit = DefaultProvisionersMax
151+
limit = DefaultAdminLimit
152+
case limit > DefaultAdminMax:
153+
limit = DefaultAdminMax
136154
}
137155

138156
n := c.sorted.Len()
139157
cursor = fmt.Sprintf("%040s", cursor)
140158
i := sort.Search(n, func(i int) bool { return c.sorted[i].uid >= cursor })
141159

142-
slice := List{}
160+
slice := []*Admin{}
143161
for ; i < n && len(slice) < limit; i++ {
144-
slice = append(slice, c.sorted[i].provisioner)
162+
slice = append(slice, c.sorted[i].admin)
145163
}
146164

147165
if i < n {
148166
return slice, strings.TrimLeft(c.sorted[i].uid, "0")
149167
}
150168
return slice, ""
151169
}
152-
*/
153170

154171
func loadAdmin(m *sync.Map, key string) (*Admin, bool) {
155172
a, ok := m.Load(key)

‎authority/authority.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func (a *Authority) ReloadAuthConfig() error {
175175
}
176176
}
177177
// Store all the admins
178-
a.admins = admin.NewCollection()
178+
a.admins = admin.NewCollection(a.provisioners)
179179
for _, adm := range a.config.AuthorityConfig.Admins {
180180
if err := a.admins.Store(adm); err != nil {
181181
return err
@@ -431,7 +431,7 @@ func (a *Authority) init() error {
431431
}
432432
}
433433
// Store all the admins
434-
a.admins = admin.NewCollection()
434+
a.admins = admin.NewCollection(a.provisioners)
435435
for _, adm := range a.config.AuthorityConfig.Admins {
436436
if err := a.admins.Store(adm); err != nil {
437437
return err

‎authority/mgmt/admin.go

+5-37
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,23 @@
11
package mgmt
22

33
import (
4-
"context"
5-
64
"github.com/smallstep/certificates/authority/admin"
75
)
86

97
// AdminType specifies the type of the admin. e.g. SUPER_ADMIN, REGULAR
10-
type AdminType string
8+
type AdminType admin.Type
119

1210
var (
1311
// AdminTypeSuper superadmin
14-
AdminTypeSuper = AdminType("SUPER_ADMIN")
12+
AdminTypeSuper = admin.TypeSuper
1513
// AdminTypeRegular regular
16-
AdminTypeRegular = AdminType("REGULAR")
14+
AdminTypeRegular = admin.TypeRegular
1715
)
1816

1917
// Admin type.
20-
type Admin struct {
21-
ID string `json:"id"`
22-
AuthorityID string `json:"-"`
23-
ProvisionerID string `json:"provisionerID"`
24-
Subject string `json:"subject"`
25-
ProvisionerName string `json:"provisionerName"`
26-
ProvisionerType string `json:"provisionerType"`
27-
Type AdminType `json:"type"`
28-
Status StatusType `json:"status"`
29-
}
30-
31-
// CreateAdmin builds and stores an admin type in the DB.
32-
func CreateAdmin(ctx context.Context, db DB, provName, sub string, typ AdminType) (*Admin, error) {
33-
adm := &Admin{
34-
Subject: sub,
35-
ProvisionerName: provName,
36-
Type: typ,
37-
Status: StatusActive,
38-
}
39-
if err := db.CreateAdmin(ctx, adm); err != nil {
40-
return nil, WrapErrorISE(err, "error creating admin")
41-
}
42-
return adm, nil
43-
}
18+
type Admin admin.Admin
4419

4520
// ToCertificates converts an Admin to the Admin type expected by the authority.
4621
func (adm *Admin) ToCertificates() (*admin.Admin, error) {
47-
return &admin.Admin{
48-
ID: adm.ID,
49-
Subject: adm.Subject,
50-
ProvisionerID: adm.ProvisionerID,
51-
ProvisionerName: adm.ProvisionerName,
52-
ProvisionerType: adm.ProvisionerType,
53-
Type: admin.Type(adm.Type),
54-
}, nil
22+
return (*admin.Admin)(adm), nil
5523
}

0 commit comments

Comments
 (0)