-
Notifications
You must be signed in to change notification settings - Fork 446
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2065 from smallstep/mariano/challenge-webhook
Add data support on SCEPCHALLENGE webhooks
- Loading branch information
Showing
7 changed files
with
353 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ import ( | |
"go.step.sm/crypto/kms/softkms" | ||
"go.step.sm/crypto/minica" | ||
"go.step.sm/crypto/pemutil" | ||
"go.step.sm/crypto/x509util" | ||
"go.step.sm/linkedca" | ||
) | ||
|
||
|
@@ -37,6 +38,7 @@ func Test_challengeValidationController_Validate(t *testing.T) { | |
} | ||
type response struct { | ||
Allow bool `json:"allow"` | ||
Data any `json:"data"` | ||
} | ||
nokServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
req := &request{} | ||
|
@@ -60,11 +62,22 @@ func Test_challengeValidationController_Validate(t *testing.T) { | |
if assert.NotNil(t, req.Request) { | ||
assert.Equal(t, []byte{1}, req.Request.Raw) | ||
} | ||
b, err := json.Marshal(response{Allow: true}) | ||
resp := response{Allow: true} | ||
if r.Header.Get("X-Smallstep-Webhook-Id") == "webhook-id-2" { | ||
resp.Data = map[string]any{ | ||
"ID": "2adcbfec-5e4a-4b93-8913-640e24faf101", | ||
"Email": "[email protected]", | ||
} | ||
} | ||
b, err := json.Marshal(resp) | ||
require.NoError(t, err) | ||
w.WriteHeader(200) | ||
w.Write(b) | ||
})) | ||
t.Cleanup(func() { | ||
nokServer.Close() | ||
okServer.Close() | ||
}) | ||
type fields struct { | ||
client *http.Client | ||
webhooks []*Webhook | ||
|
@@ -78,7 +91,7 @@ func Test_challengeValidationController_Validate(t *testing.T) { | |
name string | ||
fields fields | ||
args args | ||
server *httptest.Server | ||
want x509util.TemplateData | ||
expErr error | ||
}{ | ||
{ | ||
|
@@ -134,7 +147,6 @@ func Test_challengeValidationController_Validate(t *testing.T) { | |
challenge: "not-allowed", | ||
transactionID: "transaction-1", | ||
}, | ||
server: nokServer, | ||
expErr: errors.New("webhook server did not allow request"), | ||
}, | ||
{ | ||
|
@@ -154,26 +166,58 @@ func Test_challengeValidationController_Validate(t *testing.T) { | |
challenge: "challenge", | ||
transactionID: "transaction-1", | ||
}, | ||
server: okServer, | ||
want: x509util.TemplateData{ | ||
x509util.WebhooksKey: map[string]any{ | ||
"webhook-name-1": nil, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "ok with data", | ||
fields: fields{http.DefaultClient, []*Webhook{ | ||
{ | ||
ID: "webhook-id-2", | ||
Name: "webhook-name-2", | ||
Secret: "MTIzNAo=", | ||
Kind: linkedca.Webhook_SCEPCHALLENGE.String(), | ||
CertType: linkedca.Webhook_X509.String(), | ||
URL: okServer.URL, | ||
}, | ||
}}, | ||
args: args{ | ||
provisionerName: "my-scep-provisioner", | ||
challenge: "challenge", | ||
transactionID: "transaction-1", | ||
}, | ||
want: x509util.TemplateData{ | ||
x509util.WebhooksKey: map[string]any{ | ||
"webhook-name-2": map[string]any{ | ||
"ID": "2adcbfec-5e4a-4b93-8913-640e24faf101", | ||
"Email": "[email protected]", | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
c := newChallengeValidationController(tt.fields.client, tt.fields.webhooks) | ||
|
||
if tt.server != nil { | ||
defer tt.server.Close() | ||
} | ||
|
||
ctx := context.Background() | ||
err := c.Validate(ctx, dummyCSR, tt.args.provisionerName, tt.args.challenge, tt.args.transactionID) | ||
|
||
got, err := c.Validate(ctx, dummyCSR, tt.args.provisionerName, tt.args.challenge, tt.args.transactionID) | ||
if tt.expErr != nil { | ||
assert.EqualError(t, err, tt.expErr.Error()) | ||
return | ||
} | ||
|
||
assert.NoError(t, err) | ||
data := x509util.TemplateData{} | ||
for _, o := range got { | ||
if m, ok := o.(TemplateDataModifier); ok { | ||
m.Modify(data) | ||
} else { | ||
t.Errorf("Validate() got = %T, want TemplateDataModifier", o) | ||
} | ||
} | ||
assert.Equal(t, tt.want, data) | ||
}) | ||
} | ||
} | ||
|
@@ -257,6 +301,7 @@ func TestSCEP_ValidateChallenge(t *testing.T) { | |
} | ||
type response struct { | ||
Allow bool `json:"allow"` | ||
Data any `json:"data"` | ||
} | ||
okServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
req := &request{} | ||
|
@@ -268,11 +313,19 @@ func TestSCEP_ValidateChallenge(t *testing.T) { | |
if assert.NotNil(t, req.Request) { | ||
assert.Equal(t, []byte{1}, req.Request.Raw) | ||
} | ||
b, err := json.Marshal(response{Allow: true}) | ||
resp := response{Allow: true} | ||
if r.Header.Get("X-Smallstep-Webhook-Id") == "webhook-id-2" { | ||
resp.Data = map[string]any{ | ||
"ID": "2adcbfec-5e4a-4b93-8913-640e24faf101", | ||
"Email": "[email protected]", | ||
} | ||
} | ||
b, err := json.Marshal(resp) | ||
require.NoError(t, err) | ||
w.WriteHeader(200) | ||
w.Write(b) | ||
})) | ||
t.Cleanup(okServer.Close) | ||
type args struct { | ||
challenge string | ||
transactionID string | ||
|
@@ -282,6 +335,7 @@ func TestSCEP_ValidateChallenge(t *testing.T) { | |
p *SCEP | ||
server *httptest.Server | ||
args args | ||
want x509util.TemplateData | ||
expErr error | ||
}{ | ||
{"ok/webhooks", &SCEP{ | ||
|
@@ -299,9 +353,43 @@ func TestSCEP_ValidateChallenge(t *testing.T) { | |
}, | ||
}, | ||
}, | ||
}, okServer, args{"webhook-challenge", "webhook-transaction-1"}, | ||
nil, | ||
}, | ||
}, okServer, args{"webhook-challenge", "webhook-transaction-1"}, x509util.TemplateData{ | ||
x509util.WebhooksKey: map[string]any{ | ||
"webhook-name-1": nil, | ||
}, | ||
}, nil}, | ||
{"ok/with-data", &SCEP{ | ||
Name: "SCEP", | ||
Type: "SCEP", | ||
Options: &Options{ | ||
Webhooks: []*Webhook{ | ||
{ | ||
ID: "webhook-id-1", | ||
Name: "webhook-name-1", | ||
Secret: "MTIzNAo=", | ||
Kind: linkedca.Webhook_SCEPCHALLENGE.String(), | ||
CertType: linkedca.Webhook_X509.String(), | ||
URL: okServer.URL, | ||
}, | ||
{ | ||
ID: "webhook-id-2", | ||
Name: "webhook-name-2", | ||
Secret: "MTIzNAo=", | ||
Kind: linkedca.Webhook_SCEPCHALLENGE.String(), | ||
CertType: linkedca.Webhook_X509.String(), | ||
URL: okServer.URL, | ||
}, | ||
}, | ||
}, | ||
}, okServer, args{"webhook-challenge", "webhook-transaction-1"}, x509util.TemplateData{ | ||
x509util.WebhooksKey: map[string]any{ | ||
"webhook-name-1": nil, | ||
"webhook-name-2": map[string]any{ | ||
"ID": "2adcbfec-5e4a-4b93-8913-640e24faf101", | ||
"Email": "[email protected]", | ||
}, | ||
}, | ||
}, nil}, | ||
{"fail/webhooks-secret-configuration", &SCEP{ | ||
Name: "SCEP", | ||
Type: "SCEP", | ||
|
@@ -317,60 +405,53 @@ func TestSCEP_ValidateChallenge(t *testing.T) { | |
}, | ||
}, | ||
}, | ||
}, nil, args{"webhook-challenge", "webhook-transaction-1"}, | ||
errors.New("failed executing webhook request: illegal base64 data at input byte 0"), | ||
}, | ||
}, nil, args{"webhook-challenge", "webhook-transaction-1"}, nil, errors.New("failed executing webhook request: illegal base64 data at input byte 0")}, | ||
{"ok/static-challenge", &SCEP{ | ||
Name: "SCEP", | ||
Type: "SCEP", | ||
Options: &Options{}, | ||
ChallengePassword: "secret-static-challenge", | ||
}, nil, args{"secret-static-challenge", "static-transaction-1"}, | ||
nil, | ||
}, | ||
}, nil, args{"secret-static-challenge", "static-transaction-1"}, x509util.TemplateData{}, nil}, | ||
{"fail/wrong-static-challenge", &SCEP{ | ||
Name: "SCEP", | ||
Type: "SCEP", | ||
Options: &Options{}, | ||
ChallengePassword: "secret-static-challenge", | ||
}, nil, args{"the-wrong-challenge-secret", "static-transaction-1"}, | ||
errors.New("invalid challenge password provided"), | ||
}, | ||
}, nil, args{"the-wrong-challenge-secret", "static-transaction-1"}, nil, errors.New("invalid challenge password provided")}, | ||
{"ok/no-challenge", &SCEP{ | ||
Name: "SCEP", | ||
Type: "SCEP", | ||
Options: &Options{}, | ||
ChallengePassword: "", | ||
}, nil, args{"", "static-transaction-1"}, | ||
nil, | ||
}, | ||
}, nil, args{"", "static-transaction-1"}, x509util.TemplateData{}, nil}, | ||
{"fail/no-challenge-but-provided", &SCEP{ | ||
Name: "SCEP", | ||
Type: "SCEP", | ||
Options: &Options{}, | ||
ChallengePassword: "", | ||
}, nil, args{"a-challenge-value", "static-transaction-1"}, | ||
errors.New("invalid challenge password provided"), | ||
}, | ||
}, nil, args{"a-challenge-value", "static-transaction-1"}, nil, errors.New("invalid challenge password provided")}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
|
||
if tt.server != nil { | ||
defer tt.server.Close() | ||
} | ||
|
||
err := tt.p.Init(Config{Claims: globalProvisionerClaims, WebhookClient: http.DefaultClient}) | ||
require.NoError(t, err) | ||
ctx := context.Background() | ||
|
||
err = tt.p.ValidateChallenge(ctx, dummyCSR, tt.args.challenge, tt.args.transactionID) | ||
got, err := tt.p.ValidateChallenge(ctx, dummyCSR, tt.args.challenge, tt.args.transactionID) | ||
if tt.expErr != nil { | ||
assert.EqualError(t, err, tt.expErr.Error()) | ||
return | ||
} | ||
|
||
assert.NoError(t, err) | ||
data := x509util.TemplateData{} | ||
for _, o := range got { | ||
if m, ok := o.(TemplateDataModifier); ok { | ||
m.Modify(data) | ||
} else { | ||
t.Errorf("Validate() got = %T, want TemplateDataModifier", o) | ||
} | ||
} | ||
assert.Equal(t, tt.want, data) | ||
}) | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.