diff --git a/identity/pool.go b/identity/pool.go index e4830535b7fd..990f93deccb9 100644 --- a/identity/pool.go +++ b/identity/pool.go @@ -41,8 +41,11 @@ type ( PrivilegedPool interface { Pool - // FindByCredentialsIdentifier returns an identity by querying for it's credential identifiers. - FindByCredentialsIdentifier(ctx context.Context, ct CredentialsType, match string) (*Identity, *Credentials, error) + // FindByCredentialsTypeAndIdentifier returns an identity by querying for it's credential identifiers. + FindByCredentialsIdentifier(ctx context.Context, match string) (*Identity, error) + + // FindByCredentialsTypeAndIdentifier returns an identity by querying for it's credential type and identifiers. + FindByCredentialsTypeAndIdentifier(ctx context.Context, ct CredentialsType, match string) (*Identity, *Credentials, error) // DeleteIdentity removes an identity by its id. Will return an error // if identity exists, backend connectivity is broken, or trait validation fails. diff --git a/identity/test/pool.go b/identity/test/pool.go index 5f5a9d793ddb..99a4ce1bd3b0 100644 --- a/identity/test/pool.go +++ b/identity/test/pool.go @@ -600,7 +600,7 @@ func TestPool(ctx context.Context, conf *config.Config, p interface { require.NoError(t, p.CreateIdentity(ctx, expected)) createdIDs = append(createdIDs, expected.ID) - actual, creds, err := p.FindByCredentialsIdentifier(ctx, identity.CredentialsTypePassword, "find-credentials-identifier@ory.sh") + actual, creds, err := p.FindByCredentialsTypeAndIdentifier(ctx, identity.CredentialsTypePassword, "find-credentials-identifier@ory.sh") require.NoError(t, err) assert.EqualValues(t, expected.Credentials[identity.CredentialsTypePassword].ID, creds.ID) @@ -614,7 +614,7 @@ func TestPool(ctx context.Context, conf *config.Config, p interface { t.Run("not if on another network", func(t *testing.T) { _, p := testhelpers.NewNetwork(t, ctx, p) - _, _, err := p.FindByCredentialsIdentifier(ctx, identity.CredentialsTypePassword, "find-credentials-identifier@ory.sh") + _, _, err := p.FindByCredentialsTypeAndIdentifier(ctx, identity.CredentialsTypePassword, "find-credentials-identifier@ory.sh") require.ErrorIs(t, err, sqlcon.ErrNoRows) }) }) @@ -643,10 +643,10 @@ func TestPool(ctx context.Context, conf *config.Config, p interface { identity.CredentialsTypeLookup, } { t.Run(ct.String(), func(t *testing.T) { - _, _, err := p.FindByCredentialsIdentifier(ctx, ct, caseInsensitiveWithSpaces) + _, _, err := p.FindByCredentialsTypeAndIdentifier(ctx, ct, caseInsensitiveWithSpaces) require.Error(t, err) - actual, creds, err := p.FindByCredentialsIdentifier(ctx, ct, caseSensitive) + actual, creds, err := p.FindByCredentialsTypeAndIdentifier(ctx, ct, caseSensitive) require.NoError(t, err) assertx.EqualAsJSONExcept(t, expected.Credentials[ct], creds, []string{"created_at", "updated_at", "id"}) assertx.EqualAsJSONExcept(t, expected, actual, []string{"created_at", "state_changed_at", "updated_at", "id"}) @@ -661,7 +661,7 @@ func TestPool(ctx context.Context, conf *config.Config, p interface { } { t.Run(ct.String(), func(t *testing.T) { for _, cs := range []string{caseSensitive, caseInsensitiveWithSpaces} { - actual, creds, err := p.FindByCredentialsIdentifier(ctx, ct, cs) + actual, creds, err := p.FindByCredentialsTypeAndIdentifier(ctx, ct, cs) require.NoError(t, err) ec := expected.Credentials[ct] ec.Identifiers = []string{strings.ToLower(caseSensitive)} @@ -681,7 +681,7 @@ func TestPool(ctx context.Context, conf *config.Config, p interface { require.NoError(t, p.CreateIdentity(ctx, expected)) createdIDs = append(createdIDs, expected.ID) - actual, creds, err := p.FindByCredentialsIdentifier(ctx, identity.CredentialsTypePassword, identifier) + actual, creds, err := p.FindByCredentialsTypeAndIdentifier(ctx, identity.CredentialsTypePassword, identifier) require.NoError(t, err) assert.EqualValues(t, expected.Credentials[identity.CredentialsTypePassword].ID, creds.ID) @@ -693,7 +693,7 @@ func TestPool(ctx context.Context, conf *config.Config, p interface { t.Run("not if on another network", func(t *testing.T) { _, p := testhelpers.NewNetwork(t, ctx, p) - _, _, err := p.FindByCredentialsIdentifier(ctx, identity.CredentialsTypePassword, identifier) + _, _, err := p.FindByCredentialsTypeAndIdentifier(ctx, identity.CredentialsTypePassword, identifier) require.ErrorIs(t, err, sqlcon.ErrNoRows) }) }) @@ -1009,12 +1009,12 @@ func TestPool(ctx context.Context, conf *config.Config, p interface { _, err = p.GetIdentityConfidential(ctx, nid1) require.ErrorIs(t, err, sqlcon.ErrNoRows) - i, c, err := p.FindByCredentialsIdentifier(ctx, m[0].Name, "nid1") + i, c, err := p.FindByCredentialsTypeAndIdentifier(ctx, m[0].Name, "nid1") require.NoError(t, err) assert.Equal(t, "nid1", c.Identifiers[0]) require.Len(t, i.Credentials, 0) - _, _, err = p.FindByCredentialsIdentifier(ctx, m[0].Name, "nid2") + _, _, err = p.FindByCredentialsTypeAndIdentifier(ctx, m[0].Name, "nid2") require.ErrorIs(t, err, sqlcon.ErrNoRows) i, err = p.GetIdentityConfidential(ctx, iid) diff --git a/persistence/sql/persister_identity.go b/persistence/sql/persister_identity.go index f839b429b5d5..601fb07eb185 100644 --- a/persistence/sql/persister_identity.go +++ b/persistence/sql/persister_identity.go @@ -7,6 +7,7 @@ import ( "context" "database/sql" "fmt" + "github.com/gobuffalo/pop" "strings" "time" @@ -24,7 +25,6 @@ import ( "github.com/ory/kratos/otp" "github.com/ory/kratos/x" - "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" "github.com/pkg/errors" @@ -83,7 +83,7 @@ func (p *Persister) normalizeIdentifier(ct identity.CredentialsType, match strin return match } -func (p *Persister) FindByCredentialsIdentifier(ctx context.Context, ct identity.CredentialsType, match string) (*identity.Identity, *identity.Credentials, error) { +func (p *Persister) FindByCredentialsIdentifier(ctx context.Context, match string) (*identity.Identity, error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindByCredentialsIdentifier") defer span.End() @@ -93,6 +93,47 @@ func (p *Persister) FindByCredentialsIdentifier(ctx context.Context, ct identity IdentityID uuid.UUID `db:"identity_id"` } + // #nosec G201 + if err := p.GetConnection(ctx).RawQuery(fmt.Sprintf(`SELECT + ic.identity_id +FROM identity_credentials ic + INNER JOIN identity_credential_identifiers ici on ic.id = ici.identity_credential_id +WHERE ici.identifier = ? + AND ic.nid = ? + AND ici.nid = ?`, + "identity_credentials", + "identity_credential_types", + "identity_credential_identifiers", + ), + match, + nid, + nid, + ).First(&find); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, sqlcon.HandleError(err) // herodot.ErrNotFound.WithTrace(err).WithReasonf(`No identity matching credentials identifier "%s" could be found.`, match) + } + + return nil, sqlcon.HandleError(err) + } + + i, err := p.GetIdentityConfidential(ctx, find.IdentityID) + if err != nil { + return nil, err + } + + return i.CopyWithoutCredentials(), nil +} + +func (p *Persister) FindByCredentialsTypeAndIdentifier(ctx context.Context, ct identity.CredentialsType, match string) (*identity.Identity, *identity.Credentials, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindByCredentialsTypeAndIdentifier") + defer span.End() + + nid := p.NetworkID(ctx) + + var find struct { + IdentityID uuid.UUID `db:"identity_id"` + } + // Force case-insensitivity and trimming for identifiers match = p.normalizeIdentifier(ct, match) diff --git a/selfservice/strategy/lookup/login.go b/selfservice/strategy/lookup/login.go index b5e5fddda7e8..ab7f50ba4d9b 100644 --- a/selfservice/strategy/lookup/login.go +++ b/selfservice/strategy/lookup/login.go @@ -110,7 +110,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, s.handleLoginError(r, f, err) } - i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), s.ID(), identityID.String()) + i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(r.Context(), s.ID(), identityID.String()) if errors.Is(err, sqlcon.ErrNoRows) { return nil, s.handleLoginError(r, f, errors.WithStack(schema.NewNoLookupDefined())) } else if err != nil { diff --git a/selfservice/strategy/lookup/settings.go b/selfservice/strategy/lookup/settings.go index 261336ecdcbc..b1b06e3da93c 100644 --- a/selfservice/strategy/lookup/settings.go +++ b/selfservice/strategy/lookup/settings.go @@ -216,7 +216,7 @@ func (s *Strategy) continueSettingsFlowReveal(w http.ResponseWriter, r *http.Req return errors.WithStack(herodot.ErrBadRequest.WithReasonf("Can not reveal lookup codes because you have none.")) } - _, cred, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), s.ID(), ctxUpdate.Session.IdentityID.String()) + _, cred, err := s.d.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(r.Context(), s.ID(), ctxUpdate.Session.IdentityID.String()) if err != nil { return err } diff --git a/selfservice/strategy/lookup/settings_test.go b/selfservice/strategy/lookup/settings_test.go index 92a81e964971..320f09842706 100644 --- a/selfservice/strategy/lookup/settings_test.go +++ b/selfservice/strategy/lookup/settings_test.go @@ -214,7 +214,7 @@ func TestCompleteSettings(t *testing.T) { id, codes := createIdentity(t, reg) checkIdentity := func(t *testing.T) { - _, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeLookup, id.ID.String()) + _, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeLookup, id.ID.String()) require.NoError(t, err) assertx.EqualAsJSON(t, codes, json.RawMessage(gjson.GetBytes(cred.Config, "recovery_codes").Raw)) } @@ -280,7 +280,7 @@ func TestCompleteSettings(t *testing.T) { const reason = "You must (re-)generate recovery backup codes before you can save them." checkIdentity := func(t *testing.T) { - _, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeLookup, id.ID.String()) + _, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeLookup, id.ID.String()) require.NoError(t, err) assertx.EqualAsJSON(t, codes, json.RawMessage(gjson.GetBytes(cred.Config, "recovery_codes").Raw)) } @@ -315,7 +315,7 @@ func TestCompleteSettings(t *testing.T) { } checkIdentity := func(t *testing.T) { - _, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeLookup, id.ID.String()) + _, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeLookup, id.ID.String()) require.NoError(t, err) assertx.EqualAsJSON(t, codes, json.RawMessage(gjson.GetBytes(cred.Config, "recovery_codes").Raw)) } @@ -377,7 +377,7 @@ func TestCompleteSettings(t *testing.T) { } checkIdentity := func(t *testing.T, id *identity.Identity, f *kratos.SettingsFlow) { - _, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeLookup, id.ID.String()) + _, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeLookup, id.ID.String()) require.NoError(t, err) assert.NotContains(t, gjson.GetBytes(cred.Config, "recovery_codes").Raw, "key-1") assert.NotContains(t, gjson.GetBytes(cred.Config, "recovery_codes").Raw, "key-0") @@ -470,7 +470,7 @@ func TestCompleteSettings(t *testing.T) { } checkIdentity := func(t *testing.T, id *identity.Identity, f *kratos.SettingsFlow) { - _, _, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeLookup, id.ID.String()) + _, _, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeLookup, id.ID.String()) require.ErrorIs(t, err, sqlcon.ErrNoRows) actualFlow, err := reg.SettingsFlowPersister().GetSettingsFlow(context.Background(), uuid.FromStringOrNil(f.Id)) diff --git a/selfservice/strategy/oidc/strategy_login.go b/selfservice/strategy/oidc/strategy_login.go index 1b6c43e15a32..57fb052265bd 100644 --- a/selfservice/strategy/oidc/strategy_login.go +++ b/selfservice/strategy/oidc/strategy_login.go @@ -77,7 +77,7 @@ type UpdateLoginFlowWithOidcMethod struct { } func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, a *login.Flow, token *oauth2.Token, claims *Claims, provider Provider, container *authCodeContainer) (*registration.Flow, error) { - i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), identity.CredentialsTypeOIDC, identity.OIDCUniqueID(provider.Config().ID, claims.Subject)) + i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(r.Context(), identity.CredentialsTypeOIDC, identity.OIDCUniqueID(provider.Config().ID, claims.Subject)) if err != nil { if errors.Is(err, sqlcon.ErrNoRows) { // If no account was found we're "manually" creating a new registration flow and redirecting the browser diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index 7f2fde690124..5d06699ec7f0 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -163,7 +163,7 @@ func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registrat } func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, a *registration.Flow, token *oauth2.Token, claims *Claims, provider Provider, container *authCodeContainer) (*login.Flow, error) { - if _, _, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), identity.CredentialsTypeOIDC, identity.OIDCUniqueID(provider.Config().ID, claims.Subject)); err == nil { + if _, _, err := s.d.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(r.Context(), identity.CredentialsTypeOIDC, identity.OIDCUniqueID(provider.Config().ID, claims.Subject)); err == nil { // If the identity already exists, we should perform the login flow instead. // That will execute the "pre registration" hook which allows to e.g. disallow this flow. The registration diff --git a/selfservice/strategy/password/login.go b/selfservice/strategy/password/login.go index 30010b80eb54..1ea01329f463 100644 --- a/selfservice/strategy/password/login.go +++ b/selfservice/strategy/password/login.go @@ -67,7 +67,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, s.handleLoginError(w, r, f, &p, err) } - i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), s.ID(), stringsx.Coalesce(p.Identifier, p.LegacyIdentifier)) + i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(r.Context(), s.ID(), stringsx.Coalesce(p.Identifier, p.LegacyIdentifier)) if err != nil { time.Sleep(x.RandomDelay(s.d.Config().HasherArgon2(r.Context()).ExpectedDuration, s.d.Config().HasherArgon2(r.Context()).ExpectedDeviation)) return nil, s.handleLoginError(w, r, f, &p, errors.WithStack(schema.NewInvalidCredentialsError())) diff --git a/selfservice/strategy/password/login_test.go b/selfservice/strategy/password/login_test.go index c6357ff6920f..9ee4dc3d037b 100644 --- a/selfservice/strategy/password/login_test.go +++ b/selfservice/strategy/password/login_test.go @@ -850,7 +850,7 @@ func TestCompleteLogin(t *testing.T) { assert.Equal(t, identifier, gjson.Get(body, "identity.traits.subject").String(), "%s", body) // check if password hash algorithm is upgraded - _, c, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypePassword, identifier) + _, c, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypePassword, identifier) require.NoError(t, err) var o identity.CredentialsPassword require.NoError(t, json.NewDecoder(bytes.NewBuffer(c.Config)).Decode(&o)) diff --git a/selfservice/strategy/totp/login.go b/selfservice/strategy/totp/login.go index e3840eba1b9b..4ebe9b7ca6e4 100644 --- a/selfservice/strategy/totp/login.go +++ b/selfservice/strategy/totp/login.go @@ -106,7 +106,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, s.handleLoginError(r, f, err) } - i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), s.ID(), identityID.String()) + i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(r.Context(), s.ID(), identityID.String()) if err != nil { return nil, s.handleLoginError(r, f, errors.WithStack(schema.NewNoTOTPDeviceRegistered())) } diff --git a/selfservice/strategy/totp/settings_test.go b/selfservice/strategy/totp/settings_test.go index b9b294ffdf4e..c7cbf59a50cf 100644 --- a/selfservice/strategy/totp/settings_test.go +++ b/selfservice/strategy/totp/settings_test.go @@ -153,7 +153,7 @@ func TestCompleteSettings(t *testing.T) { } checkIdentity := func(t *testing.T) { - _, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String()) + _, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String()) require.NoError(t, err) assert.Equal(t, key.URL(), gjson.GetBytes(cred.Config, "totp_url").String()) } @@ -195,7 +195,7 @@ func TestCompleteSettings(t *testing.T) { } checkIdentity := func(t *testing.T) { - _, _, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String()) + _, _, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String()) require.ErrorIs(t, err, sqlcon.ErrNoRows) } @@ -230,7 +230,7 @@ func TestCompleteSettings(t *testing.T) { } checkIdentity := func(t *testing.T, id *identity.Identity) { - _, _, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String()) + _, _, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String()) require.ErrorIs(t, err, sqlcon.ErrNoRows) } @@ -268,7 +268,7 @@ func TestCompleteSettings(t *testing.T) { } checkIdentity := func(t *testing.T, id *identity.Identity) { - _, _, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String()) + _, _, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String()) require.ErrorIs(t, err, sqlcon.ErrNoRows) } @@ -302,7 +302,7 @@ func TestCompleteSettings(t *testing.T) { t.Run("type=set up TOTP device", func(t *testing.T) { checkIdentity := func(t *testing.T, id *identity.Identity, key string) { - i, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String()) + i, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String()) require.NoError(t, err) var c identity.CredentialsTOTPConfig require.NoError(t, json.Unmarshal(cred.Config, &c)) diff --git a/selfservice/strategy/webauthn/login.go b/selfservice/strategy/webauthn/login.go index 12050ddb00b6..324526177d61 100644 --- a/selfservice/strategy/webauthn/login.go +++ b/selfservice/strategy/webauthn/login.go @@ -239,7 +239,7 @@ func (s *Strategy) loginPasswordless(w http.ResponseWriter, r *http.Request, f * return nil, s.handleLoginError(r, f, errors.WithStack(herodot.ErrBadRequest.WithReason("identifier is required"))) } - i, _, err = s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), s.ID(), p.Identifier) + i, _, err = s.d.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(r.Context(), s.ID(), p.Identifier) if err != nil { time.Sleep(x.RandomDelay(s.d.Config().HasherArgon2(r.Context()).ExpectedDuration, s.d.Config().HasherArgon2(r.Context()).ExpectedDeviation)) return nil, s.handleLoginError(r, f, errors.WithStack(schema.NewNoWebAuthnCredentials())) diff --git a/selfservice/strategy/webauthn/registration_test.go b/selfservice/strategy/webauthn/registration_test.go index ab9baa4eb4d5..6dddf8ed49fb 100644 --- a/selfservice/strategy/webauthn/registration_test.go +++ b/selfservice/strategy/webauthn/registration_test.go @@ -294,7 +294,7 @@ func TestRegistration(t *testing.T) { assert.Equal(t, "null\n", actual, "because the registration yielded no session, the user is not expected to be signed in: %s", actual) } - i, _, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeWebAuthn, email) + i, _, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeWebAuthn, email) require.NoError(t, err) assert.Equal(t, email, gjson.GetBytes(i.Traits, "username").String(), "%s", actual) }) @@ -319,7 +319,7 @@ func TestRegistration(t *testing.T) { assert.Equal(t, email, gjson.Get(actual, prefix+"identity.traits.username").String(), "%s", actual) assert.True(t, gjson.Get(actual, prefix+"active").Bool(), "%s", actual) - i, _, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeWebAuthn, email) + i, _, err := reg.PrivilegedIdentityPool().FindByCredentialsTypeAndIdentifier(context.Background(), identity.CredentialsTypeWebAuthn, email) require.NoError(t, err) assert.Equal(t, email, gjson.GetBytes(i.Traits, "username").String(), "%s", actual) })