This commit is contained in:
Nikolay Degterinsky 2023-04-21 22:03:56 +00:00
parent 0621222737
commit b599d0bd01
12 changed files with 53 additions and 47 deletions

View File

@ -476,10 +476,10 @@
<allow_no_password>1</allow_no_password>
<allow_implicit_no_password>1</allow_implicit_no_password>
<!-- Default password type when the user does not specify it.
Accepted values are: 'plaintext', 'sha256', 'double_sha1'
<!-- When a user does not specify a password type in the CREATE USER query, the default password type is used.
Accepted values are: 'plaintext_password', 'sha256_password', and 'double_sha1_password'.
-->
<default_password_type>sha256</default_password_type>
<default_password_type>sha256_password</default_password_type>
<!-- Complexity requirements for user passwords. -->
<!-- <password_complexity>

View File

@ -271,7 +271,7 @@ void AccessControl::setUpFromMainConfig(const Poco::Util::AbstractConfiguration
setImplicitNoPasswordAllowed(config_.getBool("allow_implicit_no_password", true));
setNoPasswordAllowed(config_.getBool("allow_no_password", true));
setPlaintextPasswordAllowed(config_.getBool("allow_plaintext_password", true));
setDefaultPasswordTypeFromConfig(config_.getString("default_password_type", "sha256"));
setDefaultPasswordTypeFromConfig(config_.getString("default_password_type", "sha256_password"));
setPasswordComplexityRulesFromConfig(config_);
/// Optional improvements in access control system.
@ -656,14 +656,18 @@ bool AccessControl::isPlaintextPasswordAllowed() const
void AccessControl::setDefaultPasswordTypeFromConfig(const String & type_)
{
if (type_ == "plaintext")
default_password_type = AuthenticationType::PLAINTEXT_PASSWORD;
else if (type_ == "double_sha1")
default_password_type = AuthenticationType::DOUBLE_SHA1_PASSWORD;
else if (type_ == "sha256")
default_password_type = AuthenticationType::SHA256_PASSWORD;
else
throw Exception(ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG, "Unknown password type in 'default_password_type' in config");
for (auto check_type : collections::range(AuthenticationType::MAX))
{
const auto & info = AuthenticationTypeInfo::get(check_type);
if (type_ == info.name && info.is_password)
{
default_password_type = check_type;
return;
}
}
throw Exception(ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG, "Unknown password type in 'default_password_type' in config");
}
AuthenticationType AccessControl::getDefaultPasswordType() const

View File

@ -153,7 +153,6 @@ public:
AuthenticationType getDefaultPasswordType() const;
/// Check complexity requirements for passwords
void setPasswordComplexityRulesFromConfig(const Poco::Util::AbstractConfiguration & config_);
void setPasswordComplexityRules(const std::vector<std::pair<String, String>> & rules_);
void checkPasswordComplexityRules(const String & password_) const;

View File

@ -20,11 +20,11 @@ namespace ErrorCodes
const AuthenticationTypeInfo & AuthenticationTypeInfo::get(AuthenticationType type_)
{
static constexpr auto make_info = [](const char * raw_name_)
static constexpr auto make_info = [](const char * raw_name_, bool is_password_ = false)
{
String init_name = raw_name_;
boost::to_lower(init_name);
return AuthenticationTypeInfo{raw_name_, std::move(init_name)};
return AuthenticationTypeInfo{raw_name_, std::move(init_name), is_password_};
};
switch (type_)
@ -36,17 +36,17 @@ const AuthenticationTypeInfo & AuthenticationTypeInfo::get(AuthenticationType ty
}
case AuthenticationType::PLAINTEXT_PASSWORD:
{
static const auto info = make_info("PLAINTEXT_PASSWORD");
static const auto info = make_info("PLAINTEXT_PASSWORD", true);
return info;
}
case AuthenticationType::SHA256_PASSWORD:
{
static const auto info = make_info("SHA256_PASSWORD");
static const auto info = make_info("SHA256_PASSWORD", true);
return info;
}
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
{
static const auto info = make_info("DOUBLE_SHA1_PASSWORD");
static const auto info = make_info("DOUBLE_SHA1_PASSWORD", true);
return info;
}
case AuthenticationType::LDAP:

View File

@ -39,6 +39,7 @@ struct AuthenticationTypeInfo
{
const char * const raw_name;
const String name; /// Lowercased with underscores, e.g. "sha256_password".
bool is_password;
static const AuthenticationTypeInfo & get(AuthenticationType type_);
};

View File

@ -43,7 +43,7 @@ namespace
for (size_t i = 0; i < args_size; ++i)
args[i] = evaluateConstantExpressionAsLiteral(query.children[i], context);
if (query.expect_password)
if (query.is_password)
{
if (!query.type && !context)
throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot get default password type without context");
@ -101,23 +101,23 @@ namespace
AuthenticationData auth_data(*query.type);
if (query.expect_hash)
if (query.is_hash)
{
String value = checkAndGetLiteralArgument<String>(args[0], "hash");
auth_data.setPasswordHashHex(value);
if (*query.type == AuthenticationType::SHA256_PASSWORD && args_size == 2)
if (query.type == AuthenticationType::SHA256_PASSWORD && args_size == 2)
{
String parsed_salt = checkAndGetLiteralArgument<String>(args[1], "salt");
auth_data.setSalt(parsed_salt);
}
}
else if (query.expect_ldap_server_name)
else if (query.type == AuthenticationType::LDAP)
{
String value = checkAndGetLiteralArgument<String>(args[0], "ldap_server_name");
auth_data.setLDAPServerName(value);
}
else if (query.expect_kerberos_realm)
else if (query.type == AuthenticationType::KERBEROS)
{
if (!args.empty())
{
@ -125,7 +125,7 @@ namespace
auth_data.setKerberosRealm(value);
}
}
else if (query.expect_common_names)
else if (query.type == AuthenticationType::SSL_CERTIFICATE)
{
boost::container::flat_set<String> common_names;
for (const auto & arg : args)
@ -133,6 +133,11 @@ namespace
auth_data.setSSLCertificateCommonNames(std::move(common_names));
}
else
{
throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected ASTAuthenticationData structure");
}
return auth_data;
}

View File

@ -54,13 +54,13 @@ namespace
{
case AuthenticationType::PLAINTEXT_PASSWORD:
{
node->expect_password = true;
node->is_password = true;
node->children.push_back(std::make_shared<ASTLiteral>(auth_data.getPassword()));
break;
}
case AuthenticationType::SHA256_PASSWORD:
{
node->expect_hash = true;
node->is_hash = true;
node->children.push_back(std::make_shared<ASTLiteral>(auth_data.getPasswordHashHex()));
if (!auth_data.getSalt().empty())
@ -69,19 +69,17 @@ namespace
}
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
{
node->expect_hash = true;
node->is_hash = true;
node->children.push_back(std::make_shared<ASTLiteral>(auth_data.getPasswordHashHex()));
break;
}
case AuthenticationType::LDAP:
{
node->expect_ldap_server_name = true;
node->children.push_back(std::make_shared<ASTLiteral>(auth_data.getLDAPServerName()));
break;
}
case AuthenticationType::KERBEROS:
{
node->expect_kerberos_realm = true;
const auto & realm = auth_data.getKerberosRealm();
if (!realm.empty())
@ -91,7 +89,6 @@ namespace
}
case AuthenticationType::SSL_CERTIFICATE:
{
node->expect_common_names = true;
for (const auto & name : auth_data.getSSLCertificateCommonNames())
node->children.push_back(std::make_shared<ASTLiteral>(name));

View File

@ -17,7 +17,7 @@ namespace ErrorCodes
std::optional<String> ASTAuthenticationData::getPassword() const
{
if (expect_password)
if (is_password)
{
if (const auto * password = children[0]->as<const ASTLiteral>())
{
@ -70,7 +70,7 @@ void ASTAuthenticationData::formatImpl(const FormatSettings & settings, FormatSt
}
case AuthenticationType::SHA256_PASSWORD:
{
if (expect_hash)
if (is_hash)
auth_type_name = "sha256_hash";
prefix = "BY";
@ -81,7 +81,7 @@ void ASTAuthenticationData::formatImpl(const FormatSettings & settings, FormatSt
}
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
{
if (expect_hash)
if (is_hash)
auth_type_name = "double_sha1_hash";
prefix = "BY";

View File

@ -8,6 +8,15 @@
namespace DB
{
/** Represents authentication data in CREATE/ALTER USER query:
* ... IDENTIFIED WITH sha256_password BY 'password'
*
* Can store password, hash and salt, LDAP server name, Kerberos Realm, or common names.
* They are stored in children vector as ASTLiteral or ASTQueryParameter.
* ASTAuthenticationData without a type represents authentication data with
* the default password type that will be later inferred from the server parameters.
*/
class ASTAuthenticationData : public IAST
{
public:
@ -29,12 +38,8 @@ public:
/// AuthenticationType::NO_PASSWORD is specified explicitly.
std::optional<AuthenticationType> type;
/// TODO: Only expect_password and expect_hash are actually needed
bool expect_password = false;
bool expect_hash = false;
bool expect_ldap_server_name = false;
bool expect_kerberos_realm = false;
bool expect_common_names = false;
bool is_password = false;
bool is_hash = false;
protected:
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;

View File

@ -162,11 +162,8 @@ namespace
auth_data = std::make_shared<ASTAuthenticationData>();
auth_data->type = type;
auth_data->expect_password = expect_password;
auth_data->expect_hash = expect_hash;
auth_data->expect_ldap_server_name = expect_ldap_server_name;
auth_data->expect_kerberos_realm = expect_kerberos_realm;
auth_data->expect_common_names = expect_common_names;
auth_data->is_password = expect_password;
auth_data->is_hash = expect_hash;
if (value)
auth_data->children.push_back(std::move(value));

View File

@ -1308,7 +1308,6 @@ void TCPHandler::sendHello()
writeStringBinary(exception_message, *out);
}
}
if (client_tcp_protocol_version >= DBMS_MIN_REVISION_WITH_INTERSERVER_SECRET_V2)
{
chassert(!nonce.has_value());
@ -1321,7 +1320,6 @@ void TCPHandler::sendHello()
LOG_WARNING(LogFrequencyLimiter(log, 10),
"Using deprecated interserver protocol because the client is too old. Consider upgrading all nodes in cluster.");
}
out->next();
}

View File

@ -1,3 +1,3 @@
<clickhouse>
<default_password_type>double_sha1</default_password_type>
<default_password_type>double_sha1_password</default_password_type>
</clickhouse>