Files
wwtools/mxaccesscli/src/MxAccess.Cli/Mx/MxItem.cs
Joseph Doherty c8f31bd653 mxaccesscli: add --secured / --verifier-* options for WriteSecured
WriteCommand grows three new options:

  --secured                Route the write through
                           LMXProxyServer.WriteSecured(currentUserId,
                           verifierUserId, value) instead of plain
                           Write(value, userId). Required for attributes
                           classified as Secured Write or Verified Write,
                           and useful for testing whether the audit
                           subsystem propagates user identity when
                           explicitly told the write is "secured".

  --verifier-username      Galaxy / OS username of the verifier for a
                           two-person Verified Write. Implies --secured.
  --verifier-domain        Domain composed with --verifier-username as
                           '<domain>\<username>'.
  --verifier-password      Verifier password. Redacted in the JSON
                           query echo.

When --secured is on without a verifier, the same auth_user_id is
used for both currentUserId and verifierUserId (single-user Secured
Write semantics). When a verifier is provided, the CLI authenticates
both users and bails cleanly with "verifier-authentication-failed"
on a verifier credential mismatch.

The JSON envelope's results[] gains `secured` and `verifier_user_id`
fields so an agent can confirm which path ran.

MxItem grows WriteSecured(value, currentUserId, verifierUserId).

Verified live against TestMachine_001.TestAlarm002.AckMsg under
eOSUserBased + ArchestraUsers role: --secured succeeds with
auth_user_id=1, verifier_user_id=1, MxCategoryOk. User_Name in the
Historian Events row remains NULL — same as plain Write. The
audit-attribution gate is not Write vs WriteSecured; running engines
likely still need a redeploy to pick up the new security mode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:48:17 -04:00

82 lines
3.0 KiB
C#

using System;
using ArchestrA.MxAccess;
namespace MxAccess.Cli.Mx
{
/// One AddItem-handle. Owns Advise/UnAdvise pairing so a Dispose tears
/// down the subscription cleanly even if the caller forgets.
public sealed class MxItem : IDisposable
{
private readonly MxSession _session;
private readonly LMXProxyServerClass _proxy;
private readonly int _hServer;
private bool _advised;
private bool _disposed;
public int Handle { get; }
public string Reference { get; }
internal MxItem(MxSession session, LMXProxyServerClass proxy, int hServer, int hItem, string reference)
{
_session = session;
_proxy = proxy;
_hServer = hServer;
Handle = hItem;
Reference = reference;
}
public void Advise()
{
if (_advised) return;
_proxy.Advise(_hServer, Handle);
_advised = true;
}
/// Subscribe in supervisory mode. Use this for actions that should
/// be attributed to the hosting client (rather than to a Galaxy user)
/// in the alarm/event audit trail — e.g. anonymous bulk operators,
/// integration scripts, or automation acting on its own authority.
/// Pairs with the same UnAdvise / RemoveItem teardown as Advise().
public void AdviseSupervisory()
{
if (_advised) return;
_proxy.AdviseSupervisory(_hServer, Handle);
_advised = true;
}
public void UnAdvise()
{
if (!_advised) return;
try { _proxy.UnAdvise(_hServer, Handle); } catch { /* best effort */ }
_advised = false;
}
/// `Write` blocks neither the caller nor the proxy — it queues a write and
/// returns. Use MxSession.WaitForUpdate() to await OnWriteComplete.
/// `userId = 0` means "unauthenticated"; OK for simple writes when galaxy
/// security allows it.
public void Write(object value, int userId = 0) =>
_proxy.Write(_hServer, Handle, value, userId);
/// Two-user Secured/Verified write. Propagates the user identity into
/// the alarm/event audit trail in a way that the engine's audit
/// subsystem honors for Secured Write / Verified Write attribute
/// security classifications.
///
/// For single-user Secured Write, pass the same id for both
/// `currentUserId` and `verifierUserId`. For two-person Verified Write,
/// pass two distinct authenticated user ids (operator + verifier).
public void WriteSecured(object value, int currentUserId, int verifierUserId) =>
_proxy.WriteSecured(_hServer, Handle, currentUserId, verifierUserId, value);
public void Dispose()
{
if (_disposed) return;
_disposed = true;
try { UnAdvise(); } catch { }
try { _proxy.RemoveItem(_hServer, Handle); } catch { }
_session.RemoveItem(Handle);
}
}
}