using Microsoft.Extensions.Configuration; namespace ZB.MOM.WW.OtOpcUa.Host.OpcUa; /// /// The pre-authentication guards puts in front of the ConfigDb key /// lookup (R03:3.3). Bound from the same Security:ApiKeys section as ApiKeyOptions but /// owned by the Host, where the store lives. /// /// /// /// Why. The negative cache was keyed by key id, so a flood of DISTINCT well-formed /// otua_<random>_x credentials missed it every time and cost one indexed SQL query per /// attempt — under the SDK's SessionManager-wide lock — with no credential needed. Two guards close /// that: a known-id set (every ApiKeyId the ConfigDb holds, refreshed every /// StoreCacheSeconds) rejects an unknown id in memory, and a miss budget (token /// bucket) bounds how many lookups that reach the store and MISS are allowed per second when the /// set is unavailable. /// /// /// The budget is process-wide, not per remote endpoint: the OPC UA SDK's impersonation callback /// (the IOpcUaUserAuthenticator seam) does not carry the client's address. Per-endpoint /// accounting needs that seam widened in the OpcUaServer project — a follow-up, not this lane. /// /// public sealed class ApiKeyStoreGuardOptions { /// The configuration section the knobs live in (shared with ApiKeyOptions). public const string SectionName = "Security:ApiKeys"; /// /// Whether the known-id set is consulted. restores a store read per unknown /// id. Only meaningful when the inner store can list ids (the ConfigDb store can; the artifact /// store is never wrapped). /// public bool KnownIdSet { get; set; } = true; /// /// How many store MISSES (lookups that reach the inner store and find no key) may burst before /// further lookups for unknown ids are refused without a store read. 0 disables the budget. /// public int MissBurst { get; set; } = 100; /// How many miss tokens are restored per second, up to . public double MissRefillPerSecond { get; set; } = 20; /// Binds the section, with defaults for anything absent. /// The app configuration; null yields the defaults. /// The bound options. public static ApiKeyStoreGuardOptions Bind(IConfiguration? configuration) { var options = new ApiKeyStoreGuardOptions(); configuration?.GetSection(SectionName).Bind(options); return options; } }