Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
123 lines
4.4 KiB
Go
123 lines
4.4 KiB
Go
// Copyright © 2026 Ory Corp
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package identity_test
|
|
|
|
// Since:
|
|
// - This is a separate test package
|
|
// - Go creates one executable per test package
|
|
// - Go global variables are isolated per process (i.e. executable)
|
|
// - This test uses its own database
|
|
// , it means that this test is independent from the others and cannot interfere with them.
|
|
// We do not need to clear the global maps at the start of the test: they are still pristine (unset).
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gofrs/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
id "github.com/ory/kratos/identity"
|
|
"github.com/ory/kratos/persistence/sql/identity"
|
|
"github.com/ory/kratos/pkg"
|
|
"github.com/ory/kratos/pkg/testhelpers"
|
|
"github.com/ory/kratos/x"
|
|
"github.com/ory/x/dbal"
|
|
"github.com/ory/x/sqlxx"
|
|
)
|
|
|
|
// TestCreateIdentities_WritesExtraColumns verifies that WithExtraColumns is
|
|
// forwarded from CreateIdentities down to the batch INSERT.
|
|
func TestCreateIdentities_WritesExtraColumns(t *testing.T) {
|
|
_, reg := pkg.NewRegistryDefaultWithDSN(t, dbal.NewSQLiteTestDatabase(t))
|
|
_, p := testhelpers.NewNetwork(t, t.Context(), reg.Persister())
|
|
|
|
require.NoError(t,
|
|
p.GetConnection(t.Context()).RawQuery(`ALTER TABLE identities ADD COLUMN extra_foo TEXT`).Exec(),
|
|
)
|
|
|
|
ctx := testhelpers.WithDefaultIdentitySchemaFromRaw(t.Context(), []byte(`{"$id":"test","type":"object"}`))
|
|
|
|
ident := id.NewIdentity("")
|
|
require.NoError(t, p.CreateIdentities(ctx, []*id.Identity{ident},
|
|
id.WithExtraColumns([]id.ExtraColumn{{K: "extra_foo", V: "bar"}}),
|
|
))
|
|
|
|
var got string
|
|
require.NoError(t,
|
|
p.GetConnection(t.Context()).RawQuery(
|
|
`SELECT extra_foo FROM identities WHERE id = ?`, ident.ID,
|
|
).First(&got),
|
|
)
|
|
assert.Equal(t, "bar", got)
|
|
}
|
|
|
|
func TestNonStandardCredentialTypes(t *testing.T) {
|
|
_, reg := pkg.NewRegistryDefaultWithDSN(t, dbal.NewSQLiteTestDatabase(t))
|
|
_, p := testhelpers.NewNetwork(t, t.Context(), reg.Persister())
|
|
|
|
// Replace the content of the table with custom UUIDs. This relies on the
|
|
// process-global credential-types cache being pristine, which the header
|
|
// comment's package isolation guarantees — no other test in this package
|
|
// touches the cache first.
|
|
{
|
|
require.NoError(t, p.GetConnection(t.Context()).RawQuery(`DELETE FROM identity_credential_types`, x.NewUUID()).Exec())
|
|
|
|
// Test the case of empty credentials in the database, so that we can exercise the case of loading credentials failing,
|
|
// and then subsequent loads succeed, and the service does not get suck.
|
|
_, err := identity.FindIdentityCredentialsTypeByName(p.GetConnection(t.Context()), id.CredentialsTypeOIDC)
|
|
require.Error(t, err)
|
|
|
|
// Now fill the table with non-standard UUIDs.
|
|
q := strings.Builder{}
|
|
q.WriteString(`INSERT INTO identity_credential_types (id, name) VALUES `)
|
|
for i, ct := range id.AllCredentialTypes {
|
|
fmt.Fprintf(&q, `('%s', '%s')`, x.NewUUID(), ct)
|
|
if i < len(id.AllCredentialTypes)-1 {
|
|
q.WriteRune(',')
|
|
}
|
|
}
|
|
require.NoError(t, p.GetConnection(t.Context()).RawQuery(q.String()).Exec())
|
|
}
|
|
|
|
// Valid credential types are found.
|
|
for _, ct := range id.AllCredentialTypes {
|
|
t.Run("type="+ct.String(), func(t *testing.T) {
|
|
id, err := identity.FindIdentityCredentialsTypeByName(p.GetConnection(t.Context()), ct)
|
|
require.NoError(t, err)
|
|
|
|
require.NotEqual(t, uuid.Nil, id)
|
|
name, err := identity.FindIdentityCredentialsTypeByID(p.GetConnection(t.Context()), id)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, ct, name)
|
|
})
|
|
}
|
|
|
|
// Invalid credential types are not found.
|
|
_, err := identity.FindIdentityCredentialsTypeByName(p.GetConnection(t.Context()), "unknown")
|
|
require.Error(t, err)
|
|
|
|
_, err = identity.FindIdentityCredentialsTypeByID(p.GetConnection(t.Context()), x.NewUUID())
|
|
require.Error(t, err)
|
|
|
|
// Create an identity and find it by credential identifier.
|
|
ctx := testhelpers.WithDefaultIdentitySchemaFromRaw(t.Context(), []byte(`{"$id":"test","type":"object"}`))
|
|
email := "test-" + x.NewUUID().String() + "@example.com"
|
|
i := id.NewIdentity("")
|
|
i.SetCredentials(id.CredentialsTypePassword, id.Credentials{
|
|
Type: id.CredentialsTypePassword,
|
|
Identifiers: []string{email},
|
|
Config: sqlxx.JSONRawMessage(`{}`),
|
|
})
|
|
require.NoError(t, p.CreateIdentity(ctx, i))
|
|
|
|
actualIdentity, actualCreds, err := p.FindByCredentialsIdentifier(ctx, id.CredentialsTypePassword, email)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, i.ID, actualIdentity.ID)
|
|
assert.Equal(t, []string{email}, actualCreds.Identifiers)
|
|
}
|