Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Server] ValidateRolePermissions of MonitoredItems based of the saved user identity to allow validation when no session is present #2832

Open
wants to merge 3 commits into
base: develop/main374
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,18 @@ public Session Session
}
}

/// <summary>
/// The monitored items owner identity.
/// </summary>
public IUserIdentity EffectiveIdentity
{
get
{
ISubscription subscription = m_subscription;
return subscription?.EffectiveIdentity;
}
}

/// <summary>
/// The identifier for the subscription that the monitored item belongs to.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Opc.Ua.Server/Diagnostics/CustomNodeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3752,7 +3752,7 @@ protected virtual void OnMonitoredItemCreated(
/// <returns></returns>
public ServiceResult ValidateRolePermissions(OperationContext operationContext, NodeId nodeId, PermissionType requestedPermission)
{
if (operationContext.Session == null || requestedPermission == PermissionType.None)
if (requestedPermission == PermissionType.None)
{
// no permission is required hence the validation passes.
return StatusCodes.Good;
Expand Down
9 changes: 9 additions & 0 deletions Libraries/Opc.Ua.Server/Diagnostics/MonitoredNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,15 @@ public void OnMonitoredNodeChanged(ISystemContext context, NodeState node, NodeS

if (monitoredItem.AttributeId == Attributes.Value && (changes & NodeStateChangeMasks.Value) != 0)
{
// validate if the monitored item has the required role permissions to read the value
ServiceResult validationResult = NodeManager.ValidateRolePermissions(new OperationContext(monitoredItem), node.NodeId, PermissionType.Read);

if (ServiceResult.IsBad(validationResult))
{
// skip if the monitored item does not have permission to read
continue;
}

QueueValue(context, node, monitoredItem);
continue;
}
Expand Down
4 changes: 2 additions & 2 deletions Libraries/Opc.Ua.Server/NodeManager/MasterNodeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3233,7 +3233,7 @@ protected static ServiceResult ValidateAccessRestrictions(OperationContext conte
/// <returns></returns>
protected internal static ServiceResult ValidateRolePermissions(OperationContext context, NodeMetadata nodeMetadata, PermissionType requestedPermission)
{
if (context.Session == null || nodeMetadata == null || requestedPermission == PermissionType.None)
if (nodeMetadata == null || requestedPermission == PermissionType.None)
{
// no permission is required hence the validation passes
return StatusCodes.Good;
Expand Down Expand Up @@ -3323,7 +3323,7 @@ protected internal static ServiceResult ValidateRolePermissions(OperationContext
}
}

var currentRoleIds = context.Session.Identity.GrantedRoleIds;
var currentRoleIds = context.UserIdentity.GrantedRoleIds;
if (currentRoleIds == null || currentRoleIds.Count == 0)
{
return ServiceResult.Create(StatusCodes.BadUserAccessDenied, "Current user has no granted role.");
Expand Down
1 change: 1 addition & 0 deletions Libraries/Opc.Ua.Server/Server/OperationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ public OperationContext(IMonitoredItem monitoredItem)
if (monitoredItem == null) throw new ArgumentNullException(nameof(monitoredItem));

m_channelContext = null;
m_identity = monitoredItem.EffectiveIdentity;
m_session = monitoredItem.Session;

if (m_session != null)
Expand Down
5 changes: 5 additions & 0 deletions Libraries/Opc.Ua.Server/Subscription/IMonitoredItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public interface IMonitoredItem
/// </summary>
Session Session { get; }

/// <summary>
/// The monitored items owner identity.
/// </summary>
IUserIdentity EffectiveIdentity { get; }

/// <summary>
/// The identifier for the item that is unique within the server.
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions Libraries/Opc.Ua.Server/Subscription/MonitoredItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,19 @@ public Session Session
}
}
}
/// <summary>
/// The monitored items owner identity.
/// </summary>
public IUserIdentity EffectiveIdentity
{
get
{
lock (m_lock)
{
return m_subscription?.EffectiveIdentity;
}
}
}

/// <summary>
/// The identifier for the item that is unique within the server.
Expand Down
25 changes: 15 additions & 10 deletions Libraries/Opc.Ua.Server/Subscription/Subscription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public interface ISubscription
/// </summary>
Session Session { get; }

/// <summary>
/// The subscriptions owner identity.
/// </summary>
IUserIdentity EffectiveIdentity { get; }

/// <summary>
/// The identifier for the item that is unique within the server.
/// </summary>
Expand Down Expand Up @@ -208,6 +213,14 @@ public uint Id
get { return m_id; }
}

/// <summary>
/// The subscriptions owner identity.
/// </summary>
public IUserIdentity EffectiveIdentity
{
get { return (m_session != null) ? m_session.EffectiveIdentity : m_savedOwnerIdentity; }
}

/// <summary>
/// Queues an item that is ready to publish.
/// </summary>
Expand Down Expand Up @@ -255,14 +268,6 @@ public NodeId SessionId
}
}

/// <summary>
/// The owner identity.
/// </summary>
public UserIdentityToken OwnerIdentity
{
get { return (m_session != null) ? m_session.IdentityToken : m_savedOwnerIdentity; }
}

/// <summary>
/// Gets the lock that must be acquired before accessing the contents of the Diagnostics property.
/// </summary>
Expand Down Expand Up @@ -594,7 +599,7 @@ public void SessionClosed()
{
if (m_session != null)
{
m_savedOwnerIdentity = m_session.IdentityToken;
m_savedOwnerIdentity = m_session.EffectiveIdentity;
m_session = null;
}
}
Expand Down Expand Up @@ -2414,7 +2419,7 @@ private void TraceState(LogLevel logLevel, TraceStateId id, string context)
private IServerInternal m_server;
private Session m_session;
private uint m_id;
private UserIdentityToken m_savedOwnerIdentity;
private IUserIdentity m_savedOwnerIdentity;
private double m_publishingInterval;
private uint m_maxLifetimeCount;
private uint m_maxKeepAliveCount;
Expand Down
4 changes: 2 additions & 2 deletions Libraries/Opc.Ua.Server/Subscription/SubscriptionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1223,11 +1223,11 @@ public void TransferSubscriptions(
}

// get the identity of the current or last owner
UserIdentityToken ownerIdentity = subscription.OwnerIdentity;
UserIdentityToken ownerIdentity = subscription.EffectiveIdentity.GetIdentityToken();

// Validate the identity of the user who owns/owned the subscription
// is the same as the new owner.
bool validIdentity = Utils.IsEqualUserIdentity(ownerIdentity, context.Session.IdentityToken);
bool validIdentity = Utils.IsEqualUserIdentity(ownerIdentity, context.Session.EffectiveIdentity.GetIdentityToken());

// Test if anonymous user is using a
// secure session using Sign or SignAndEncrypt
Expand Down