mirror of
https://github.com/MAKS-IT-COM/maksit-certs-ui.git
synced 2026-05-16 04:48:12 +02:00
(bugfix): redundant users.JwtTokensJson, fluent migrator improvements
This commit is contained in:
parent
86a31999bf
commit
c6d5b3fd1e
16
CHANGELOG.md
16
CHANGELOG.md
@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [3.3.14] - 2026-04-26
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Identity / PostgreSQL:** Removed redundant `users.JwtTokensJson` (historical JSON blob of sessions on the user row). **Server-side session allowlist semantics are unchanged:** issued sessions remain rows in `jwt_tokens` and are validated the same way as in Vault’s persisted `JwtToken` model—only the duplicate JSON encoding was dropped. New `users` inserts no longer hit `23502` on that column. FluentMigrator `DropUsersJwtTokensJson` (`20260426140000`) drops the column when present; the baseline no longer creates it; `JwtTokensTableMigrateFromJson` copies from JSON only if that column still exists (upgrades from older DBs).
|
||||
|
||||
### Changed
|
||||
|
||||
- **FluentMigrator:** `RestoreUsersJwtTokensJsonIfDropped` (`20260426120000`) is now a no-op (revision kept for databases that already applied it). Session material is stored only in `jwt_tokens`, not duplicated as JSON on `users`.
|
||||
|
||||
## [3.3.13] - 2026-04-26
|
||||
|
||||
### Fixed
|
||||
@ -29,13 +39,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
|
||||
### Added
|
||||
|
||||
- **Database:** FluentMigrator `RestoreUsersJwtTokensJsonIfDropped` (`20260426120000`) restores `users.JwtTokensJson` with `ADD COLUMN IF NOT EXISTS` when an older database had it removed by a prior `JwtTokensTableMigrateFromJson` revision.
|
||||
- **Database:** FluentMigrator `RestoreUsersJwtTokensJsonIfDropped` (`20260426120000`) initially re-added `users.JwtTokensJson` with `ADD COLUMN IF NOT EXISTS` for databases that had dropped it under an older `JwtTokensTableMigrateFromJson` revision. **Superseded in 3.3.14:** that revision is a no-op and `DropUsersJwtTokensJson` drops the column; tokens stay in `jwt_tokens` only.
|
||||
- **Helm / config:** `certsServerConfig.configuration.certsUIEngineConfiguration.autoSyncSchema` (default `true`) is rendered into server `appsettings.json` so add-only schema sync runs on every startup unless explicitly disabled.
|
||||
|
||||
### Changed
|
||||
|
||||
- **Startup schema policy:** Documented expand-only expectations — FluentMigrator `Up()` should add tables/columns; avoid dropping renamed or legacy columns in `Up()`. `JwtTokensTableMigrateFromJson` no longer drops `JwtTokensJson` (tokens remain in `jwt_tokens`; legacy JSON column may remain for audit).
|
||||
- **Schema sync:** `AutoSyncSchema` defaults to **true** in repo `appsettings.json`; `SchemaSyncService` desired map includes `users.IsActive`, `TwoFactorSharedKey`, and optional `JwtTokensJson` for additive repair. Still **ADD COLUMN IF NOT EXISTS** only (no DROP).
|
||||
- **Startup schema policy:** Documented expand-only expectations — FluentMigrator `Up()` should add tables/columns; avoid dropping renamed columns in routine `Up()` without an explicit follow-up plan. `JwtTokensTableMigrateFromJson` no longer drops `JwtTokensJson` in that revision’s `Up()` (tokens are normalized into `jwt_tokens`). **3.3.14** removes `JwtTokensJson` from the live schema via `DropUsersJwtTokensJson`.
|
||||
- **Schema sync:** `AutoSyncSchema` defaults to **true** in repo `appsettings.json`; `SchemaSyncService` desired map includes `users.IsActive` and `TwoFactorSharedKey`. **3.3.14** stops treating `JwtTokensJson` as a desired column. Still **ADD COLUMN IF NOT EXISTS** only (no DROP in sync).
|
||||
- **ICertsEngineConfiguration / ISchemaSyncService:** Clarified that add-only sync is recommended and describes the no-DROP guarantee.
|
||||
|
||||
## [3.3.10] - 2026-04-26
|
||||
|
||||
@ -3,13 +3,13 @@ using MaksIT.Core.Abstractions.Dto;
|
||||
namespace MaksIT.CertsUI.Engine.Dto.Identity;
|
||||
|
||||
/// <summary>
|
||||
/// PostgreSQL <c>users</c> row (Linq2DB). JWT sessions live in <c>jwt_tokens</c>; <see cref="JwtTokens"/> is not a mapped column.
|
||||
/// A legacy <c>JwtTokensJson</c> column may still exist on the table for expand-only migrations; it is not mapped here.
|
||||
/// PostgreSQL <c>users</c> row (Linq2DB). JWT sessions are rows in <c>jwt_tokens</c>; <see cref="JwtTokens"/> is loaded separately, not a column on <c>users</c>.
|
||||
/// </summary>
|
||||
public class UserDto : DtoDocumentBase<Guid> {
|
||||
public required string Name { get; set; }
|
||||
public required string Salt { get; set; }
|
||||
public required string Hash { get; set; }
|
||||
|
||||
public DateTime LastLoginUtc { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
public string? TwoFactorSharedKey { get; set; }
|
||||
|
||||
@ -25,7 +25,6 @@ public class BaselineCertsSchema : Migration {
|
||||
.WithColumn("Name").AsCustom("text").NotNullable()
|
||||
.WithColumn("Salt").AsCustom("text").NotNullable()
|
||||
.WithColumn("Hash").AsCustom("text").NotNullable()
|
||||
.WithColumn("JwtTokensJson").AsCustom("text").NotNullable()
|
||||
.WithColumn("LastLoginUtc").AsDateTimeOffset().NotNullable();
|
||||
|
||||
Create.Index("IX_users_Name").OnTable("users").OnColumn("Name").Unique();
|
||||
|
||||
@ -4,8 +4,8 @@ using FluentMigrator;
|
||||
namespace MaksIT.CertsUI.Engine.FluentMigrations;
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes JWT refresh/access tokens into <c>jwt_tokens</c> (one row per token). Legacy <c>users.JwtTokensJson</c> is retained
|
||||
/// (expand-only policy); the app reads <c>jwt_tokens</c> only.
|
||||
/// Normalizes JWT refresh/access tokens into <c>jwt_tokens</c> (one row per token).
|
||||
/// If <c>users.JwtTokensJson</c> exists (older databases), rows are copied from that JSON; otherwise this step only creates <c>jwt_tokens</c>.
|
||||
/// </summary>
|
||||
[Migration(20260418100000)]
|
||||
public class JwtTokensTableMigrateFromJson : Migration {
|
||||
@ -29,6 +29,7 @@ public class JwtTokensTableMigrateFromJson : Migration {
|
||||
Create.Index("IX_jwt_tokens_Token").OnTable("jwt_tokens").OnColumn("Token");
|
||||
Create.Index("IX_jwt_tokens_RefreshToken").OnTable("jwt_tokens").OnColumn("RefreshToken");
|
||||
|
||||
if (Schema.Table("users").Column("JwtTokensJson").Exists()) {
|
||||
Execute.Sql("""
|
||||
INSERT INTO "jwt_tokens" ("Id", "UserId", "Token", "RefreshToken", "IssuedAt", "ExpiresAt", "RefreshTokenExpiresAt", "IsRevoked")
|
||||
SELECT
|
||||
@ -48,6 +49,7 @@ public class JwtTokensTableMigrateFromJson : Migration {
|
||||
WHERE (elem->>'Id') IS NOT NULL
|
||||
""");
|
||||
}
|
||||
}
|
||||
|
||||
public override void Down() =>
|
||||
throw new NotSupportedException("Restore from backup; this migration does not support rollback.");
|
||||
|
||||
@ -3,15 +3,13 @@ using FluentMigrator;
|
||||
namespace MaksIT.CertsUI.Engine.FluentMigrations;
|
||||
|
||||
/// <summary>
|
||||
/// Databases that already applied <see cref="JwtTokensTableMigrateFromJson"/> when it still dropped <c>JwtTokensJson</c>
|
||||
/// get the column back (empty default). Expand-only: we never remove renamed/legacy columns in <c>Up()</c>.
|
||||
/// Previously re-added <c>users.JwtTokensJson</c> when a prior migration had dropped that JSON column.
|
||||
/// <see cref="DropUsersJwtTokensJson"/> removes the column; persisted sessions use <c>jwt_tokens</c> only (same role as Vault’s <c>JwtToken</c> rows).
|
||||
/// </summary>
|
||||
[Migration(20260426120000)]
|
||||
public class RestoreUsersJwtTokensJsonIfDropped : Migration {
|
||||
public override void Up() {
|
||||
Execute.Sql("""
|
||||
ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "JwtTokensJson" text NOT NULL DEFAULT '';
|
||||
""");
|
||||
// No-op: revision kept so databases that already applied the old DDL remain valid; see DropUsersJwtTokensJson.
|
||||
}
|
||||
|
||||
public override void Down() =>
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
using FluentMigrator;
|
||||
|
||||
namespace MaksIT.CertsUI.Engine.FluentMigrations;
|
||||
|
||||
/// <summary>
|
||||
/// Drops <c>users.JwtTokensJson</c> when present (old JSON copy of sessions). Sessions remain in <c>jwt_tokens</c> for server-side validation / allowlist behavior.
|
||||
/// </summary>
|
||||
[Migration(20260426140000)]
|
||||
public class DropUsersJwtTokensJson : Migration {
|
||||
public override void Up() {
|
||||
if (Schema.Table("users").Column("JwtTokensJson").Exists())
|
||||
Delete.Column("JwtTokensJson").FromTable("users");
|
||||
}
|
||||
|
||||
public override void Down() =>
|
||||
throw new NotSupportedException("Down is not supported; restore from backup if required.");
|
||||
}
|
||||
@ -83,7 +83,6 @@ public class SchemaSyncService(ICertsEngineConfiguration config, ILogger<SchemaS
|
||||
("Name", "text"),
|
||||
("Salt", "text"),
|
||||
("Hash", "text"),
|
||||
("JwtTokensJson", "text"),
|
||||
("LastLoginUtc", "timestamp with time zone"),
|
||||
("IsActive", "boolean"),
|
||||
("TwoFactorSharedKey", "text"),
|
||||
@ -168,7 +167,6 @@ public class SchemaSyncService(ICertsEngineConfiguration config, ILogger<SchemaS
|
||||
|
||||
if (table.Equals("users", StringComparison.OrdinalIgnoreCase)) {
|
||||
if (column.Equals("TwoFactorSharedKey", StringComparison.OrdinalIgnoreCase)) return false;
|
||||
if (column.Equals("JwtTokensJson", StringComparison.OrdinalIgnoreCase)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>3.3.13</Version>
|
||||
<Version>3.3.14</Version>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user