Skip to content
This repository was archived by the owner on Jul 11, 2023. It is now read-only.

Commit 00f10a7

Browse files
committed
a few tests implemented
Signed-off-by: Sean Teeling <[email protected]>
1 parent 35d03d6 commit 00f10a7

File tree

5 files changed

+137
-133
lines changed

5 files changed

+137
-133
lines changed

pkg/certificate/certificate.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ const (
2626
func (c *Certificate) newMergedWithRoot(root pem.RootCertificate) *Certificate {
2727
cert := *c
2828

29-
buf := make([]byte, 0, len(root)+len(c.IssuingCA)+1)
30-
buf = append(buf, root...)
31-
buf = append(buf, '\n')
29+
buf := make([]byte, 0, len(root)+len(c.IssuingCA))
3230
buf = append(buf, c.IssuingCA...)
31+
buf = append(buf, root...)
3332
cert.IssuingCA = buf
3433
return &cert
3534
}

pkg/certificate/fake_manager.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"k8s.io/client-go/tools/cache"
88

99
"github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
10+
"github.com/openservicemesh/osm/pkg/certificate/pem"
1011
)
1112

1213
var (
@@ -34,15 +35,22 @@ func (c *fakeMRCClient) List() ([]*v1alpha2.MeshRootCertificate, error) {
3435
func (c *fakeMRCClient) AddEventHandler(cache.ResourceEventHandler) {}
3536

3637
type fakeIssuer struct {
37-
err error
38+
err bool
39+
id string
3840
}
3941

4042
// IssueCertificate is a testing helper to satisfy the certificate client interface
4143
func (i *fakeIssuer) IssueCertificate(cn CommonName, validityPeriod time.Duration) (*Certificate, error) {
44+
if i.err {
45+
return nil, fmt.Errorf("%s failed", i.id)
46+
}
4247
return &Certificate{
4348
CommonName: cn,
4449
Expiration: time.Now().Add(validityPeriod),
45-
}, i.err
50+
// simply used to distinguish the private/public key from other issuers
51+
IssuingCA: pem.RootCertificate(i.id),
52+
PrivateKey: pem.PrivateKey(i.id),
53+
}, nil
4654
}
4755

4856
func (i *fakeIssuer) GetRootCertificate() *Certificate {

pkg/certificate/manager.go

+25-39
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package certificate
22

33
import (
4+
"fmt"
45
"time"
56

67
"github.com/pkg/errors"
78
"github.com/rs/zerolog/log"
89

910
"github.com/openservicemesh/osm/pkg/announcements"
10-
"github.com/openservicemesh/osm/pkg/certificate/pem"
1111
"github.com/openservicemesh/osm/pkg/errcode"
1212
"github.com/openservicemesh/osm/pkg/k8s/events"
1313
"github.com/openservicemesh/osm/pkg/messaging"
@@ -28,10 +28,12 @@ func NewManager(mrcClient MRCClient, serviceCertValidityDuration time.Duration,
2828
return nil, err
2929
}
3030

31+
c := &issuer{Issuer: client, ID: clientID}
32+
3133
m := &Manager{
3234
// The root certificate signing all newly issued certificates
33-
clients: map[string]Issuer{clientID: client},
34-
keyIssuer: clientID,
35+
keyIssuer: c,
36+
pubIssuer: c,
3537
serviceCertValidityDuration: serviceCertValidityDuration,
3638
msgBroker: msgBroker,
3739
}
@@ -96,57 +98,41 @@ func (m *Manager) getFromCache(cn CommonName) *Certificate {
9698
log.Trace().Msgf("Certificate found in cache SerialNumber=%s", cert.GetSerialNumber())
9799
if cert.ShouldRotate() {
98100
log.Trace().Msgf("Certificate found in cache but has expired SerialNumber=%s", cert.GetSerialNumber())
101+
return nil
99102
}
100103
return cert
101104
}
102105

103106
// IssueCertificate implements Manager and returns a newly issued certificate from the given client.
104107
func (m *Manager) IssueCertificate(cn CommonName, validityPeriod time.Duration) (*Certificate, error) {
105-
var additionalRoot pem.RootCertificate
106-
108+
// var additionalRoot pem.RootCertificate
109+
var err error
107110
cert := m.getFromCache(cn) // Don't call this while holding the lock
108111

109-
m.mu.Lock()
112+
m.mu.RLock()
110113
pubIssuer := m.pubIssuer
111114
keyIssuer := m.keyIssuer
115+
m.mu.RUnlock()
112116

113-
if pubIssuer != "" && (cert == nil || cert.pubIssuer != pubIssuer) {
114-
pubCert, err := m.clients[keyIssuer].IssueCertificate(cn, validityPeriod)
117+
start := time.Now()
118+
if cert == nil || cert.keyIssuer != keyIssuer.ID || cert.pubIssuer != pubIssuer.ID {
119+
fmt.Println("issuing!")
120+
cert, err = keyIssuer.IssueCertificate(cn, validityPeriod)
115121
if err != nil {
116122
return nil, err
117123
}
118-
additionalRoot = pubCert.GetIssuingCA()
119-
}
120-
121-
m.mu.Unlock()
122-
123-
// this can be nil
124-
switch {
125-
case cert == nil:
126-
break
127-
case cert.keyIssuer != keyIssuer:
128-
break
129-
case cert.pubIssuer == pubIssuer:
130-
return cert, nil
131-
case cert.pubIssuer != pubIssuer:
132-
// copy to avoid mutating original. The copied fields may be pointers as well, but those shouldn't be modified
133-
// later, and the field we mutate is completely changed.
134-
certCopy := *cert
135-
cert = cert.newMergedWithRoot(additionalRoot)
136-
cert = &certCopy
137-
m.cache.Store(cn, &cert)
138-
return cert, nil
139-
}
124+
if pubIssuer.ID != keyIssuer.ID {
125+
pubCert, err := pubIssuer.IssueCertificate(cn, validityPeriod)
126+
if err != nil {
127+
return nil, err
128+
}
140129

141-
start := time.Now()
142-
cert, err := m.clients[keyIssuer].IssueCertificate(cn, validityPeriod)
143-
if err != nil {
144-
return nil, err
145-
}
130+
cert = cert.newMergedWithRoot(pubCert.GetIssuingCA())
131+
}
146132

147-
if pubIssuer != "" {
148-
// Add the other issuing CA
149-
cert = cert.newMergedWithRoot(additionalRoot)
133+
cert.keyIssuer = keyIssuer.ID
134+
cert.pubIssuer = m.pubIssuer.ID
135+
fmt.Println("issued!", cert.keyIssuer, keyIssuer.ID)
150136
}
151137

152138
m.cache.Store(cn, cert)
@@ -225,5 +211,5 @@ func (m *Manager) GetCertificate(cn CommonName) (*Certificate, error) {
225211
// GetRootCertificate returns the root
226212
func (m *Manager) GetRootCertificate() *Certificate {
227213
// TODO(#4502): determine client(s) to use based on the rotation stage(s) of the client(s)
228-
return m.clients[m.keyIssuer].GetRootCertificate()
214+
return m.keyIssuer.GetRootCertificate()
229215
}

pkg/certificate/manager_test.go

+93-83
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package certificate
22

33
import (
4-
"fmt"
54
"testing"
65
time "time"
76

@@ -10,6 +9,7 @@ import (
109
tassert "github.com/stretchr/testify/assert"
1110

1211
"github.com/openservicemesh/osm/pkg/announcements"
12+
"github.com/openservicemesh/osm/pkg/certificate/pem"
1313
"github.com/openservicemesh/osm/pkg/messaging"
1414
)
1515

@@ -70,11 +70,8 @@ func TestRotor(t *testing.T) {
7070
assert.NoError(err)
7171
certRotateChan := msgBroker.GetCertPubSub().Sub(announcements.CertificateRotated.String())
7272

73-
start := time.Now()
74-
// Wait for one certificate rotation to be announced and terminate
73+
// Wait for two certificate rotations to be announced and terminate
7574
<-certRotateChan
76-
77-
fmt.Printf("It took %+v to rotate certificate %s\n", time.Since(start), cn)
7875
newCert, err := certManager.IssueCertificate(cn, validityPeriod)
7976
assert.NoError(err)
8077
assert.NotEqual(certA.GetExpiration(), newCert.GetExpiration())
@@ -216,7 +213,10 @@ func TestListCertificate(t *testing.T) {
216213
func TestGetRootCertificate(t *testing.T) {
217214
assert := tassert.New(t)
218215

219-
manager := &Manager{clients: map[string]Issuer{"fake-issuer-1": &fakeIssuer{}}}
216+
manager := &Manager{
217+
keyIssuer: &issuer{ID: "fake-1", Issuer: &fakeIssuer{}},
218+
pubIssuer: &issuer{ID: "fake-1", Issuer: &fakeIssuer{}},
219+
}
220220

221221
got := manager.GetRootCertificate()
222222

@@ -227,103 +227,113 @@ func TestIssueCertificate(t *testing.T) {
227227
cn := CommonName("fake-cert-cn")
228228
assert := tassert.New(t)
229229

230-
cm := &Manager{
231-
// The root certificate signing all newly issued certificates
232-
clients: map[string]Issuer{"id1": &fakeIssuer{}},
233-
keyIssuer: "id1",
234-
}
235-
236230
t.Run("single key issuer", func(t *testing.T) {
231+
cm := &Manager{
232+
// The root certificate signing all newly issued certificates
233+
keyIssuer: &issuer{ID: "id1", Issuer: &fakeIssuer{id: "id1"}},
234+
pubIssuer: &issuer{ID: "id1", Issuer: &fakeIssuer{id: "id1"}},
235+
}
237236
// single keyIssuer, not cached
238-
cert, err := cm.IssueCertificate(cn, time.Minute)
237+
cert1, err := cm.IssueCertificate(cn, time.Minute)
239238
assert.NoError(err)
240-
assert.NotNil(cert)
241-
assert.Equal(cert.keyIssuer, "id1")
242-
assert.Empty(cert.pubIssuer)
239+
assert.NotNil(cert1)
240+
assert.Equal(cert1.keyIssuer, "id1")
241+
assert.Equal(cert1.pubIssuer, "id1")
242+
assert.Equal(cert1.GetIssuingCA(), pem.RootCertificate("id1"))
243243

244244
// single keyIssuer cached
245-
cert1, err := cm.IssueCertificate(cn, time.Minute)
245+
cert2, err := cm.IssueCertificate(cn, time.Minute)
246246
assert.NoError(err)
247-
assert.Equal(cert, cert1)
247+
assert.Equal(cert1, cert2)
248248

249249
// single key issuer, old version cached
250250
// TODO: could use informer logic to test mrc updates instead of just manually making changes.
251-
cm.clients["id2"] = &fakeIssuer{}
252-
delete(cm.clients, "id1")
253-
cm.keyIssuer = "id2"
251+
cm.keyIssuer = &issuer{ID: "id2", Issuer: &fakeIssuer{id: "id2"}}
252+
cm.pubIssuer = &issuer{ID: "id2", Issuer: &fakeIssuer{id: "id2"}}
254253

255254
cert3, err := cm.IssueCertificate(cn, time.Minute)
256255
assert.NoError(err)
257-
assert.NotNil(cert)
258-
assert.Equal(cert.keyIssuer, "id2")
259-
assert.NotEqual(cert1, cert3)
260-
assert.Empty(cert.pubIssuer)
256+
assert.NotNil(cert3)
257+
assert.Equal(cert3.keyIssuer, "id2")
258+
assert.Equal(cert3.pubIssuer, "id2")
259+
assert.NotEqual(cert2, cert3)
260+
assert.Equal(cert3.GetIssuingCA(), pem.RootCertificate("id2"))
261261
})
262262

263263
t.Run("2 issuers", func(t *testing.T) {
264-
// {
265-
// name: "2 issuers, nothing cached",
266-
// test: func(a *tassert.Assertions) {
267-
268-
// },
269-
// },
270-
// {
271-
// name: "2 issuers, old version cached",
272-
// test: func(a *tassert.Assertions) {
273-
274-
// },
275-
// },
276-
// {
277-
// name: "2 issuers, 1 cached",
278-
// test: func(a *tassert.Assertions) {
279-
280-
// },
281-
// },
282-
// {
283-
// name: "2 issuers, both cached",
284-
// test: func(a *tassert.Assertions) {
285-
286-
// },
287-
// },
288-
})
289-
290-
testCases := []struct {
291-
name string
292-
test func(*tassert.Assertions)
293-
}{
294-
{
295-
name: "",
296-
test: func(a *tassert.Assertions) {
297-
298-
},
299-
},
300-
{
301-
name: "single keyIssuer, cached",
302-
test: func(a *tassert.Assertions) {
264+
cm := &Manager{
265+
// The root certificate signing all newly issued certificates
266+
keyIssuer: &issuer{ID: "id1", Issuer: &fakeIssuer{id: "id1"}},
267+
pubIssuer: &issuer{ID: "id2", Issuer: &fakeIssuer{id: "id2"}},
268+
}
303269

304-
},
305-
},
306-
{
307-
name: "single keyIssuer, old version cached",
308-
test: func(a *tassert.Assertions) {
270+
// Not cached
271+
cert1, err := cm.IssueCertificate(cn, time.Minute)
272+
assert.NoError(err)
273+
assert.NotNil(cert1)
274+
assert.Equal(cert1.keyIssuer, "id1")
275+
assert.Equal(cert1.pubIssuer, "id2")
276+
assert.Equal(cert1.GetIssuingCA(), pem.RootCertificate("idid2"))
309277

310-
},
311-
},
278+
// cached
279+
cert2, err := cm.IssueCertificate(cn, time.Minute)
280+
assert.NoError(err)
281+
assert.Equal(cert1, cert2)
312282

313-
// 2 keyissuers
283+
// cached, but pubIssuer is removed
284+
cm.pubIssuer = cm.keyIssuer
285+
cert3, err := cm.IssueCertificate(cn, time.Minute)
286+
assert.NoError(err)
287+
assert.NotEqual(cert1, cert3)
288+
assert.Equal(cert3.keyIssuer, "id1")
289+
assert.Equal(cert3.pubIssuer, "id1")
290+
assert.Equal(cert3.GetIssuingCA(), pem.RootCertificate("id1"))
314291

315-
{
316-
name: "bad key issuer",
317-
test: func(a *tassert.Assertions) {
292+
// cached, but keyIssuer is old
293+
cm.keyIssuer = &issuer{ID: "id2", Issuer: &fakeIssuer{id: "id2"}}
294+
cert4, err := cm.IssueCertificate(cn, time.Minute)
295+
assert.NoError(err)
296+
assert.NotEqual(cert3, cert4)
297+
assert.Equal(cert4.keyIssuer, "id2")
298+
assert.Equal(cert4.pubIssuer, "id1")
299+
assert.Equal(cert4.GetIssuingCA(), pem.RootCertificate("idid1"))
300+
301+
// cached, but pubIssuer is old
302+
cm.pubIssuer = &issuer{ID: "id3", Issuer: &fakeIssuer{id: "id3"}}
303+
cert5, err := cm.IssueCertificate(cn, time.Minute)
304+
assert.NoError(err)
305+
assert.NotEqual(cert4, cert5)
306+
assert.Equal(cert5.keyIssuer, "id2")
307+
assert.Equal(cert5.pubIssuer, "id3")
308+
assert.Equal(cert5.GetIssuingCA(), pem.RootCertificate("idid3"))
309+
})
318310

319-
},
320-
},
321-
{
322-
name: "bad pub issuer",
323-
test: func(a *tassert.Assertions) {
311+
t.Run("bad issuers", func(t *testing.T) {
312+
cm := &Manager{
313+
// The root certificate signing all newly issued certificates
314+
keyIssuer: &issuer{ID: "id1", Issuer: &fakeIssuer{id: "id1", err: true}},
315+
pubIssuer: &issuer{ID: "id2", Issuer: &fakeIssuer{id: "id2", err: true}},
316+
}
324317

325-
},
326-
},
327-
}
318+
// bad private key
319+
cert, err := cm.IssueCertificate(cn, time.Minute)
320+
assert.Nil(cert)
321+
assert.EqualError(err, "id1 failed")
322+
323+
// bad public key
324+
cm.keyIssuer = &issuer{ID: "id3", Issuer: &fakeIssuer{id: "id3"}}
325+
cert, err = cm.IssueCertificate(cn, time.Minute)
326+
assert.Nil(cert)
327+
assert.EqualError(err, "id2 failed")
328+
329+
// insert a cached cert
330+
cm.pubIssuer = cm.keyIssuer
331+
cert, err = cm.IssueCertificate(cn, time.Minute)
332+
assert.NoError(err)
328333

334+
// bad public key on an existing cached cert, because the pubIssuer is new
335+
cm.pubIssuer = &issuer{ID: "id1", Issuer: &fakeIssuer{id: "id1", err: true}}
336+
cert, err = cm.IssueCertificate(cn, time.Minute)
337+
assert.EqualError(err, "id1 failed")
338+
})
329339
}

0 commit comments

Comments
 (0)