mxaccesscli: add --username / --domain / --password to write

Wraps LMXProxyServer.AuthenticateUser at the session level
(MxSession.Authenticate) and surfaces three new options on the
write command:

  -u, --username <name>   galaxy / OS user
      --domain   <name>   composed as <domain>\<username>; omit for
                          galaxy-authenticated logins or UPN forms
  -p, --password <pwd>    redacted to "***" in the JSON query echo

The CLI calls AuthenticateUser before AddItem so an auth failure
(userId == 0) bails out cleanly without leaving a half-set-up item.
On success the resolved userId flows into Write(hServer, hItem,
value, userId) and is reflected in:

  - human output: "[OK ] write <tag> = <val> (as <verify-user>, userId=N)"
  - LLM-JSON results[]: { "authenticated": true, "auth_user_id": N }

Verified live against TestChildObject.TestInt with credentials
DESKTOP-6JL3KKO\dohertj / Sonamu89:

  read   -> 99
  write 7 with --username/--domain/--password -> ok, auth_user_id=1
  read   -> 7
  write 99 with same auth -> ok
  read   -> 99 (restored)

Important behavior surfaced and documented in docs/usage.md
"Authentication" section: on a galaxy configured in permissive
(Free Access) mode, AuthenticateUser returns a non-zero userId
regardless of credentials — verified by intentionally passing a
wrong password and an unknown user, both of which still resolved
to userId=1 and the write went through. The CLI's auth path is
wired correctly; the galaxy just isn't strict. To exercise real
authentication, target a galaxy with galaxyAuthenticationMode and
attribute-level security above Free Access.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-03 22:00:06 -04:00
parent 7da30cf515
commit 0d25ec445f
3 changed files with 126 additions and 9 deletions
@@ -45,6 +45,22 @@ namespace MxAccess.Cli.Mx
return item;
}
/// Authenticate a user against the galaxy and return the user id
/// to pass to subsequent Write/WriteSecured calls. Returns 0 on
/// failure (bad credentials, unknown user, galaxy auth disabled).
///
/// `verifyUser` is the credential string the proxy expects for its
/// configured galaxy authentication mode:
/// - osAuthenticationMode → `<domain-or-host>\<username>`
/// - galaxyAuthenticationMode → `<username>` only
/// - mixed/AAD → `<UPN>` (e.g. `user@example.com`)
public int Authenticate(string verifyUser, string password)
{
if (string.IsNullOrEmpty(verifyUser))
throw new ArgumentException("verifyUser must be non-empty.", nameof(verifyUser));
return _proxy.AuthenticateUser(_hServer, verifyUser, password ?? string.Empty);
}
/// Pump COM messages while watching for an update that matches the predicate.
/// Returns true when one is captured, false on timeout.
public bool WaitForUpdate(Predicate<MxUpdate> match, TimeSpan timeout, out MxUpdate captured)