#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int INCORRECT_ACCESS_ENTITY_DEFINITION; extern const int RBAC_VERSION_IS_TOO_NEW; } extern const UInt64 RBAC_INITIAL_VERSION; extern const UInt64 RBAC_LATEST_VERSION; namespace { constexpr const char RBAC_VERSION_SETTING_NAME[] = "rbac_version"; /// Special parser for the 'ATTACH access entity' queries. class ParserAttachAccessEntity : public IParserBase { protected: const char * getName() const override { return "ATTACH access entity query"; } bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override { ParserCreateUserQuery create_user_p; ParserCreateRoleQuery create_role_p; ParserCreateRowPolicyQuery create_policy_p; ParserCreateQuotaQuery create_quota_p; ParserCreateSettingsProfileQuery create_profile_p; ParserGrantQuery grant_p; ParserSetQuery set_p; create_user_p.useAttachMode(); create_role_p.useAttachMode(); create_policy_p.useAttachMode(); create_quota_p.useAttachMode(); create_profile_p.useAttachMode(); grant_p.useAttachMode(); return create_user_p.parse(pos, node, expected) || create_role_p.parse(pos, node, expected) || create_policy_p.parse(pos, node, expected) || create_quota_p.parse(pos, node, expected) || create_profile_p.parse(pos, node, expected) || grant_p.parse(pos, node, expected) || set_p.parse(pos, node, expected); } }; } String serializeAccessEntity(const IAccessEntity & entity) { ASTs queries; { /// Prepend the list with "SET rbac_version = ..." query. auto set_rbac_version_query = std::make_shared(); set_rbac_version_query->changes.emplace_back(RBAC_VERSION_SETTING_NAME, RBAC_LATEST_VERSION); queries.push_back(set_rbac_version_query); } /// Build list of ATTACH queries. queries.push_back(InterpreterShowCreateAccessEntityQuery::getAttachQuery(entity)); if ((entity.getType() == AccessEntityType::USER) || (entity.getType() == AccessEntityType::ROLE)) boost::range::push_back(queries, InterpreterShowGrantsQuery::getAttachGrantQueries(entity)); /// Serialize the list of ATTACH queries to a string. WriteBufferFromOwnString buf; for (const ASTPtr & query : queries) { formatAST(*query, buf, false, true); buf.write(";\n", 2); } return buf.str(); } AccessEntityPtr deserializeAccessEntityImpl(const String & definition) { ASTs queries; ParserAttachAccessEntity parser; const char * begin = definition.data(); /// begin of current query const char * pos = begin; /// parser moves pos from begin to the end of current query const char * end = begin + definition.size(); while (pos < end) { queries.emplace_back(parseQueryAndMovePosition(parser, pos, end, "", true, 0, DBMS_DEFAULT_MAX_PARSER_DEPTH)); while (isWhitespaceASCII(*pos) || *pos == ';') ++pos; } /// Number of queries interpreted. size_t query_index = 0; /// If there is no "SET rbac_version = ..." query we assume that it's the initial version. UInt64 rbac_version = RBAC_INITIAL_VERSION; /// Interpret the AST to build an access entity. std::shared_ptr user; std::shared_ptr role; std::shared_ptr policy; std::shared_ptr quota; std::shared_ptr profile; AccessEntityPtr res; for (const auto & query : queries) { if (auto * set_query = query->as()) { if ((set_query->changes.size() != 1) || (set_query->changes[0].name != RBAC_VERSION_SETTING_NAME)) throw Exception(ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION, "SET query in this file is only allowed to set {}", RBAC_VERSION_SETTING_NAME); if (query_index != 0) throw Exception(ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION, "SET {} should be the first query in the file", RBAC_VERSION_SETTING_NAME); rbac_version = set_query->changes[0].value.safeGet(); if (rbac_version < RBAC_INITIAL_VERSION) throw Exception(ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION, "{} must be >= {}", RBAC_VERSION_SETTING_NAME, RBAC_INITIAL_VERSION); if (rbac_version > RBAC_LATEST_VERSION) throw Exception(ErrorCodes::RBAC_VERSION_IS_TOO_NEW, "{} must be <= {}, {} {} is too new", RBAC_VERSION_SETTING_NAME, RBAC_LATEST_VERSION, RBAC_VERSION_SETTING_NAME, rbac_version); } else if (auto * create_user_query = query->as()) { if (res) throw Exception("Two access entities attached in the same file", ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION); res = user = std::make_unique(); InterpreterCreateUserQuery::updateUserFromQuery(*user, *create_user_query); } else if (auto * create_role_query = query->as()) { if (res) throw Exception("Two access entities attached in the same file", ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION); res = role = std::make_unique(); InterpreterCreateRoleQuery::updateRoleFromQuery(*role, *create_role_query); } else if (auto * create_policy_query = query->as()) { if (res) throw Exception("Two access entities attached in the same file", ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION); res = policy = std::make_unique(); InterpreterCreateRowPolicyQuery::updateRowPolicyFromQuery(*policy, *create_policy_query, rbac_version); } else if (auto * create_quota_query = query->as()) { if (res) throw Exception("Two access entities attached in the same file", ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION); res = quota = std::make_unique(); InterpreterCreateQuotaQuery::updateQuotaFromQuery(*quota, *create_quota_query); } else if (auto * create_profile_query = query->as()) { if (res) throw Exception("Two access entities attached in the same file", ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION); res = profile = std::make_unique(); InterpreterCreateSettingsProfileQuery::updateSettingsProfileFromQuery(*profile, *create_profile_query); } else if (auto * grant_query = query->as()) { if (!user && !role) throw Exception("A user or role should be attached before grant", ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION); if (user) InterpreterGrantQuery::updateUserFromQuery(*user, *grant_query); else InterpreterGrantQuery::updateRoleFromQuery(*role, *grant_query); } else throw Exception("No interpreter found for query " + query->getID(), ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION); ++query_index; } if (!res) throw Exception("No access entities attached", ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION); return res; } AccessEntityPtr deserializeAccessEntity(const String & definition, const String & file_path) { if (file_path.empty()) return deserializeAccessEntityImpl(definition); try { return deserializeAccessEntityImpl(definition); } catch (Exception & e) { e.addMessage("Could not parse " + file_path); e.rethrow(); __builtin_unreachable(); } } }