2020-02-04 22:37:04 +00:00
|
|
|
#include <Interpreters/InterpreterGrantQuery.h>
|
2021-02-23 10:30:15 +00:00
|
|
|
#include <Interpreters/QueryLog.h>
|
2020-02-04 22:37:04 +00:00
|
|
|
#include <Parsers/ASTGrantQuery.h>
|
2020-05-30 20:10:45 +00:00
|
|
|
#include <Parsers/ASTRolesOrUsersSet.h>
|
2020-02-04 22:37:04 +00:00
|
|
|
#include <Interpreters/Context.h>
|
2020-11-03 13:47:26 +00:00
|
|
|
#include <Interpreters/executeDDLQueryOnCluster.h>
|
2020-02-04 22:37:04 +00:00
|
|
|
#include <Access/AccessControlManager.h>
|
2020-03-07 17:37:38 +00:00
|
|
|
#include <Access/ContextAccess.h>
|
2020-05-30 20:10:45 +00:00
|
|
|
#include <Access/RolesOrUsersSet.h>
|
2020-02-04 22:37:04 +00:00
|
|
|
#include <Access/User.h>
|
2020-02-17 02:59:56 +00:00
|
|
|
#include <Access/Role.h>
|
|
|
|
#include <boost/range/algorithm/copy.hpp>
|
2020-07-02 00:09:57 +00:00
|
|
|
#include <boost/range/algorithm/set_algorithm.hpp>
|
2020-02-04 22:37:04 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
2021-02-26 22:37:00 +00:00
|
|
|
namespace ErrorCodes
|
2020-02-04 22:37:04 +00:00
|
|
|
{
|
2021-02-26 22:37:00 +00:00
|
|
|
extern const int LOGICAL_ERROR;
|
|
|
|
}
|
2020-07-02 00:09:57 +00:00
|
|
|
|
2021-02-26 22:37:00 +00:00
|
|
|
namespace
|
|
|
|
{
|
2020-07-02 00:09:57 +00:00
|
|
|
template <typename T>
|
|
|
|
void updateFromQueryTemplate(
|
|
|
|
T & grantee,
|
|
|
|
const ASTGrantQuery & query,
|
2020-10-12 18:29:02 +00:00
|
|
|
const std::vector<UUID> & roles_to_grant_or_revoke)
|
2020-02-04 22:37:04 +00:00
|
|
|
{
|
2020-02-17 02:59:56 +00:00
|
|
|
if (!query.access_rights_elements.empty())
|
|
|
|
{
|
2021-02-26 22:37:00 +00:00
|
|
|
if (query.is_revoke)
|
|
|
|
grantee.access.revoke(query.access_rights_elements);
|
2020-02-17 02:59:56 +00:00
|
|
|
else
|
2021-02-26 22:37:00 +00:00
|
|
|
grantee.access.grant(query.access_rights_elements);
|
2020-02-17 02:59:56 +00:00
|
|
|
}
|
|
|
|
|
2020-10-12 18:29:02 +00:00
|
|
|
if (!roles_to_grant_or_revoke.empty())
|
2020-02-04 22:37:04 +00:00
|
|
|
{
|
2021-02-26 22:37:00 +00:00
|
|
|
if (query.is_revoke)
|
2020-10-12 18:29:02 +00:00
|
|
|
{
|
|
|
|
if (query.admin_option)
|
2021-02-26 22:37:00 +00:00
|
|
|
grantee.granted_roles.revokeAdminOption(roles_to_grant_or_revoke);
|
2020-10-12 18:29:02 +00:00
|
|
|
else
|
2021-02-26 22:37:00 +00:00
|
|
|
grantee.granted_roles.revoke(roles_to_grant_or_revoke);
|
2020-10-12 18:29:02 +00:00
|
|
|
}
|
2020-02-17 02:59:56 +00:00
|
|
|
else
|
|
|
|
{
|
2020-10-12 18:29:02 +00:00
|
|
|
if (query.admin_option)
|
2021-02-26 22:37:00 +00:00
|
|
|
grantee.granted_roles.grantWithAdminOption(roles_to_grant_or_revoke);
|
2020-10-12 18:29:02 +00:00
|
|
|
else
|
2021-02-26 22:37:00 +00:00
|
|
|
grantee.granted_roles.grant(roles_to_grant_or_revoke);
|
2020-02-17 02:59:56 +00:00
|
|
|
}
|
2020-02-04 22:37:04 +00:00
|
|
|
}
|
2020-02-21 19:27:12 +00:00
|
|
|
}
|
2020-07-02 00:09:57 +00:00
|
|
|
|
|
|
|
void updateFromQueryImpl(
|
|
|
|
IAccessEntity & grantee,
|
|
|
|
const ASTGrantQuery & query,
|
2020-10-12 18:29:02 +00:00
|
|
|
const std::vector<UUID> & roles_to_grant_or_revoke)
|
2020-07-02 00:09:57 +00:00
|
|
|
{
|
|
|
|
if (auto * user = typeid_cast<User *>(&grantee))
|
2020-10-12 18:29:02 +00:00
|
|
|
updateFromQueryTemplate(*user, query, roles_to_grant_or_revoke);
|
2020-07-02 00:09:57 +00:00
|
|
|
else if (auto * role = typeid_cast<Role *>(&grantee))
|
2020-10-12 18:29:02 +00:00
|
|
|
updateFromQueryTemplate(*role, query, roles_to_grant_or_revoke);
|
2020-07-02 00:09:57 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 22:37:00 +00:00
|
|
|
void checkGrantOption(
|
|
|
|
const AccessControlManager & access_control,
|
|
|
|
const ContextAccess & access,
|
|
|
|
const ASTGrantQuery & query,
|
|
|
|
const std::vector<UUID> & grantees_from_query)
|
|
|
|
{
|
|
|
|
const auto & elements = query.access_rights_elements;
|
|
|
|
if (elements.empty())
|
|
|
|
return;
|
2020-07-02 00:09:57 +00:00
|
|
|
|
2021-02-26 22:37:00 +00:00
|
|
|
/// To execute the command GRANT the current user needs to have the access granted
|
|
|
|
/// with GRANT OPTION.
|
|
|
|
if (!query.is_revoke)
|
|
|
|
{
|
|
|
|
access.checkGrantOption(elements);
|
|
|
|
return;
|
|
|
|
}
|
2020-07-02 00:09:57 +00:00
|
|
|
|
2021-02-26 22:37:00 +00:00
|
|
|
if (access.hasGrantOption(elements))
|
|
|
|
return;
|
2020-10-12 18:29:02 +00:00
|
|
|
|
2021-02-26 22:37:00 +00:00
|
|
|
/// Special case for the command REVOKE: it's possible that the current user doesn't have
|
|
|
|
/// the access granted with GRANT OPTION but it's still ok because the roles or users
|
|
|
|
/// from whom the access rights will be revoked don't have the specified access granted either.
|
2020-10-12 18:29:02 +00:00
|
|
|
///
|
|
|
|
/// For example, to execute
|
|
|
|
/// GRANT ALL ON mydb.* TO role1
|
|
|
|
/// REVOKE ALL ON *.* FROM role1
|
2021-02-26 22:37:00 +00:00
|
|
|
/// the current user needs to have grants only on the 'mydb' database.
|
|
|
|
AccessRights all_granted_access;
|
|
|
|
for (const auto & id : grantees_from_query)
|
2020-07-02 00:09:57 +00:00
|
|
|
{
|
2021-02-26 22:37:00 +00:00
|
|
|
auto entity = access_control.tryRead(id);
|
|
|
|
if (auto role = typeid_cast<RolePtr>(entity))
|
|
|
|
all_granted_access.makeUnion(role->access);
|
|
|
|
else if (auto user = typeid_cast<UserPtr>(entity))
|
|
|
|
all_granted_access.makeUnion(user->access);
|
|
|
|
}
|
|
|
|
|
|
|
|
AccessRights required_access;
|
|
|
|
if (elements[0].is_partial_revoke)
|
|
|
|
{
|
|
|
|
AccessRightsElements non_revoke_elements = elements;
|
|
|
|
std::for_each(non_revoke_elements.begin(), non_revoke_elements.end(), [&](AccessRightsElement & element) { element.is_partial_revoke = false; });
|
|
|
|
required_access.grant(non_revoke_elements);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
required_access.grant(elements);
|
2020-07-02 00:09:57 +00:00
|
|
|
}
|
2021-02-26 22:37:00 +00:00
|
|
|
required_access.makeIntersection(all_granted_access);
|
2020-10-12 18:29:02 +00:00
|
|
|
|
2021-02-26 22:37:00 +00:00
|
|
|
for (auto & required_access_element : required_access.getElements())
|
|
|
|
{
|
|
|
|
if (!required_access_element.is_partial_revoke && (required_access_element.grant_option || !elements[0].grant_option))
|
|
|
|
access.checkGrantOption(required_access_element);
|
|
|
|
}
|
2020-02-21 19:27:12 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 22:37:00 +00:00
|
|
|
|
|
|
|
std::vector<UUID> getRoleIDsAndCheckAdminOption(
|
|
|
|
const AccessControlManager & access_control,
|
|
|
|
const ContextAccess & access,
|
|
|
|
const ASTGrantQuery & query,
|
|
|
|
const RolesOrUsersSet & roles_from_query,
|
|
|
|
const std::vector<UUID> & grantees_from_query)
|
2020-07-02 00:09:57 +00:00
|
|
|
{
|
2021-02-26 22:37:00 +00:00
|
|
|
std::vector<UUID> matching_ids;
|
|
|
|
|
|
|
|
if (!query.is_revoke)
|
|
|
|
{
|
|
|
|
matching_ids = roles_from_query.getMatchingIDs(access_control);
|
|
|
|
access.checkAdminOption(matching_ids);
|
|
|
|
return matching_ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!roles_from_query.all)
|
|
|
|
{
|
|
|
|
matching_ids = roles_from_query.getMatchingIDs();
|
|
|
|
if (access.hasAdminOption(matching_ids))
|
|
|
|
return matching_ids;
|
|
|
|
}
|
2020-10-12 18:29:02 +00:00
|
|
|
|
2021-02-26 22:37:00 +00:00
|
|
|
/// Special case for the command REVOKE: it's possible that the current user doesn't have the admin option
|
|
|
|
/// for some of the specified roles but it's still ok because the roles or users from whom the roles will be
|
|
|
|
/// revoked from don't have the specified roles granted either.
|
2020-10-12 18:29:02 +00:00
|
|
|
///
|
|
|
|
/// For example, to execute
|
|
|
|
/// GRANT role2 TO role1
|
|
|
|
/// REVOKE ALL FROM role1
|
|
|
|
/// the current user needs to have only 'role2' to be granted with admin option (not all the roles).
|
2021-02-26 22:37:00 +00:00
|
|
|
GrantedRoles all_granted_roles;
|
|
|
|
for (const auto & id : grantees_from_query)
|
2020-10-12 18:29:02 +00:00
|
|
|
{
|
2021-02-26 22:37:00 +00:00
|
|
|
auto entity = access_control.tryRead(id);
|
|
|
|
if (auto role = typeid_cast<RolePtr>(entity))
|
|
|
|
all_granted_roles.makeUnion(role->granted_roles);
|
|
|
|
else if (auto user = typeid_cast<UserPtr>(entity))
|
|
|
|
all_granted_roles.makeUnion(user->granted_roles);
|
2020-10-12 18:29:02 +00:00
|
|
|
}
|
2020-04-05 23:03:20 +00:00
|
|
|
|
2021-02-26 22:37:00 +00:00
|
|
|
const auto & all_granted_roles_set = query.admin_option ? all_granted_roles.getGrantedWithAdminOption() : all_granted_roles.getGranted();
|
|
|
|
if (roles_from_query.all)
|
|
|
|
boost::range::set_difference(all_granted_roles_set, roles_from_query.except_ids, std::back_inserter(matching_ids));
|
|
|
|
else
|
|
|
|
boost::range::remove_erase_if(matching_ids, [&](const UUID & id) { return !all_granted_roles_set.count(id); });
|
|
|
|
access.checkAdminOption(matching_ids);
|
|
|
|
return matching_ids;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BlockIO InterpreterGrantQuery::execute()
|
|
|
|
{
|
|
|
|
auto & query = query_ptr->as<ASTGrantQuery &>();
|
|
|
|
|
|
|
|
query.replaceCurrentUserTag(context.getUserName());
|
|
|
|
query.access_rights_elements.eraseNonGrantable();
|
|
|
|
|
|
|
|
if (!query.access_rights_elements.sameOptions())
|
|
|
|
throw Exception("Elements of an ASTGrantQuery are expected to have the same options", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
if (!query.access_rights_elements.empty() && query.access_rights_elements[0].is_partial_revoke && !query.is_revoke)
|
|
|
|
throw Exception("A partial revoke should be revoked, not granted", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
|
|
auto & access_control = context.getAccessControlManager();
|
|
|
|
std::optional<RolesOrUsersSet> roles_set;
|
|
|
|
if (query.roles)
|
|
|
|
roles_set = RolesOrUsersSet{*query.roles, access_control};
|
|
|
|
|
|
|
|
std::vector<UUID> grantees = RolesOrUsersSet{*query.grantees, access_control, context.getUserID()}.getMatchingIDs(access_control);
|
|
|
|
|
|
|
|
/// Check if the current user has corresponding roles granted with admin option.
|
|
|
|
std::vector<UUID> roles;
|
|
|
|
if (roles_set)
|
|
|
|
roles = getRoleIDsAndCheckAdminOption(access_control, *context.getAccess(), query, *roles_set, grantees);
|
|
|
|
|
|
|
|
if (!query.cluster.empty())
|
|
|
|
{
|
|
|
|
/// To execute the command GRANT the current user needs to have the access granted with GRANT OPTION.
|
|
|
|
auto required_access = query.access_rights_elements;
|
|
|
|
std::for_each(required_access.begin(), required_access.end(), [&](AccessRightsElement & element) { element.grant_option = true; });
|
|
|
|
return executeDDLQueryOnCluster(query_ptr, context, std::move(required_access));
|
2020-07-02 00:09:57 +00:00
|
|
|
}
|
2020-02-21 19:27:12 +00:00
|
|
|
|
2021-02-26 22:37:00 +00:00
|
|
|
query.replaceEmptyDatabase(context.getCurrentDatabase());
|
|
|
|
|
|
|
|
/// Check if the current user has corresponding access rights with grant option.
|
|
|
|
if (!query.access_rights_elements.empty())
|
|
|
|
checkGrantOption(access_control, *context.getAccess(), query, grantees);
|
|
|
|
|
|
|
|
/// Update roles and users listed in `grantees`.
|
2020-02-21 19:27:12 +00:00
|
|
|
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
|
|
|
{
|
|
|
|
auto clone = entity->clone();
|
2021-02-26 22:37:00 +00:00
|
|
|
updateFromQueryImpl(*clone, query, roles);
|
2020-07-02 00:09:57 +00:00
|
|
|
return clone;
|
2020-02-04 22:37:04 +00:00
|
|
|
};
|
|
|
|
|
2021-02-26 22:37:00 +00:00
|
|
|
access_control.update(grantees, update_func);
|
2020-02-10 02:26:56 +00:00
|
|
|
|
2020-02-04 22:37:04 +00:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2020-02-21 19:27:12 +00:00
|
|
|
|
|
|
|
void InterpreterGrantQuery::updateUserFromQuery(User & user, const ASTGrantQuery & query)
|
|
|
|
{
|
2020-10-12 18:29:02 +00:00
|
|
|
std::vector<UUID> roles_to_grant_or_revoke;
|
2020-02-21 19:27:12 +00:00
|
|
|
if (query.roles)
|
2020-10-12 18:29:02 +00:00
|
|
|
roles_to_grant_or_revoke = RolesOrUsersSet{*query.roles}.getMatchingIDs();
|
|
|
|
updateFromQueryImpl(user, query, roles_to_grant_or_revoke);
|
2020-02-21 19:27:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void InterpreterGrantQuery::updateRoleFromQuery(Role & role, const ASTGrantQuery & query)
|
|
|
|
{
|
2020-10-12 18:29:02 +00:00
|
|
|
std::vector<UUID> roles_to_grant_or_revoke;
|
2020-02-21 19:27:12 +00:00
|
|
|
if (query.roles)
|
2020-10-12 18:29:02 +00:00
|
|
|
roles_to_grant_or_revoke = RolesOrUsersSet{*query.roles}.getMatchingIDs();
|
|
|
|
updateFromQueryImpl(role, query, roles_to_grant_or_revoke);
|
2020-02-21 19:27:12 +00:00
|
|
|
}
|
|
|
|
|
2021-02-23 10:30:15 +00:00
|
|
|
void InterpreterGrantQuery::extendQueryLogElemImpl(QueryLogElement & elem, const ASTPtr & /*ast*/, const Context &) const
|
|
|
|
{
|
|
|
|
auto & query = query_ptr->as<ASTGrantQuery &>();
|
2021-02-26 22:37:00 +00:00
|
|
|
if (query.is_revoke)
|
2021-02-23 10:30:15 +00:00
|
|
|
elem.query_kind = "Revoke";
|
2021-02-26 22:37:00 +00:00
|
|
|
else
|
|
|
|
elem.query_kind = "Grant";
|
2021-02-23 10:30:15 +00:00
|
|
|
}
|
|
|
|
|
2020-02-04 22:37:04 +00:00
|
|
|
}
|