diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_password_migration_hook_enabled.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_password_migration_hook_enabled.json new file mode 100644 index 00000000000..e89fc60f2d8 --- /dev/null +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_password_migration_hook_enabled.json @@ -0,0 +1,22 @@ +{ + "credentials": { + "password": { + "type": "password", + "identifiers": [ + "pw-migration-hook@ory.sh" + ], + "config": { + "use_password_migration_hook": true + }, + "version": 0 + } + }, + "schema_id": "default", + "state": "active", + "traits": { + "email": "pw-migration-hook@ory.sh" + }, + "metadata_public": null, + "metadata_admin": null, + "organization_id": null +} diff --git a/identity/handler.go b/identity/handler.go index cf4d3ff835e..cf85dc792c4 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -424,6 +424,9 @@ type AdminIdentityImportCredentialsPasswordConfig struct { // The password in plain text if no hash is available. Password string `json:"password"` + + // If set to true, the password will be migrated using the password migration hook. + UsePasswordMigrationHook bool `json:"use_password_migration_hook,omitempty"` } // Create Identity and Import Social Sign In Credentials diff --git a/identity/handler_import.go b/identity/handler_import.go index a3a7ca2ab0a..cca346e8e67 100644 --- a/identity/handler_import.go +++ b/identity/handler_import.go @@ -35,6 +35,10 @@ func (h *Handler) importCredentials(ctx context.Context, i *Identity, creds *Ide } func (h *Handler) importPasswordCredentials(ctx context.Context, i *Identity, creds *AdminIdentityImportCredentialsPassword) (err error) { + if creds.Config.UsePasswordMigrationHook { + return i.SetCredentialsWithConfig(CredentialsTypePassword, Credentials{}, CredentialsPassword{UsePasswordMigrationHook: true}) + } + // In here we deliberately ignore any password policies as the point here is to import passwords, even if they // are not matching the policy, as the user needs to able to sign in with their old password. hashed := []byte(creds.Config.HashedPassword) diff --git a/identity/handler_test.go b/identity/handler_test.go index 53ca219b231..d97c2f73fae 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -307,6 +307,21 @@ func TestHandler(t *testing.T) { } }) + t.Run("with password migration hook enabled", func(t *testing.T) { + res := send(t, adminTS, "POST", "/identities", http.StatusCreated, identity.CreateIdentityBody{ + Traits: []byte(`{"email": "pw-migration-hook@ory.sh"}`), + Credentials: &identity.IdentityWithCredentials{Password: &identity.AdminIdentityImportCredentialsPassword{ + Config: identity.AdminIdentityImportCredentialsPasswordConfig{UsePasswordMigrationHook: true}, + }}, + }) + actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, uuid.FromStringOrNil(res.Get("id").String())) + require.NoError(t, err) + + snapshotx.SnapshotT(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), snapshotx.ExceptNestedKeys(ignoreDefault...), snapshotx.ExceptNestedKeys("hashed_password")) + + assert.True(t, gjson.GetBytes(actual.Credentials[identity.CredentialsTypePassword].Config, "use_password_migration_hook").Bool()) + }) + t.Run("with not-normalized email", func(t *testing.T) { res := send(t, adminTS, "POST", "/identities", http.StatusCreated, identity.CreateIdentityBody{ SchemaID: "customer",