mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-23 08:02:02 +00:00
disabled mysql_native_password when password is specified as a plain text as it allows to connect to ClickHouse knowing only SHA1 instead of a password
This commit is contained in:
parent
760afb007c
commit
b1d5f4ca20
@ -227,9 +227,9 @@ void MySQLHandler::finishHandshake(MySQLProtocol::HandshakeResponse & packet)
|
|||||||
|
|
||||||
void MySQLHandler::authenticate(const String & user_name, const String & auth_plugin_name, const String & initial_auth_response)
|
void MySQLHandler::authenticate(const String & user_name, const String & auth_plugin_name, const String & initial_auth_response)
|
||||||
{
|
{
|
||||||
// For compatibility with JavaScript MySQL client, Native41 authentication plugin is used when it is possible. If password is specified using SHA-2, then SHA256 plugin is used.
|
// For compatibility with JavaScript MySQL client, Native41 authentication plugin is used when possible (if password is specified using double SHA1). Otherwise SHA256 plugin is used.
|
||||||
auto user = connection_context.getUser(user_name);
|
auto user = connection_context.getUser(user_name);
|
||||||
if (!user->password_sha256_hex.empty())
|
if (user->password_double_sha1_hex.empty())
|
||||||
auth_plugin = std::make_unique<Authentication::Sha256Password>(public_key, private_key, log);
|
auth_plugin = std::make_unique<Authentication::Sha256Password>(public_key, private_key, log);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -899,26 +899,13 @@ public:
|
|||||||
|
|
||||||
auto user = context.getUser(user_name);
|
auto user = context.getUser(user_name);
|
||||||
|
|
||||||
if (!user->password_sha256_hex.empty())
|
if (user->password_double_sha1_hex.empty())
|
||||||
throw Exception("Cannot use " + getName() + " auth plugin for user " + user_name + " since its password is specified using SHA256.", ErrorCodes::UNKNOWN_EXCEPTION);
|
throw Exception("Cannot use " + getName() + " auth plugin for user " + user_name + " since its password isn't specified using double SHA1.", ErrorCodes::UNKNOWN_EXCEPTION);
|
||||||
|
|
||||||
Poco::SHA1Engine::Digest double_sha1_value;
|
Poco::SHA1Engine::Digest double_sha1_value = Poco::DigestEngine::digestFromHex(user->password_double_sha1_hex);
|
||||||
Poco::SHA1Engine engine;
|
|
||||||
|
|
||||||
/// If password is specified using double SHA1, than it is non-empty (unlike plaintext password, which can be empty).
|
|
||||||
if (!user->password_double_sha1_hex.empty())
|
|
||||||
{
|
|
||||||
double_sha1_value = Poco::DigestEngine::digestFromHex(user->password_double_sha1_hex);
|
|
||||||
assert(double_sha1_value.size() == Poco::SHA1Engine::DIGEST_SIZE);
|
assert(double_sha1_value.size() == Poco::SHA1Engine::DIGEST_SIZE);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
engine.update(user->password);
|
|
||||||
const Poco::SHA1Engine::Digest & first_sha1 = engine.digest();
|
|
||||||
engine.update(first_sha1.data(), first_sha1.size());
|
|
||||||
double_sha1_value = engine.digest();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Poco::SHA1Engine engine;
|
||||||
engine.update(scramble.data(), SCRAMBLE_LENGTH);
|
engine.update(scramble.data(), SCRAMBLE_LENGTH);
|
||||||
engine.update(double_sha1_value.data(), double_sha1_value.size());
|
engine.update(double_sha1_value.data(), double_sha1_value.size());
|
||||||
|
|
||||||
@ -948,8 +935,8 @@ public:
|
|||||||
scramble.resize(SCRAMBLE_LENGTH + 1, 0);
|
scramble.resize(SCRAMBLE_LENGTH + 1, 0);
|
||||||
Poco::RandomInputStream generator;
|
Poco::RandomInputStream generator;
|
||||||
|
|
||||||
for (char & c : scramble)
|
for (size_t i = 0; i < SCRAMBLE_LENGTH; i++)
|
||||||
generator >> c;
|
generator >> scramble[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
String getName() override
|
String getName() override
|
||||||
@ -975,7 +962,8 @@ public:
|
|||||||
packet_sender->sendPacket(AuthSwitchRequest(getName(), scramble), true);
|
packet_sender->sendPacket(AuthSwitchRequest(getName(), scramble), true);
|
||||||
|
|
||||||
if (packet_sender->in->eof())
|
if (packet_sender->in->eof())
|
||||||
throw Exception("Client doesn't support authentication method " + getName() + " used by ClickHouse", ErrorCodes::MYSQL_CLIENT_INSUFFICIENT_CAPABILITIES);
|
throw Exception("Client doesn't support authentication method " + getName() + " used by ClickHouse. Specifying user password using 'password_double_sha1_hex' may fix the problem.",
|
||||||
|
ErrorCodes::MYSQL_CLIENT_INSUFFICIENT_CAPABILITIES);
|
||||||
|
|
||||||
AuthSwitchResponse response;
|
AuthSwitchResponse response;
|
||||||
packet_sender->receivePacket(response);
|
packet_sender->receivePacket(response);
|
||||||
|
@ -82,7 +82,7 @@ UserPtr UsersManager::authorizeAndGetUser(
|
|||||||
const auto & first_sha1 = engine.digest();
|
const auto & first_sha1 = engine.digest();
|
||||||
|
|
||||||
/// If it was MySQL compatibility server, then first_sha1 already contains double SHA1.
|
/// If it was MySQL compatibility server, then first_sha1 already contains double SHA1.
|
||||||
if (Poco::SHA1Engine::digestToHex(first_sha1) != it->second->password_double_sha1_hex)
|
if (Poco::SHA1Engine::digestToHex(first_sha1) == it->second->password_double_sha1_hex)
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
||||||
engine.update(first_sha1.data(), first_sha1.size());
|
engine.update(first_sha1.data(), first_sha1.size());
|
||||||
@ -92,14 +92,6 @@ UserPtr UsersManager::authorizeAndGetUser(
|
|||||||
}
|
}
|
||||||
else if (password != it->second->password)
|
else if (password != it->second->password)
|
||||||
{
|
{
|
||||||
/// MySQL compatibility server passes SHA1 instead of a password.
|
|
||||||
if (password.size() != Poco::SHA1Engine::DIGEST_SIZE)
|
|
||||||
on_wrong_password();
|
|
||||||
|
|
||||||
Poco::SHA1Engine engine;
|
|
||||||
engine.update(it->second->password);
|
|
||||||
|
|
||||||
if (engine.digest() != Poco::SHA1Engine::Digest(password.begin(), password.end()))
|
|
||||||
on_wrong_password();
|
on_wrong_password();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,14 +173,16 @@ def test_php_client(server_address, php_container):
|
|||||||
|
|
||||||
|
|
||||||
def test_mysqljs_client(server_address, nodejs_container):
|
def test_mysqljs_client(server_address, nodejs_container):
|
||||||
code, (_, _) = nodejs_container.exec_run('node test.js {host} {port} default 123'.format(host=server_address, port=server_port), demux=True)
|
code, (_, stderr) = nodejs_container.exec_run('node test.js {host} {port} default 123'.format(host=server_address, port=server_port), demux=True)
|
||||||
assert code == 0
|
assert code == 1
|
||||||
|
assert 'MySQL is requesting the sha256_password authentication method, which is not supported.' in stderr
|
||||||
|
|
||||||
|
code, (_, stderr) = nodejs_container.exec_run('node test.js {host} {port} user_with_empty_password ""'.format(host=server_address, port=server_port), demux=True)
|
||||||
|
assert code == 1
|
||||||
|
assert 'MySQL is requesting the sha256_password authentication method, which is not supported.' in stderr
|
||||||
|
|
||||||
code, (_, _) = nodejs_container.exec_run('node test.js {host} {port} user_with_double_sha1 abacaba'.format(host=server_address, port=server_port), demux=True)
|
code, (_, _) = nodejs_container.exec_run('node test.js {host} {port} user_with_double_sha1 abacaba'.format(host=server_address, port=server_port), demux=True)
|
||||||
assert code == 0
|
assert code == 0
|
||||||
|
|
||||||
code, (_, _) = nodejs_container.exec_run('node test.js {host} {port} user_with_empty_password ""'.format(host=server_address, port=server_port), demux=True)
|
|
||||||
assert code == 0
|
|
||||||
|
|
||||||
code, (_, _) = nodejs_container.exec_run('node test.js {host} {port} user_with_empty_password 123'.format(host=server_address, port=server_port), demux=True)
|
code, (_, _) = nodejs_container.exec_run('node test.js {host} {port} user_with_empty_password 123'.format(host=server_address, port=server_port), demux=True)
|
||||||
assert code == 1
|
assert code == 1
|
||||||
|
Loading…
Reference in New Issue
Block a user