2019-10-08 13:44:44 +00:00
|
|
|
#include <Access/Authentication.h>
|
2021-03-11 20:41:10 +00:00
|
|
|
#include <Access/Credentials.h>
|
2020-05-27 21:06:33 +00:00
|
|
|
#include <Access/ExternalAuthenticators.h>
|
2021-03-11 20:41:10 +00:00
|
|
|
#include <Access/LDAPClient.h>
|
|
|
|
#include <Access/GSSAcceptor.h>
|
2019-10-08 13:44:44 +00:00
|
|
|
#include <Common/Exception.h>
|
|
|
|
#include <Poco/SHA1Engine.h>
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2020-05-20 20:31:55 +00:00
|
|
|
extern const int NOT_IMPLEMENTED;
|
2021-03-11 20:41:10 +00:00
|
|
|
extern const int LOGICAL_ERROR;
|
2019-10-08 13:44:44 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 07:47:01 +00:00
|
|
|
|
2020-02-06 01:48:14 +00:00
|
|
|
Authentication::Digest Authentication::getPasswordDoubleSHA1() const
|
2019-12-06 01:30:01 +00:00
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case NO_PASSWORD:
|
|
|
|
{
|
|
|
|
Poco::SHA1Engine engine;
|
|
|
|
return engine.digest();
|
|
|
|
}
|
|
|
|
|
|
|
|
case PLAINTEXT_PASSWORD:
|
|
|
|
{
|
|
|
|
Poco::SHA1Engine engine;
|
|
|
|
engine.update(getPassword());
|
|
|
|
const Digest & first_sha1 = engine.digest();
|
|
|
|
engine.update(first_sha1.data(), first_sha1.size());
|
|
|
|
return engine.digest();
|
|
|
|
}
|
|
|
|
|
|
|
|
case DOUBLE_SHA1_PASSWORD:
|
|
|
|
return password_hash;
|
2020-05-27 21:06:33 +00:00
|
|
|
|
2021-03-11 20:41:10 +00:00
|
|
|
case SHA256_PASSWORD:
|
|
|
|
case LDAP:
|
|
|
|
case KERBEROS:
|
|
|
|
throw Exception("Cannot get password double SHA1 hash for authentication type " + toString(type), ErrorCodes::LOGICAL_ERROR);
|
2020-05-29 06:52:44 +00:00
|
|
|
|
2020-05-20 20:31:55 +00:00
|
|
|
case MAX_TYPE:
|
|
|
|
break;
|
2019-12-06 01:30:01 +00:00
|
|
|
}
|
2020-05-20 20:31:55 +00:00
|
|
|
throw Exception("getPasswordDoubleSHA1(): authentication type " + toString(type) + " not supported", ErrorCodes::NOT_IMPLEMENTED);
|
2019-12-06 01:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 20:41:10 +00:00
|
|
|
bool Authentication::areCredentialsValid(const Credentials & credentials, const ExternalAuthenticators & external_authenticators) const
|
2019-10-08 13:44:44 +00:00
|
|
|
{
|
2021-03-11 20:41:10 +00:00
|
|
|
if (!credentials.isReady())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (const auto * gss_acceptor_context = dynamic_cast<const GSSAcceptorContext *>(&credentials))
|
2019-10-08 13:44:44 +00:00
|
|
|
{
|
2021-03-11 20:41:10 +00:00
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case NO_PASSWORD:
|
|
|
|
case PLAINTEXT_PASSWORD:
|
|
|
|
case SHA256_PASSWORD:
|
|
|
|
case DOUBLE_SHA1_PASSWORD:
|
|
|
|
case LDAP:
|
|
|
|
throw Require<BasicCredentials>("ClickHouse Basic Authentication");
|
|
|
|
|
|
|
|
case KERBEROS:
|
|
|
|
return external_authenticators.checkKerberosCredentials(kerberos_realm, *gss_acceptor_context);
|
|
|
|
|
|
|
|
case MAX_TYPE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-10-08 13:44:44 +00:00
|
|
|
|
2021-03-11 20:41:10 +00:00
|
|
|
if (const auto * basic_credentials = dynamic_cast<const BasicCredentials *>(&credentials))
|
|
|
|
{
|
|
|
|
switch (type)
|
2019-12-05 00:19:36 +00:00
|
|
|
{
|
2021-03-11 20:41:10 +00:00
|
|
|
case NO_PASSWORD:
|
|
|
|
return true; // N.B. even if the password is not empty!
|
2019-10-08 13:44:44 +00:00
|
|
|
|
2021-03-11 20:41:10 +00:00
|
|
|
case PLAINTEXT_PASSWORD:
|
|
|
|
{
|
|
|
|
if (basic_credentials->getPassword() == std::string_view{reinterpret_cast<const char *>(password_hash.data()), password_hash.size()})
|
|
|
|
return true;
|
2019-12-05 00:35:52 +00:00
|
|
|
|
2021-03-11 20:41:10 +00:00
|
|
|
// For compatibility with MySQL clients which support only native authentication plugin, SHA1 can be passed instead of password.
|
|
|
|
const auto password_sha1 = encodeSHA1(password_hash);
|
|
|
|
return basic_credentials->getPassword() == std::string_view{reinterpret_cast<const char *>(password_sha1.data()), password_sha1.size()};
|
|
|
|
}
|
2019-10-08 13:44:44 +00:00
|
|
|
|
2021-03-11 20:41:10 +00:00
|
|
|
case SHA256_PASSWORD:
|
|
|
|
return encodeSHA256(basic_credentials->getPassword()) == password_hash;
|
2019-10-08 13:44:44 +00:00
|
|
|
|
2021-03-11 20:41:10 +00:00
|
|
|
case DOUBLE_SHA1_PASSWORD:
|
|
|
|
{
|
|
|
|
const auto first_sha1 = encodeSHA1(basic_credentials->getPassword());
|
2019-10-08 13:44:44 +00:00
|
|
|
|
2021-03-11 20:41:10 +00:00
|
|
|
/// If it was MySQL compatibility server, then first_sha1 already contains double SHA1.
|
|
|
|
if (first_sha1 == password_hash)
|
|
|
|
return true;
|
2020-05-27 21:06:33 +00:00
|
|
|
|
2021-03-11 20:41:10 +00:00
|
|
|
return encodeSHA1(first_sha1) == password_hash;
|
|
|
|
}
|
2020-05-29 06:52:44 +00:00
|
|
|
|
2021-03-11 20:41:10 +00:00
|
|
|
case LDAP:
|
|
|
|
return external_authenticators.checkLDAPCredentials(ldap_server_name, *basic_credentials);
|
|
|
|
|
|
|
|
case KERBEROS:
|
|
|
|
throw Require<GSSAcceptorContext>(kerberos_realm);
|
|
|
|
|
|
|
|
case MAX_TYPE:
|
|
|
|
break;
|
|
|
|
}
|
2019-10-08 13:44:44 +00:00
|
|
|
}
|
2021-03-11 20:41:10 +00:00
|
|
|
|
|
|
|
if ([[maybe_unused]] const auto * always_allow_credentials = dynamic_cast<const AlwaysAllowCredentials *>(&credentials))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
throw Exception("areCredentialsValid(): authentication type " + toString(type) + " not supported", ErrorCodes::NOT_IMPLEMENTED);
|
2019-10-08 13:44:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|