Files
natsnet/docs/plans/2026-02-26-stub-features-design.md

7.9 KiB
Raw Permalink Blame History

Stub Features Implementation Design

Date: 2026-02-26 Scope: Complete the 93 remaining stub features in Phase 6 Approach: Two parallel sessions (Config + Auth)

Overview

After Phase 6's 23 porting sessions, 93 features remain at stub status. They fall into two independent concerns that can be implemented in parallel:

Group Go File Stubs Go LOC Concern
Config server/opts.go 67 ~4,876 Configuration file parsing / binding
Auth server/auth.go 19 ~1,296 Authentication dispatch
Auth server/auth_callout.go 3 ~456 External auth callout
Auth server/jwt.go 3 ~137 Operator JWT validation
Signals server/signal.go 1 ~46 OS signal handling

Session A: Configuration Binding (67 stubs, opts.go)

Decision

Map all NATS server configuration to appsettings.json via Microsoft.Extensions.Configuration. The Go conf package tokenizer and the 765-line processConfigFileLine dispatch loop are not ported — JSON deserialization replaces them.

New Files

Config/ServerOptionsConfiguration.cs

public static class ServerOptionsConfiguration
{
    public static ServerOptions ProcessConfigFile(string path);
    public static ServerOptions ProcessConfigString(string json);
    public static void BindConfiguration(IConfiguration config, ServerOptions target);
}
  • ProcessConfigFile uses new ConfigurationBuilder().AddJsonFile(path).Build()
  • ProcessConfigString uses AddJsonStream(new MemoryStream(Encoding.UTF8.GetBytes(json)))
  • BindConfiguration calls config.Bind(target) with custom converters registered

Config/NatsJsonConverters.cs

Custom JsonConverter<T> for non-trivial types:

Converter Input Output Mirrors
DurationJsonConverter "2s", "100ms", "1h30m" TimeSpan parseDuration
TlsVersionJsonConverter "1.2", "TLS12" SslProtocols parseTLSVersion
NatsUrlJsonConverter "nats://host:port" validated string parseURL
StorageSizeJsonConverter "1GB", "512mb" long (bytes) getStorageSize

ServerOptions.cs Changes

Add [JsonPropertyName("...")] attributes for fields whose JSON key names differ from C# names. JSON key names follow NATS server conventions (lowercase, underscore-separated):

{
  "port": 4222,
  "host": "0.0.0.0",
  "tls": { "cert_file": "...", "key_file": "...", "ca_file": "..." },
  "cluster": { "port": 6222, "name": "my-cluster" },
  "gateway": { "port": 7222, "name": "my-gateway" },
  "jetstream": { "store_dir": "/data/jetstream", "max_memory": "1GB" },
  "leafnodes": { "port": 7422 },
  "mqtt": { "port": 1883 },
  "websocket": { "port": 8080 },
  "accounts": [ { "name": "A", "users": [ { "user": "u1", "password": "p1" } ] } ]
}

DB Outcome

All 67 opts.go stubs → complete:

  • Feature IDs 25052574, 2580, 2584 (+ configureSystemAccount 2509, setupUsersAndNKeysDuplicateCheckMap 2515)
  • parse* functions have no C# equivalent — their logic is subsumed by converters and JSON binding

Session B: Auth Implementation (26 stubs)

New Files

NatsServer.Auth.cspartial class NatsServer with:

Method Go Equivalent Notes
ConfigureAuthorization() configureAuthorization Builds _nkeys/_users dicts from _opts
BuildNkeysAndUsersFromOptions() buildNkeysAndUsersFromOptions Creates typed lookup maps
CheckAuthforWarnings() checkAuthforWarnings Validates auth config consistency
AssignGlobalAccountToOrphanUsers() assignGlobalAccountToOrphanUsers
CheckAuthentication(ClientConnection) checkAuthentication Entry point
IsClientAuthorized(ClientConnection) isClientAuthorized Check user credentials
ProcessClientOrLeafAuthentication(ClientConnection, ServerOptions) processClientOrLeafAuthentication Main 554-line auth dispatch
IsRouterAuthorized(ClientConnection) isRouterAuthorized Route-specific auth
IsGatewayAuthorized(ClientConnection) isGatewayAuthorized Gateway-specific auth
RegisterLeafWithAccount(ClientConnection, string) registerLeafWithAccount
IsLeafNodeAuthorized(ClientConnection) isLeafNodeAuthorized Leaf-specific auth
ProcessProxiesTrustedKeys() processProxiesTrustedKeys Proxy key setup
ProxyCheck(ClientConnection, ServerOptions) proxyCheck Validate proxy headers

Auth dispatch flow in ProcessClientOrLeafAuthentication:

if callout configured  → ProcessClientOrLeafCallout()
else if JWT bearer     → JwtProcessor.ValidateAndRegisterUser()
else if NKey           → verify NKey signature (NATS.NKeys NuGet)
else if user+password  → BCrypt.Net.BCrypt.Verify() (BCrypt.Net-Next NuGet)
else if TLS cert map   → CheckClientTlsCertSubject()
else if no-auth mode   → allow (if opts.NoAuth)
→ set client account, permissions, labels

Auth/AuthCallout.cspartial class NatsServer with:

  • ProcessClientOrLeafCallout(ClientConnection, ServerOptions) — publishes to $SYS.REQ.USER.AUTH, waits for signed JWT response, validates it
  • FillClientInfo(AuthorizationRequestClaims, ClientConnection) — populate auth request payload
  • FillConnectOpts(AuthorizationRequestClaims, ClientConnection) — populate connect opts in payload

Auth/JwtProcessor.cs additions:

  • ReadOperatorJwt(string path) — read operator JWT from file, decode OperatorClaims
  • ReadOperatorJwtInternal(string jwtString) — decode from string
  • ValidateTrustedOperators(ServerOptions opts) — walk operator → account → user signing key chain

Auth/AuthHandler.cs additions:

  • ProcessUserPermissionsTemplate(UserPermissionLimits, UserClaims, Account) — expand {{account}}, {{tag.*}} template variables in JWT user permissions
  • GetTlsAuthDcs(X509DistinguishedName) — extract DC= components from TLS cert RDN
  • CheckClientTlsCertSubject(ClientConnection, Func<string, bool>) — TLS cert subject matching
  • ValidateProxies(ServerOptions) — validate proxy configuration
  • GetAuthErrClosedState(ClientConnection) — map auth failure to client closed state enum

New NuGet Packages

Package Version Purpose
BCrypt.Net-Next ≥4.0 bcrypt password hashing and comparison
NATS.NKeys ≥2.0 NKey keypair creation, signature verify

NatsServer.Signals.cs

New partial class file:

// Registers OS signal handlers via PosixSignalRegistration (cross-platform).
// SIGHUP  → server.Reload()
// SIGTERM → server.Shutdown()
// SIGINT  → server.Shutdown()
// Windows fallback: Console.CancelKeyPress → Shutdown()

DB Outcome

All 26 auth/jwt/callout/signal stubs → complete:

  • Feature IDs 354383, 19731976, 2584, 3156

File Summary

File Action
Config/ServerOptionsConfiguration.cs CREATE
Config/NatsJsonConverters.cs CREATE
NatsServer.Auth.cs CREATE (partial)
NatsServer.Signals.cs CREATE (partial)
Auth/AuthCallout.cs CREATE (partial)
Auth/JwtProcessor.cs MODIFY (add 3 methods)
Auth/AuthHandler.cs MODIFY (add 5 methods)
ServerOptions.cs MODIFY (add JsonPropertyName attrs)
ZB.MOM.NatsNet.Server.csproj MODIFY (add 2 NuGet packages)

Testing

Unit tests in ZB.MOM.NatsNet.Server.Tests/:

  • Config/ServerOptionsConfigurationTests.cs — round-trip JSON bind tests for each major option group
  • Auth/AuthHandlerTests.cs additions — bcrypt comparison, NKey verify, TLS cert subject matching
  • Auth/JwtProcessorTests.cs additions — operator JWT read/validate

No new test IDs needed — these are implementations of already-tracked Phase 6 features. After implementation, relevant test IDs in Phase 7 will be marked complete.