docs(m4.2): reconcile InboundAPI (Bearer/audit-timing/type-validation), Security (cookie session, role names), Notification (Email-only, AuditKind vocab) to code
This commit is contained in:
@@ -29,7 +29,7 @@ Central cluster only (active node). Not available at site clusters.
|
||||
- **Enabled/Disabled Flag**: Keys can be disabled without deletion.
|
||||
|
||||
### Management
|
||||
- Managed by users with the **Admin** role via the Central UI.
|
||||
- Managed by users with the **Administrator** role via the Central UI.
|
||||
- All key changes (create, enable/disable, delete) are audit logged.
|
||||
|
||||
## API Method Definition
|
||||
@@ -48,7 +48,7 @@ Each API method definition includes:
|
||||
- **Timeout**: Configurable per method. Defines the maximum time the method is allowed to execute (including any routed calls to sites) before returning a timeout error to the caller.
|
||||
|
||||
### Management
|
||||
- Managed by users with the **Design** role via the Central UI.
|
||||
- Managed by users with the **Designer** role via the Central UI.
|
||||
- All method definition changes are audit logged.
|
||||
|
||||
## HTTP Contract
|
||||
@@ -58,8 +58,12 @@ Each API method definition includes:
|
||||
- Method names map directly to URL path segments (e.g., method "GetProductionReport" → `POST /api/GetProductionReport`).
|
||||
- All calls are POST — these are RPC-style script invocations, not RESTful resource operations.
|
||||
|
||||
### API Key Header
|
||||
- API key is passed via the `X-API-Key` HTTP header.
|
||||
### Authentication Header
|
||||
- The API key token (`sbk_<keyId>_<secret>`) is accepted from **either** of two headers:
|
||||
- `Authorization: Bearer sbk_<keyId>_<secret>` — the preferred form.
|
||||
- `X-API-Key: sbk_<keyId>_<secret>` — alternate form for callers that cannot set the Authorization header.
|
||||
- When both headers are present, `Authorization` takes precedence.
|
||||
- Both forms are processed by the same `IApiKeyVerifier` from the shared `ZB.MOM.WW.Auth.ApiKeys` library; the verifier strips the optional `Bearer ` prefix and performs the same peppered-HMAC constant-time verification regardless of which header was used.
|
||||
|
||||
### Request Format
|
||||
- Content-Type: `application/json`.
|
||||
@@ -130,7 +134,7 @@ API method scripts are compiled at central startup — all method definitions ar
|
||||
|
||||
- **Every request — success or failure — emits one `ApiInbound.Completed` row** to `ICentralAuditWriter` from request middleware before the HTTP response is flushed. The row captures the API key **name** (never the key material), remote IP, user-agent, response status, duration, and the request/response bodies. Bodies are captured in full up to `AuditLog:InboundMaxBytes` (default 1 MiB); `PayloadTruncated = 1` only when that ceiling is hit. Header redaction and per-target body redactors still apply (see Component-AuditLog.md, Payload Capture Policy). This supersedes the earlier failures-only stance: operational API traffic is now part of the centralized audit log, so configuration changes and call activity share a single retention/query surface.
|
||||
- Script execution errors (500 responses) remain captured on the same `ApiInbound.Completed` row (response status + error fields) rather than emitting a separate failure-only event.
|
||||
- **Fail-soft semantics.** The audit write is synchronous (inline before the response is flushed), but failures are caught: a write that throws is logged and increments `CentralAuditWriteFailures` (see Health Monitoring #11) and the request still returns its normal HTTP response. A failed audit append never turns a successful API call into an error returned to the caller.
|
||||
- **Fail-soft semantics (fire-and-forget).** The audit write is **fire-and-forget** (`InboundAPI-018`): `WriteAsync` is called without `await` so the user-facing HTTP response is never blocked or delayed by the audit path. Asynchronous faults are observed via a `ContinueWith` continuation that logs at Warning and increments `CentralAuditWriteFailures` (see Health Monitoring #11) rather than being silently dropped. A failed audit append never turns a successful API call into an error returned to the caller.
|
||||
- No rate limiting — this is a private API in a controlled industrial environment with a known set of callers. Misbehaving callers are handled operationally (disable the API key).
|
||||
|
||||
## Request Flow
|
||||
@@ -216,12 +220,13 @@ Inbound API scripts **cannot** call shared scripts directly — shared scripts a
|
||||
|
||||
## Authentication Details
|
||||
|
||||
- API key is passed via the `X-API-Key` HTTP header.
|
||||
- The API key token is accepted from **either** the `Authorization: Bearer <token>` header (preferred) **or** the `X-API-Key: <token>` header (alternate). `Authorization` takes precedence when both are present.
|
||||
- The token format is `sbk_<keyId>_<secret>`. Both header forms are verified by the same `IApiKeyVerifier` from `ZB.MOM.WW.Auth.ApiKeys`.
|
||||
- The system validates:
|
||||
1. The key exists in the configuration database.
|
||||
2. The key is enabled.
|
||||
3. The key is in the approved list for the requested method.
|
||||
- Failed authentication returns an appropriate HTTP error (401 Unauthorized or 403 Forbidden).
|
||||
1. The token is well-formed and the key ID exists in the key store.
|
||||
2. The key is enabled (not revoked).
|
||||
3. The key's provisioned scopes include the requested method name (case-sensitive).
|
||||
- Failed authentication returns an appropriate HTTP error (401 Unauthorized for invalid/missing credentials; 403 Forbidden for a valid key not approved for the method). For enumeration-safety, both "method not found" and "key not in scope" return 403 with an identical body.
|
||||
|
||||
## Error Handling
|
||||
|
||||
@@ -246,5 +251,5 @@ Inbound API scripts **cannot** call shared scripts directly — shared scripts a
|
||||
- **External Systems**: Call the API with API keys.
|
||||
- **Communication Layer**: API method scripts use this to reach sites.
|
||||
- **Site Runtime (Instance Actors, Script Actors)**: Routed calls execute on site Instance Actors via their Script Actors.
|
||||
- **Central UI**: Admin manages API keys; Design manages method definitions.
|
||||
- **Central UI**: Administrator manages API keys; Designer manages method definitions.
|
||||
- **Configuration Database (via IAuditService)**: Configuration changes are audited.
|
||||
|
||||
@@ -15,7 +15,7 @@ Central cluster only. The Notification Service manages definitions in the centra
|
||||
### Definitions (Central)
|
||||
- Store notification lists in the configuration database: list name, list **type**, and type-specific targets (e.g. recipients for an `Email` list).
|
||||
- Store email server configuration (SMTP settings).
|
||||
- Managed by users with the Design role.
|
||||
- Managed by users with the Designer role.
|
||||
- Notification lists and SMTP configuration are **not deployed to sites** — they exist centrally only. There is no deploy-to-sites artifact and no local SQLite copy.
|
||||
|
||||
### Delivery Adapters (Central)
|
||||
@@ -87,7 +87,7 @@ Each `Deliver(...)` call returns one of `success | transient failure | permanent
|
||||
|
||||
- **Configuration Database (MS SQL)**: Stores notification list definitions (name, type, type-specific targets) and SMTP config.
|
||||
- **Notification Outbox**: Invokes the delivery adapters supplied by this component and asks it to resolve notification lists at delivery time.
|
||||
- **Security & Auth**: Design role manages notification lists.
|
||||
- **Security & Auth**: Designer role manages notification lists.
|
||||
- **Configuration Database (via IAuditService)**: Notification list changes are audit logged.
|
||||
|
||||
## Interactions
|
||||
|
||||
@@ -13,7 +13,7 @@ Central cluster. Sites do not have user-facing interfaces and do not perform ind
|
||||
- Authenticate users against LDAP/Active Directory using a direct LDAP/AD bind (username/password).
|
||||
- Map LDAP group memberships to system roles.
|
||||
- Enforce role-based access control on all API and UI operations.
|
||||
- Support site-scoped permissions for the Deployment role.
|
||||
- Support site-scoped permissions for the Deployer role.
|
||||
|
||||
## Authentication
|
||||
|
||||
@@ -39,7 +39,7 @@ Set in a local or docker-dev environment via the environment variable `ScadaBrid
|
||||
- The JWT is embedded in an **authentication cookie** rather than being passed as a bearer token. This is the correct transport for Blazor Server, where persistent SignalR circuits do not carry Authorization headers — the browser automatically sends the cookie with every SignalR connection and HTTP request.
|
||||
- The cookie is **HttpOnly** and **Secure** (requires HTTPS).
|
||||
- On each request, the server extracts and validates the JWT from the cookie. All authorization decisions are made from the JWT claims without hitting the database.
|
||||
- **JWT claims**: User display name, username, list of roles (Admin, Design, Deployment), and for site-scoped Deployment, the list of permitted site IDs.
|
||||
- **JWT claims**: User display name, username, list of roles (`Administrator`, `Designer`, `Deployer`, `Viewer`), and for site-scoped Deployer, the list of permitted site IDs.
|
||||
|
||||
### Token Lifecycle
|
||||
|
||||
@@ -80,7 +80,7 @@ Set in a local or docker-dev environment via the environment variable `ScadaBrid
|
||||
|
||||
## Roles
|
||||
|
||||
### Admin
|
||||
### Administrator
|
||||
- **Scope**: System-wide (always).
|
||||
- **Permissions**:
|
||||
- Manage site definitions.
|
||||
@@ -89,9 +89,9 @@ Set in a local or docker-dev environment via the environment variable `ScadaBrid
|
||||
- Manage LDAP group-to-role mappings.
|
||||
- Manage API keys (create, enable/disable, delete).
|
||||
- System-level configuration.
|
||||
- View audit logs.
|
||||
- View and export audit logs.
|
||||
|
||||
### Design
|
||||
### Designer
|
||||
- **Scope**: System-wide (always).
|
||||
- **Permissions**:
|
||||
- Create, edit, delete templates (including attributes, alarms, scripts).
|
||||
@@ -102,7 +102,7 @@ Set in a local or docker-dev environment via the environment variable `ScadaBrid
|
||||
- Manage inbound API method definitions.
|
||||
- Run on-demand validation (template flattening, script compilation).
|
||||
|
||||
### Deployment
|
||||
### Deployer
|
||||
- **Scope**: System-wide or site-scoped.
|
||||
- **Permissions**:
|
||||
- Create and manage instances (overrides, connection bindings, area assignment).
|
||||
@@ -114,25 +114,32 @@ Set in a local or docker-dev environment via the environment variable `ScadaBrid
|
||||
- Manage parked messages.
|
||||
- Monitor and manage the Notification Outbox (retry and discard parked notifications).
|
||||
- View site event logs.
|
||||
- **Site scoping**: A user with site-scoped Deployment role can only perform these actions for instances at their permitted sites.
|
||||
- **Site scoping**: A user with site-scoped Deployer role can only perform these actions for instances at their permitted sites.
|
||||
|
||||
### Viewer
|
||||
- **Scope**: System-wide (always).
|
||||
- **Permissions**:
|
||||
- Read-only access to operational audit data (Audit Log, Notifications, Site Calls).
|
||||
- Navigation to audit pages.
|
||||
- Does not grant export or any mutating action.
|
||||
|
||||
## Multi-Role Support
|
||||
|
||||
- A user can hold **multiple roles simultaneously** by being a member of multiple LDAP groups.
|
||||
- Roles are **independent** — there is no implied hierarchy between roles.
|
||||
- For example, a user who is a member of both `SCADA-Designers` and `SCADA-Deploy-All` holds both the Design and Deployment roles, allowing them to author templates and also deploy configurations.
|
||||
- For example, a user who is a member of both `SCADA-Designers` and `SCADA-Deploy-All` holds both the Designer and Deployer roles, allowing them to author templates and also deploy configurations.
|
||||
|
||||
## LDAP Group Mapping
|
||||
|
||||
- System administrators configure mappings between LDAP groups and roles.
|
||||
- Examples:
|
||||
- `SCADA-Admins` → Admin role
|
||||
- `SCADA-Designers` → Design role
|
||||
- `SCADA-Deploy-All` → Deployment role (all sites)
|
||||
- `SCADA-Deploy-SiteA` → Deployment role (Site A only)
|
||||
- `SCADA-Deploy-SiteB` → Deployment role (Site B only)
|
||||
- `SCADA-Admins` → Administrator role
|
||||
- `SCADA-Designers` → Designer role
|
||||
- `SCADA-Deploy-All` → Deployer role (all sites)
|
||||
- `SCADA-Deploy-SiteA` → Deployer role (Site A only)
|
||||
- `SCADA-Deploy-SiteB` → Deployer role (Site B only)
|
||||
- A user can be a member of multiple groups, granting multiple independent roles.
|
||||
- Group mappings are stored in the configuration database and managed via the Central UI (Admin role).
|
||||
- Group mappings are stored in the configuration database and managed via the Central UI (Administrator role).
|
||||
|
||||
## Permission Enforcement
|
||||
|
||||
@@ -149,8 +156,8 @@ Set in a local or docker-dev environment via the environment variable `ScadaBrid
|
||||
## Interactions
|
||||
|
||||
- **Central UI**: All UI requests pass through authentication and authorization.
|
||||
- **Template Engine**: Design role enforcement.
|
||||
- **Deployment Manager**: Deployment role enforcement with site scoping.
|
||||
- **Template Engine**: Designer role enforcement.
|
||||
- **Deployment Manager**: Deployer role enforcement with site scoping.
|
||||
- **All central components**: Role checks are a cross-cutting concern applied at the API layer.
|
||||
- **Management Service**: The ManagementActor enforces role-based authorization on every incoming command using the authenticated user identity carried in the message envelope. The CLI authenticates users via the same LDAP bind mechanism and passes the user's identity (username, roles, permitted sites) in every request message. The ManagementActor applies the same role and site-scoping rules as the Central UI — no separate authentication path exists on the server side.
|
||||
- **Transport (#24)**: Provides the `RequireDesign` policy (export) and `RequireAdmin` policy (import) enforced at both the Razor page layer and inside the `ZB.MOM.WW.ScadaBridge.Transport` service entrypoints.
|
||||
|
||||
Reference in New Issue
Block a user