fix no pwd authentication

This commit is contained in:
Arthur Passos 2024-06-14 14:39:55 -03:00
parent c1250ccb35
commit 70e4933221
7 changed files with 65 additions and 33 deletions

View File

@ -161,7 +161,7 @@ namespace
{
auto basic_credentials_authentication_methods = getAuthenticationMethodsOfType(
authentication_methods,
{AuthenticationType::PLAINTEXT_PASSWORD, AuthenticationType::SHA256_PASSWORD,
{AuthenticationType::NO_PASSWORD, AuthenticationType::PLAINTEXT_PASSWORD, AuthenticationType::SHA256_PASSWORD,
AuthenticationType::DOUBLE_SHA1_PASSWORD, AuthenticationType::LDAP, AuthenticationType::BCRYPT_PASSWORD,
AuthenticationType::HTTP});
@ -169,6 +169,10 @@ namespace
{
switch (auth_method.getType())
{
case AuthenticationType::NO_PASSWORD:
{
return true;
}
case AuthenticationType::PLAINTEXT_PASSWORD:
if (checkPasswordPlainText(basic_credentials->getPassword(), auth_method.getPasswordHashBinary()))
{

View File

@ -1903,11 +1903,11 @@ void ClientBase::processParsedSingleQuery(const String & full_query, const Strin
if (const auto * create_user_query = parsed_query->as<ASTCreateUserQuery>())
{
if (!create_user_query->attach && create_user_query->auth_data)
if (!create_user_query->attach && !create_user_query->auth_data.empty())
{
if (const auto * auth_data = create_user_query->auth_data->as<ASTAuthenticationData>())
for (const auto & authentication_method : create_user_query->auth_data)
{
auto password = auth_data->getPassword();
auto password = authentication_method->getPassword();
if (password)
global_context->getAccessControl().checkPasswordComplexityRules(*password);

View File

@ -33,7 +33,7 @@ namespace
void updateUserFromQueryImpl(
User & user,
const ASTCreateUserQuery & query,
const std::optional<AuthenticationData> auth_data,
const std::vector<AuthenticationData> auth_data,
const std::shared_ptr<ASTUserNameWithHost> & override_name,
const std::optional<RolesOrUsersSet> & override_default_roles,
const std::optional<SettingsProfileElements> & override_settings,
@ -51,15 +51,19 @@ namespace
else if (query.names->size() == 1)
user.setName(query.names->front()->toString());
if (!query.attach && !query.alter && !auth_data && !allow_implicit_no_password)
// todo arthur check if auth_data.empty makes sense
if (!query.attach && !query.alter && !auth_data.empty() && !allow_implicit_no_password)
throw Exception(ErrorCodes::BAD_ARGUMENTS,
"Authentication type NO_PASSWORD must "
"be explicitly specified, check the setting allow_implicit_no_password "
"in the server configuration");
if (auth_data)
if (!auth_data.empty())
{
user.authentication_methods.push_back(*auth_data);
for (const auto & authentication_method : auth_data)
{
user.authentication_methods.push_back(authentication_method);
}
}
else if (user.authentication_methods.empty())
{
@ -75,7 +79,7 @@ namespace
user.authentication_methods.push_back(primary_authentication_method);
}
if (auth_data || !query.alter)
if (!auth_data.empty() || !query.alter)
{
// I suppose it is guaranteed a user will always have at least one authentication method
auto auth_type = user.authentication_methods.back().getType();
@ -145,9 +149,14 @@ BlockIO InterpreterCreateUserQuery::execute()
bool no_password_allowed = access_control.isNoPasswordAllowed();
bool plaintext_password_allowed = access_control.isPlaintextPasswordAllowed();
std::optional<AuthenticationData> auth_data;
if (query.auth_data)
auth_data = AuthenticationData::fromAST(*query.auth_data, getContext(), !query.attach);
std::vector<AuthenticationData> auth_data;
if (!query.auth_data.empty())
{
for (const auto & authentication_method_ast : query.auth_data)
{
auth_data.push_back(AuthenticationData::fromAST(*authentication_method_ast, getContext(), !query.attach));
}
}
std::optional<time_t> valid_until;
if (query.valid_until)
@ -272,9 +281,14 @@ BlockIO InterpreterCreateUserQuery::execute()
void InterpreterCreateUserQuery::updateUserFromQuery(User & user, const ASTCreateUserQuery & query, bool allow_no_password, bool allow_plaintext_password)
{
std::optional<AuthenticationData> auth_data;
if (query.auth_data)
auth_data = AuthenticationData::fromAST(*query.auth_data, {}, !query.attach);
std::vector<AuthenticationData> auth_data;
if (!query.auth_data.empty())
{
for (const auto & authentication_method_ast : query.auth_data)
{
auth_data.emplace_back(AuthenticationData::fromAST(*authentication_method_ast, {}, !query.attach));
}
}
updateUserFromQueryImpl(user, query, auth_data, {}, {}, {}, {}, {}, query.reset_authentication_methods_to_new, allow_no_password, allow_plaintext_password, true);
}

View File

@ -64,11 +64,13 @@ namespace
query->default_roles = user.default_roles.toASTWithNames(*access_control);
}
// todo arthur
// to fix this, I'll need to turn `query->auth_data` into a list
// that also means creating a user with multiple authentication methods should be allowed
if (user.authentication_methods[0].getType() != AuthenticationType::NO_PASSWORD)
query->auth_data = user.authentication_methods[0].toAST();
for (const auto & authentication_method : user.authentication_methods)
{
if (authentication_method.getType() != AuthenticationType::NO_PASSWORD)
{
query->auth_data.push_back(authentication_method.toAST());
}
}
if (user.valid_until)
{

View File

@ -18,9 +18,12 @@ namespace
<< quoteString(new_name);
}
void formatAuthenticationData(const ASTAuthenticationData & auth_data, const IAST::FormatSettings & settings)
void formatAuthenticationData(const std::vector<std::shared_ptr<ASTAuthenticationData>> & auth_data, const IAST::FormatSettings & settings)
{
auth_data.format(settings);
for (const auto & authentication_method : auth_data)
{
authentication_method->format(settings);
}
}
void formatValidUntil(const IAST & valid_until, const IAST::FormatSettings & settings)
@ -180,10 +183,13 @@ ASTPtr ASTCreateUserQuery::clone() const
if (settings)
res->settings = std::static_pointer_cast<ASTSettingsProfileElements>(settings->clone());
if (auth_data)
if (!auth_data.empty())
{
res->auth_data = std::static_pointer_cast<ASTAuthenticationData>(auth_data->clone());
res->children.push_back(res->auth_data);
for (const auto & authentication_method : auth_data)
{
res->auth_data.push_back(std::static_pointer_cast<ASTAuthenticationData>(authentication_method->clone()));
res->children.push_back(res->auth_data.back());
}
}
return res;
@ -222,8 +228,8 @@ void ASTCreateUserQuery::formatImpl(const FormatSettings & format, FormatState &
if (new_name)
formatRenameTo(*new_name, format);
if (auth_data)
formatAuthenticationData(*auth_data, format);
if (!auth_data.empty())
formatAuthenticationData(auth_data, format);
if (valid_until)
formatValidUntil(*valid_until, format);

View File

@ -48,7 +48,7 @@ public:
std::optional<String> new_name;
String storage_name;
std::shared_ptr<ASTAuthenticationData> auth_data;
std::vector<std::shared_ptr<ASTAuthenticationData>> auth_data;
std::optional<AllowedClientHosts> hosts;
std::optional<AllowedClientHosts> add_hosts;

View File

@ -455,7 +455,7 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
std::optional<AllowedClientHosts> hosts;
std::optional<AllowedClientHosts> add_hosts;
std::optional<AllowedClientHosts> remove_hosts;
std::shared_ptr<ASTAuthenticationData> auth_data;
std::vector<std::shared_ptr<ASTAuthenticationData>> auth_data;
std::shared_ptr<ASTRolesOrUsersSet> default_roles;
std::shared_ptr<ASTSettingsProfileElements> settings;
std::shared_ptr<ASTRolesOrUsersSet> grantees;
@ -467,12 +467,12 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
while (true)
{
if (!auth_data)
if (auth_data.empty())
{
std::shared_ptr<ASTAuthenticationData> new_auth_data;
if (parseAuthenticationData(pos, expected, new_auth_data))
{
auth_data = std::move(new_auth_data);
auth_data.push_back(new_auth_data);
continue;
}
}
@ -582,8 +582,14 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
query->storage_name = std::move(storage_name);
query->reset_authentication_methods_to_new = reset_authentication_methods_to_new.value_or(false);
if (query->auth_data)
query->children.push_back(query->auth_data);
if (!query->auth_data.empty())
{
// as of now, this will always have a single element, but looping just in case.
for (const auto & authentication_method : query->auth_data)
{
query->children.push_back(authentication_method);
}
}
if (query->valid_until)
query->children.push_back(query->valid_until);