feat(config+ws): add TLS cert reload, WS compression negotiation, WS JWT auth (E9+E10+E11)

E9: TLS Certificate Reload
- Add TlsCertificateProvider with Interlocked-swappable cert field
- New connections get current cert, existing connections keep theirs
- ConfigReloader.ReloadTlsCertificate rebuilds SslServerAuthenticationOptions
- NatsServer.ApplyConfigChanges triggers TLS reload on TLS config changes
- 11 tests covering cert swap, versioning, thread safety, config diff

E10: WebSocket Compression Negotiation (RFC 7692)
- Add WsDeflateNegotiator to parse Sec-WebSocket-Extensions parameters
- Parse server_no_context_takeover, client_no_context_takeover,
  server_max_window_bits, client_max_window_bits
- WsDeflateParams record struct with ToResponseHeaderValue()
- NATS always enforces no_context_takeover (matching Go server)
- WsUpgrade returns negotiated WsDeflateParams in upgrade result
- 22 tests covering parameter parsing, clamping, response headers

E11: WebSocket JWT Authentication
- Extract JWT from Authorization header (Bearer token), cookie, or ?jwt= query param
- Priority: Authorization header > cookie > query parameter
- WsUpgrade.TryUpgradeAsync now parses query string from request URI
- Add FailUnauthorizedAsync for 401 responses
- 24 tests covering all JWT extraction sources and priority ordering
This commit is contained in:
Joseph Doherty
2026-02-24 16:03:46 -05:00
parent c6ecbbfbcc
commit 02531dda58
9 changed files with 1284 additions and 14 deletions

View File

@@ -1,6 +1,9 @@
// Port of Go server/reload.go — config diffing, validation, and CLI override merging
// for hot reload support. Reference: golang/nats-server/server/reload.go.
using System.Net.Security;
using NATS.Server.Tls;
namespace NATS.Server.Configuration;
/// <summary>
@@ -459,6 +462,29 @@ public static class ConfigReloader
return !string.Equals(oldJetStream.StoreDir, newJetStream.StoreDir, StringComparison.Ordinal);
}
/// <summary>
/// Reloads TLS certificates from the current options and atomically swaps them
/// into the certificate provider. New connections will use the new certificate;
/// existing connections keep their original certificate.
/// Reference: golang/nats-server/server/reload.go — tlsOption.Apply.
/// </summary>
public static bool ReloadTlsCertificate(
NatsOptions options,
TlsCertificateProvider? certProvider)
{
if (certProvider == null || !options.HasTls)
return false;
var oldCert = certProvider.SwapCertificate(options.TlsCert!, options.TlsKey);
oldCert?.Dispose();
// Rebuild SslServerAuthenticationOptions with the new certificate
var newSslOptions = TlsHelper.BuildServerAuthOptions(options);
certProvider.SwapSslOptions(newSslOptions);
return true;
}
}
/// <summary>