Add authentication and role-based write access control
Implements configurable user authentication (anonymous + username/password) with pluggable credential provider (IUserAuthenticationProvider). Anonymous writes can be disabled via AnonymousCanWrite setting while reads remain open. Adds -U/-P flags to all CLI commands for authenticated sessions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -192,6 +192,56 @@ Pass `AuthenticationConfiguration` and `IUserAuthenticationProvider` through:
|
||||
- `OpcUaServerHost` uses `AllowAnonymous` and user count for `UserTokenPolicies`
|
||||
- `LmxNodeManager` receives `AnonymousCanWrite` flag for write enforcement
|
||||
|
||||
### 7. CLI tool authentication — `tools/opcuacli-dotnet/`
|
||||
|
||||
Add `--username` and `--password` options to `OpcUaHelper.ConnectAsync` so all commands can authenticate.
|
||||
|
||||
**`OpcUaHelper.cs`** — update `ConnectAsync` to accept optional credentials:
|
||||
|
||||
```csharp
|
||||
public static async Task<Session> ConnectAsync(string endpointUrl, string? username = null, string? password = null)
|
||||
{
|
||||
// ... existing config setup ...
|
||||
|
||||
UserIdentity identity = (username != null)
|
||||
? new UserIdentity(username, password ?? "")
|
||||
: new UserIdentity();
|
||||
|
||||
var session = await Session.Create(
|
||||
config, configuredEndpoint, false,
|
||||
"OpcUaCli", 60000, identity, null);
|
||||
|
||||
return session;
|
||||
}
|
||||
```
|
||||
|
||||
**Each command** — add shared options. Since CliFx doesn't support base classes for shared options, add `-U` / `-P` to each command:
|
||||
|
||||
```csharp
|
||||
[CommandOption("username", 'U', Description = "Username for authentication")]
|
||||
public string? Username { get; init; }
|
||||
|
||||
[CommandOption("password", 'P', Description = "Password for authentication")]
|
||||
public string? Password { get; init; }
|
||||
```
|
||||
|
||||
And pass to `OpcUaHelper.ConnectAsync(Url, Username, Password)`.
|
||||
|
||||
**Usage examples:**
|
||||
|
||||
```bash
|
||||
# Anonymous (current behavior)
|
||||
dotnet run -- read -u opc.tcp://localhost:4840/LmxOpcUa -n "ns=1;s=TestMachine_001.MachineID"
|
||||
|
||||
# Authenticated
|
||||
dotnet run -- read -u opc.tcp://localhost:4840/LmxOpcUa -n "ns=1;s=TestMachine_001.MachineID" -U operator -P op123
|
||||
|
||||
# Write with credentials (when AnonymousCanWrite is false)
|
||||
dotnet run -- write -u opc.tcp://localhost:4840/LmxOpcUa -n "ns=1;s=TestMachine_001.MachineID" -v "NEW" -U operator -P op123
|
||||
```
|
||||
|
||||
**README update** — document the `-U` / `-P` flags.
|
||||
|
||||
## Files to Create/Modify
|
||||
|
||||
| File | Change |
|
||||
@@ -207,7 +257,39 @@ Pass `AuthenticationConfiguration` and `IUserAuthenticationProvider` through:
|
||||
| `src/.../appsettings.json` | Add Authentication section |
|
||||
| `tests/.../Authentication/UserAuthenticationTests.cs` | NEW — credential validation tests |
|
||||
| `tests/.../Integration/WriteAccessTests.cs` | NEW — anonymous vs authenticated write tests |
|
||||
| `docs/Configuration.md` | Update with Authentication section |
|
||||
| `tools/opcuacli-dotnet/OpcUaHelper.cs` | Add username/password parameters to `ConnectAsync` |
|
||||
| `tools/opcuacli-dotnet/Commands/*.cs` | Add `-U` / `-P` options to all 7 commands |
|
||||
| `tools/opcuacli-dotnet/README.md` | Document authentication flags |
|
||||
| `docs/Configuration.md` | Add Authentication section with settings table |
|
||||
| `docs/OpcUaServer.md` | Update security policy and UserTokenPolicies section |
|
||||
| `docs/ReadWriteOperations.md` | Document role-based write enforcement |
|
||||
| `docs/CliTool.md` | Document `-U` / `-P` authentication flags |
|
||||
|
||||
## Tests
|
||||
|
||||
### Unit tests — `tests/.../Authentication/UserAuthenticationTests.cs` (NEW)
|
||||
|
||||
- `ConfigUserAuthenticationProvider` validates correct username/password
|
||||
- `ConfigUserAuthenticationProvider` rejects wrong password
|
||||
- `ConfigUserAuthenticationProvider` rejects unknown username
|
||||
- `ConfigUserAuthenticationProvider` is case-insensitive on username
|
||||
- Empty user list rejects all credentials
|
||||
- `AuthenticationConfiguration` defaults: `AllowAnonymous=true`, `AnonymousCanWrite=true`, empty Users list
|
||||
|
||||
### Integration tests — `tests/.../Integration/WriteAccessTests.cs` (NEW)
|
||||
|
||||
- Anonymous connect succeeds when `AllowAnonymous=true`
|
||||
- Anonymous connect rejected when `AllowAnonymous=false` (requires test fixture to configure auth)
|
||||
- Anonymous read succeeds regardless of `AnonymousCanWrite`
|
||||
- Anonymous write succeeds when `AnonymousCanWrite=true`
|
||||
- Anonymous write rejected with `BadUserAccessDenied` when `AnonymousCanWrite=false`
|
||||
- Authenticated user write succeeds when `AnonymousCanWrite=false`
|
||||
- Invalid credentials rejected with `BadUserAccessDenied`
|
||||
|
||||
### Existing test updates
|
||||
|
||||
- `OpcUaServerFixture` — add option to configure `AuthenticationConfiguration` for auth-aware test fixtures
|
||||
- Existing write tests continue passing (default config allows anonymous writes)
|
||||
|
||||
## Verification
|
||||
|
||||
|
||||
Reference in New Issue
Block a user