7.9 KiB
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);
}
ProcessConfigFileusesnew ConfigurationBuilder().AddJsonFile(path).Build()ProcessConfigStringusesAddJsonStream(new MemoryStream(Encoding.UTF8.GetBytes(json)))BindConfigurationcallsconfig.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 2505–2574, 2580, 2584 (+
configureSystemAccount2509,setupUsersAndNKeysDuplicateCheckMap2515) 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.cs — partial 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.cs — partial class NatsServer with:
ProcessClientOrLeafCallout(ClientConnection, ServerOptions)— publishes to$SYS.REQ.USER.AUTH, waits for signed JWT response, validates itFillClientInfo(AuthorizationRequestClaims, ClientConnection)— populate auth request payloadFillConnectOpts(AuthorizationRequestClaims, ClientConnection)— populate connect opts in payload
Auth/JwtProcessor.cs additions:
ReadOperatorJwt(string path)— read operator JWT from file, decodeOperatorClaimsReadOperatorJwtInternal(string jwtString)— decode from stringValidateTrustedOperators(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 permissionsGetTlsAuthDcs(X509DistinguishedName)— extract DC= components from TLS cert RDNCheckClientTlsCertSubject(ClientConnection, Func<string, bool>)— TLS cert subject matchingValidateProxies(ServerOptions)— validate proxy configurationGetAuthErrClosedState(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 354–383, 1973–1976, 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 groupAuth/AuthHandlerTests.csadditions — bcrypt comparison, NKey verify, TLS cert subject matchingAuth/JwtProcessorTests.csadditions — 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.