diff --git a/programs/client/Client.cpp b/programs/client/Client.cpp index cc8721f3dde..df0abceb8c6 100644 --- a/programs/client/Client.cpp +++ b/programs/client/Client.cpp @@ -350,7 +350,6 @@ try /// Set user password complexity rules auto & access_control = global_context->getAccessControl(); access_control.setPasswordComplexityRules(connection->getPasswordComplexityRules()); - access_control.setBcryptWorkfactor(connection->getBcryptWorkfactor()); if (is_interactive && !delayed_interactive) { diff --git a/src/Access/AccessControl.cpp b/src/Access/AccessControl.cpp index fa5571d4537..6179c823b56 100644 --- a/src/Access/AccessControl.cpp +++ b/src/Access/AccessControl.cpp @@ -701,11 +701,13 @@ void AccessControl::setBcryptWorkfactor(int workfactor_) { if (workfactor_ < 4) bcrypt_workfactor = 4; + else if (workfactor_ > 31) + bcrypt_workfactor = 31; else bcrypt_workfactor = workfactor_; } -int AccessControl::getBcryptWorkfactor() +int AccessControl::getBcryptWorkfactor() const { return bcrypt_workfactor; } diff --git a/src/Access/AccessControl.h b/src/Access/AccessControl.h index cd2a2252edd..2a8293a49e7 100644 --- a/src/Access/AccessControl.h +++ b/src/Access/AccessControl.h @@ -160,7 +160,7 @@ public: /// Workfactor for bcrypt encoded passwords void setBcryptWorkfactor(int workfactor_); - int getBcryptWorkfactor(); + int getBcryptWorkfactor() const; /// Enables logic that users without permissive row policies can still read rows using a SELECT query. /// For example, if there two users A, B and a row policy is defined only for A, then diff --git a/src/Access/AuthenticationData.cpp b/src/Access/AuthenticationData.cpp index 6073a79852b..dfec9bd1cd5 100644 --- a/src/Access/AuthenticationData.cpp +++ b/src/Access/AuthenticationData.cpp @@ -44,7 +44,7 @@ AuthenticationData::Digest AuthenticationData::Util::encodeSHA256(std::string_vi ::DB::encodeSHA256(text, hash.data()); return hash; #else - throw DB::Exception(DB::ErrorCodes::SUPPORT_IS_DISABLED, "SHA256 passwords support is disabled, because ClickHouse was built without SSL library"); + throw Exception(ErrorCodes::SUPPORT_IS_DISABLED, "SHA256 passwords support is disabled, because ClickHouse was built without SSL library"); #endif } @@ -60,9 +60,9 @@ AuthenticationData::Digest AuthenticationData::Util::encodeBcrypt(std::string_vi { #if USE_BCRYPT if (text.size() > 72) - throw DB::Exception( - "bcrypt does not support passwords with a length of more than 72 bytes", - DB::ErrorCodes::BAD_ARGUMENTS); + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "bcrypt does not support passwords with a length of more than 72 bytes"); char salt[BCRYPT_HASHSIZE]; Digest hash; @@ -70,17 +70,17 @@ AuthenticationData::Digest AuthenticationData::Util::encodeBcrypt(std::string_vi int ret = bcrypt_gensalt(workfactor, salt); if (ret != 0) - throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "BCrypt library failed: bcrypt_gensalt returned {}", ret); + throw Exception(ErrorCodes::LOGICAL_ERROR, "BCrypt library failed: bcrypt_gensalt returned {}", ret); ret = bcrypt_hashpw(text.data(), salt, reinterpret_cast(hash.data())); if (ret != 0) - throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "BCrypt library failed: bcrypt_hashpw returned {}", ret); + throw Exception(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); + throw Exception( + ErrorCodes::SUPPORT_IS_DISABLED, + "bcrypt passwords support is disabled, because ClickHouse was built without bcrypt library"); #endif } @@ -89,12 +89,12 @@ bool AuthenticationData::Util::checkPasswordBcrypt(std::string_view password [[m #if USE_BCRYPT int ret = bcrypt_checkpw(password.data(), reinterpret_cast(password_bcrypt.data())); if (ret == -1) - throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "BCrypt library failed: bcrypt_checkpw returned {}", ret); + throw Exception(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); + throw Exception( + ErrorCodes::SUPPORT_IS_DISABLED, + "bcrypt passwords support is disabled, because ClickHouse was built without bcrypt library"); #endif } @@ -210,8 +210,15 @@ void AuthenticationData::setPasswordHashBinary(const Digest & hash) case AuthenticationType::BCRYPT_PASSWORD: { - /// TODO: check size + /// Depending on the workfactor the resulting hash can be 59 or 60 characters long. + /// However the library we use to encode it requires hash string to be 64 characters long, + /// so we also allow the hash of this length. + if (hash.size() != 59 && hash.size() != 60 && hash.size() != 64) + throw Exception(ErrorCodes::BAD_ARGUMENTS, + "Password hash for the 'BCRYPT_PASSWORD' authentication type has length {} " + "but must be 59 or 60 bytes.", hash.size()); password_hash = hash; + password_hash.resize(64); return; } @@ -278,7 +285,7 @@ std::shared_ptr AuthenticationData::toAST() const case AuthenticationType::BCRYPT_PASSWORD: { node->contains_hash = true; - node->children.push_back(std::make_shared(getPasswordHashHex())); + node->children.push_back(std::make_shared(AuthenticationData::Util::digestToString(getPasswordHashBinary()))); break; } case AuthenticationType::LDAP: @@ -391,7 +398,16 @@ AuthenticationData AuthenticationData::fromAST(const ASTAuthenticationData & que if (query.contains_hash) { String value = checkAndGetLiteralArgument(args[0], "hash"); - auth_data.setPasswordHashHex(value); + + if (query.type == AuthenticationType::BCRYPT_PASSWORD) + { + auth_data.setPasswordHashBinary(AuthenticationData::Util::stringToDigest(value)); + return auth_data; + } + else + { + auth_data.setPasswordHashHex(value); + } if (query.type == AuthenticationType::SHA256_PASSWORD && args_size == 2) { diff --git a/src/Access/AuthenticationData.h b/src/Access/AuthenticationData.h index ff5cc1f9618..5ebef7d44f2 100644 --- a/src/Access/AuthenticationData.h +++ b/src/Access/AuthenticationData.h @@ -65,6 +65,7 @@ public: struct Util { + static String digestToString(const Digest & text) { return String(text.data(), text.data() + text.size()); } static Digest stringToDigest(std::string_view text) { return Digest(text.data(), text.data() + text.size()); } static Digest encodeSHA256(std::string_view text); static Digest encodeSHA1(std::string_view text); diff --git a/src/Parsers/Access/ASTAuthenticationData.cpp b/src/Parsers/Access/ASTAuthenticationData.cpp index 4e0cabfdec7..3dd05d831ee 100644 --- a/src/Parsers/Access/ASTAuthenticationData.cpp +++ b/src/Parsers/Access/ASTAuthenticationData.cpp @@ -87,6 +87,15 @@ void ASTAuthenticationData::formatImpl(const FormatSettings & settings, FormatSt password = true; break; } + case AuthenticationType::BCRYPT_PASSWORD: + { + if (contains_hash) + auth_type_name = "bcrypt_hash"; + + prefix = "BY"; + password = true; + break; + } case AuthenticationType::LDAP: { prefix = "SERVER";