mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-27 21:55:54 +08:00
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:
@@ -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.");
|
||||
}
|
||||
|
||||
+12
-72
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-9
@@ -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>
|
||||
+7
-7
@@ -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
|
||||
|
||||
+23
-11
@@ -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(
|
||||
|
||||
+21
-23
@@ -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
|
||||
Reference in New Issue
Block a user