diff --git a/src/Parsers/Access/ParserCreateUserQuery.cpp b/src/Parsers/Access/ParserCreateUserQuery.cpp index 1c4b23e1a34..71d8e344646 100644 --- a/src/Parsers/Access/ParserCreateUserQuery.cpp +++ b/src/Parsers/Access/ParserCreateUserQuery.cpp @@ -26,6 +26,11 @@ namespace DB { +namespace ErrorCodes +{ + extern const int BAD_ARGUMENTS; +} + namespace { bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, std::optional & new_name) @@ -48,7 +53,6 @@ namespace { return IParserBase::wrapParseImpl(pos, [&] { - ParserKeyword{Keyword::ADD_NEW_AUTHENTICATION_METHOD}.ignore(pos, expected); if (ParserKeyword{Keyword::NOT_IDENTIFIED}.ignore(pos, expected)) { auth_data = std::make_shared(); @@ -403,6 +407,19 @@ namespace }); } + bool parseAddNewAuthenticationMethod(IParserBase::Pos & pos, Expected & expected, std::shared_ptr & auth_data) + { + return IParserBase::wrapParseImpl(pos, [&] + { + if (!ParserKeyword{Keyword::ADD_NEW_AUTHENTICATION_METHOD}.ignore(pos, expected)) + { + return false; + } + + return parseAuthenticationData(pos, expected, auth_data); + }); + } + bool parseResetAuthenticationMethods(IParserBase::Pos & pos, Expected & expected) { return IParserBase::wrapParseImpl(pos, [&] @@ -465,18 +482,42 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec String storage_name; std::optional reset_authentication_methods_to_new; + bool parsed_identified_with = false; + bool parsed_add_new_method = false; + while (true) { - if (auth_data.empty()) + std::shared_ptr identified_with_auth_data; + bool parse_auth_data = parseAuthenticationData(pos, expected, identified_with_auth_data); + + bool found_multiple_identified_with = parsed_identified_with && parse_auth_data; + + if (found_multiple_identified_with) { - std::shared_ptr new_auth_data; - if (parseAuthenticationData(pos, expected, new_auth_data)) - { - auth_data.push_back(new_auth_data); - continue; - } + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Only one identified with is permitted"); } + if (parse_auth_data) + { + if (parsed_add_new_method) + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Identified with must precede add new auth"); + } + auth_data.push_back(identified_with_auth_data); + parsed_identified_with = true; + continue; + } + + std::shared_ptr add_new_auth_method; + parsed_add_new_method = parseAddNewAuthenticationMethod(pos, expected, add_new_auth_method); + + if (parsed_add_new_method) + { + auth_data.push_back(add_new_auth_method); + continue; + } + + // todo arthur maybe check that neither identified with or add new auth method has been parsed if (!reset_authentication_methods_to_new.has_value()) { reset_authentication_methods_to_new = parseResetAuthenticationMethods(pos, expected); @@ -580,15 +621,11 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec query->default_database = std::move(default_database); query->valid_until = std::move(valid_until); query->storage_name = std::move(storage_name); - query->reset_authentication_methods_to_new = reset_authentication_methods_to_new.value_or(false); + query->reset_authentication_methods_to_new = parsed_identified_with || reset_authentication_methods_to_new.value_or(false); - if (!query->auth_data.empty()) + for (const auto & authentication_method : query->auth_data) { - // 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); - } + query->children.push_back(authentication_method); } if (query->valid_until)