Skip to content

Commit

Permalink
fix: passing transient payloads (#3838)
Browse files Browse the repository at this point in the history
  • Loading branch information
hperl committed Mar 22, 2024
1 parent 34399c2 commit d01b670
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 7 deletions.
1 change: 1 addition & 0 deletions internal/client-go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
1 change: 1 addition & 0 deletions selfservice/strategy/code/hook.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
function(ctx) ctx
1 change: 1 addition & 0 deletions selfservice/strategy/code/strategy_recovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ func (s *Strategy) recoveryHandleFormSubmission(w http.ResponseWriter, r *http.R
return s.HandleRecoveryError(w, r, f, body, err)
}

f.TransientPayload = body.TransientPayload
if err := s.deps.CodeSender().SendRecoveryCode(ctx, f, identity.VerifiableAddressTypeEmail, body.Email); err != nil {
if !errors.Is(err, ErrUnknownAddress) {
return s.HandleRecoveryError(w, r, f, body, err)
Expand Down
73 changes: 66 additions & 7 deletions selfservice/strategy/code/strategy_recovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,68 @@ func TestRecovery(t *testing.T) {
assert.Contains(t, gjson.Get(body, "redirect_browser_to").String(), "settings-ts?")
})

t.Run("description=should pass transient data to email template and webhooks", func(t *testing.T) {
var webhookReceivedTransientPayload string
webhookTS := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
webhookReceivedTransientPayload = gjson.GetBytes(ioutilx.MustReadAll(r.Body), "flow.transient_payload").String()
w.WriteHeader(http.StatusOK)
}))
t.Cleanup(webhookTS.Close)

conf.MustSet(
ctx,
"selfservice.flows.recovery.after.hooks",
[]config.SelfServiceHook{{Name: "web_hook", Config: []byte(
fmt.Sprintf(`{
"method":"POST",
"url": "%s",
"body":"file://./hook.jsonnet"
}`, webhookTS.URL),
)}},
)

t.Cleanup(func() {
conf.MustSet(ctx, "selfservice.flows.recovery.after.hooks", nil)
})
client := testhelpers.NewClientWithCookies(t)
email := testhelpers.RandomEmail()
createIdentityToRecover(t, reg, email)
templatePayload := `{"payload":"template data"}`
webhookPayload := `{"payload":"webhook data"}`

f := testhelpers.InitializeRecoveryFlowViaBrowser(t, client, false, public, nil)

formPayload := testhelpers.SDKFormFieldsToURLValues(f.Ui.Nodes)
formPayload.Set("email", email)
formPayload.Set("transient_payload", templatePayload)

body, _ := testhelpers.RecoveryMakeRequest(t, false, f, client, formPayload.Encode())
message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Recover access to your account")
assert.Equal(t, templatePayload, gjson.GetBytes(message.TemplateData, "transient_payload").String(),
"should pass transient payload to email template")

recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, recoveryCode)

action := gjson.Get(body, "ui.action").String()
assert.NotEmpty(t, action)

_, err := client.Post(action, "application/x-www-form-urlencoded", bytes.NewBufferString(
withCSRFToken(t, RecoveryClientTypeBrowser, body, url.Values{
"code": {recoveryCode},
"method": {"code"},
"transient_payload": {webhookPayload},
})))
require.NoError(t, err)

assert.JSONEq(t, webhookPayload, webhookReceivedTransientPayload,
"should pass transient payload to webhook")
})

t.Run("description=should return browser to return url", func(t *testing.T) {
returnTo := public.URL + "/return-to"
conf.Set(ctx, config.ViperKeyURLsAllowedReturnToDomains, []string{returnTo})
conf.MustSet(ctx, config.ViperKeyURLsAllowedReturnToDomains, []string{returnTo})

for _, tc := range []struct {
desc string
returnTo string
Expand All @@ -313,9 +372,9 @@ func TestRecovery(t *testing.T) {
desc: "should use return_to from config",
returnTo: returnTo,
f: func(t *testing.T, client *http.Client, identity *identity.Identity) *kratos.RecoveryFlow {
conf.Set(ctx, config.ViperKeySelfServiceRecoveryBrowserDefaultReturnTo, returnTo)
conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryBrowserDefaultReturnTo, returnTo)
t.Cleanup(func() {
conf.Set(ctx, config.ViperKeySelfServiceRecoveryBrowserDefaultReturnTo, "")
conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryBrowserDefaultReturnTo, "")
})
return testhelpers.InitializeRecoveryFlowViaBrowser(t, client, false, public, nil)
},
Expand All @@ -331,10 +390,10 @@ func TestRecovery(t *testing.T) {
desc: "should use return_to with an account that has 2fa enabled",
returnTo: returnTo,
f: func(t *testing.T, client *http.Client, id *identity.Identity) *kratos.RecoveryFlow {
conf.Set(ctx, config.ViperKeySelfServiceSettingsRequiredAAL, config.HighestAvailableAAL)
conf.Set(ctx, config.ViperKeySessionWhoAmIAAL, config.HighestAvailableAAL)
conf.Set(ctx, config.ViperKeyWebAuthnRPDisplayName, "Kratos")
conf.Set(ctx, config.ViperKeyWebAuthnRPID, "ory.sh")
conf.MustSet(ctx, config.ViperKeySelfServiceSettingsRequiredAAL, config.HighestAvailableAAL)
conf.MustSet(ctx, config.ViperKeySessionWhoAmIAAL, config.HighestAvailableAAL)
conf.MustSet(ctx, config.ViperKeyWebAuthnRPDisplayName, "Kratos")
conf.MustSet(ctx, config.ViperKeyWebAuthnRPID, "ory.sh")

t.Cleanup(func() {
conf.MustSet(ctx, config.ViperKeySessionWhoAmIAAL, identity.AuthenticatorAssuranceLevel1)
Expand Down
2 changes: 2 additions & 0 deletions selfservice/strategy/oidc/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ func (s *Strategy) HandleCallback(w http.ResponseWriter, r *http.Request, ps htt

switch a := req.(type) {
case *login.Flow:
a.TransientPayload = cntnr.TransientPayload
if ff, err := s.processLogin(w, r, a, et, claims, provider, cntnr); err != nil {
if ff != nil {
s.forwardError(w, r, ff, err)
Expand All @@ -479,6 +480,7 @@ func (s *Strategy) HandleCallback(w http.ResponseWriter, r *http.Request, ps htt
}
return
case *settings.Flow:
a.TransientPayload = cntnr.TransientPayload
sess, err := s.d.SessionManager().FetchFromRequest(r.Context(), r)
if err != nil {
s.forwardError(w, r, a, s.handleError(w, r, a, pid, nil, err))
Expand Down

0 comments on commit d01b670

Please sign in to comment.