Skip to content

Commit 51d55d7

Browse files
Merge pull request ClickHouse#78586 from ClickHouse/ssh-pass
Support password auth type in SSH protocol
2 parents df439b2 + a6f2c1f commit 51d55d7

File tree

2 files changed

+47
-5
lines changed

2 files changed

+47
-5
lines changed

src/Server/SSH/SSHPtyHandler.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,8 @@ class SessionCallback
345345
{
346346
server_cb.userdata = this;
347347
server_cb.auth_pubkey_function = authPublickeyAdapter<ssh_session, const char *, ssh_key, char>;
348-
ssh_set_auth_methods(session.getInternalPtr(), SSH_AUTH_METHOD_PUBLICKEY);
348+
server_cb.auth_password_function = authPasswordAdapter<ssh_session, const char *, const char *>;
349+
ssh_set_auth_methods(session.getInternalPtr(), SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY);
349350
server_cb.channel_open_request_session_function = channelOpenAdapter<ssh_session>;
350351

351352
ssh_callbacks_init(&server_cb)
@@ -395,11 +396,11 @@ class SessionCallback
395396
{
396397
auto user_has_ssh_auth_type = [](auto user_authentication_type) { return user_authentication_type == AuthenticationType::SSH_KEY; };
397398
auto user_auth_types = db_session_created->getAuthenticationTypes(user_name);
399+
400+
/// User {} doesn't have SSH_KEY authentication type, so we will try to authenticate it using a password.
398401
if (auto result = std::ranges::find_if(user_auth_types, user_has_ssh_auth_type); result == user_auth_types.end())
399-
{
400-
LOG_WARNING(log, "User {} doesn't have SSH_KEY authentication type", user_name);
401-
return SSH_AUTH_DENIED;
402-
}
402+
return SSH_AUTH_PARTIAL;
403+
403404
return SSH_AUTH_SUCCESS;
404405
}
405406

@@ -431,6 +432,27 @@ class SessionCallback
431432

432433
GENERATE_ADAPTER_FUNCTION(SessionCallback, authPublickey, int)
433434

435+
int authPassword(ssh_session, const char * user, const char * password)
436+
{
437+
try
438+
{
439+
LOG_TRACE(log, "Authenticating with password");
440+
auto db_session_created = std::make_unique<Session>(server_context, ClientInfo::Interface::LOCAL);
441+
db_session_created->authenticate(BasicCredentials{user, password}, peer_address);
442+
authenticated = true;
443+
db_session = std::move(db_session_created);
444+
return SSH_AUTH_SUCCESS;
445+
}
446+
catch (...)
447+
{
448+
tryLogCurrentException(log);
449+
++auth_attempts;
450+
return SSH_AUTH_DENIED;
451+
}
452+
}
453+
454+
GENERATE_ADAPTER_FUNCTION(SessionCallback, authPassword, int)
455+
434456
ssh_server_callbacks_struct server_cb = {};
435457
};
436458

tests/integration/test_ssh/test.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,23 @@ def test_simple_query_with_paramiko(started_cluster):
138138
# Secsh channel 1 open FAILED: : Administratively prohibited
139139

140140
client.close()
141+
142+
def test_paramiko_password(started_cluster):
143+
instance.query("CREATE USER OR REPLACE mister IDENTIFIED BY 'P@$$WORD';")
144+
145+
pkey = paramiko.Ed25519Key.from_private_key_file(f"{SCRIPT_DIR}/keys/lucy_ed25519")
146+
client = paramiko.SSHClient()
147+
policy = paramiko.AutoAddPolicy()
148+
client.set_missing_host_key_policy(policy)
149+
client.connect(hostname=instance.ip_address, port=9022, username="mister", password='P@$$WORD')
150+
151+
stdin, stdout, stderr = client.exec_command("SELECT 1;")
152+
stdin.close()
153+
result = stdout.read().decode()
154+
expected = instance.query("SELECT 1;")
155+
assert result.replace("\n\x00", "\n") == expected
156+
157+
# FIXME: If I'm trying to execute more queries with the same client I get the error:
158+
# Secsh channel 1 open FAILED: : Administratively prohibited
159+
160+
client.close()

0 commit comments

Comments
 (0)