mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Add bcrypt authentification type
This commit is contained in:
parent
cb8e7c8059
commit
aa52956412
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -294,3 +294,6 @@
|
|||||||
[submodule "contrib/libdivide"]
|
[submodule "contrib/libdivide"]
|
||||||
path = contrib/libdivide
|
path = contrib/libdivide
|
||||||
url = https://github.com/ridiculousfish/libdivide.git
|
url = https://github.com/ridiculousfish/libdivide.git
|
||||||
|
[submodule "contrib/libbcrypt"]
|
||||||
|
path = contrib/libbcrypt
|
||||||
|
url = https://github.com/rg3/libbcrypt.git
|
||||||
|
2
contrib/CMakeLists.txt
vendored
2
contrib/CMakeLists.txt
vendored
@ -170,6 +170,8 @@ add_contrib (annoy-cmake annoy)
|
|||||||
|
|
||||||
add_contrib (xxHash-cmake xxHash)
|
add_contrib (xxHash-cmake xxHash)
|
||||||
|
|
||||||
|
add_contrib (libbcrypt-cmake libbcrypt)
|
||||||
|
|
||||||
add_contrib (google-benchmark-cmake google-benchmark)
|
add_contrib (google-benchmark-cmake google-benchmark)
|
||||||
|
|
||||||
# Put all targets defined here and in subdirectories under "contrib/<immediate-subdir>" folders in GUI-based IDEs.
|
# Put all targets defined here and in subdirectories under "contrib/<immediate-subdir>" folders in GUI-based IDEs.
|
||||||
|
1
contrib/libbcrypt
vendored
Submodule
1
contrib/libbcrypt
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 8aa32ad94ebe06b76853b0767c910c9fbf7ccef4
|
19
contrib/libbcrypt-cmake/CMakeLists.txt
Normal file
19
contrib/libbcrypt-cmake/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
option(ENABLE_BCRYPT "Enable bcrypt" ${ENABLE_LIBRARIES})
|
||||||
|
|
||||||
|
if (NOT ENABLE_BCRYPT)
|
||||||
|
message(STATUS "Not using bcrypt")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set (LIBRARY_DIR "${ClickHouse_SOURCE_DIR}/contrib/libbcrypt")
|
||||||
|
|
||||||
|
set(SRCS
|
||||||
|
"${LIBRARY_DIR}/bcrypt.c"
|
||||||
|
"${LIBRARY_DIR}/crypt_blowfish/crypt_blowfish.c"
|
||||||
|
"${LIBRARY_DIR}/crypt_blowfish/crypt_gensalt.c"
|
||||||
|
"${LIBRARY_DIR}/crypt_blowfish/wrapper.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(_bcrypt ${SRCS})
|
||||||
|
target_include_directories(_bcrypt SYSTEM PUBLIC "${LIBRARY_DIR}")
|
||||||
|
add_library(ch_contrib::bcrypt ALIAS _bcrypt)
|
@ -31,6 +31,11 @@ namespace
|
|||||||
return (Util::encodeDoubleSHA1(password) == password_double_sha1);
|
return (Util::encodeDoubleSHA1(password) == password_double_sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool checkPasswordBcrypt(std::string_view password, const Digest & password_bcrypt)
|
||||||
|
{
|
||||||
|
return Util::checkPasswordBcrypt(password, password_bcrypt);
|
||||||
|
}
|
||||||
|
|
||||||
bool checkPasswordSHA256(std::string_view password, const Digest & password_sha256, const String & salt)
|
bool checkPasswordSHA256(std::string_view password, const Digest & password_sha256, const String & salt)
|
||||||
{
|
{
|
||||||
return Util::encodeSHA256(String(password).append(salt)) == password_sha256;
|
return Util::encodeSHA256(String(password).append(salt)) == password_sha256;
|
||||||
@ -81,6 +86,7 @@ bool Authentication::areCredentialsValid(const Credentials & credentials, const
|
|||||||
case AuthenticationType::PLAINTEXT_PASSWORD:
|
case AuthenticationType::PLAINTEXT_PASSWORD:
|
||||||
case AuthenticationType::SHA256_PASSWORD:
|
case AuthenticationType::SHA256_PASSWORD:
|
||||||
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
||||||
|
case AuthenticationType::BCRYPT_PASSWORD:
|
||||||
case AuthenticationType::LDAP:
|
case AuthenticationType::LDAP:
|
||||||
throw Authentication::Require<BasicCredentials>("ClickHouse Basic Authentication");
|
throw Authentication::Require<BasicCredentials>("ClickHouse Basic Authentication");
|
||||||
|
|
||||||
@ -109,6 +115,7 @@ bool Authentication::areCredentialsValid(const Credentials & credentials, const
|
|||||||
return checkPasswordDoubleSHA1MySQL(mysql_credentials->getScramble(), mysql_credentials->getScrambledPassword(), auth_data.getPasswordHashBinary());
|
return checkPasswordDoubleSHA1MySQL(mysql_credentials->getScramble(), mysql_credentials->getScrambledPassword(), auth_data.getPasswordHashBinary());
|
||||||
|
|
||||||
case AuthenticationType::SHA256_PASSWORD:
|
case AuthenticationType::SHA256_PASSWORD:
|
||||||
|
case AuthenticationType::BCRYPT_PASSWORD:
|
||||||
case AuthenticationType::LDAP:
|
case AuthenticationType::LDAP:
|
||||||
case AuthenticationType::KERBEROS:
|
case AuthenticationType::KERBEROS:
|
||||||
throw Authentication::Require<BasicCredentials>("ClickHouse Basic Authentication");
|
throw Authentication::Require<BasicCredentials>("ClickHouse Basic Authentication");
|
||||||
@ -137,6 +144,9 @@ bool Authentication::areCredentialsValid(const Credentials & credentials, const
|
|||||||
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
||||||
return checkPasswordDoubleSHA1(basic_credentials->getPassword(), auth_data.getPasswordHashBinary());
|
return checkPasswordDoubleSHA1(basic_credentials->getPassword(), auth_data.getPasswordHashBinary());
|
||||||
|
|
||||||
|
case AuthenticationType::BCRYPT_PASSWORD:
|
||||||
|
return checkPasswordBcrypt(basic_credentials->getPassword(), auth_data.getPasswordHashBinary());
|
||||||
|
|
||||||
case AuthenticationType::LDAP:
|
case AuthenticationType::LDAP:
|
||||||
return external_authenticators.checkLDAPCredentials(auth_data.getLDAPServerName(), *basic_credentials);
|
return external_authenticators.checkLDAPCredentials(auth_data.getLDAPServerName(), *basic_credentials);
|
||||||
|
|
||||||
@ -159,6 +169,7 @@ bool Authentication::areCredentialsValid(const Credentials & credentials, const
|
|||||||
case AuthenticationType::PLAINTEXT_PASSWORD:
|
case AuthenticationType::PLAINTEXT_PASSWORD:
|
||||||
case AuthenticationType::SHA256_PASSWORD:
|
case AuthenticationType::SHA256_PASSWORD:
|
||||||
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
||||||
|
case AuthenticationType::BCRYPT_PASSWORD:
|
||||||
case AuthenticationType::LDAP:
|
case AuthenticationType::LDAP:
|
||||||
throw Authentication::Require<BasicCredentials>("ClickHouse Basic Authentication");
|
throw Authentication::Require<BasicCredentials>("ClickHouse Basic Authentication");
|
||||||
|
|
||||||
|
@ -6,6 +6,11 @@
|
|||||||
#include <boost/algorithm/hex.hpp>
|
#include <boost/algorithm/hex.hpp>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#if USE_BCRYPT
|
||||||
|
# include <bcrypt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
@ -49,6 +54,11 @@ const AuthenticationTypeInfo & AuthenticationTypeInfo::get(AuthenticationType ty
|
|||||||
static const auto info = make_info("DOUBLE_SHA1_PASSWORD");
|
static const auto info = make_info("DOUBLE_SHA1_PASSWORD");
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
case AuthenticationType::BCRYPT_PASSWORD:
|
||||||
|
{
|
||||||
|
static const auto info = make_info("BCRYPT_PASSWORD");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
case AuthenticationType::LDAP:
|
case AuthenticationType::LDAP:
|
||||||
{
|
{
|
||||||
static const auto info = make_info("LDAP");
|
static const auto info = make_info("LDAP");
|
||||||
@ -85,6 +95,40 @@ AuthenticationData::Digest AuthenticationData::Util::encodeSHA256(std::string_vi
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AuthenticationData::Digest AuthenticationData::Util::encodeBcrypt(std::string_view text [[maybe_unused]])
|
||||||
|
{
|
||||||
|
#if USE_BCRYPT
|
||||||
|
char salt[BCRYPT_HASHSIZE];
|
||||||
|
Digest hash;
|
||||||
|
hash.resize(64);
|
||||||
|
int ret = bcrypt_gensalt(12, salt);
|
||||||
|
if (ret != 0)
|
||||||
|
throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "BCrypt library failed: bcrypt_gensalt returned {}", ret);
|
||||||
|
ret = bcrypt_hashpw(text.data(), salt, reinterpret_cast<char *>(hash.data()));
|
||||||
|
if (ret != 0)
|
||||||
|
throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "BCrypt library failed: bcrypt_hashpw returned {}", ret);
|
||||||
|
return hash;
|
||||||
|
#else
|
||||||
|
throw DB::Exception(
|
||||||
|
"bcrypt passwords support is disabled, because ClickHouse was built without bcrypt library",
|
||||||
|
DB::ErrorCodes::SUPPORT_IS_DISABLED);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AuthenticationData::Util::checkPasswordBcrypt(std::string_view password [[maybe_unused]], const Digest & password_bcrypt [[maybe_unused]])
|
||||||
|
{
|
||||||
|
#if USE_BCRYPT
|
||||||
|
int ret = bcrypt_checkpw(password.data(), reinterpret_cast<const char *>(password_bcrypt.data()));
|
||||||
|
if (ret == -1)
|
||||||
|
throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "BCrypt library failed: bcrypt_checkpw returned {}", ret);
|
||||||
|
return (ret == 0);
|
||||||
|
#else
|
||||||
|
throw DB::Exception(
|
||||||
|
"bcrypt passwords support is disabled, because ClickHouse was built without bcrypt library",
|
||||||
|
DB::ErrorCodes::SUPPORT_IS_DISABLED);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
AuthenticationData::Digest AuthenticationData::Util::encodeSHA1(std::string_view text)
|
AuthenticationData::Digest AuthenticationData::Util::encodeSHA1(std::string_view text)
|
||||||
{
|
{
|
||||||
@ -115,6 +159,9 @@ void AuthenticationData::setPassword(const String & password_)
|
|||||||
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
||||||
return setPasswordHashBinary(Util::encodeDoubleSHA1(password_));
|
return setPasswordHashBinary(Util::encodeDoubleSHA1(password_));
|
||||||
|
|
||||||
|
case AuthenticationType::BCRYPT_PASSWORD:
|
||||||
|
return setPasswordHashBinary(Util::encodeBcrypt(password_));
|
||||||
|
|
||||||
case AuthenticationType::NO_PASSWORD:
|
case AuthenticationType::NO_PASSWORD:
|
||||||
case AuthenticationType::LDAP:
|
case AuthenticationType::LDAP:
|
||||||
case AuthenticationType::KERBEROS:
|
case AuthenticationType::KERBEROS:
|
||||||
@ -198,6 +245,12 @@ void AuthenticationData::setPasswordHashBinary(const Digest & hash)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case AuthenticationType::BCRYPT_PASSWORD:
|
||||||
|
{
|
||||||
|
password_hash = hash;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
case AuthenticationType::NO_PASSWORD:
|
case AuthenticationType::NO_PASSWORD:
|
||||||
case AuthenticationType::LDAP:
|
case AuthenticationType::LDAP:
|
||||||
case AuthenticationType::KERBEROS:
|
case AuthenticationType::KERBEROS:
|
||||||
|
@ -22,6 +22,9 @@ enum class AuthenticationType
|
|||||||
/// This kind of hash is used by the `mysql_native_password` authentication plugin.
|
/// This kind of hash is used by the `mysql_native_password` authentication plugin.
|
||||||
DOUBLE_SHA1_PASSWORD,
|
DOUBLE_SHA1_PASSWORD,
|
||||||
|
|
||||||
|
/// Password is encrypted in bcrypt hash.
|
||||||
|
BCRYPT_PASSWORD,
|
||||||
|
|
||||||
/// Password is checked by a [remote] LDAP server. Connection will be made at each authentication attempt.
|
/// Password is checked by a [remote] LDAP server. Connection will be made at each authentication attempt.
|
||||||
LDAP,
|
LDAP,
|
||||||
|
|
||||||
@ -102,6 +105,8 @@ public:
|
|||||||
static Digest encodeSHA1(const Digest & text) { return encodeSHA1(std::string_view{reinterpret_cast<const char *>(text.data()), text.size()}); }
|
static Digest encodeSHA1(const Digest & text) { return encodeSHA1(std::string_view{reinterpret_cast<const char *>(text.data()), text.size()}); }
|
||||||
static Digest encodeDoubleSHA1(std::string_view text) { return encodeSHA1(encodeSHA1(text)); }
|
static Digest encodeDoubleSHA1(std::string_view text) { return encodeSHA1(encodeSHA1(text)); }
|
||||||
static Digest encodeDoubleSHA1(const Digest & text) { return encodeSHA1(encodeSHA1(text)); }
|
static Digest encodeDoubleSHA1(const Digest & text) { return encodeSHA1(encodeSHA1(text)); }
|
||||||
|
static Digest encodeBcrypt(std::string_view text);
|
||||||
|
static bool checkPasswordBcrypt(std::string_view password, const Digest & password_bcrypt);
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -536,6 +536,10 @@ if (TARGET ch_contrib::sqlite)
|
|||||||
dbms_target_link_libraries(PUBLIC ch_contrib::sqlite)
|
dbms_target_link_libraries(PUBLIC ch_contrib::sqlite)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (TARGET ch_contrib::bcrypt)
|
||||||
|
target_link_libraries (clickhouse_common_io PUBLIC ch_contrib::bcrypt)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (TARGET ch_contrib::msgpack)
|
if (TARGET ch_contrib::msgpack)
|
||||||
target_link_libraries (clickhouse_common_io PUBLIC ch_contrib::msgpack)
|
target_link_libraries (clickhouse_common_io PUBLIC ch_contrib::msgpack)
|
||||||
endif()
|
endif()
|
||||||
|
@ -54,3 +54,4 @@
|
|||||||
#cmakedefine01 USE_BLAKE3
|
#cmakedefine01 USE_BLAKE3
|
||||||
#cmakedefine01 USE_SKIM
|
#cmakedefine01 USE_SKIM
|
||||||
#cmakedefine01 USE_OPENSSL_INTREE
|
#cmakedefine01 USE_OPENSSL_INTREE
|
||||||
|
#cmakedefine01 USE_BCRYPT
|
||||||
|
@ -84,12 +84,13 @@ NamesAndTypesList SessionLogElement::getNamesAndTypes()
|
|||||||
AUTH_TYPE_NAME_AND_VALUE(AuthType::PLAINTEXT_PASSWORD),
|
AUTH_TYPE_NAME_AND_VALUE(AuthType::PLAINTEXT_PASSWORD),
|
||||||
AUTH_TYPE_NAME_AND_VALUE(AuthType::SHA256_PASSWORD),
|
AUTH_TYPE_NAME_AND_VALUE(AuthType::SHA256_PASSWORD),
|
||||||
AUTH_TYPE_NAME_AND_VALUE(AuthType::DOUBLE_SHA1_PASSWORD),
|
AUTH_TYPE_NAME_AND_VALUE(AuthType::DOUBLE_SHA1_PASSWORD),
|
||||||
|
AUTH_TYPE_NAME_AND_VALUE(AuthType::BCRYPT_PASSWORD),
|
||||||
AUTH_TYPE_NAME_AND_VALUE(AuthType::LDAP),
|
AUTH_TYPE_NAME_AND_VALUE(AuthType::LDAP),
|
||||||
AUTH_TYPE_NAME_AND_VALUE(AuthType::KERBEROS),
|
AUTH_TYPE_NAME_AND_VALUE(AuthType::KERBEROS),
|
||||||
AUTH_TYPE_NAME_AND_VALUE(AuthType::SSL_CERTIFICATE),
|
AUTH_TYPE_NAME_AND_VALUE(AuthType::SSL_CERTIFICATE),
|
||||||
});
|
});
|
||||||
#undef AUTH_TYPE_NAME_AND_VALUE
|
#undef AUTH_TYPE_NAME_AND_VALUE
|
||||||
static_assert(static_cast<int>(AuthenticationType::MAX) == 7);
|
static_assert(static_cast<int>(AuthenticationType::MAX) == 8);
|
||||||
|
|
||||||
auto interface_type_column = std::make_shared<DataTypeEnum8>(
|
auto interface_type_column = std::make_shared<DataTypeEnum8>(
|
||||||
DataTypeEnum8::Values
|
DataTypeEnum8::Values
|
||||||
|
@ -64,6 +64,13 @@ namespace
|
|||||||
password = auth_data.getPasswordHashHex();
|
password = auth_data.getPasswordHashHex();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case AuthenticationType::BCRYPT_PASSWORD:
|
||||||
|
{
|
||||||
|
auth_type_name = "bcrypt_hash";
|
||||||
|
prefix = "BY";
|
||||||
|
password = auth_data.getPasswordHashHex();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case AuthenticationType::LDAP:
|
case AuthenticationType::LDAP:
|
||||||
{
|
{
|
||||||
prefix = "SERVER";
|
prefix = "SERVER";
|
||||||
|
@ -104,6 +104,11 @@ namespace
|
|||||||
type = AuthenticationType::DOUBLE_SHA1_PASSWORD;
|
type = AuthenticationType::DOUBLE_SHA1_PASSWORD;
|
||||||
expect_hash = true;
|
expect_hash = true;
|
||||||
}
|
}
|
||||||
|
else if (ParserKeyword{"BCRYPT_HASH"}.ignore(pos, expected))
|
||||||
|
{
|
||||||
|
type = AuthenticationType::BCRYPT_PASSWORD;
|
||||||
|
expect_hash = true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,9 @@ endif()
|
|||||||
if (TARGET ch_contrib::capnp)
|
if (TARGET ch_contrib::capnp)
|
||||||
set(USE_CAPNP 1)
|
set(USE_CAPNP 1)
|
||||||
endif()
|
endif()
|
||||||
|
if (TARGET ch_contrib::bcrypt)
|
||||||
|
set(USE_BCRYPT 1)
|
||||||
|
endif()
|
||||||
if (NOT (ENABLE_OPENSSL OR ENABLE_OPENSSL_DYNAMIC))
|
if (NOT (ENABLE_OPENSSL OR ENABLE_OPENSSL_DYNAMIC))
|
||||||
set(USE_BORINGSSL 1)
|
set(USE_BORINGSSL 1)
|
||||||
endif ()
|
endif ()
|
||||||
|
Loading…
Reference in New Issue
Block a user