fix(opcua): credential lockout review fixes (#833)

- Reserve an in-flight slot per client before authenticating (TryBegin /
  Complete / Abandon under one lock); refuse once recorded failures +
  in-flight attempts reach MaxFailedAttempts, so a parallel burst cannot
  pass the check before its first failure is recorded.
- An expired lockout resets the count (LockoutSeconds < FailureWindowSeconds
  relocked on every single failure after the first lockout).
- Validate OpcUa:CredentialLockout at host start: disabled, or both
  durations > 0.
- Log the first refusal of a lockout episode at Information, the rest at
  Debug.
- Document that on None endpoints the key is effectively IP-only (NAT
  neighbours share a UserName count) and a null peer shares one key.
This commit is contained in:
Joseph Doherty
2026-11-11 02:32:40 -05:00
parent 0856261ef8
commit 988927c8ac
8 changed files with 386 additions and 70 deletions
+2 -2
View File
@@ -75,8 +75,8 @@ Until #678.6 the overlay never loaded on a node carrying a `cluster-*` role (the
| `AutoAcceptUntrustedClientCertificates` | bool | `false` | Auto-trust unknown client certs on first connect (dev convenience). Not validated. See [`security.md`](security.md). |
| `PeerApplicationUris` | list of string | `[]` (empty) | Partner node `ApplicationUri`s published in `Server.ServerArray` for redundancy discovery. See [`Redundancy.md`](Redundancy.md). |
| `CredentialLockout:MaxFailedAttempts` | int | `5` | Failed UserName (API-key) activations from one client before its UserName activations are refused `BadUserAccessDenied` (#833). `≤ 0` disables. **Never refuses Anonymous.** See [`security.md`](security.md#failed-credential-lockout-opcuacredentiallockout). |
| `CredentialLockout:FailureWindowSeconds` | int | `60` | A failure more than this long after the client's previous one starts a fresh count. |
| `CredentialLockout:LockoutSeconds` | int | `300` | How long a locked-out client's UserName activations are refused. |
| `CredentialLockout:FailureWindowSeconds` | int | `60` | A failure more than this long after the client's previous one starts a fresh count. Must be `> 0` while the lockout is enabled (validated). |
| `CredentialLockout:LockoutSeconds` | int | `300` | How long a locked-out client's UserName activations are refused; an expired lockout starts a fresh count. Must be `> 0` while the lockout is enabled (validated). |
> **Transport security profiles** (the values in `EnabledSecurityProfiles` — `None`, `Basic256Sha256Sign`, `Basic256Sha256SignAndEncrypt`) and the PKI trust flow are documented in full in [`security.md`](security.md). This page does not duplicate them.