diff --git a/docs/plans/2026-02-23-mqtt-connection-type-design.md b/docs/plans/2026-02-23-mqtt-connection-type-design.md new file mode 100644 index 0000000..80179d3 --- /dev/null +++ b/docs/plans/2026-02-23-mqtt-connection-type-design.md @@ -0,0 +1,93 @@ +# MQTT Connection Type Port Design + +## Goal +Port MQTT-related connection type parity from Go into the .NET server for two scoped areas: +1. JWT `allowed_connection_types` behavior for `MQTT` / `MQTT_WS` (plus existing known types). +2. `/connz` filtering by `mqtt_client`. + +## Scope +- In scope: + - JWT allowed connection type normalization and enforcement semantics. + - `/connz?mqtt_client=` option parsing and filtering. + - Unit/integration tests for new and updated behavior. + - `differences.md` updates after implementation is verified. +- Out of scope: + - Full MQTT transport implementation. + - 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 +- `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`). +- `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). + +## 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. + +## 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. + +## 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. +- Added tests pass. +- `differences.md` accurately reflects implemented parity.