kratos/internal/registrationhelpers/helpers.go

513 lines
23 KiB
Go

// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package registrationhelpers
import (
"bytes"
"context"
_ "embed"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
"github.com/ory/kratos/driver"
"github.com/ory/kratos/driver/config"
"github.com/ory/kratos/internal"
kratos "github.com/ory/kratos/internal/httpclient"
"github.com/ory/kratos/internal/testhelpers"
"github.com/ory/kratos/selfservice/flow"
"github.com/ory/kratos/selfservice/flow/registration"
"github.com/ory/kratos/x"
"github.com/ory/kratos/x/nosurfx"
"github.com/ory/x/assertx"
"github.com/ory/x/httpx"
"github.com/ory/x/ioutilx"
"github.com/ory/x/stringslice"
)
func setupServer(t *testing.T, reg *driver.RegistryDefault) *httptest.Server {
publicTS, _ := testhelpers.NewKratosServer(t, reg)
redirTS := testhelpers.NewRedirSessionEchoTS(t, reg)
conf := reg.Config()
conf.MustSet(t.Context(), config.ViperKeySelfServiceBrowserDefaultReturnTo, redirTS.URL+"/default-return-to") //nolint:staticcheck
conf.MustSet(t.Context(), config.ViperKeySelfServiceRegistrationAfter+"."+config.DefaultBrowserReturnURL, redirTS.URL+"/registration-return-ts") //nolint:staticcheck
return publicTS
}
func ExpectValidationError(t *testing.T, ts *httptest.Server, conf *config.Config, flow string, values func(url.Values)) string {
isSPA := flow == "spa"
isAPI := flow == "api"
ctx := context.Background()
return testhelpers.SubmitRegistrationForm(t, isAPI, nil, ts, values,
isSPA,
testhelpers.ExpectStatusCode(isAPI || isSPA, http.StatusBadRequest, http.StatusOK),
testhelpers.ExpectURL(isAPI || isSPA, ts.URL+registration.RouteSubmitFlow, conf.SelfServiceFlowRegistrationUI(ctx).String()))
}
func CheckFormContent(t *testing.T, body []byte, requiredFields ...string) {
FieldNameSet(t, body, requiredFields)
OutdatedFieldsDoNotExist(t, body)
FormMethodIsPOST(t, body)
}
// FieldNameSet checks if the fields have the right "name" set.
func FieldNameSet(t *testing.T, body []byte, fields []string) {
for _, f := range fields {
assert.Equal(t, f, gjson.GetBytes(body, fmt.Sprintf("ui.nodes.#(attributes.name==%s).attributes.name", f)).String(), "%s", body)
}
}
// checks if some keys are not set, this should be used to catch regression issues
func OutdatedFieldsDoNotExist(t *testing.T, body []byte) {
for _, k := range []string{"request"} {
assert.Equal(t, false, gjson.GetBytes(body, fmt.Sprintf("ui.nodes.fields.#(name==%s)", k)).Exists())
}
}
func FormMethodIsPOST(t *testing.T, body []byte) {
assert.Equal(t, "POST", gjson.GetBytes(body, "ui.method").String())
}
//go:embed stub/basic.schema.json
var basicSchema []byte
//go:embed stub/multifield.schema.json
var multifieldSchema []byte
var skipIfNotEnabled = func(t *testing.T, flows []string, flow string) {
if !stringslice.Has(flows, flow) {
t.Skipf("Skipping for %s flow because it was not included in the list of flows to be executed.", flow)
}
}
func AssertSchemaDoesNotExist(t *testing.T, reg *driver.RegistryDefault, flows []string, payload func(v url.Values)) {
conf := reg.Config()
_ = testhelpers.NewRegistrationUIFlowEchoServer(t, reg)
publicTS := setupServer(t, reg)
apiClient := testhelpers.NewDebugClient(t)
errTS := testhelpers.NewErrorTestServer(t, reg)
reset := func() {
testhelpers.SetDefaultIdentitySchemaFromRaw(conf, basicSchema)
}
reset()
t.Run("case=should fail because schema does not exist", func(t *testing.T) {
check := func(t *testing.T, actual string) {
assert.Equal(t, int64(http.StatusInternalServerError), gjson.Get(actual, "code").Int(), "%s", actual)
assert.Equal(t, "Internal Server Error", gjson.Get(actual, "status").String(), "%s", actual)
assert.Contains(t, gjson.Get(actual, "reason").String(), "no such file or directory", "%s", actual)
}
values := url.Values{
"traits.username": {testhelpers.RandomEmail()},
"traits.foobar": {"bar"},
"csrf_token": {nosurfx.FakeCSRFToken},
}
payload(values)
t.Run("type=api", func(t *testing.T) {
skipIfNotEnabled(t, flows, "api")
f := testhelpers.InitializeRegistrationFlowViaAPI(t, apiClient, publicTS)
testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/i-do-not-exist.schema.json")
t.Cleanup(reset)
body, res := testhelpers.RegistrationMakeRequest(t, false, false, f, apiClient, values.Encode())
assert.Contains(t, res.Request.URL.String(), publicTS.URL)
check(t, gjson.Get(body, "error").Raw)
})
t.Run("type=spa", func(t *testing.T) {
skipIfNotEnabled(t, flows, "spa")
browserClient := testhelpers.NewClientWithCookies(t)
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true, false, false)
testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/i-do-not-exist.schema.json")
t.Cleanup(reset)
body, res := testhelpers.RegistrationMakeRequest(t, false, true, f, apiClient, values.Encode())
assert.Contains(t, res.Request.URL.String(), publicTS.URL)
check(t, gjson.Get(body, "error").Raw)
})
t.Run("type=browser", func(t *testing.T) {
skipIfNotEnabled(t, flows, "browser")
browserClient := testhelpers.NewClientWithCookies(t)
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false)
testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/i-do-not-exist.schema.json")
t.Cleanup(reset)
body, res := testhelpers.RegistrationMakeRequest(t, false, false, f, apiClient, values.Encode())
assert.Contains(t, res.Request.URL.String(), errTS.URL)
check(t, body)
})
})
}
func AssertCSRFFailures(t *testing.T, reg *driver.RegistryDefault, flows []string, payload func(v url.Values)) {
conf := reg.Config()
testhelpers.SetDefaultIdentitySchemaFromRaw(conf, multifieldSchema)
_ = testhelpers.NewRegistrationUIFlowEchoServer(t, reg)
publicTS := setupServer(t, reg)
apiClient := testhelpers.NewDebugClient(t)
_ = testhelpers.NewErrorTestServer(t, reg)
values := url.Values{
"csrf_token": {"invalid_token"},
"traits.username": {testhelpers.RandomEmail()},
"traits.foobar": {"bar"},
}
payload(values)
t.Run("case=should fail because of missing CSRF token/type=browser", func(t *testing.T) {
skipIfNotEnabled(t, flows, "browser")
browserClient := testhelpers.NewClientWithCookies(t)
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false)
actual, res := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, values.Encode())
assert.EqualValues(t, http.StatusOK, res.StatusCode)
assertx.EqualAsJSON(t, nosurfx.ErrInvalidCSRFToken,
json.RawMessage(actual), "%s", actual)
})
t.Run("case=should fail because of missing CSRF token/type=spa", func(t *testing.T) {
skipIfNotEnabled(t, flows, "spa")
browserClient := testhelpers.NewClientWithCookies(t)
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true, false, false)
actual, res := testhelpers.RegistrationMakeRequest(t, false, true, f, browserClient, values.Encode())
assert.EqualValues(t, http.StatusForbidden, res.StatusCode)
assertx.EqualAsJSON(t, nosurfx.ErrInvalidCSRFToken,
json.RawMessage(gjson.Get(actual, "error").Raw), "%s", actual)
})
t.Run("case=should pass even without CSRF token/type=api", func(t *testing.T) {
skipIfNotEnabled(t, flows, "api")
f := testhelpers.InitializeRegistrationFlowViaAPI(t, apiClient, publicTS)
actual, res := testhelpers.RegistrationMakeRequest(t, true, false, f, apiClient, testhelpers.EncodeFormAsJSON(t, true, values))
assert.EqualValues(t, http.StatusOK, res.StatusCode)
assert.NotEmpty(t, gjson.Get(actual, "identity.id").Raw, "%s", actual) // registration successful
})
t.Run("case=should fail with correct CSRF error cause/type=api", func(t *testing.T) {
skipIfNotEnabled(t, flows, "api")
for k, tc := range []struct {
mod func(http.Header)
exp string
}{
{
mod: func(h http.Header) {
h.Add("Cookie", "name=bar")
},
exp: "The HTTP Request Header included the \\\"Cookie\\\" key",
},
{
mod: func(h http.Header) {
h.Add("Origin", "www.bar.com")
},
exp: "The HTTP Request Header included the \\\"Origin\\\" key",
},
} {
t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) {
f := testhelpers.InitializeRegistrationFlowViaAPI(t, apiClient, publicTS)
c := f.Ui
req := testhelpers.NewRequest(t, true, "POST", c.Action, bytes.NewBufferString(testhelpers.EncodeFormAsJSON(t, true, values)))
tc.mod(req.Header)
res, err := apiClient.Do(req)
require.NoError(t, err)
defer func() { _ = res.Body.Close() }()
actual := string(ioutilx.MustReadAll(res.Body))
assert.EqualValues(t, http.StatusBadRequest, res.StatusCode)
assert.Contains(t, actual, tc.exp)
})
}
})
}
func AssertRegistrationRespectsValidation(t *testing.T, reg *driver.RegistryDefault, flows []string, payload func(url.Values)) {
conf := reg.Config()
testhelpers.SetDefaultIdentitySchemaFromRaw(conf, multifieldSchema)
_ = testhelpers.NewRegistrationUIFlowEchoServer(t, reg)
publicTS := setupServer(t, reg)
t.Run("case=should return an error because not passing validation", func(t *testing.T) {
email := testhelpers.RandomEmail()
check := func(t *testing.T, actual string) {
assert.NotEmpty(t, gjson.Get(actual, "id").String(), "%s", actual)
assert.Contains(t, gjson.Get(actual, "ui.action").String(), publicTS.URL+registration.RouteSubmitFlow, "%s", actual)
CheckFormContent(t, []byte(actual), "password", "csrf_token", "traits.username", "traits.foobar")
assert.Contains(t, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.foobar).messages.0").String(), `Property foobar is missing`, "%s", actual)
assert.Equal(t, email, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.username).attributes.value").String(), "%s", actual)
}
values := func(v url.Values) {
v.Set("traits.username", email)
v.Del("traits.foobar")
payload(v)
}
for _, f := range flows {
t.Run("type="+f, func(t *testing.T) {
check(t, ExpectValidationError(t, publicTS, conf, f, values))
})
}
})
}
func AssertCommonErrorCases(t *testing.T, flows []string) {
ctx := context.Background()
conf, reg := internal.NewFastRegistryWithMocks(t)
conf.MustSet(ctx, "selfservice.flows.registration.enable_legacy_one_step", true)
testhelpers.SetDefaultIdentitySchemaFromRaw(conf, basicSchema)
uiTS := testhelpers.NewRegistrationUIFlowEchoServer(t, reg)
publicTS := setupServer(t, reg)
apiClient := testhelpers.NewDebugClient(t)
errTS := testhelpers.NewErrorTestServer(t, reg)
t.Run("description=can call endpoints only without session", func(t *testing.T) {
values := url.Values{}
t.Run("type=browser", func(t *testing.T) {
res, err := testhelpers.NewHTTPClientWithArbitrarySessionCookie(t, ctx, reg).
Do(httpx.MustNewRequest("POST", publicTS.URL+registration.RouteSubmitFlow, strings.NewReader(values.Encode()), "application/x-www-form-urlencoded"))
require.NoError(t, err)
defer func() { _ = res.Body.Close() }()
assert.EqualValues(t, http.StatusOK, res.StatusCode, "%+v", res.Request)
assert.Contains(t, res.Request.URL.String(), conf.GetProvider(ctx).String(config.ViperKeySelfServiceBrowserDefaultReturnTo))
})
t.Run("type=api", func(t *testing.T) {
res, err := testhelpers.NewHTTPClientWithArbitrarySessionToken(t, ctx, reg).
Do(httpx.MustNewRequest("POST", publicTS.URL+registration.RouteSubmitFlow, strings.NewReader(testhelpers.EncodeFormAsJSON(t, true, values)), "application/json"))
require.NoError(t, err)
assert.Len(t, res.Cookies(), 0)
defer func() { _ = res.Body.Close() }()
assertx.EqualAsJSON(t, registration.ErrAlreadyLoggedIn, json.RawMessage(gjson.GetBytes(ioutilx.MustReadAll(res.Body), "error").Raw))
})
})
t.Run("case=should show the error ui because the request payload is malformed", func(t *testing.T) {
t.Run("type=api", func(t *testing.T) {
f := testhelpers.InitializeRegistrationFlowViaAPI(t, apiClient, publicTS)
body, res := testhelpers.RegistrationMakeRequest(t, true, false, f, apiClient, "14=)=!(%)$/ZP()GHIÖ")
assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow)
assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body)
assert.Contains(t, body, `Expected JSON sent in request body to be an object but got: Number`)
})
t.Run("type=spa", func(t *testing.T) {
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, apiClient, publicTS, true, false, false)
body, res := testhelpers.RegistrationMakeRequest(t, true, false, f, apiClient, "14=)=!(%)$/ZP()GHIÖ")
assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow)
assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body)
assert.Contains(t, body, `Expected JSON sent in request body to be an object but got: Number`)
})
t.Run("type=browser", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false)
body, res := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, "14=)=!(%)$/ZP()GHIÖ")
assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/registration-ts")
assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body)
assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "invalid URL escape", "%s", body)
assert.Equal(t, "email", gjson.Get(body, "ui.nodes.#(attributes.name==\"traits.email\").attributes.type").String(), "%s", body)
})
})
t.Run("description=can call endpoints only without session", func(t *testing.T) {
values := url.Values{}
t.Run("type=browser", func(t *testing.T) {
res, err := testhelpers.NewHTTPClientWithArbitrarySessionCookie(t, ctx, reg).
Do(httpx.MustNewRequest("POST", publicTS.URL+registration.RouteSubmitFlow, strings.NewReader(values.Encode()), "application/x-www-form-urlencoded"))
require.NoError(t, err)
defer func() { _ = res.Body.Close() }()
assert.EqualValues(t, http.StatusOK, res.StatusCode, "%+v", res.Request)
assert.Contains(t, res.Request.URL.String(), conf.GetProvider(ctx).String(config.ViperKeySelfServiceBrowserDefaultReturnTo))
})
t.Run("type=api", func(t *testing.T) {
res, err := testhelpers.NewHTTPClientWithArbitrarySessionToken(t, ctx, reg).
Do(httpx.MustNewRequest("POST", publicTS.URL+registration.RouteSubmitFlow, strings.NewReader(testhelpers.EncodeFormAsJSON(t, true, values)), "application/json"))
require.NoError(t, err)
assert.Len(t, res.Cookies(), 0)
defer func() { _ = res.Body.Close() }()
assertx.EqualAsJSON(t, registration.ErrAlreadyLoggedIn, json.RawMessage(gjson.GetBytes(ioutilx.MustReadAll(res.Body), "error").Raw))
})
})
t.Run("case=should show the error ui because the request payload is malformed", func(t *testing.T) {
t.Run("type=api", func(t *testing.T) {
f := testhelpers.InitializeRegistrationFlowViaAPI(t, apiClient, publicTS)
body, res := testhelpers.RegistrationMakeRequest(t, true, false, f, apiClient, "14=)=!(%)$/ZP()GHIÖ")
assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow)
assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body)
assert.Contains(t, body, `Expected JSON sent in request body to be an object but got: Number`)
})
t.Run("type=spa", func(t *testing.T) {
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, apiClient, publicTS, true, false, false)
body, res := testhelpers.RegistrationMakeRequest(t, true, false, f, apiClient, "14=)=!(%)$/ZP()GHIÖ")
assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow)
assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body)
assert.Contains(t, body, `Expected JSON sent in request body to be an object but got: Number`)
})
t.Run("type=browser", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false)
body, res := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, "14=)=!(%)$/ZP()GHIÖ")
assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/registration-ts")
assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body)
assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "invalid URL escape", "%s", body)
assert.Equal(t, "email", gjson.Get(body, "ui.nodes.#(attributes.name==\"traits.email\").attributes.type").String(), "%s", body)
})
})
t.Run("case=should show the error ui because the method is missing in payload", func(t *testing.T) {
t.Run("type=api", func(t *testing.T) {
f := testhelpers.InitializeRegistrationFlowViaAPI(t, apiClient, publicTS)
body, res := testhelpers.RegistrationMakeRequest(t, true, false, f, apiClient, "{}}")
assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow)
assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body)
assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "Could not find a strategy to sign you up with. Did you fill out the form correctly?", "%s", body)
})
t.Run("type=spa", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true, false, false)
body, res := testhelpers.RegistrationMakeRequest(t, false, true, f, browserClient, "{}}")
assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow)
assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body)
assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "Could not find a strategy to sign you up with. Did you fill out the form correctly?", "%s", body)
})
t.Run("type=browser", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false)
body, res := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, "foo=bar")
assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/registration-ts")
assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body)
assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "Could not find a strategy to sign you up with. Did you fill out the form correctly?", "%s", body)
})
})
t.Run("case=should show the error ui because the request id is missing", func(t *testing.T) {
check := func(t *testing.T, actual string) {
assert.Equal(t, int64(http.StatusNotFound), gjson.Get(actual, "code").Int(), "%s", actual)
assert.Equal(t, "Not Found", gjson.Get(actual, "status").String(), "%s", actual)
assert.Contains(t, gjson.Get(actual, "message").String(), "Unable to locate the resource", "%s", actual)
}
fakeFlow := &kratos.RegistrationFlow{Ui: kratos.UiContainer{
Action: publicTS.URL + registration.RouteSubmitFlow + "?flow=" + x.NewUUID().String(),
}}
t.Run("type=api", func(t *testing.T) {
actual, res := testhelpers.RegistrationMakeRequest(t, true, false, fakeFlow, apiClient, "{}")
assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow)
check(t, gjson.Get(actual, "error").Raw)
})
t.Run("type=api", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
actual, res := testhelpers.RegistrationMakeRequest(t, false, true, fakeFlow, browserClient, "{}")
assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow)
check(t, gjson.Get(actual, "error").Raw)
})
t.Run("type=browser", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
actual, res := testhelpers.RegistrationMakeRequest(t, false, false, fakeFlow, browserClient, "")
assert.Contains(t, res.Request.URL.String(), errTS.URL)
check(t, actual)
})
})
t.Run("case=should return an error because the request is expired", func(t *testing.T) {
conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationRequestLifespan, "500ms")
t.Cleanup(func() {
conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationRequestLifespan, "10m")
})
t.Run("type=api", func(t *testing.T) {
f := testhelpers.InitializeRegistrationFlowViaAPI(t, apiClient, publicTS)
time.Sleep(time.Millisecond * 600)
actual, res := testhelpers.RegistrationMakeRequest(t, true, false, f, apiClient, "{}")
assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow)
assert.NotEqual(t, "00000000-0000-0000-0000-000000000000", gjson.Get(actual, "use_flow_id").String())
assertx.EqualAsJSONExcept(t, flow.NewFlowExpiredError(time.Now()), json.RawMessage(actual), []string{"use_flow_id", "expired_at", "since"}, "expired", "%s", actual)
})
t.Run("type=spa", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true, false, false)
time.Sleep(time.Millisecond * 600)
actual, res := testhelpers.RegistrationMakeRequest(t, false, true, f, browserClient, "{}")
assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow)
assert.NotEqual(t, "00000000-0000-0000-0000-000000000000", gjson.Get(actual, "use_flow_id").String())
assertx.EqualAsJSONExcept(t, flow.NewFlowExpiredError(time.Now()), json.RawMessage(actual), []string{"use_flow_id", "expired_at", "since"}, "expired", "%s", actual)
})
t.Run("type=browser", func(t *testing.T) {
browserClient := testhelpers.NewClientWithCookies(t)
f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false)
time.Sleep(time.Millisecond * 600)
actual, res := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, "")
assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/registration-ts")
assert.NotEqual(t, f.Id, gjson.Get(actual, "id").String(), "%s", actual)
assert.Contains(t, gjson.Get(actual, "ui.messages.0.text").String(), "expired", "%s", actual)
})
})
t.Run("case=should fail because the password was used in databreaches", func(t *testing.T) {
testhelpers.SetDefaultIdentitySchemaFromRaw(conf, multifieldSchema)
t.Cleanup(func() {
testhelpers.SetDefaultIdentitySchemaFromRaw(conf, basicSchema)
})
email := testhelpers.RandomEmail()
check := func(t *testing.T, actual string) {
assert.NotEmpty(t, gjson.Get(actual, "id").String(), "%s", actual)
assert.Contains(t, gjson.Get(actual, "ui.action").String(), publicTS.URL+registration.RouteSubmitFlow, "%s", actual)
CheckFormContent(t, []byte(actual), "password", "csrf_token", "traits.username", "traits.foobar")
assert.Contains(t, gjson.Get(actual, "ui.nodes.#(attributes.name==password).messages.0").String(), "data breaches and must no longer be used.", "%s", actual)
// but the method is still set
assert.Equal(t, "password", gjson.Get(actual, "ui.nodes.#(attributes.name==method).attributes.value").String(), "%s", actual)
}
values := func(v url.Values) {
v.Set("traits.username", email)
v.Set("password", "password")
v.Set("traits.foobar", "bar")
}
for _, f := range flows {
t.Run("type="+f, func(t *testing.T) {
check(t, ExpectValidationError(t, publicTS, conf, f, values))
})
}
})
}