202 lines
10 KiB
C#
202 lines
10 KiB
C#
using System;
|
|
using Microsoft.EntityFrameworkCore.Migrations;
|
|
|
|
#nullable disable
|
|
|
|
namespace Tiku.Infrastructure.Persistence.Migrations
|
|
{
|
|
/// <inheritdoc />
|
|
public partial class AddAuthorizationCaching : Migration
|
|
{
|
|
/// <inheritdoc />
|
|
protected override void Up(MigrationBuilder migrationBuilder)
|
|
{
|
|
migrationBuilder.CreateTable(
|
|
name: "authorization_cache_invalidations",
|
|
columns: table => new
|
|
{
|
|
id = table.Column<Guid>(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"),
|
|
target_type = table.Column<string>(type: "character varying(40)", maxLength: 40, nullable: false),
|
|
tenant_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
user_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
session_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
realm = table.Column<string>(type: "text", nullable: true),
|
|
version = table.Column<long>(type: "bigint", nullable: true),
|
|
processed_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
|
attempt_count = table.Column<int>(type: "integer", nullable: false),
|
|
last_error = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true),
|
|
created_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
|
updated_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()")
|
|
},
|
|
constraints: table =>
|
|
{
|
|
table.PrimaryKey("pk_authorization_cache_invalidations", x => x.id);
|
|
});
|
|
|
|
migrationBuilder.CreateTable(
|
|
name: "authorization_scope_versions",
|
|
columns: table => new
|
|
{
|
|
id = table.Column<Guid>(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"),
|
|
realm = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
tenant_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
version = table.Column<long>(type: "bigint", nullable: false, defaultValue: 1L),
|
|
created_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
|
updated_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()")
|
|
},
|
|
constraints: table =>
|
|
{
|
|
table.PrimaryKey("pk_authorization_scope_versions", x => x.id);
|
|
table.CheckConstraint("ck_authorization_scope_versions_realm_tenant", "(realm = 'tenant' and tenant_id is not null) or (realm = 'platform' and tenant_id is null)");
|
|
table.ForeignKey(
|
|
name: "fk_authorization_scope_versions_tenants_tenant_id",
|
|
column: x => x.tenant_id,
|
|
principalTable: "tenants",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
});
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_authorization_cache_invalidations_processed_at_created_at",
|
|
table: "authorization_cache_invalidations",
|
|
columns: new[] { "processed_at", "created_at" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_authorization_cache_invalidations_target_type_tenant_id_use~",
|
|
table: "authorization_cache_invalidations",
|
|
columns: new[] { "target_type", "tenant_id", "user_id", "session_id", "version" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_authorization_scope_versions_realm",
|
|
table: "authorization_scope_versions",
|
|
column: "realm",
|
|
unique: true,
|
|
filter: "realm = 'platform'");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_authorization_scope_versions_tenant_id",
|
|
table: "authorization_scope_versions",
|
|
column: "tenant_id",
|
|
unique: true,
|
|
filter: "tenant_id is not null");
|
|
|
|
migrationBuilder.Sql("""
|
|
INSERT INTO authorization_scope_versions
|
|
(id, realm, tenant_id, version, created_at, updated_at)
|
|
VALUES
|
|
(gen_random_uuid(), 'platform', NULL, 1, now(), now());
|
|
|
|
INSERT INTO authorization_scope_versions
|
|
(id, realm, tenant_id, version, created_at, updated_at)
|
|
SELECT gen_random_uuid(), 'tenant', id, 1, now(), now()
|
|
FROM tenants;
|
|
""");
|
|
|
|
migrationBuilder.Sql("""
|
|
CREATE OR REPLACE FUNCTION tiku_bump_tenant_authorization_version()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $$
|
|
DECLARE
|
|
scope_tenant_id uuid;
|
|
next_version bigint;
|
|
BEGIN
|
|
IF TG_OP = 'DELETE' THEN
|
|
scope_tenant_id := OLD.tenant_id;
|
|
ELSE
|
|
scope_tenant_id := NEW.tenant_id;
|
|
END IF;
|
|
|
|
UPDATE authorization_scope_versions
|
|
SET version = version + 1, updated_at = now()
|
|
WHERE realm = 'tenant' AND tenant_id = scope_tenant_id
|
|
RETURNING version INTO next_version;
|
|
|
|
IF next_version IS NOT NULL THEN
|
|
INSERT INTO authorization_cache_invalidations
|
|
(id, target_type, tenant_id, realm, version, attempt_count, created_at, updated_at)
|
|
VALUES
|
|
(gen_random_uuid(), 'scope', scope_tenant_id, 'tenant', next_version, 0, now(), now());
|
|
END IF;
|
|
IF TG_OP = 'DELETE' THEN RETURN OLD; END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
|
|
CREATE OR REPLACE FUNCTION tiku_bump_platform_authorization_version()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $$
|
|
DECLARE next_version bigint;
|
|
BEGIN
|
|
UPDATE authorization_scope_versions
|
|
SET version = version + 1, updated_at = now()
|
|
WHERE realm = 'platform' AND tenant_id IS NULL
|
|
RETURNING version INTO next_version;
|
|
INSERT INTO authorization_cache_invalidations
|
|
(id, target_type, realm, version, attempt_count, created_at, updated_at)
|
|
VALUES
|
|
(gen_random_uuid(), 'scope', 'platform', next_version, 0, now(), now());
|
|
IF TG_OP = 'DELETE' THEN RETURN OLD; END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
|
|
CREATE OR REPLACE FUNCTION tiku_bump_all_authorization_versions()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $$
|
|
BEGIN
|
|
UPDATE authorization_scope_versions SET version = version + 1, updated_at = now();
|
|
INSERT INTO authorization_cache_invalidations
|
|
(id, target_type, tenant_id, realm, version, attempt_count, created_at, updated_at)
|
|
SELECT gen_random_uuid(), 'scope', tenant_id, realm, version, 0, now(), now()
|
|
FROM authorization_scope_versions;
|
|
IF TG_OP = 'DELETE' THEN RETURN OLD; END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
|
|
CREATE TRIGGER trg_tenant_backend_roles_authorization_version
|
|
AFTER INSERT OR UPDATE OR DELETE ON tenant_backend_roles
|
|
FOR EACH ROW EXECUTE FUNCTION tiku_bump_tenant_authorization_version();
|
|
CREATE TRIGGER trg_tenant_backend_role_permissions_authorization_version
|
|
AFTER INSERT OR UPDATE OR DELETE ON tenant_backend_role_permissions
|
|
FOR EACH ROW EXECUTE FUNCTION tiku_bump_tenant_authorization_version();
|
|
CREATE TRIGGER trg_tenant_backend_user_roles_authorization_version
|
|
AFTER INSERT OR UPDATE OR DELETE ON tenant_backend_user_roles
|
|
FOR EACH ROW EXECUTE FUNCTION tiku_bump_tenant_authorization_version();
|
|
|
|
CREATE TRIGGER trg_platform_backend_roles_authorization_version
|
|
AFTER INSERT OR UPDATE OR DELETE ON platform_backend_roles
|
|
FOR EACH ROW EXECUTE FUNCTION tiku_bump_platform_authorization_version();
|
|
CREATE TRIGGER trg_platform_backend_role_permissions_authorization_version
|
|
AFTER INSERT OR UPDATE OR DELETE ON platform_backend_role_permissions
|
|
FOR EACH ROW EXECUTE FUNCTION tiku_bump_platform_authorization_version();
|
|
CREATE TRIGGER trg_platform_backend_user_roles_authorization_version
|
|
AFTER INSERT OR UPDATE OR DELETE ON platform_backend_user_roles
|
|
FOR EACH ROW EXECUTE FUNCTION tiku_bump_platform_authorization_version();
|
|
|
|
CREATE TRIGGER trg_backend_permissions_authorization_version
|
|
AFTER INSERT OR UPDATE OR DELETE ON backend_permissions
|
|
FOR EACH STATEMENT EXECUTE FUNCTION tiku_bump_all_authorization_versions();
|
|
""");
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override void Down(MigrationBuilder migrationBuilder)
|
|
{
|
|
migrationBuilder.Sql("""
|
|
DROP FUNCTION IF EXISTS tiku_bump_tenant_authorization_version() CASCADE;
|
|
DROP FUNCTION IF EXISTS tiku_bump_platform_authorization_version() CASCADE;
|
|
DROP FUNCTION IF EXISTS tiku_bump_all_authorization_versions() CASCADE;
|
|
""");
|
|
migrationBuilder.DropTable(
|
|
name: "authorization_cache_invalidations");
|
|
|
|
migrationBuilder.DropTable(
|
|
name: "authorization_scope_versions");
|
|
}
|
|
}
|
|
}
|