# Component: Security

## Purpose

Provides API key-based authentication and role-based authorization for the gRPC service, along with TLS certificate management for transport security.

## Location

- `src/ZB.MOM.WW.LmxProxy.Host/Security/ApiKeyService.cs` — API key storage and validation.
- `src/ZB.MOM.WW.LmxProxy.Host/Security/ApiKeyInterceptor.cs` — gRPC server interceptor for authentication/authorization.
- `src/ZB.MOM.WW.LmxProxy.Client/Security/GrpcChannelFactory.cs` — Client-side TLS channel factory.

## Responsibilities

- Load and hot-reload API keys from a JSON configuration file.
- Validate API keys on every gRPC request via a server interceptor.
- Enforce role-based access control (ReadOnly vs ReadWrite).
- Manage TLS certificates for server and optional mutual TLS.

## 1. API Key Service

### 1.1 Key Storage

- Keys are stored in a JSON file (default `apikeys.json`).
- File format: `{ "ApiKeys": [{ "Key": "...", "Description": "...", "Role": "ReadOnly|ReadWrite", "Enabled": true|false }] }`.
- If the file does not exist at startup, the service auto-generates a default file with two random keys: one ReadOnly and one ReadWrite.

### 1.2 Hot Reload

- A `FileSystemWatcher` monitors the API key file for changes.
- Rapid changes are debounced (1-second minimum between reloads).
- `ReloadConfigurationAsync` uses a `SemaphoreSlim` to serialize reload operations.
- New and modified keys take effect on the next request. Removed or disabled keys reject future requests immediately.
- Active sessions are not affected by key changes — sessions are tracked independently by SessionManager.

### 1.3 Validation

- `ValidateApiKey(apiKey)` — Returns the `ApiKey` object if the key exists and `Enabled` is true, otherwise null.
- `HasRole(apiKey, requiredRole)` — Returns true if the key has the required role. Role hierarchy: ReadWrite implies ReadOnly.

## 2. API Key Interceptor

### 2.1 Authentication Flow

The `ApiKeyInterceptor` intercepts every unary and server-streaming RPC:

1. Extracts the `x-api-key` header from gRPC request metadata.
2. Calls `ApiKeyService.ValidateApiKey()`.
3. If the key is invalid or missing, returns `StatusCode.Unauthenticated`.
4. For write-protected methods (`Write`, `WriteBatch`, `WriteBatchAndWait`), checks that the key has the `ReadWrite` role. Returns `StatusCode.PermissionDenied` if the key is `ReadOnly`.
5. Adds the validated `ApiKey` to `context.UserState["ApiKey"]` for downstream use.
6. Continues to the service method.

### 2.2 Write-Protected Methods

These RPCs require the `ReadWrite` role:
- `Write`
- `WriteBatch`
- `WriteBatchAndWait`

All other RPCs (`Connect`, `Disconnect`, `GetConnectionState`, `Read`, `ReadBatch`, `Subscribe`, `CheckApiKey`) are allowed for `ReadOnly` keys.

## 3. API Key Model

| Field | Type | Description |
|-------|------|-------------|
| Key | string | The secret API key value |
| Description | string | Human-readable name for the key |
| Role | ApiKeyRole | `ReadOnly` or `ReadWrite` |
| Enabled | bool | Whether the key is active |

`ApiKeyRole` enum: `ReadOnly` (read and subscribe only), `ReadWrite` (full access including writes).

## 4. TLS Configuration

### 4.1 Server-Side (Host)

Configured via `TlsConfiguration` in `appsettings.json`:

| Setting | Default | Description |
|---------|---------|-------------|
| Enabled | false | Enable TLS on the gRPC server |
| ServerCertificatePath | `certs/server.crt` | PEM server certificate |
| ServerKeyPath | `certs/server.key` | PEM server private key |
| ClientCaCertificatePath | `certs/ca.crt` | CA certificate for mTLS client validation |
| RequireClientCertificate | false | Require client certificates (mutual TLS) |
| CheckCertificateRevocation | false | Check certificate revocation lists |

If TLS is enabled but certificates are missing, the service generates self-signed certificates at startup.

### 4.2 Client-Side

`ClientTlsConfiguration` in the client library:

| Setting | Default | Description |
|---------|---------|-------------|
| UseTls | false | Enable TLS on the client connection |
| ClientCertificatePath | null | Client certificate for mTLS |
| ClientKeyPath | null | Client private key for mTLS |
| ServerCaCertificatePath | null | Custom CA for server validation |
| ServerNameOverride | null | SNI/hostname override |
| ValidateServerCertificate | true | Validate the server certificate chain |
| AllowSelfSignedCertificates | false | Accept self-signed server certificates |
| IgnoreAllCertificateErrors | false | Skip all certificate validation (dangerous) |

- SSL protocols: TLS 1.2 and TLS 1.3.
- Client certificates loaded from PEM files and converted to PKCS12.
- Custom CA trust store support via chain building.

## Dependencies

- **Configuration** — TLS settings and API key file path from `appsettings.json`.
- **System.IO.FileSystemWatcher** — API key file change detection.

## Interactions

- **GrpcServer** — the ApiKeyInterceptor runs before every RPC in ScadaGrpcService.
- **ServiceHost** — creates ApiKeyService and ApiKeyInterceptor at startup, configures gRPC server credentials.
- **Client** — GrpcChannelFactory creates TLS-configured gRPC channels in LmxProxyClient.
