Files
Copilot ce9b2b4bff [Server] Load existing users through IUserDatabase.GetUsers (#3811)
**User Management Improvements:**

* The `UserManagement` class now loads existing users from the user
database during initialization, ensuring that the in-memory user list
reflects the database state through the abstraction boundary.
* The `IUserDatabase` interface now exposes `GetUsers()`, returning
`UserManagementDataType` records instead of only user names.
* `UserManagement.LoadUsersFromDatabase()` now consumes
`IUserDatabase.GetUsers()` so custom user database implementations can
provide persisted user metadata such as `UserConfiguration` and
`Description`.
* `LinqUserDatabase` implements `GetUsers()` and returns user records
with the stored user name and default user-management metadata.
`JsonUserDatabase` inherits this behavior through `LinqUserDatabase`.

**Address Space Management:**

* The server now properly removes the UserManagement node from the
address space when user management is not enabled, preventing stale or
orphaned nodes.

**Test Coverage Enhancements:**

* Added tests to verify that the UserManagement node is removed when
user management is not present.
* Added tests to confirm that `LinqUserDatabase.GetUsers()` returns the
correct users.
* Added tests to confirm that `UserManagement` starts with all users
from the database, including custom `IUserDatabase` implementations that
return full `UserManagementDataType` metadata.

These changes keep user discovery on the `IUserDatabase` abstraction,
remove the concrete-type dependency from startup, and allow existing
users to be loaded with their associated management metadata.
2026-05-28 11:00:18 +02:00

143 lines
4.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Opc.Ua.Server.UserDatabase;
namespace Opc.Ua.Server.Tests
{
[TestFixture]
[Category("Server")]
[SetCulture("en-us")]
[SetUICulture("en-us")]
[Parallelizable]
public sealed class LinqUserDatabaseTests
{
private static readonly string[] s_createdUsers = ["TestUser1", "TestUser2"];
[Test]
public void CreateInvalidUser()
{
// Arrange
var usersDb = new LinqUserDatabase();
// Act + Assert
Assert.Throws<ArgumentException>(
() => usersDb.CreateUser(null, "PW"u8, [Role.AuthenticatedUser]));
Assert.Throws<ArgumentException>(
() => usersDb.CreateUser("Name", null, [Role.AuthenticatedUser]));
Assert.Throws<ArgumentException>(
() => usersDb.CreateUser(string.Empty, "PW"u8, [Role.AuthenticatedUser]));
Assert.Throws<ArgumentException>(
() => usersDb.CreateUser("Name", ""u8, [Role.AuthenticatedUser]));
}
[Test]
public void DeleteExistingUser()
{
// Arrrange
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW"u8, [Role.AuthenticatedUser]);
// Act
bool result = usersDb.DeleteUser("TestUser");
// Assert
Assert.That(result, Is.True);
}
[Test]
public void DeleteNonExistingUser()
{
// Arrrange
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW"u8, [Role.AuthenticatedUser]);
// Act
bool result = usersDb.DeleteUser("NoTestUser");
// Assert
Assert.That(result, Is.False);
}
[Test]
public void ChangePwOfExistingUser()
{
// Arrange
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW"u8, [Role.AuthenticatedUser]);
// Act
bool result = usersDb.ChangePassword("TestUser", "PW"u8, "newPW"u8);
bool login = usersDb.CheckCredentials("TestUser", "newPW"u8);
bool loginOldPW = usersDb.CheckCredentials("TestUser", "PW"u8);
// Assert
Assert.That(result, Is.True);
Assert.That(login, Is.True);
Assert.That(loginOldPW, Is.False);
}
[Test]
public void ChangePwOfNonExistingUser()
{
// Arrange
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW"u8, [Role.AuthenticatedUser]);
// Act
bool result = usersDb.DeleteUser("NoTestUser");
// Assert
Assert.That(result, Is.False);
}
[Test]
public void CheckPWofExistingUser()
{
// Arrange
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW"u8, [Role.AuthenticatedUser]);
// Act
bool result = usersDb.CheckCredentials("TestUser", "PW"u8);
bool loginWrongPw = usersDb.CheckCredentials("TestUser", "newPW"u8);
// Assert
Assert.That(result, Is.True);
Assert.That(loginWrongPw, Is.False);
}
[Test]
public void CheckPWofNonExistingUser()
{
// Arrange
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW"u8, [Role.AuthenticatedUser]);
// Act
bool result = usersDb.CheckCredentials("NoTestUser", "PW"u8);
// Assert
Assert.That(result, Is.False);
}
[Test]
public void GetUsersReturnsCreatedUsers()
{
// Arrange
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser1", "PW"u8, [Role.AuthenticatedUser]);
usersDb.CreateUser("TestUser2", "PW2"u8, [Role.Engineer]);
// Act
IReadOnlyList<UserManagementDataType> users = usersDb.GetUsers();
// Assert
Assert.That(users.Select(user => user.UserName), Is.EquivalentTo(s_createdUsers));
Assert.That(users.All(user => user.UserConfiguration == (uint)UserConfigurationMask.None), Is.True);
Assert.That(users.Select(user => user.Description), Is.All.Empty);
}
}
}