using System.Threading.Tasks; using Opc.Ua; using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Host.Configuration; using ZB.MOM.WW.OtOpcUa.Host.Domain; using ZB.MOM.WW.OtOpcUa.Tests.Helpers; namespace ZB.MOM.WW.OtOpcUa.Tests.Integration { public class PermissionEnforcementTests { private static FakeAuthenticationProvider CreateTestAuthProvider() { return new FakeAuthenticationProvider() .AddUser("readonly", "readonly123", AppRoles.ReadOnly) .AddUser("writeop", "writeop123", AppRoles.WriteOperate) .AddUser("writetune", "writetune123", AppRoles.WriteTune) .AddUser("writeconfig", "writeconfig123", AppRoles.WriteConfigure) .AddUser("alarmack", "alarmack123", AppRoles.AlarmAck) .AddUser("admin", "admin123", AppRoles.ReadOnly, AppRoles.WriteOperate, AppRoles.WriteTune, AppRoles.WriteConfigure, AppRoles.AlarmAck); } private static AuthenticationConfiguration CreateAuthConfig(bool anonymousCanWrite = false) { return new AuthenticationConfiguration { AllowAnonymous = true, AnonymousCanWrite = anonymousCanWrite }; } [Fact] public async Task AnonymousRead_Allowed() { var mxClient = new FakeMxAccessClient(); mxClient.TagValues["TestMachine_001.MachineID"] = Vtq.Good("hello"); var fixture = OpcUaServerFixture.WithFakeMxAccessClient( mxClient, authConfig: CreateAuthConfig(), authProvider: CreateTestAuthProvider()); await fixture.InitializeAsync(); try { using var client = new OpcUaTestClient(); await client.ConnectAsync(fixture.EndpointUrl); var result = client.Read(client.MakeNodeId("TestMachine_001.MachineID")); result.StatusCode.ShouldNotBe(StatusCodes.BadUserAccessDenied); } finally { await fixture.DisposeAsync(); } } [Fact] public async Task AnonymousWrite_Denied_WhenAnonymousCanWriteFalse() { var fixture = OpcUaServerFixture.WithFakeMxAccessClient( authConfig: CreateAuthConfig(false), authProvider: CreateTestAuthProvider()); await fixture.InitializeAsync(); try { using var client = new OpcUaTestClient(); await client.ConnectAsync(fixture.EndpointUrl); var status = client.Write(client.MakeNodeId("TestMachine_001.MachineID"), "test"); status.Code.ShouldBe(StatusCodes.BadUserAccessDenied); } finally { await fixture.DisposeAsync(); } } [Fact] public async Task AnonymousWrite_Allowed_WhenAnonymousCanWriteTrue() { var mxClient = new FakeMxAccessClient(); mxClient.TagValues["TestMachine_001.MachineID"] = Vtq.Good("initial"); var fixture = OpcUaServerFixture.WithFakeMxAccessClient( mxClient, authConfig: CreateAuthConfig(true), authProvider: CreateTestAuthProvider()); await fixture.InitializeAsync(); try { using var client = new OpcUaTestClient(); await client.ConnectAsync(fixture.EndpointUrl); var status = client.Write(client.MakeNodeId("TestMachine_001.MachineID"), "test"); status.Code.ShouldNotBe(StatusCodes.BadUserAccessDenied); } finally { await fixture.DisposeAsync(); } } [Fact] public async Task ReadOnlyUser_Write_Denied() { var fixture = OpcUaServerFixture.WithFakeMxAccessClient( authConfig: CreateAuthConfig(), authProvider: CreateTestAuthProvider()); await fixture.InitializeAsync(); try { using var client = new OpcUaTestClient(); await client.ConnectAsync(fixture.EndpointUrl, username: "readonly", password: "readonly123"); var status = client.Write(client.MakeNodeId("TestMachine_001.MachineID"), "test"); status.Code.ShouldBe(StatusCodes.BadUserAccessDenied); } finally { await fixture.DisposeAsync(); } } [Fact] public async Task WriteOperateUser_Write_Allowed() { var mxClient = new FakeMxAccessClient(); mxClient.TagValues["TestMachine_001.MachineID"] = Vtq.Good("initial"); var fixture = OpcUaServerFixture.WithFakeMxAccessClient( mxClient, authConfig: CreateAuthConfig(), authProvider: CreateTestAuthProvider()); await fixture.InitializeAsync(); try { using var client = new OpcUaTestClient(); await client.ConnectAsync(fixture.EndpointUrl, username: "writeop", password: "writeop123"); var status = client.Write(client.MakeNodeId("TestMachine_001.MachineID"), "test"); status.Code.ShouldNotBe(StatusCodes.BadUserAccessDenied); } finally { await fixture.DisposeAsync(); } } [Fact] public async Task AlarmAckOnlyUser_Write_Denied() { var fixture = OpcUaServerFixture.WithFakeMxAccessClient( authConfig: CreateAuthConfig(), authProvider: CreateTestAuthProvider()); await fixture.InitializeAsync(); try { using var client = new OpcUaTestClient(); await client.ConnectAsync(fixture.EndpointUrl, username: "alarmack", password: "alarmack123"); var status = client.Write(client.MakeNodeId("TestMachine_001.MachineID"), "test"); status.Code.ShouldBe(StatusCodes.BadUserAccessDenied); } finally { await fixture.DisposeAsync(); } } [Fact] public async Task AdminUser_Write_Allowed() { var mxClient = new FakeMxAccessClient(); mxClient.TagValues["TestMachine_001.MachineID"] = Vtq.Good("initial"); var fixture = OpcUaServerFixture.WithFakeMxAccessClient( mxClient, authConfig: CreateAuthConfig(), authProvider: CreateTestAuthProvider()); await fixture.InitializeAsync(); try { using var client = new OpcUaTestClient(); await client.ConnectAsync(fixture.EndpointUrl, username: "admin", password: "admin123"); var status = client.Write(client.MakeNodeId("TestMachine_001.MachineID"), "test"); status.Code.ShouldNotBe(StatusCodes.BadUserAccessDenied); } finally { await fixture.DisposeAsync(); } } [Fact] public async Task InvalidPassword_ConnectionRejected() { var fixture = OpcUaServerFixture.WithFakeMxAccessClient( authConfig: CreateAuthConfig(), authProvider: CreateTestAuthProvider()); await fixture.InitializeAsync(); try { using var client = new OpcUaTestClient(); await Should.ThrowAsync(async () => await client.ConnectAsync(fixture.EndpointUrl, username: "readonly", password: "wrongpassword")); } finally { await fixture.DisposeAsync(); } } } }