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:
Yuriy 2019-07-28 17:17:33 +03:00
parent 760afb007c
commit b1d5f4ca20
4 changed files with 20 additions and 38 deletions

View File

@ -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)
{
// 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);
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);
try {

View File

@ -899,26 +899,13 @@ public:
auto user = context.getUser(user_name);
if (!user->password_sha256_hex.empty())
throw Exception("Cannot use " + getName() + " auth plugin for user " + user_name + " since its password is specified using SHA256.", ErrorCodes::UNKNOWN_EXCEPTION);
if (user->password_double_sha1_hex.empty())
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::DigestEngine::digestFromHex(user->password_double_sha1_hex);
assert(double_sha1_value.size() == Poco::SHA1Engine::DIGEST_SIZE);
Poco::SHA1Engine::Digest double_sha1_value;
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);
}
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();
}
engine.update(scramble.data(), SCRAMBLE_LENGTH);
engine.update(double_sha1_value.data(), double_sha1_value.size());
@ -948,8 +935,8 @@ public:
scramble.resize(SCRAMBLE_LENGTH + 1, 0);
Poco::RandomInputStream generator;
for (char & c : scramble)
generator >> c;
for (size_t i = 0; i < SCRAMBLE_LENGTH; i++)
generator >> scramble[i];
}
String getName() override
@ -975,7 +962,8 @@ public:
packet_sender->sendPacket(AuthSwitchRequest(getName(), scramble), true);
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;
packet_sender->receivePacket(response);

View File

@ -82,7 +82,7 @@ UserPtr UsersManager::authorizeAndGetUser(
const auto & first_sha1 = engine.digest();
/// 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;
engine.update(first_sha1.data(), first_sha1.size());
@ -92,15 +92,7 @@ UserPtr UsersManager::authorizeAndGetUser(
}
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();
}
return it->second;

View File

@ -173,14 +173,16 @@ def test_php_client(server_address, php_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)
assert code == 0
code, (_, stderr) = nodejs_container.exec_run('node test.js {host} {port} default 123'.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, (_, 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)
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)
assert code == 1