User Management Improvements for Standard Server (Support Well Known Roles) (#2444)

- move IUserDatabase + RoleBased Identity into standard Server
- subclass SystemConfigurationIdentity from RoleBased Identity for backward compatibility
- add OPC UA Spec Defined Roles to the RoleBasedIdentity
This commit is contained in:
romanett
2024-01-16 22:24:51 +01:00
committed by GitHub
parent 08c83c2f5b
commit 4f43f68cd9
12 changed files with 340 additions and 221 deletions
@@ -237,16 +237,6 @@ namespace Quickstarts.ReferenceServer
Utils.LogInfo(Utils.TraceMasks.Security, "Username Token Accepted: {0}", args.Identity?.DisplayName);
// set AuthenticatedUser role for accepted user/password authentication
args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_AuthenticatedUser);
if (args.Identity is SystemConfigurationIdentity)
{
// set ConfigureAdmin role for user with permission to configure server
args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_ConfigureAdmin);
args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_SecurityAdmin);
}
return;
}
@@ -256,11 +246,10 @@ namespace Quickstarts.ReferenceServer
if (x509Token != null)
{
VerifyUserTokenCertificate(x509Token.Certificate);
args.Identity = new UserIdentity(x509Token);
Utils.LogInfo(Utils.TraceMasks.Security, "X509 Token Accepted: {0}", args.Identity?.DisplayName);
// set AuthenticatedUser role for accepted certificate authentication
args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_AuthenticatedUser);
args.Identity = new RoleBasedIdentity(new UserIdentity(x509Token),
new List<Role>() { Role.AuthenticatedUser });
Utils.LogInfo(Utils.TraceMasks.Security, "X509 Token Accepted: {0}", args.Identity?.DisplayName);
return;
}
@@ -280,9 +269,8 @@ namespace Quickstarts.ReferenceServer
if (args.NewIdentity is AnonymousIdentityToken || args.NewIdentity == null)
{
// allow anonymous authentication and set Anonymous role for this authentication
args.Identity = new UserIdentity();
args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_Anonymous);
args.Identity = new RoleBasedIdentity(new UserIdentity(),
new List<Role>() { Role.Anonymous });
return;
}
@@ -336,8 +324,8 @@ namespace Quickstarts.ReferenceServer
LoadServerProperties().ProductUri,
new LocalizedText(info)));
}
return new UserIdentity(userNameToken);
return new RoleBasedIdentity(new UserIdentity(userNameToken),
new List<Role>() { Role.AuthenticatedUser});
}
/// <summary>
@@ -168,7 +168,7 @@ namespace Opc.Ua.Gds.Server
{
RoleBasedIdentity identity = context.UserIdentity as RoleBasedIdentity;
if ((identity == null) || (identity.Role != GdsRole.ApplicationAdmin))
if ((identity == null) || (!identity.Roles.Contains(GdsRole.ApplicationAdmin)))
{
throw new ServiceResultException(StatusCodes.BadUserAccessDenied, "Application Administrator access required.");
}
@@ -27,92 +27,32 @@
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/
using System.Xml;
using Opc.Ua.Server;
namespace Opc.Ua.Gds.Server
{
/// <summary>
/// The supported roles in a GDS server.
/// </summary>
public enum GdsRole
public class GdsRole : Role
{
/// <summary>
/// The GDS application Administrator.
/// </summary>
ApplicationAdmin,
public static Role ApplicationAdmin { get; } = new Role(NodeId.Null, "ApplicationAdmin");
/// <summary>
/// This Role grants rights to register, update and unregister any OPC UA Application.
/// </summary>
public static Role DiscoveryAdmin { get; } = new Role( NodeId.Null, "DiscoveryAdmin");
/// <summary>
/// The GDS application user.
/// </summary>
ApplicationUser
}
public static Role ApplicationUser { get; } = new Role(NodeId.Null, "ApplicationUser");
/// <summary>
/// The role based identity for a GDS server.
/// </summary>
public class RoleBasedIdentity : IUserIdentity
{
private IUserIdentity m_identity;
private GdsRole m_role;
/// <summary>
/// Initialize the role based identity.
/// </summary>
public RoleBasedIdentity(IUserIdentity identity, GdsRole role)
{
m_identity = identity;
m_role = role;
}
/// <inheritdoc/>
public NodeIdCollection GrantedRoleIds
{
get { return m_identity.GrantedRoleIds; }
set { m_identity.GrantedRoleIds = value; }
}
/// <summary>
/// The role in the context of a Gds.
/// </summary>
public GdsRole Role
{
get { return m_role; }
}
/// <inheritdoc/>
public string DisplayName
{
get { return m_identity.DisplayName; }
}
/// <inheritdoc/>
public string PolicyId
{
get { return m_identity.PolicyId; }
}
/// <inheritdoc/>
public UserTokenType TokenType
{
get { return m_identity.TokenType; }
}
/// <inheritdoc/>
public XmlQualifiedName IssuedTokenType
{
get { return m_identity.IssuedTokenType; }
}
/// <inheritdoc/>
public bool SupportsSignatures
{
get { return m_identity.SupportsSignatures; }
}
/// <inheritdoc/>
public UserIdentityToken GetIdentityToken()
{
return m_identity.GetIdentityToken();
}
public GdsRole(NodeId roleId, string name):
base(roleId, name)
{}
}
}
@@ -33,6 +33,8 @@ using System.Security.Cryptography.X509Certificates;
using System.Threading;
using Opc.Ua.Server;
using Opc.Ua.Gds.Server.Database;
using Opc.Ua.Server.UserDatabase;
using System.Linq;
namespace Opc.Ua.Gds.Server
{
@@ -54,7 +56,7 @@ namespace Opc.Ua.Gds.Server
IApplicationsDatabase database,
ICertificateRequest request,
ICertificateGroup certificateGroup,
IUsersDatabase userDatabase,
IUserDatabase userDatabase,
bool autoApprove = true,
bool createStandardUsers = true
)
@@ -206,24 +208,21 @@ namespace Opc.Ua.Gds.Server
Utils.LogInfo("SystemConfigurationAdmin Token Accepted: {0}", args.Identity.DisplayName);
return;
}
switch (m_userDatabase.GetUserRole(userNameToken.UserName))
IEnumerable<Role> roles = m_userDatabase.GetUserRoles(userNameToken.UserName);
//GdsAdmin
if (roles.Contains(GdsRole.ApplicationAdmin))
{
// GDS administrator
case GdsRole.ApplicationAdmin:
{
args.Identity = new RoleBasedIdentity(new UserIdentity(userNameToken), GdsRole.ApplicationAdmin);
Utils.LogInfo("ApplicationAdmin Token Accepted: {0}", args.Identity.DisplayName);
return;
}
// GDS user
case GdsRole.ApplicationUser:
{
args.Identity = new RoleBasedIdentity(new UserIdentity(userNameToken), GdsRole.ApplicationUser);
Utils.LogInfo("ApplicationUser Token Accepted: {0}", args.Identity.DisplayName);
return;
}
args.Identity = new RoleBasedIdentity(new UserIdentity(userNameToken), new List<Role> { GdsRole.ApplicationAdmin });
Utils.LogInfo("ApplicationAdmin Token Accepted: {0}", args.Identity.DisplayName);
return;
}
//GdsUser
if (roles.Contains(GdsRole.ApplicationUser))
{
args.Identity = new RoleBasedIdentity(new UserIdentity(userNameToken), new List<Role> { GdsRole.ApplicationUser });
Utils.LogInfo("ApplicationUser Token Accepted: {0}", args.Identity.DisplayName);
return;
}
}
}
@@ -231,14 +230,13 @@ namespace Opc.Ua.Gds.Server
X509IdentityToken x509Token = args.NewIdentity as X509IdentityToken;
if (x509Token != null)
{
GdsRole role = GdsRole.ApplicationUser;
VerifyUserTokenCertificate(x509Token.Certificate);
// todo: is cert listed in admin list? then
// role = GdsRole.ApplicationAdmin;
Utils.LogInfo("X509 Token Accepted: {0} as {1}", args.Identity.DisplayName, role.ToString());
args.Identity = new RoleBasedIdentity(new UserIdentity(x509Token), role);
Utils.LogInfo("X509 Token Accepted: {0} as {1}", args.Identity.DisplayName, GdsRole.ApplicationUser);
args.Identity = new RoleBasedIdentity(new UserIdentity(x509Token), new List<Role> { GdsRole.ApplicationUser });
return;
}
}
@@ -297,9 +295,9 @@ namespace Opc.Ua.Gds.Server
/// </summary>
private void RegisterDefaultUsers()
{
m_userDatabase.CreateUser("sysadmin", "demo", GdsRole.ApplicationAdmin);
m_userDatabase.CreateUser("appadmin", "demo", GdsRole.ApplicationAdmin);
m_userDatabase.CreateUser("appuser", "demo", GdsRole.ApplicationUser);
m_userDatabase.CreateUser("sysadmin", "demo", new List<Role> { GdsRole.ApplicationAdmin, Role.SecurityAdmin, Role.ConfigureAdmin });
m_userDatabase.CreateUser("appadmin", "demo", new List<Role> { GdsRole.ApplicationAdmin });
m_userDatabase.CreateUser("appuser", "demo", new List<Role> { GdsRole.ApplicationUser });
}
#endregion
@@ -308,7 +306,7 @@ namespace Opc.Ua.Gds.Server
private IApplicationsDatabase m_database = null;
private ICertificateRequest m_request = null;
private ICertificateGroup m_certificateGroup = null;
private IUsersDatabase m_userDatabase = null;
private IUserDatabase m_userDatabase = null;
private bool m_autoApprove;
private bool m_createStandardUsers;
#endregion
@@ -36,67 +36,20 @@ using System.Xml;
namespace Opc.Ua.Server
{
/// <summary>
/// Priviledged identity which can access the system configuration.
/// </summary>
public class SystemConfigurationIdentity : IUserIdentity
public class SystemConfigurationIdentity : RoleBasedIdentity
{
private IUserIdentity m_identity;
/// <summary>
/// Create a user identity with the priviledge
/// to modify the system configuration.
/// </summary>
/// <param name="identity">The user identity.</param>
public SystemConfigurationIdentity(IUserIdentity identity)
{
m_identity = identity;
:base(identity, new List<Role> {Role.SecurityAdmin, Role.ConfigureAdmin }){
}
#region IUserIdentity
/// <inheritdoc/>
public string DisplayName
{
get { return m_identity.DisplayName; }
}
/// <inheritdoc/>
public string PolicyId
{
get { return m_identity.PolicyId; }
}
/// <inheritdoc/>
public UserTokenType TokenType
{
get { return m_identity.TokenType; }
}
/// <inheritdoc/>
public XmlQualifiedName IssuedTokenType
{
get { return m_identity.IssuedTokenType; }
}
/// <inheritdoc/>
public bool SupportsSignatures
{
get { return m_identity.SupportsSignatures; }
}
/// <inheritdoc/>
public NodeIdCollection GrantedRoleIds
{
get { return m_identity.GrantedRoleIds; }
set { m_identity.GrantedRoleIds = value; }
}
/// <inheritdoc/>
public UserIdentityToken GetIdentityToken()
{
return m_identity.GetIdentityToken();
}
#endregion
}
/// <summary>
@@ -355,10 +308,11 @@ namespace Opc.Ua.Server
}
// allow access to system configuration only through special identity
SystemConfigurationIdentity user = context.UserIdentity as SystemConfigurationIdentity;
if (user == null || user.TokenType == UserTokenType.Anonymous)
IUserIdentity user = context.UserIdentity as RoleBasedIdentity;
if (user == null || user.TokenType == UserTokenType.Anonymous ||
!user.GrantedRoleIds.Contains(ObjectIds.WellKnownRole_SecurityAdmin))
{
throw new ServiceResultException(StatusCodes.BadUserAccessDenied, "System Configuration Administrator access required.");
throw new ServiceResultException(StatusCodes.BadUserAccessDenied, "Security Admin Role required.");
}
}
@@ -1547,7 +1547,8 @@ namespace Opc.Ua.Server
return false;
}
SystemConfigurationIdentity user = context.UserIdentity as SystemConfigurationIdentity;
IUserIdentity user = context.UserIdentity as RoleBasedIdentity;
if (user == null ||
user.TokenType == UserTokenType.Anonymous ||
!user.GrantedRoleIds.Contains(ObjectIds.WellKnownRole_SecurityAdmin))
@@ -0,0 +1,226 @@
/* ========================================================================
* Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* The complete license agreement can be found here:
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/
using System;
using System.Collections.Generic;
using System.Xml;
namespace Opc.Ua.Server
{
/// <summary>
/// The well known roles in a server.
/// https://reference.opcfoundation.org/Core/Part3/v105/docs/4.9.2
/// </summary>
public class Role : IEquatable<Role>
{
/// <summary>
/// The Role is allowed to browse and read non-security related Nodes only in the Server Object and all type Nodes.
/// </summary>
public static Role Anonymous { get; } = new Role(ObjectIds.WellKnownRole_Anonymous, BrowseNames.WellKnownRole_Anonymous);
/// <summary>
/// The Role is allowed to browse and read non-security related Nodes.
/// </summary>
public static Role AuthenticatedUser { get; } = new Role(ObjectIds.WellKnownRole_AuthenticatedUser, BrowseNames.WellKnownRole_AuthenticatedUser);
/// <summary>
/// The Role is allowed to browse, read live data, read historical data/events or subscribe to data/events.
/// </summary>
public static Role Observer { get; } = new Role(ObjectIds.WellKnownRole_Observer, BrowseNames.WellKnownRole_Observer);
/// <summary>
/// The Role is allowed to browse, read live data, read historical data/events or subscribe to data/events.
/// In addition, the Session is allowed to write some live data and call some Methods.
/// </summary>
public static Role Operator { get; } = new Role(ObjectIds.WellKnownRole_Operator, BrowseNames.WellKnownRole_Operator);
/// <summary>
/// The Role is allowed to browse, read/write configuration data, read historical data/events, call Methods or subscribe to data/events.
/// </summary>
public static Role Engineer { get; } = new Role(ObjectIds.WellKnownRole_Engineer, BrowseNames.WellKnownRole_Engineer);
/// <summary>
/// The Role is allowed to browse, read live data, read historical data/events, call Methods or subscribe to data/events.
/// </summary>
public static Role Supervisor { get; } = new Role(ObjectIds.WellKnownRole_Supervisor, BrowseNames.WellKnownRole_Supervisor);
/// <summary>
/// The Role is allowed to change the non-security related configuration settings.
/// </summary>
public static Role ConfigureAdmin { get; } = new Role(ObjectIds.WellKnownRole_ConfigureAdmin, BrowseNames.WellKnownRole_ConfigureAdmin);
/// <summary>
/// The Role is allowed to change security related settings.
/// </summary>
public static Role SecurityAdmin { get; } = new Role(ObjectIds.WellKnownRole_SecurityAdmin, BrowseNames.WellKnownRole_SecurityAdmin);
/// <summary>
/// Constructor for new Role
/// </summary>
/// <param name="roleId">NodeId of the Role, used for WellKnownRoles</param>
/// <param name="name">Name of the Role</param>
public Role(NodeId roleId, string name)
{
RoleId = roleId;
Name = name;
}
/// <summary>
/// the NodeId of the role
/// </summary>
public NodeId RoleId { get; private set; }
/// <summary>
/// the name of the role
/// </summary>
public string Name { get; private set; }
#region value equality
/// <inheritdoc/>
public bool Equals(Role other)
{
if (other is null)
{
return false;
}
if (Object.ReferenceEquals(this, other))
{
return true;
}
if (this.GetType() != other.GetType())
{
return false;
}
return (Name == other.Name) && (RoleId == other.RoleId);
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
return Equals(obj as Role);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return (Name, RoleId).GetHashCode();
}
/// <inheritdoc/>
public static bool operator ==(Role lhs, Role rhs)
{
if (lhs is null)
{
if (rhs is null)
{
return true;
}
// Only the left side is null.
return false;
}
// Equals handles case of null on right side.
return lhs.Equals(rhs);
}
/// <inheritdoc/>
public static bool operator !=(Role lhs, Role rhs) => !(lhs == rhs);
#endregion
}
/// <summary>
/// The role based identity for a server.
/// </summary>
public class RoleBasedIdentity : IUserIdentity
{
private IUserIdentity m_identity;
private IEnumerable<Role> m_roles;
/// <summary>
/// Initialize the role based identity.
/// </summary>
public RoleBasedIdentity(IUserIdentity identity, IEnumerable<Role> roles)
{
m_identity = identity;
m_roles = roles;
foreach (Role role in roles)
{
if (!(role.RoleId?.IsNullNodeId ?? true))
{
GrantedRoleIds.Add(role.RoleId);
}
}
}
/// <inheritdoc/>
public NodeIdCollection GrantedRoleIds
{
get { return m_identity.GrantedRoleIds; }
set { m_identity.GrantedRoleIds = value; }
}
/// <summary>
/// The role in the context of a server.
/// </summary>
public IEnumerable<Role> Roles
{
get { return m_roles; }
}
/// <inheritdoc/>
public string DisplayName
{
get { return m_identity.DisplayName; }
}
/// <inheritdoc/>
public string PolicyId
{
get { return m_identity.PolicyId; }
}
/// <inheritdoc/>
public UserTokenType TokenType
{
get { return m_identity.TokenType; }
}
/// <inheritdoc/>
public XmlQualifiedName IssuedTokenType
{
get { return m_identity.IssuedTokenType; }
}
/// <inheritdoc/>
public bool SupportsSignatures
{
get { return m_identity.SupportsSignatures; }
}
/// <inheritdoc/>
public UserIdentityToken GetIdentityToken()
{
return m_identity.GetIdentityToken();
}
}
}
@@ -28,29 +28,30 @@
* ======================================================================*/
using System;
using System.Collections.Generic;
using System.Security;
namespace Opc.Ua.Gds.Server.Database
namespace Opc.Ua.Server.UserDatabase
{
/// <summary>
/// An abstract interface to the user database which stores logins
/// An abstract interface to the user database which stores logins with associated Roles
/// </summary>
public interface IUsersDatabase
public interface IUserDatabase
{
/// <summary>
/// Initialize User Database
/// </summary>
void Initialize();
/// <summary>
/// Register new GDS User
/// Register new user
/// </summary>
/// <param name="userName">the username</param>
/// <param name="password">the password</param>
/// <param name="role">the GdsRole of the new User</param>
/// <param name="roles">the role of the new user</param>
/// <returns>true if registered sucessfull</returns>
bool CreateUser(string userName, string password, GdsRole role);
bool CreateUser(string userName, string password, IEnumerable<Role> roles);
/// <summary>
/// Delete existring GDS user
/// Delete existring user
/// </summary>
/// <param name="userName">the user to delete</param>
/// <returns>true if deleted sucessfully</returns>
@@ -66,9 +67,9 @@ namespace Opc.Ua.Gds.Server.Database
/// returns the Role of the provided user
/// </summary>
/// <param name="userName"></param>
/// <returns>the GdsRole of the provided users</returns>
/// <returns>the Role of the provided users</returns>
/// <exception cref="ArgumentException">When the user is not found</exception>
GdsRole GetUserRole(string userName);
IEnumerable<Role> GetUserRoles(string userName);
/// <summary>
/// changes the password of an existing users
/// </summary>
@@ -31,21 +31,21 @@ using System;
using System.IO;
using Newtonsoft.Json;
namespace Opc.Ua.Gds.Server.Database.Linq
namespace Opc.Ua.Server.UserDatabase
{
/// <summary>
/// A GDS database with JSON storage.
/// A user database with JSON storage.
/// </summary>
/// <remarks>
/// This db is good for testing but not for production use.
/// </remarks>
public class JsonUsersDatabase : LinQUsersDatabase
public class JsonUserDatabase : LinqUserDatabase
{
#region Constructors
/// <summary>
/// Create a JSON database.
/// </summary>
public JsonUsersDatabase(string fileName)
public JsonUserDatabase(string fileName)
{
m_fileName = fileName;
}
@@ -53,7 +53,7 @@ namespace Opc.Ua.Gds.Server.Database.Linq
/// <summary>
/// Load the JSON application database.
/// </summary>
static public JsonUsersDatabase Load(string fileName)
static public JsonUserDatabase Load(string fileName)
{
if (fileName == null) throw new ArgumentNullException(nameof(fileName));
try
@@ -61,7 +61,7 @@ namespace Opc.Ua.Gds.Server.Database.Linq
if (File.Exists(fileName))
{
string json = File.ReadAllText(fileName);
JsonUsersDatabase db = JsonConvert.DeserializeObject<JsonUsersDatabase>(json);
JsonUserDatabase db = JsonConvert.DeserializeObject<JsonUserDatabase>(json);
db.FileName = fileName;
return db;
}
@@ -70,7 +70,7 @@ namespace Opc.Ua.Gds.Server.Database.Linq
{
}
return new JsonUsersDatabase(fileName);
return new JsonUserDatabase(fileName);
}
#endregion
@@ -31,31 +31,40 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using Newtonsoft.Json;
using static System.Net.Mime.MediaTypeNames;
namespace Opc.Ua.Gds.Server.Database.Linq
namespace Opc.Ua.Server.UserDatabase
{
[Serializable]
class User
{
[JsonRequired]
public Guid ID { get; set; }
public string UserName { get; set; }
public string Hash { get; set; }
public GdsRole GdsRole { get; set; }
public IEnumerable<Role> Roles { get; set; }
}
/// <summary>
/// Implementation of a Serializable User Database using LINQ for querying users
/// </summary>
[Serializable]
public class LinQUsersDatabase : IUsersDatabase
public class LinqUserDatabase : IUserDatabase
{
#region IUsersDatabase
/// <summary>
/// initializes the collection the users database is working with
/// </summary>
public virtual void Initialize()
{
}
public bool CreateUser(string userName, string password, GdsRole role)
/// <inheritdoc/>
public bool CreateUser(string userName, string password, IEnumerable<Role> roles)
{
if (string.IsNullOrEmpty(userName))
{
@@ -73,7 +82,7 @@ namespace Opc.Ua.Gds.Server.Database.Linq
string hash = Hash(password);
var user = new User { UserName = userName, Hash = hash, GdsRole = role };
var user = new User { UserName = userName, Hash = hash, Roles = roles };
Users.Add(user);
@@ -81,7 +90,7 @@ namespace Opc.Ua.Gds.Server.Database.Linq
return true;
}
/// <inheritdoc/>
public bool DeleteUser(string userName)
{
if (string.IsNullOrEmpty(userName))
@@ -98,7 +107,7 @@ namespace Opc.Ua.Gds.Server.Database.Linq
Users.Remove(user);
return true;
}
/// <inheritdoc/>
public bool CheckCredentials(string userName, string password)
{
if (string.IsNullOrEmpty(userName))
@@ -119,8 +128,8 @@ namespace Opc.Ua.Gds.Server.Database.Linq
return Check(user.Hash, password);
}
public GdsRole GetUserRole(string userName)
/// <inheritdoc/>
public IEnumerable<Role> GetUserRoles(string userName)
{
if (string.IsNullOrEmpty(userName))
{
@@ -133,9 +142,9 @@ namespace Opc.Ua.Gds.Server.Database.Linq
throw new ArgumentException("No user found with the UserName " + userName);
}
return user.GdsRole;
return user.Roles;
}
/// <inheritdoc/>
public bool ChangePassword(string userName, string oldPassword, string newPassword)
{
if (string.IsNullOrEmpty(userName))
@@ -169,6 +178,9 @@ namespace Opc.Ua.Gds.Server.Database.Linq
#endregion
#region Public Members
/// <summary>
/// Persists the changes to the users database
/// </summary>
public virtual void Save()
{
}
@@ -33,6 +33,7 @@ using System.Threading.Tasks;
using Opc.Ua.Configuration;
using Opc.Ua.Gds.Server;
using Opc.Ua.Gds.Server.Database.Linq;
using Opc.Ua.Server.UserDatabase;
namespace Opc.Ua.Gds.Tests
{
@@ -119,7 +120,7 @@ namespace Opc.Ua.Gds.Tests
}
var applicationsDatabase = JsonApplicationsDatabase.Load(databaseStorePath);
var usersDatabase = JsonUsersDatabase.Load(usersDatabaseStorePath);
var usersDatabase = JsonUserDatabase.Load(usersDatabaseStorePath);
// start the server.
m_server = new GlobalDiscoverySampleServer(
@@ -1,17 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using Opc.Ua.Gds.Server.Database.Linq;
using Opc.Ua.Server;
using Opc.Ua.Server.UserDatabase;
namespace Opc.Ua.Gds.Tests
namespace Opc.Ua.Server.Tests
{
[TestFixture, Category("GDS")]
[TestFixture, Category("Server")]
[SetCulture("en-us"), SetUICulture("en-us")]
[Parallelizable]
internal class LinqUsersDatabaseTests
internal class LinqUserDatabaseTests
{
#region Test Methods
@@ -19,21 +17,21 @@ namespace Opc.Ua.Gds.Tests
public void CreateInvalidUser()
{
//Arrrange
var usersDb = new LinQUsersDatabase();
var usersDb = new LinqUserDatabase();
//Act+ Assert
Assert.Throws<ArgumentException>(
() => usersDb.CreateUser("", "PW", Server.GdsRole.ApplicationAdmin));
() => usersDb.CreateUser("", "PW", new List<Role> { Role.AuthenticatedUser }));
Assert.Throws<ArgumentException>(
() => usersDb.CreateUser("Name", "", Server.GdsRole.ApplicationAdmin));
() => usersDb.CreateUser("Name", "", new List<Role> { Role.AuthenticatedUser }));
}
[Test]
public void DeleteExistingUser()
{
//Arrrange
var usersDb = new LinQUsersDatabase();
usersDb.CreateUser("TestUser", "PW", Server.GdsRole.ApplicationAdmin);
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW", new List<Role> { Role.AuthenticatedUser });
//Act
var result = usersDb.DeleteUser("TestUser");
//Assert
@@ -44,8 +42,8 @@ namespace Opc.Ua.Gds.Tests
public void DeleteNonExistingUser()
{
//Arrrange
var usersDb = new LinQUsersDatabase();
usersDb.CreateUser("TestUser", "PW", Server.GdsRole.ApplicationAdmin);
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW", new List<Role> { Role.AuthenticatedUser });
//Act
var result = usersDb.DeleteUser("NoTestUser");
//Assert
@@ -56,8 +54,8 @@ namespace Opc.Ua.Gds.Tests
public void ChangePwOfExistingUser()
{
//Arrrange
var usersDb = new LinQUsersDatabase();
usersDb.CreateUser("TestUser", "PW", Server.GdsRole.ApplicationAdmin);
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW", new List<Role> { Role.AuthenticatedUser });
//Act
var result = usersDb.ChangePassword("TestUser", "PW", "newPW");
var login = usersDb.CheckCredentials("TestUser", "newPW");
@@ -72,8 +70,8 @@ namespace Opc.Ua.Gds.Tests
public void ChangePwOfNonExistingUser()
{
//Arrrange
var usersDb = new LinQUsersDatabase();
usersDb.CreateUser("TestUser", "PW", Server.GdsRole.ApplicationAdmin);
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW", new List<Role> { Role.AuthenticatedUser });
//Act
var result = usersDb.DeleteUser("NoTestUser");
//Assert
@@ -84,8 +82,8 @@ namespace Opc.Ua.Gds.Tests
public void CheckPWofExistingUser()
{
//Arrrange
var usersDb = new LinQUsersDatabase();
usersDb.CreateUser("TestUser", "PW", Server.GdsRole.ApplicationAdmin);
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW", new List<Role> { Role.AuthenticatedUser });
//Act
var result = usersDb.CheckCredentials("TestUser", "PW");
var loginWrongPw = usersDb.CheckCredentials("TestUser", "newPW");
@@ -98,8 +96,8 @@ namespace Opc.Ua.Gds.Tests
public void CheckPWofNonExistingUser()
{
//Arrrange
var usersDb = new LinQUsersDatabase();
usersDb.CreateUser("TestUser", "PW", Server.GdsRole.ApplicationAdmin);
var usersDb = new LinqUserDatabase();
usersDb.CreateUser("TestUser", "PW", new List<Role> { Role.AuthenticatedUser });
//Act
var result = usersDb.CheckCredentials("NoTestUser", "PW");
//Assert