fix(localdb): sync endpoint enforces the configured ApiKey (scadaproj#36)
LocalDbSyncService never read request headers, so setting LocalDb:Replication:ApiKey on both nodes left the passive endpoint open (LocalDb-001). It now requires Authorization: Bearer <key> (constant-time) before the handshake and before newest-wins takeover, refusing anything else with Unauthenticated. A blank key keeps the old accept-all behaviour and logs a startup warning. Wire-compatible: the initiator has always sent the header when the key is set; ScadaBridge/OtOpcUa interceptors use the same key. LocalDb 0.3.5 -> 0.3.6 (unpublished). Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -8,7 +8,15 @@ public sealed class ReplicationOptions
|
||||
/// <summary>gRPC address of the peer to dial. Required for the initiator role (validated in the sync host).</summary>
|
||||
public string PeerAddress { get; set; } = "";
|
||||
|
||||
/// <summary>API key presented to / expected from the peer; null disables key auth.</summary>
|
||||
/// <summary>
|
||||
/// Shared key that authenticates the pair partner. Set the SAME value on both nodes. The initiator
|
||||
/// sends it as <c>Authorization: Bearer <key></c>; since 0.3.6 the passive
|
||||
/// <see cref="LocalDbSyncService"/> also requires it (constant-time compare) and refuses any other
|
||||
/// stream with <c>Unauthenticated</c>, before the handshake and before displacing the current
|
||||
/// stream. Null, empty or whitespace disables key auth on both sides: the initiator sends no
|
||||
/// header and the endpoint accepts any caller (a warning is logged at startup), so protect it some
|
||||
/// other way — network isolation or a host interceptor.
|
||||
/// </summary>
|
||||
public string? ApiKey { get; set; }
|
||||
|
||||
/// <summary>How often the change pump flushes pending oplog deltas to the peer.</summary>
|
||||
|
||||
Reference in New Issue
Block a user