using Tiku.Domain.Identity; using Tiku.Domain.Tenancy; using Tiku.Application.Auth; namespace Tiku.Application.Security; public enum AuthorizationCacheMode { Disabled, Shadow, Active } public sealed class AuthorizationCacheOptions { public const string SectionName = "Security:AuthorizationCache"; public AuthorizationCacheMode Mode { get; set; } = AuthorizationCacheMode.Disabled; public int LocalSnapshotSeconds { get; set; } = 60; public int DistributedStateSeconds { get; set; } = 60; public int DistributedSnapshotSeconds { get; set; } = 300; public int JitterPercent { get; set; } = 20; } public sealed record CachedSessionSecurityState( Guid SessionId, Guid UserId, AuthRealm Realm, Guid? TenantId, string SecurityStamp, DateTimeOffset ExpiresAt, bool Revoked); public sealed record CachedUserSecurityState(Guid UserId, UserStatus Status, string SecurityStamp); public sealed record CachedTenantSecurityState(Guid TenantId, TenantStatus Status); public sealed record CachedMembershipSecurityState(Guid TenantId, Guid UserId, MembershipStatus Status); public sealed record CachedPlatformAccessState(Guid UserId, long AuthorizationVersion, bool Allowed); public sealed record CachedAuthorizationVersion(AuthRealm Realm, Guid? TenantId, long Version); public sealed record AccessSecurityCacheLookup(Guid SessionId, Guid UserId, AuthRealm Realm, Guid? TenantId); public sealed record AccessSecurityCacheState( CachedSessionSecurityState? Session, CachedUserSecurityState? User, CachedTenantSecurityState? Tenant, CachedMembershipSecurityState? Membership, CachedPlatformAccessState? PlatformAccess, CachedAuthorizationVersion? AuthorizationVersion) { public bool Complete => Session is not null && User is not null && AuthorizationVersion is not null && (Session.Realm == AuthRealm.Platform && PlatformAccess is not null || Session.Realm == AuthRealm.Tenant && Tenant is not null && Membership is not null); } public sealed record CachedAuthorizationSnapshot(long Version, CurrentAccessSnapshot Snapshot); public interface IAccessSecurityCache { bool IsConfigured { get; } Task GetAsync(AccessSecurityCacheLookup lookup, CancellationToken cancellationToken = default); Task SetAsync(AccessSecurityCacheState state, CancellationToken cancellationToken = default); Task InvalidateSessionAsync(Guid sessionId, CancellationToken cancellationToken = default); Task InvalidateUserAsync(Guid userId, CancellationToken cancellationToken = default); Task InvalidateTenantAsync(Guid tenantId, CancellationToken cancellationToken = default); Task InvalidateMembershipAsync(Guid tenantId, Guid userId, CancellationToken cancellationToken = default); Task SetAuthorizationVersionAsync(AuthRealm realm, Guid? tenantId, long version, CancellationToken cancellationToken = default); } public interface IAuthorizationSnapshotCache { Task GetAsync(AuthRealm realm, Guid? tenantId, Guid userId, CancellationToken cancellationToken = default); Task SetAsync(AuthRealm realm, Guid? tenantId, Guid userId, CachedAuthorizationSnapshot snapshot, CancellationToken cancellationToken = default); } public interface IAuthorizationStateInvalidator { Task InvalidateSessionAsync(Guid sessionId, CancellationToken cancellationToken = default); Task InvalidateUserAsync(Guid userId, CancellationToken cancellationToken = default); Task InvalidateTenantAsync(Guid tenantId, CancellationToken cancellationToken = default); Task InvalidateMembershipAsync(Guid tenantId, Guid userId, CancellationToken cancellationToken = default); Task BumpScopeAsync(AuthRealm realm, Guid? tenantId, CancellationToken cancellationToken = default); } public interface IAuthorizationCacheInvalidationProcessor { Task ProcessPendingAsync(int batchSize = 100, CancellationToken cancellationToken = default); } public interface IRequestAccessValidator { Task ValidateAsync( Guid sessionId, Guid userId, AuthRealm realm, Guid? tenantId, CancellationToken cancellationToken = default); } public sealed class AuthorizationSecurityUnavailableException(Exception innerException) : Exception("Authentication security dependencies are unavailable.", innerException);