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"]
|
||||
path = contrib/libdivide
|
||||
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 (libbcrypt-cmake libbcrypt)
|
||||
|
||||
add_contrib (google-benchmark-cmake google-benchmark)
|
||||
|
||||
# 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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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::SHA256_PASSWORD:
|
||||
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
||||
case AuthenticationType::BCRYPT_PASSWORD:
|
||||
case AuthenticationType::LDAP:
|
||||
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());
|
||||
|
||||
case AuthenticationType::SHA256_PASSWORD:
|
||||
case AuthenticationType::BCRYPT_PASSWORD:
|
||||
case AuthenticationType::LDAP:
|
||||
case AuthenticationType::KERBEROS:
|
||||
throw Authentication::Require<BasicCredentials>("ClickHouse Basic Authentication");
|
||||
@ -137,6 +144,9 @@ bool Authentication::areCredentialsValid(const Credentials & credentials, const
|
||||
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
||||
return checkPasswordDoubleSHA1(basic_credentials->getPassword(), auth_data.getPasswordHashBinary());
|
||||
|
||||
case AuthenticationType::BCRYPT_PASSWORD:
|
||||
return checkPasswordBcrypt(basic_credentials->getPassword(), auth_data.getPasswordHashBinary());
|
||||
|
||||
case AuthenticationType::LDAP:
|
||||
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::SHA256_PASSWORD:
|
||||
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
||||
case AuthenticationType::BCRYPT_PASSWORD:
|
||||
case AuthenticationType::LDAP:
|
||||
throw Authentication::Require<BasicCredentials>("ClickHouse Basic Authentication");
|
||||
|
||||
|
@ -6,6 +6,11 @@
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if USE_BCRYPT
|
||||
# include <bcrypt.h>
|
||||
#endif
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -49,6 +54,11 @@ const AuthenticationTypeInfo & AuthenticationTypeInfo::get(AuthenticationType ty
|
||||
static const auto info = make_info("DOUBLE_SHA1_PASSWORD");
|
||||
return info;
|
||||
}
|
||||
case AuthenticationType::BCRYPT_PASSWORD:
|
||||
{
|
||||
static const auto info = make_info("BCRYPT_PASSWORD");
|
||||
return info;
|
||||
}
|
||||
case AuthenticationType::LDAP:
|
||||
{
|
||||
static const auto info = make_info("LDAP");
|
||||
@ -85,6 +95,40 @@ AuthenticationData::Digest AuthenticationData::Util::encodeSHA256(std::string_vi
|
||||
#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)
|
||||
{
|
||||
@ -115,6 +159,9 @@ void AuthenticationData::setPassword(const String & password_)
|
||||
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
|
||||
return setPasswordHashBinary(Util::encodeDoubleSHA1(password_));
|
||||
|
||||
case AuthenticationType::BCRYPT_PASSWORD:
|
||||
return setPasswordHashBinary(Util::encodeBcrypt(password_));
|
||||
|
||||
case AuthenticationType::NO_PASSWORD:
|
||||
case AuthenticationType::LDAP:
|
||||
case AuthenticationType::KERBEROS:
|
||||
@ -198,6 +245,12 @@ void AuthenticationData::setPasswordHashBinary(const Digest & hash)
|
||||
return;
|
||||
}
|
||||
|
||||
case AuthenticationType::BCRYPT_PASSWORD:
|
||||
{
|
||||
password_hash = hash;
|
||||
return;
|
||||
}
|
||||
|
||||
case AuthenticationType::NO_PASSWORD:
|
||||
case AuthenticationType::LDAP:
|
||||
case AuthenticationType::KERBEROS:
|
||||
|
@ -22,6 +22,9 @@ enum class AuthenticationType
|
||||
/// This kind of hash is used by the `mysql_native_password` authentication plugin.
|
||||
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.
|
||||
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 encodeDoubleSHA1(std::string_view 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:
|
||||
|
@ -536,6 +536,10 @@ if (TARGET ch_contrib::sqlite)
|
||||
dbms_target_link_libraries(PUBLIC ch_contrib::sqlite)
|
||||
endif()
|
||||
|
||||
if (TARGET ch_contrib::bcrypt)
|
||||
target_link_libraries (clickhouse_common_io PUBLIC ch_contrib::bcrypt)
|
||||
endif()
|
||||
|
||||
if (TARGET ch_contrib::msgpack)
|
||||
target_link_libraries (clickhouse_common_io PUBLIC ch_contrib::msgpack)
|
||||
endif()
|
||||
|
@ -54,3 +54,4 @@
|
||||
#cmakedefine01 USE_BLAKE3
|
||||
#cmakedefine01 USE_SKIM
|
||||
#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::SHA256_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::KERBEROS),
|
||||
AUTH_TYPE_NAME_AND_VALUE(AuthType::SSL_CERTIFICATE),
|
||||
});
|
||||
#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>(
|
||||
DataTypeEnum8::Values
|
||||
|
@ -64,6 +64,13 @@ namespace
|
||||
password = auth_data.getPasswordHashHex();
|
||||
break;
|
||||
}
|
||||
case AuthenticationType::BCRYPT_PASSWORD:
|
||||
{
|
||||
auth_type_name = "bcrypt_hash";
|
||||
prefix = "BY";
|
||||
password = auth_data.getPasswordHashHex();
|
||||
break;
|
||||
}
|
||||
case AuthenticationType::LDAP:
|
||||
{
|
||||
prefix = "SERVER";
|
||||
|
@ -104,6 +104,11 @@ namespace
|
||||
type = AuthenticationType::DOUBLE_SHA1_PASSWORD;
|
||||
expect_hash = true;
|
||||
}
|
||||
else if (ParserKeyword{"BCRYPT_HASH"}.ignore(pos, expected))
|
||||
{
|
||||
type = AuthenticationType::BCRYPT_PASSWORD;
|
||||
expect_hash = true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -138,6 +138,9 @@ endif()
|
||||
if (TARGET ch_contrib::capnp)
|
||||
set(USE_CAPNP 1)
|
||||
endif()
|
||||
if (TARGET ch_contrib::bcrypt)
|
||||
set(USE_BCRYPT 1)
|
||||
endif()
|
||||
if (NOT (ENABLE_OPENSSL OR ENABLE_OPENSSL_DYNAMIC))
|
||||
set(USE_BORINGSSL 1)
|
||||
endif ()
|
||||
|
Loading…
Reference in New Issue
Block a user