Skip to content

Commit ff37bf1

Browse files
committed
Add unit tests for scepchallenge webhooks
1 parent f2663dd commit ff37bf1

File tree

3 files changed

+298
-41
lines changed

3 files changed

+298
-41
lines changed

authority/provisioner/scep_test.go

+119-38
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"go.step.sm/crypto/kms/softkms"
2323
"go.step.sm/crypto/minica"
2424
"go.step.sm/crypto/pemutil"
25+
"go.step.sm/crypto/x509util"
2526
"go.step.sm/linkedca"
2627
)
2728

@@ -37,6 +38,7 @@ func Test_challengeValidationController_Validate(t *testing.T) {
3738
}
3839
type response struct {
3940
Allow bool `json:"allow"`
41+
Data any `json:"data"`
4042
}
4143
nokServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
4244
req := &request{}
@@ -60,11 +62,22 @@ func Test_challengeValidationController_Validate(t *testing.T) {
6062
if assert.NotNil(t, req.Request) {
6163
assert.Equal(t, []byte{1}, req.Request.Raw)
6264
}
63-
b, err := json.Marshal(response{Allow: true})
65+
resp := response{Allow: true}
66+
if r.Header.Get("X-Smallstep-Webhook-Id") == "webhook-id-2" {
67+
resp.Data = map[string]any{
68+
"ID": "2adcbfec-5e4a-4b93-8913-640e24faf101",
69+
"Email": "[email protected]",
70+
}
71+
}
72+
b, err := json.Marshal(resp)
6473
require.NoError(t, err)
6574
w.WriteHeader(200)
6675
w.Write(b)
6776
}))
77+
t.Cleanup(func() {
78+
nokServer.Close()
79+
okServer.Close()
80+
})
6881
type fields struct {
6982
client *http.Client
7083
webhooks []*Webhook
@@ -78,7 +91,7 @@ func Test_challengeValidationController_Validate(t *testing.T) {
7891
name string
7992
fields fields
8093
args args
81-
server *httptest.Server
94+
want x509util.TemplateData
8295
expErr error
8396
}{
8497
{
@@ -134,7 +147,6 @@ func Test_challengeValidationController_Validate(t *testing.T) {
134147
challenge: "not-allowed",
135148
transactionID: "transaction-1",
136149
},
137-
server: nokServer,
138150
expErr: errors.New("webhook server did not allow request"),
139151
},
140152
{
@@ -154,26 +166,58 @@ func Test_challengeValidationController_Validate(t *testing.T) {
154166
challenge: "challenge",
155167
transactionID: "transaction-1",
156168
},
157-
server: okServer,
169+
want: x509util.TemplateData{
170+
x509util.WebhooksKey: map[string]any{
171+
"webhook-name-1": nil,
172+
},
173+
},
174+
},
175+
{
176+
name: "ok with data",
177+
fields: fields{http.DefaultClient, []*Webhook{
178+
{
179+
ID: "webhook-id-2",
180+
Name: "webhook-name-2",
181+
Secret: "MTIzNAo=",
182+
Kind: linkedca.Webhook_SCEPCHALLENGE.String(),
183+
CertType: linkedca.Webhook_X509.String(),
184+
URL: okServer.URL,
185+
},
186+
}},
187+
args: args{
188+
provisionerName: "my-scep-provisioner",
189+
challenge: "challenge",
190+
transactionID: "transaction-1",
191+
},
192+
want: x509util.TemplateData{
193+
x509util.WebhooksKey: map[string]any{
194+
"webhook-name-2": map[string]any{
195+
"ID": "2adcbfec-5e4a-4b93-8913-640e24faf101",
196+
"Email": "[email protected]",
197+
},
198+
},
199+
},
158200
},
159201
}
160202
for _, tt := range tests {
161203
t.Run(tt.name, func(t *testing.T) {
162204
c := newChallengeValidationController(tt.fields.client, tt.fields.webhooks)
163-
164-
if tt.server != nil {
165-
defer tt.server.Close()
166-
}
167-
168205
ctx := context.Background()
169-
err := c.Validate(ctx, dummyCSR, tt.args.provisionerName, tt.args.challenge, tt.args.transactionID)
170-
206+
got, err := c.Validate(ctx, dummyCSR, tt.args.provisionerName, tt.args.challenge, tt.args.transactionID)
171207
if tt.expErr != nil {
172208
assert.EqualError(t, err, tt.expErr.Error())
173209
return
174210
}
175-
176211
assert.NoError(t, err)
212+
data := x509util.TemplateData{}
213+
for _, o := range got {
214+
if m, ok := o.(TemplateDataModifier); ok {
215+
m.Modify(data)
216+
} else {
217+
t.Errorf("Validate() got = %T, want TemplateDataModifier", o)
218+
}
219+
}
220+
assert.Equal(t, tt.want, data)
177221
})
178222
}
179223
}
@@ -257,6 +301,7 @@ func TestSCEP_ValidateChallenge(t *testing.T) {
257301
}
258302
type response struct {
259303
Allow bool `json:"allow"`
304+
Data any `json:"data"`
260305
}
261306
okServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
262307
req := &request{}
@@ -268,11 +313,19 @@ func TestSCEP_ValidateChallenge(t *testing.T) {
268313
if assert.NotNil(t, req.Request) {
269314
assert.Equal(t, []byte{1}, req.Request.Raw)
270315
}
271-
b, err := json.Marshal(response{Allow: true})
316+
resp := response{Allow: true}
317+
if r.Header.Get("X-Smallstep-Webhook-Id") == "webhook-id-2" {
318+
resp.Data = map[string]any{
319+
"ID": "2adcbfec-5e4a-4b93-8913-640e24faf101",
320+
"Email": "[email protected]",
321+
}
322+
}
323+
b, err := json.Marshal(resp)
272324
require.NoError(t, err)
273325
w.WriteHeader(200)
274326
w.Write(b)
275327
}))
328+
t.Cleanup(okServer.Close)
276329
type args struct {
277330
challenge string
278331
transactionID string
@@ -282,6 +335,7 @@ func TestSCEP_ValidateChallenge(t *testing.T) {
282335
p *SCEP
283336
server *httptest.Server
284337
args args
338+
want x509util.TemplateData
285339
expErr error
286340
}{
287341
{"ok/webhooks", &SCEP{
@@ -299,9 +353,43 @@ func TestSCEP_ValidateChallenge(t *testing.T) {
299353
},
300354
},
301355
},
302-
}, okServer, args{"webhook-challenge", "webhook-transaction-1"},
303-
nil,
304-
},
356+
}, okServer, args{"webhook-challenge", "webhook-transaction-1"}, x509util.TemplateData{
357+
x509util.WebhooksKey: map[string]any{
358+
"webhook-name-1": nil,
359+
},
360+
}, nil},
361+
{"ok/with-data", &SCEP{
362+
Name: "SCEP",
363+
Type: "SCEP",
364+
Options: &Options{
365+
Webhooks: []*Webhook{
366+
{
367+
ID: "webhook-id-1",
368+
Name: "webhook-name-1",
369+
Secret: "MTIzNAo=",
370+
Kind: linkedca.Webhook_SCEPCHALLENGE.String(),
371+
CertType: linkedca.Webhook_X509.String(),
372+
URL: okServer.URL,
373+
},
374+
{
375+
ID: "webhook-id-2",
376+
Name: "webhook-name-2",
377+
Secret: "MTIzNAo=",
378+
Kind: linkedca.Webhook_SCEPCHALLENGE.String(),
379+
CertType: linkedca.Webhook_X509.String(),
380+
URL: okServer.URL,
381+
},
382+
},
383+
},
384+
}, okServer, args{"webhook-challenge", "webhook-transaction-1"}, x509util.TemplateData{
385+
x509util.WebhooksKey: map[string]any{
386+
"webhook-name-1": nil,
387+
"webhook-name-2": map[string]any{
388+
"ID": "2adcbfec-5e4a-4b93-8913-640e24faf101",
389+
"Email": "[email protected]",
390+
},
391+
},
392+
}, nil},
305393
{"fail/webhooks-secret-configuration", &SCEP{
306394
Name: "SCEP",
307395
Type: "SCEP",
@@ -317,60 +405,53 @@ func TestSCEP_ValidateChallenge(t *testing.T) {
317405
},
318406
},
319407
},
320-
}, nil, args{"webhook-challenge", "webhook-transaction-1"},
321-
errors.New("failed executing webhook request: illegal base64 data at input byte 0"),
322-
},
408+
}, nil, args{"webhook-challenge", "webhook-transaction-1"}, nil, errors.New("failed executing webhook request: illegal base64 data at input byte 0")},
323409
{"ok/static-challenge", &SCEP{
324410
Name: "SCEP",
325411
Type: "SCEP",
326412
Options: &Options{},
327413
ChallengePassword: "secret-static-challenge",
328-
}, nil, args{"secret-static-challenge", "static-transaction-1"},
329-
nil,
330-
},
414+
}, nil, args{"secret-static-challenge", "static-transaction-1"}, x509util.TemplateData{}, nil},
331415
{"fail/wrong-static-challenge", &SCEP{
332416
Name: "SCEP",
333417
Type: "SCEP",
334418
Options: &Options{},
335419
ChallengePassword: "secret-static-challenge",
336-
}, nil, args{"the-wrong-challenge-secret", "static-transaction-1"},
337-
errors.New("invalid challenge password provided"),
338-
},
420+
}, nil, args{"the-wrong-challenge-secret", "static-transaction-1"}, nil, errors.New("invalid challenge password provided")},
339421
{"ok/no-challenge", &SCEP{
340422
Name: "SCEP",
341423
Type: "SCEP",
342424
Options: &Options{},
343425
ChallengePassword: "",
344-
}, nil, args{"", "static-transaction-1"},
345-
nil,
346-
},
426+
}, nil, args{"", "static-transaction-1"}, x509util.TemplateData{}, nil},
347427
{"fail/no-challenge-but-provided", &SCEP{
348428
Name: "SCEP",
349429
Type: "SCEP",
350430
Options: &Options{},
351431
ChallengePassword: "",
352-
}, nil, args{"a-challenge-value", "static-transaction-1"},
353-
errors.New("invalid challenge password provided"),
354-
},
432+
}, nil, args{"a-challenge-value", "static-transaction-1"}, nil, errors.New("invalid challenge password provided")},
355433
}
356434
for _, tt := range tests {
357435
t.Run(tt.name, func(t *testing.T) {
358-
359-
if tt.server != nil {
360-
defer tt.server.Close()
361-
}
362-
363436
err := tt.p.Init(Config{Claims: globalProvisionerClaims, WebhookClient: http.DefaultClient})
364437
require.NoError(t, err)
365438
ctx := context.Background()
366439

367-
err = tt.p.ValidateChallenge(ctx, dummyCSR, tt.args.challenge, tt.args.transactionID)
440+
got, err := tt.p.ValidateChallenge(ctx, dummyCSR, tt.args.challenge, tt.args.transactionID)
368441
if tt.expErr != nil {
369442
assert.EqualError(t, err, tt.expErr.Error())
370443
return
371444
}
372-
373445
assert.NoError(t, err)
446+
data := x509util.TemplateData{}
447+
for _, o := range got {
448+
if m, ok := o.(TemplateDataModifier); ok {
449+
m.Modify(data)
450+
} else {
451+
t.Errorf("Validate() got = %T, want TemplateDataModifier", o)
452+
}
453+
}
454+
assert.Equal(t, tt.want, data)
374455
})
375456
}
376457
}

authority/provisioner/sign_options.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -546,11 +546,11 @@ func (s csrFingerprintValidator) Valid(cr *x509.CertificateRequest) error {
546546
return nil
547547
}
548548

549-
// SignCSROption is the interface used to collect extra option in the SignCSR
549+
// SignCSROption is the interface used to collect extra options in the SignCSR
550550
// method of the SCEP authority.
551-
type SignCSROption interface{}
551+
type SignCSROption any
552552

553-
// TemplateDataModifier in an interface that allows to modify template data.
553+
// TemplateDataModifier is an interface that allows to modify template data.
554554
type TemplateDataModifier interface {
555555
Modify(data x509util.TemplateData)
556556
}

0 commit comments

Comments
 (0)