test(validation): ScadaBridge consumer matrix — provisioned client identity, Sign leg, trust negative controls (ScadaBridge#121)

Probe 'prepare' provisions the consumer identity via OpcUaApplicationIdentity.EnsureApplicationCertificateAsync
and exports the public DER; runner installs it in the server trusted store before start. Adds Sign
(OPCUA_MATRIX_SERVER_SECURITY=sign), untrusted-client / untrusted-server fail-closed controls per secure
mode, and OPCUA_MATRIX_ACL=off. Autoaccept stays false everywhere.
This commit is contained in:
Joseph Doherty
2026-11-12 06:28:15 -05:00
parent f127f45428
commit ea83fc58b2
3 changed files with 76 additions and 17 deletions
@@ -112,8 +112,12 @@ internal static class ProcessHost
PkiStoreRoot = Path.Combine(Root, "server-pki"),
AllowAnonymous = false,
AutoAcceptUntrustedClientCertificates = false,
EnabledSecurityProfiles = Environment.GetEnvironmentVariable("OPCUA_MATRIX_SERVER_SECURITY") == "none"
? [OpcUaSecurityProfile.None] : [OpcUaSecurityProfile.Basic256Sha256SignAndEncrypt]
EnabledSecurityProfiles = Environment.GetEnvironmentVariable("OPCUA_MATRIX_SERVER_SECURITY") switch
{
"none" => [OpcUaSecurityProfile.None],
"sign" => [OpcUaSecurityProfile.Basic256Sha256Sign],
_ => [OpcUaSecurityProfile.Basic256Sha256SignAndEncrypt],
}
};
using (var listener = new TcpListener(IPAddress.Loopback, 0)) { listener.Start(); options.OpcUaPort = ((IPEndPoint)listener.LocalEndpoint).Port; }
var server = new OtOpcUaSdkServer();
@@ -124,6 +128,8 @@ internal static class ProcessHost
authority.Apply("matrix", "rev1", [new ApiKey { ApiKeyId = "matrix", Name = "matrix", SecretHash = "fixture", Principal = "matrix", Enabled = true, CreatedUtc = DateTime.UtcNow.AddDays(-1) }],
[new NodeAcl { NodeAclId = "all", ClusterId = "matrix", Principal = "matrix", ScopeKind = NodeAclScopeKind.Cluster, PermissionFlags = (NodePermissions)int.MaxValue }], new Dictionary<AclScopeRef, IReadOnlyList<NodeAclPath>>());
nm.DataPlaneAuthority = authority;
// OPCUA_MATRIX_ACL=off mirrors the shipped default (Security:Acl:Enabled=false): no node authorizer.
if (Environment.GetEnvironmentVariable("OPCUA_MATRIX_ACL") != "off")
nm.Authorizer = new DataPlaneAuthorizer(authority, new TriePermissionEvaluator(authority.Tries), true, NullLogger.Instance, TimeProvider.System);
var history = new Source(Root); nm.HistorianDataSource = history;
sink.EnsureFolder(Folder, null, "dev", AddressSpaceRealm.Raw);