Internal
Public Access
Fix connect-time username prompt never reaching SSH/RDP authentication
The username entered at the connect-time prompt (added for issue #21) was updating SessionTab's own in-memory Profile copy, but SshSessionBackend/RdpSessionBackend are constructed with -- and only ever read from -- their own separate Profile copy on a worker thread, which never saw that edit. Authentication was still built from the original (blank) username regardless of what was typed into the prompt. SessionConnectOptions gains a username field, populated by SessionTab on every connect attempt and threaded through the same way password already is; both backends now prefer options.username over profile().username. Covered by a new SSH regression test using an exact-match fixture host that only succeeds for a specific user@host target. Bump version to v2026.9.16.5. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Vendored
+16
@@ -6,6 +6,22 @@
|
||||
# host, optionally as user@host, as the final argument).
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
prompted-user@requireuser)
|
||||
# Only the exact user@host below is accepted -- used to prove a
|
||||
# username supplied via SessionConnectOptions (prompted for at
|
||||
# connect time because the saved profile's own username was
|
||||
# blank) actually reaches the ssh command line, not just that
|
||||
# *some* connection to this host succeeds.
|
||||
echo "Welcome to the fake host."
|
||||
while IFS= read -r line; do
|
||||
echo "$line"
|
||||
done
|
||||
exit 0
|
||||
;;
|
||||
*@requireuser|requireuser)
|
||||
echo "Permission denied (publickey,password)." >&2
|
||||
exit 255
|
||||
;;
|
||||
*@succeed|succeed)
|
||||
echo "Welcome to the fake host."
|
||||
# Stay alive echoing stdin back (simulates an interactive
|
||||
|
||||
@@ -21,6 +21,13 @@ Profile makeProfile(const QString& fixtureHost)
|
||||
return profile;
|
||||
}
|
||||
|
||||
Profile makeBlankUsernameProfile(const QString& fixtureHost)
|
||||
{
|
||||
Profile profile = makeProfile(fixtureHost);
|
||||
profile.username.clear();
|
||||
return profile;
|
||||
}
|
||||
|
||||
SessionConnectOptions makeOptions()
|
||||
{
|
||||
SessionConnectOptions options;
|
||||
@@ -50,10 +57,12 @@ private slots:
|
||||
void connectionRefusedReachesFailedState();
|
||||
void sendInputEchoesThroughOutputReceived();
|
||||
void reconnectRestartsAndReachesConnectedAgain();
|
||||
void connectOptionsUsernameReachesProcessWhenProfileUsernameIsBlank();
|
||||
|
||||
private:
|
||||
QString fixturePath() const;
|
||||
void createBackend(const QString& fixtureHost);
|
||||
void createBackend(const Profile& profile);
|
||||
|
||||
std::unique_ptr<SshSessionBackend> m_backend;
|
||||
SessionState m_lastState = SessionState::Disconnected;
|
||||
@@ -69,8 +78,12 @@ QString TestSshSessionBackend::fixturePath() const
|
||||
|
||||
void TestSshSessionBackend::createBackend(const QString& fixtureHost)
|
||||
{
|
||||
m_backend =
|
||||
std::make_unique<SshSessionBackend>(makeProfile(fixtureHost), fixturePath(), nullptr);
|
||||
createBackend(makeProfile(fixtureHost));
|
||||
}
|
||||
|
||||
void TestSshSessionBackend::createBackend(const Profile& profile)
|
||||
{
|
||||
m_backend = std::make_unique<SshSessionBackend>(profile, fixturePath(), nullptr);
|
||||
connect(m_backend.get(),
|
||||
&SessionBackend::stateChanged,
|
||||
this,
|
||||
@@ -232,5 +245,24 @@ void TestSshSessionBackend::reconnectRestartsAndReachesConnectedAgain()
|
||||
QTRY_COMPARE(m_lastState, SessionState::Connected);
|
||||
}
|
||||
|
||||
void TestSshSessionBackend::connectOptionsUsernameReachesProcessWhenProfileUsernameIsBlank()
|
||||
{
|
||||
// Regression test for a bug where a username entered at the
|
||||
// connect-time prompt (SessionTab::requestConnectOptions(), for a
|
||||
// profile with no saved username -- issue #21) never actually reached
|
||||
// the ssh process: SshSessionBackend built its target purely from
|
||||
// profile().username, which is a separate copy captured when the
|
||||
// backend was constructed and never sees SessionTab's later edit.
|
||||
// fixtures/fake_ssh.sh's "requireuser" host only accepts the exact
|
||||
// target "prompted-user@requireuser", so this fails unless
|
||||
// SessionConnectOptions::username is actually used.
|
||||
createBackend(makeBlankUsernameProfile(QStringLiteral("requireuser")));
|
||||
|
||||
SessionConnectOptions options = makeOptions();
|
||||
options.username = QStringLiteral("prompted-user");
|
||||
m_backend->connectSession(options);
|
||||
QTRY_COMPARE(m_lastState, SessionState::Connected);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(TestSshSessionBackend)
|
||||
#include "test_ssh_session_backend.moc"
|
||||
|
||||
Reference in New Issue
Block a user