Skip to content

Bug - Fix CLI login error - #231

Merged
tonygermano merged 6 commits into
OpenIntegrationEngine:mainfrom
miguel-figueiredoPT:feature/224-fix-cli-login-error
Sep 30, 2026
Merged

tonygermano merged 6 commits into
OpenIntegrationEngine:mainfrom
miguel-figueiredoPT:feature/224-fix-cli-login-error

Conversation

@miguel-figueiredoPT

@miguel-figueiredoPT miguel-figueiredoPT commented Dec 22, 2025 •

Copy link
Copy Markdown
Contributor

This PR implements a change on the CLI - When logging in, catch UnauthorizedException and fetch the login status from it.

Resolution for issue: #224

@miguel-figueiredoPT
miguel-figueiredoPT force-pushed the feature/224-fix-cli-login-error branch from 20f5769 to 599ec0c Compare December 22, 2025 17:14

@mgaffigan mgaffigan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Omit the null check or handle at :192. Other comment is just a suggestion.

Comment thread command/src/com/mirth/connect/cli/CommandLineInterface.java Outdated
Comment thread command/src/com/mirth/connect/cli/CommandLineInterface.java Outdated
@miguel-figueiredoPT
miguel-figueiredoPT force-pushed the feature/224-fix-cli-login-error branch from 71cc19c to 8e7a76a Compare December 22, 2025 17:33
mgaffigan
mgaffigan previously approved these changes Dec 22, 2025
Comment thread command/src/com/mirth/connect/cli/CommandLineInterface.java Outdated
mgaffigan
mgaffigan previously approved these changes Dec 23, 2025
Comment thread command/src/com/mirth/connect/cli/CommandLineInterface.java Outdated
mgaffigan
mgaffigan previously approved these changes Dec 23, 2025
@tonygermano tonygermano linked an issue Dec 23, 2025 that may be closed by this pull request
NicoPiel
NicoPiel previously approved these changes Dec 23, 2025

@NicoPiel NicoPiel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Mitch already suggested the only change I would have made.

@tonygermano tonygermano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just testing, and this does resolve the uncaught exception, but the program still hangs after a failed login. We're going to need to dig a little more to see why the program is still not ending.

Looking at the error messages, I think the first one on line 191 is fine, because I can't think of a reason that we'd ever get a UnauthorizedException where the response wasn't a LoginStatus, so printing the stack trace would be useful there.

The second one on line 197 we might want to make a little more user-friendly, since that is the one that shows up for a bad password. I don't know that it's necessary to print the loginStatus, since we already know we have one, and it's not successful at this point. Perhaps a message like, Could not login to server. Please check your username and password and try again. would be more appropriate. This is similar to what was requested in the linked issue.

@tonygermano tonygermano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was hanging because the client wasn't getting closed after the function returned, but I think it's better to return an appropriate exit code than to let it return 0 like it worked successfully since this can be used to run scripts as well as interactively.

Comment thread command/src/com/mirth/connect/cli/CommandLineInterface.java
Comment thread command/src/com/mirth/connect/cli/CommandLineInterface.java Outdated
Comment thread command/src/com/mirth/connect/cli/CommandLineInterface.java Outdated
@pacmano1
pacmano1 requested review from Copilot and removed request for gibson9583 and pacmano1 December 26, 2025 13:27

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a CLI login error handling issue by catching UnauthorizedException and extracting the LoginStatus from the exception's response. The fix addresses issue #224 where login failures were not properly handled.

Key Changes:

  • Added exception handling around client.login() to catch UnauthorizedException
  • Extracted LoginStatus from the exception response using pattern matching
  • Improved error messaging to include the login status details

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ChristopherSchultz

Copy link
Copy Markdown

I'm curious about this patch (I haven't tried it).

The root problem is that the main() function and main thread are exiting, but this one is still running (from MC):

"Thread-0" #14 prio=5 os_prio=0 cpu=0.20ms elapsed=4.57s tid=0x00007faefc9782a0 nid=0x127811 in Object.wait()  [0x00007faee43d3000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
	at java.lang.Object.wait(java.base@17.0.18/Native Method)
	- waiting on <0x00000000e2900018> (a com.mirth.connect.client.core.ServerConnection$IdleConnectionMonitor)
	at com.mirth.connect.client.core.ServerConnection$IdleConnectionMonitor.run(ServerConnection.java:710)
	- locked <0x00000000e2900018> (a com.mirth.connect.client.core.ServerConnection$IdleConnectionMonitor)

What is required in order to shut-down this thread? Do you just need to fetch the status from the error, or is the "Real work" being done by the System.exit?

If System.exit() is all that is being added, here, I wonder if there isn't a better approach.

@tonygermano

Copy link
Copy Markdown
Member

I'm curious about this patch (I haven't tried it).

The root problem is that the main() function and main thread are exiting, but this one is still running (from MC):

"Thread-0" #14 prio=5 os_prio=0 cpu=0.20ms elapsed=4.57s tid=0x00007faefc9782a0 nid=0x127811 in Object.wait()  [0x00007faee43d3000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
	at java.lang.Object.wait(java.base@17.0.18/Native Method)
	- waiting on <0x00000000e2900018> (a com.mirth.connect.client.core.ServerConnection$IdleConnectionMonitor)
	at com.mirth.connect.client.core.ServerConnection$IdleConnectionMonitor.run(ServerConnection.java:710)
	- locked <0x00000000e2900018> (a com.mirth.connect.client.core.ServerConnection$IdleConnectionMonitor)

What is required in order to shut-down this thread? Do you just need to fetch the status from the error, or is the "Real work" being done by the System.exit?

If System.exit() is all that is being added, here, I wonder if there isn't a better approach.

@ChristopherSchultz See my previous comment #231 (review)

@github-actions

Copy link
Copy Markdown

Test Results

126 files  ±0  126 suites  ±0   3m 3s ⏱️ +54s
717 tests ±0  717 ✅ ±0  0 💤 ±0  0 ❌ ±0 
765 runs  ±0  759 ✅ ±0  6 💤 ±0  0 ❌ ±0 

Results for commit fc7b90b. ± Comparison against base commit 03eefcf.

@tonygermano

Copy link
Copy Markdown
Member

I pushed an update that builds on what @miguel-figueiredoPT had already started and squashed it all into a single commit fc7b90b.

@tonygermano tonygermano removed this from the Next Release + 1 milestone Sep 28, 2026
mgaffigan and others added 5 commits September 29, 2026 08:06
processMessage returns a single message id, taken from the response
handler's selected result. For a batch that is only the first or last
message, leaving a caller no way to learn the ids of the others. The
smoke test harness needs them to assert per-message content.

POST /channels/{channelId}/batchMessagesWithObj returns every id. The
response handler is already threaded through dispatchBatchMessage, so
CollectingResponseHandler only has to record each id as it is set. It
keeps the ids and not the DispatchResults, so a long batch does not
retain the processed messages, maps and content of the messages that
have already finished.

Processing is unchanged. Whether a batch is split is still governed by
the channel's Process Batch setting; on a channel with batch processing
disabled the dispatch takes the single-message path and the endpoint
returns a one-element list.

EngineController.dispatchRawMessage gains a five-argument overload. The
existing four-argument form delegates to it with a SimpleResponseHandler,
so its callers are unaffected, but the interface gains an abstract method
and out-of-tree implementations will need updating.

Signed-off-by: Mitch Gaffigan <mitch.gaffigan@comcast.net>
A batch fixture produces several messages, and the harness could only
submit a payload and assert against one of them. Assertion files for a
fixture that expects N messages now live in numbered subdirectories,
01 through NN; a fixture that expects one message keeps its flat layout
and reads exactly as before. The generator rejects numbering that does
not start at 01 or that leaves gaps, and rejects a fixture that mixes
loose assertion files with numbered ones.

An empty source_rejected file declares that the server must refuse the
submission. It cannot be combined with assertion files, since a refused
submission produces no message to assert against.

source_raw, destNN_raw and destNN_encoded are now assertable.

OieServer.submitMessage calls the new batchMessagesWithObj endpoint so
the harness learns every id the payload produced, and runMessage fails
if the count does not match what the fixture expects. Failure output
renders every message rather than one, and now includes the source map.

ci/tests/120-delimited-batch covers the new layout with a CSV batch
channel, independent of any XML change.

Note that routing every submission through batchMessagesWithObj leaves
processMessage without end-to-end coverage.

Signed-off-by: Mitch Gaffigan <mitch.gaffigan@comcast.net>
Signed-off-by: Mitch Gaffigan <mitch.gaffigan@comcast.net>
CVE-2026-82578 found an XXE vulnerability in XML batch parsing. This
closes that vulnerability and adds regression tests.

setNamespaceAware(true) is not a behavior change. XPath.evaluate(String,
InputSource, QName) built its DOM with a namespace aware DocumentBuilder,
so the batch splitter has always been namespace aware. Without it, split
messages lose the xmlns declarations they inherit from the batch element.

Signed-off-by: Mitch Gaffigan <mitch.gaffigan@comcast.net>
The startup scripts read .vmoptions files with a shell `while read`
loop, which skips a last line that has no trailing newline. An option
typed as the last line of conf/custom.vmoptions in an editor that does
not add a final newline never reached the JVM, so the engine kept the
-Xmx256m from base_includes.vmoptions.

The install4j-generated scripts (oieservice, oieserver, oiecommand) use
that loop and are not ours to change, so the template now ends with a
comment line. Options added above it always end in a newline. If an
editor leaves the comment without a newline, the scripts drop the
comment, which is harmless.

Closes OpenIntegrationEngine#464

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Finnegan's Owner <44065187+pacmano1@users.noreply.github.com>

@pacmano1 pacmano1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested the CLI from fc7b90bcf against an engine built from the same commit (Temurin 17, Linux).

Case Result
4.6.0 release CLI, wrong password (control) Stack trace, then hangs until killed
Wrong password One-line error, exit 77, no hang
Wrong password, -d Same, plus the UnauthorizedException stack trace
Nothing listening on the port "Could not communicate with server", exit 69
Missing script file Connects, "Could not load script file", logs out, exit 74
Good login, script running status Runs, disconnects, exit 0
Good login, status piped into the console Runs, disconnects, exit 0

Each case was java -jar mirth-cli-launcher.jar -a https://localhost:8443 -u <user> -p <password> -v 0.0.0 -s status.txt under a 30-second timeout, run from that build's own install directory. The launcher loads cli-lib from the current directory, so running one build's launcher from another build's directory tests the wrong CLI.

Related: #439 stops the server from telling a locked account apart from a wrong password. The fixed message here already matches that, and any later change to print the server's reason in the CLI should build on #439.

The CLI only closed its Client on the success path. Client starts
non-daemon threads, so a failed login, a connection error or a missing
script file left the process hanging instead of exiting.

Manage the Client with try-with-resources so it is always closed, and
log out in a finally block so a failed script still ends the session.
runShell now returns an exit code and run() exits once, after the
client has been closed:

- 0 (EX_OK) on success
- 77 (EX_NOPERM) when the server rejects the login
- 69 (EX_UNAVAILABLE) when the server cannot be reached
- 70 (EX_SOFTWARE) for other server errors
- 74 (EX_IOERR) when the script file cannot be read

Invalid arguments and configuration errors still exit with 2, now
through a named constant.

Signed-off-by: miguelfigueiredo <miguelsfigueiredo90@gmail.com>
Co-authored-by: Tony Germano <tony@germano.name>
Signed-off-by: Tony Germano <tony@germano.name>
@tonygermano
tonygermano merged commit 11ad744 into OpenIntegrationEngine:main Sep 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

oiecommand hangs after failed login attempt

9 participants