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:
@@ -1640,7 +1640,13 @@ void RdpSessionBackend::workerMain()
|
||||
const Profile& p = profile();
|
||||
|
||||
const QString host = p.host.trimmed();
|
||||
QString username = p.username.trimmed();
|
||||
// m_activeOptions.username carries a value prompted for at connect time
|
||||
// (see SessionTab::requestConnectOptions()) when the saved profile's
|
||||
// own username was blank; profile().username never sees that edit
|
||||
// since this backend's Profile copy was captured at construction time.
|
||||
QString username = m_activeOptions.username.trimmed().isEmpty()
|
||||
? p.username.trimmed()
|
||||
: m_activeOptions.username.trimmed();
|
||||
QString domain = p.domain.trimmed();
|
||||
if (domain.isEmpty()) {
|
||||
const int domainSeparator = username.indexOf(QLatin1Char('\\'));
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
class SessionConnectOptions
|
||||
{
|
||||
public:
|
||||
// Only set when the profile's own username was blank and SessionTab
|
||||
// prompted for one inline at connect time (see issue #21); empty means
|
||||
// "use the backend's own profile().username" as before. SSH/RDP need
|
||||
// this up front, unlike VNC's Apple auth which discovers the need for
|
||||
// one mid-connection via usernameRequested()/provideUsername() instead.
|
||||
QString username;
|
||||
QString password;
|
||||
QString privateKeyPath;
|
||||
QString knownHostsPolicy;
|
||||
|
||||
@@ -998,6 +998,10 @@ void SessionTab::requestConnectOptions(
|
||||
{
|
||||
SessionConnectOptions baseOptions;
|
||||
baseOptions.knownHostsPolicy = m_profile.knownHostsPolicy;
|
||||
// The backend's own Profile copy was captured when it was constructed
|
||||
// and never sees later edits to m_profile (e.g. the username prompt
|
||||
// below) -- it has to travel through here instead.
|
||||
baseOptions.username = m_profile.username.trimmed();
|
||||
|
||||
const bool isSsh = m_profile.protocol.compare(QStringLiteral("SSH"), Qt::CaseInsensitive) == 0;
|
||||
const bool isRdp = m_profile.protocol.compare(QStringLiteral("RDP"), Qt::CaseInsensitive) == 0;
|
||||
|
||||
@@ -388,9 +388,16 @@ bool SshSessionBackend::startSshProcess(const SessionConnectOptions& options)
|
||||
<< QStringLiteral("PasswordAuthentication=no");
|
||||
}
|
||||
|
||||
const QString target = p.username.trimmed().isEmpty()
|
||||
// options.username carries a value prompted for at connect time (see
|
||||
// SessionTab::requestConnectOptions()) when the saved profile's own
|
||||
// username was blank; profile().username never sees that edit since
|
||||
// the backend's Profile copy was captured at construction time.
|
||||
const QString username = options.username.trimmed().isEmpty()
|
||||
? p.username.trimmed()
|
||||
: options.username.trimmed();
|
||||
const QString target = username.isEmpty()
|
||||
? p.host.trimmed()
|
||||
: QStringLiteral("%1@%2").arg(p.username.trimmed(), p.host.trimmed());
|
||||
: QStringLiteral("%1@%2").arg(username, p.host.trimmed());
|
||||
args << target;
|
||||
|
||||
m_process->setProcessEnvironment(environment);
|
||||
|
||||
Reference in New Issue
Block a user