# MQTT Connection Type Port Design ## Goal Port MQTT-related connection type parity from Go into the .NET server for three scoped areas: 1. JWT `allowed_connection_types` behavior for `MQTT` / `MQTT_WS` (plus existing known types). 2. `/connz` filtering by `mqtt_client`. 3. Full MQTT configuration parsing from `mqtt {}` config blocks (all Go `MQTTOpts` fields). ## Scope - In scope: - JWT allowed connection type normalization and enforcement semantics. - `/connz?mqtt_client=` option parsing and filtering. - MQTT configuration model and config file parsing (all Go `MQTTOpts` fields). - Expanded `MqttOptsVarz` monitoring output. - Unit/integration tests for new and updated behavior. - `differences.md` updates after implementation is verified. - Out of scope: - Full MQTT transport implementation (listener, protocol parser, sessions). - WebSocket transport implementation. - Leaf/route/gateway transport plumbing. ## Architecture - Add an auth-facing connection-type model that can be passed through `ClientAuthContext`. - Implement Go-style allowed connection type conversion and matching in `JwtAuthenticator`: - normalize input to uppercase. - retain recognized types. - collect unknown types as non-fatal if at least one valid type remains. - reject when only unknown types are present. - enforce current connection type against the resulting allowed set. - Extend connz monitoring options to parse `mqtt_client` and apply exact-match filtering before sort/pagination. ## Components ### JWT Connection-Type Enforcement - `src/NATS.Server/Auth/IAuthenticator.cs` - Extend `ClientAuthContext` with a connection-type value. - `src/NATS.Server/Auth/Jwt/JwtConnectionTypes.cs` (new) - Canonical constants for known connection types: - `STANDARD`, `WEBSOCKET`, `LEAFNODE`, `LEAFNODE_WS`, `MQTT`, `MQTT_WS`, `INPROCESS`. - Helper(s) for normalization and validation behavior. - `src/NATS.Server/Auth/JwtAuthenticator.cs` - Evaluate `userClaims.Nats?.AllowedConnectionTypes` using Go-compatible semantics. - Enforce against current `ClientAuthContext.ConnectionType`. - `src/NATS.Server/NatsClient.cs` - Populate auth context connection type (currently `STANDARD`). ### Connz MQTT Client Filtering - `src/NATS.Server/Monitoring/Connz.cs` - Add `MqttClient` to `ConnzOptions` with JSON field `mqtt_client`. - `src/NATS.Server/Monitoring/ConnzHandler.cs` - Parse `mqtt_client` query param. - Filter connection list by exact `MqttClient` match when provided. - `src/NATS.Server/Monitoring/ClosedClient.cs` - Add `MqttClient` field to closed snapshots. - `src/NATS.Server/NatsServer.cs` - Persist `MqttClient` into `ClosedClient` snapshot (empty for now). ### MQTT Configuration Parsing - `src/NATS.Server/MqttOptions.cs` (new) - Full model matching Go `MQTTOpts` struct (opts.go:613-707): - Network: `Host`, `Port` - Auth override: `NoAuthUser`, `Username`, `Password`, `Token`, `AuthTimeout` - TLS: `TlsCert`, `TlsKey`, `TlsCaCert`, `TlsVerify`, `TlsTimeout`, `TlsMap`, `TlsPinnedCerts` - JetStream: `JsDomain`, `StreamReplicas`, `ConsumerReplicas`, `ConsumerMemoryStorage`, `ConsumerInactiveThreshold` - QoS: `AckWait`, `MaxAckPending`, `JsApiTimeout` - `src/NATS.Server/NatsOptions.cs` - Add `Mqtt` property of type `MqttOptions?`. - `src/NATS.Server/Configuration/ConfigProcessor.cs` - Add `ParseMqtt()` for `mqtt {}` config block with Go-compatible key aliases: - `host`/`net` → Host, `listen` → Host+Port - `ack_wait`/`ackwait` → AckWait - `max_ack_pending`/`max_pending`/`max_inflight` → MaxAckPending - `js_domain` → JsDomain - `js_api_timeout`/`api_timeout` → JsApiTimeout - `consumer_inactive_threshold`/`consumer_auto_cleanup` → ConsumerInactiveThreshold - Nested `tls {}` and `authorization {}`/`authentication {}` blocks - `src/NATS.Server/Monitoring/Varz.cs` - Expand `MqttOptsVarz` from 3 fields to full monitoring-visible set. - `src/NATS.Server/Monitoring/VarzHandler.cs` - Populate expanded `MqttOptsVarz` from `NatsOptions.Mqtt`. ## Data Flow 1. Client sends `CONNECT`. 2. `NatsClient.ProcessConnectAsync` builds `ClientAuthContext` with `ConnectionType=STANDARD`. 3. `AuthService` invokes `JwtAuthenticator` for JWT-based auth. 4. `JwtAuthenticator`: - converts `allowed_connection_types` to valid/unknown buckets. - rejects unknown-only lists. - enforces connection-type membership when valid list is non-empty. 5. Monitoring request `/connz`: - `ConnzHandler.ParseQueryParams` reads `mqtt_client`. - open/closed conn rows are materialized. - rows are filtered on exact `MqttClient` when filter is present. - sorting and pagination run on filtered results. ## Error Handling and Compatibility - Auth failures remain non-throwing (`Authenticate` returns `null`). - Unknown connection type tokens in JWT are tolerated only when at least one known allowed type remains. - Unknown-only allowed lists are rejected to avoid unintended allow-all behavior. - `mqtt_client` query parsing is lenient and string-based; empty filter means no filter. - Existing JSON schema compatibility is preserved. ## Current Runtime Limitation (Explicit) - MQTT transport is not implemented yet in this repository. - Runtime connection type currently resolves to `STANDARD` in auth context. - `mqtt_client` values remain empty until MQTT path populates them. - MQTT config is parsed and stored but no listener is started. ## Testing Strategy - `tests/NATS.Server.Tests/JwtAuthenticatorTests.cs` - allow `STANDARD` for current client context. - reject `MQTT` for current client context. - allow mixed known+unknown when current type is known allowed. - reject unknown-only list. - validate case normalization behavior. - `tests/NATS.Server.Tests/MonitorTests.cs` - `/connz?mqtt_client=` returns matching connections only. - `/connz?state=closed&mqtt_client=` filters closed snapshots. - non-existing ID yields empty connection set. - `tests/NATS.Server.Tests/ConfigProcessorTests.cs` (or similar) - Parse valid `mqtt {}` block with all fields. - Parse config with aliases (ackwait vs ack_wait, host vs net, etc.). - Parse nested `tls {}` and `authorization {}` blocks within mqtt. - Varz MQTT section populated from config. ## Success Criteria - JWT `allowed_connection_types` behavior matches Go semantics for known/unknown mixing and unknown-only rejection. - `/connz` supports exact `mqtt_client` filtering for open and closed sets. - `mqtt {}` config block parses all Go `MQTTOpts` fields with aliases. - `MqttOptsVarz` includes full monitoring output. - Added tests pass. - `differences.md` accurately reflects implemented parity.