Skip to content

Commit 7eb8aeb

Browse files
committed
Add tests for bootstrap functions.
1 parent abe503e commit 7eb8aeb

File tree

2 files changed

+220
-1
lines changed

2 files changed

+220
-1
lines changed

ca/bootstrap.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func Bootstrap(token string) (*Client, error) {
2424
}
2525
var claims tokenClaims
2626
if err := tok.UnsafeClaimsWithoutVerification(&claims); err != nil {
27-
return nil, errors.Wrap(err, "error parsing ott")
27+
return nil, errors.Wrap(err, "error parsing token")
2828
}
2929

3030
// Validate bootstrap token

ca/bootstrap_test.go

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package ca
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"reflect"
7+
"testing"
8+
"time"
9+
10+
"github.com/smallstep/certificates/api"
11+
"github.com/smallstep/certificates/authority"
12+
13+
"github.com/smallstep/cli/crypto/randutil"
14+
stepJOSE "github.com/smallstep/cli/jose"
15+
jose "gopkg.in/square/go-jose.v2"
16+
"gopkg.in/square/go-jose.v2/jwt"
17+
)
18+
19+
func startCABootstrapServer() *httptest.Server {
20+
config, err := authority.LoadConfiguration("testdata/ca.json")
21+
if err != nil {
22+
panic(err)
23+
}
24+
srv := httptest.NewUnstartedServer(nil)
25+
config.Address = srv.Listener.Addr().String()
26+
ca, err := New(config)
27+
if err != nil {
28+
panic(err)
29+
}
30+
srv.Config.Handler = ca.srv.Handler
31+
srv.TLS = ca.srv.TLSConfig
32+
srv.StartTLS()
33+
// Force the use of GetCertificate on IPs
34+
srv.TLS.Certificates = nil
35+
return srv
36+
}
37+
38+
func generateBootstrapToken(ca, subject, sha string) string {
39+
now := time.Now()
40+
jwk, err := stepJOSE.ParseKey("testdata/secrets/ott_mariano_priv.jwk", stepJOSE.WithPassword([]byte("password")))
41+
if err != nil {
42+
panic(err)
43+
}
44+
opts := new(jose.SignerOptions).WithType("JWT").WithHeader("kid", jwk.KeyID)
45+
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.ES256, Key: jwk.Key}, opts)
46+
if err != nil {
47+
panic(err)
48+
}
49+
id, err := randutil.ASCII(64)
50+
if err != nil {
51+
panic(err)
52+
}
53+
cl := struct {
54+
SHA string `json:"sha"`
55+
jwt.Claims
56+
}{
57+
SHA: sha,
58+
Claims: jwt.Claims{
59+
ID: id,
60+
Subject: subject,
61+
Issuer: "mariano",
62+
NotBefore: jwt.NewNumericDate(now),
63+
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
64+
Audience: []string{ca + "/sign"},
65+
},
66+
}
67+
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
68+
if err != nil {
69+
panic(err)
70+
}
71+
return raw
72+
}
73+
74+
func TestBootstrap(t *testing.T) {
75+
srv := startCABootstrapServer()
76+
defer srv.Close()
77+
token := generateBootstrapToken(srv.URL, "subject", "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7")
78+
client, err := NewClient(srv.URL+"/sign", WithRootFile("testdata/secrets/root_ca.crt"))
79+
if err != nil {
80+
t.Fatal(err)
81+
}
82+
83+
type args struct {
84+
token string
85+
}
86+
tests := []struct {
87+
name string
88+
args args
89+
want *Client
90+
wantErr bool
91+
}{
92+
{"ok", args{token}, client, false},
93+
{"token err", args{"badtoken"}, nil, true},
94+
{"bad claims", args{"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.foo.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}, nil, true},
95+
{"bad sha", args{generateBootstrapToken(srv.URL, "subject", "")}, nil, true},
96+
{"bad aud", args{generateBootstrapToken("", "subject", "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7")}, nil, true},
97+
}
98+
for _, tt := range tests {
99+
t.Run(tt.name, func(t *testing.T) {
100+
got, err := Bootstrap(tt.args.token)
101+
if (err != nil) != tt.wantErr {
102+
t.Errorf("Bootstrap() error = %v, wantErr %v", err, tt.wantErr)
103+
return
104+
}
105+
if tt.wantErr {
106+
if !reflect.DeepEqual(got, tt.want) {
107+
t.Errorf("Bootstrap() = %v, want %v", got, tt.want)
108+
}
109+
} else {
110+
if got == nil {
111+
t.Error("Bootstrap() = nil, want not nil")
112+
} else {
113+
if !reflect.DeepEqual(got.endpoint, tt.want.endpoint) {
114+
t.Errorf("Bootstrap() endpoint = %v, want %v", got.endpoint, tt.want.endpoint)
115+
}
116+
if !reflect.DeepEqual(got.certPool, tt.want.certPool) {
117+
t.Errorf("Bootstrap() certPool = %v, want %v", got.certPool, tt.want.certPool)
118+
}
119+
}
120+
}
121+
})
122+
}
123+
}
124+
125+
func TestBootstrapServer(t *testing.T) {
126+
srv := startCABootstrapServer()
127+
defer srv.Close()
128+
token := func() string {
129+
return generateBootstrapToken(srv.URL, "subject", "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7")
130+
}
131+
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
132+
w.Write([]byte("ok"))
133+
})
134+
type args struct {
135+
addr string
136+
token string
137+
handler http.Handler
138+
}
139+
tests := []struct {
140+
name string
141+
args args
142+
wantErr bool
143+
}{
144+
{"ok", args{":0", token(), handler}, false},
145+
{"fail", args{":0", "bad-token", handler}, true},
146+
}
147+
for _, tt := range tests {
148+
t.Run(tt.name, func(t *testing.T) {
149+
got, err := BootstrapServer(tt.args.addr, tt.args.token, tt.args.handler)
150+
if (err != nil) != tt.wantErr {
151+
t.Errorf("BootstrapServer() error = %v, wantErr %v", err, tt.wantErr)
152+
return
153+
}
154+
if tt.wantErr {
155+
if got != nil {
156+
t.Errorf("BootstrapServer() = %v, want nil", got)
157+
}
158+
} else {
159+
if !reflect.DeepEqual(got.Addr, tt.args.addr) {
160+
t.Errorf("BootstrapServer() Addr = %v, want %v", got.Addr, tt.args.addr)
161+
}
162+
if got.TLSConfig == nil || got.TLSConfig.ClientCAs == nil || got.TLSConfig.RootCAs == nil || got.TLSConfig.GetCertificate == nil || got.TLSConfig.GetClientCertificate == nil {
163+
t.Errorf("BootstrapServer() invalid TLSConfig = %#v", got.TLSConfig)
164+
}
165+
}
166+
})
167+
}
168+
}
169+
170+
func TestBootstrapClient(t *testing.T) {
171+
srv := startCABootstrapServer()
172+
defer srv.Close()
173+
token := func() string {
174+
return generateBootstrapToken(srv.URL, "subject", "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7")
175+
}
176+
type args struct {
177+
token string
178+
}
179+
tests := []struct {
180+
name string
181+
args args
182+
wantErr bool
183+
}{
184+
{"ok", args{token()}, false},
185+
{"fail", args{"bad-token"}, true},
186+
}
187+
for _, tt := range tests {
188+
t.Run(tt.name, func(t *testing.T) {
189+
got, err := BootstrapClient(tt.args.token)
190+
if (err != nil) != tt.wantErr {
191+
t.Errorf("BootstrapClient() error = %v, wantErr %v", err, tt.wantErr)
192+
return
193+
}
194+
if tt.wantErr {
195+
if got != nil {
196+
t.Errorf("BootstrapClient() = %v, want nil", got)
197+
}
198+
} else {
199+
tlsConfig := got.Transport.(*http.Transport).TLSClientConfig
200+
if tlsConfig == nil || tlsConfig.ClientCAs != nil || tlsConfig.GetClientCertificate == nil || tlsConfig.RootCAs == nil || tlsConfig.GetCertificate != nil {
201+
t.Errorf("BootstrapClient() invalid Transport = %#v", tlsConfig)
202+
}
203+
resp, err := got.Post(srv.URL+"/renew", "application/json", http.NoBody)
204+
if err != nil {
205+
t.Errorf("BootstrapClient() failed renewing certificate")
206+
return
207+
}
208+
var renewal api.SignResponse
209+
if err := readJSON(resp.Body, &renewal); err != nil {
210+
t.Errorf("BootstrapClient() error reading response: %v", err)
211+
return
212+
}
213+
if renewal.CaPEM.Certificate == nil || renewal.ServerPEM.Certificate == nil {
214+
t.Errorf("BootstrapClient() invalid renewal response: %v", renewal)
215+
}
216+
}
217+
})
218+
}
219+
}

0 commit comments

Comments
 (0)