docs: add mqtt connection type design
This commit is contained in:
93
docs/plans/2026-02-23-mqtt-connection-type-design.md
Normal file
93
docs/plans/2026-02-23-mqtt-connection-type-design.md
Normal file
@@ -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=<id>` returns matching connections only.
|
||||||
|
- `/connz?state=closed&mqtt_client=<id>` 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.
|
||||||
Reference in New Issue
Block a user