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
|
|
|
|
{
|
2020-02-21 19:27:12 +00:00
|
|
|
namespace
|
2020-02-04 22:37:04 +00:00
|
|
|
{
|
2020-07-02 00:09:57 +00:00
|
|
|
using Kind = ASTGrantQuery::Kind;
|
|
|
|
|
|
|
|
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())
|
|
|
|
{
|
|
|
|
if (query.kind == Kind::GRANT)
|
2020-10-12 18:29:02 +00:00
|
|
|
{
|
|
|
|
if (query.grant_option)
|
|
|
|
grantee.access.grantWithGrantOption(query.access_rights_elements);
|
|
|
|
else
|
|
|
|
grantee.access.grant(query.access_rights_elements);
|
|
|
|
}
|
2020-02-17 02:59:56 +00:00
|
|
|
else
|
2020-10-12 18:29:02 +00:00
|
|
|
{
|
|
|
|
if (query.grant_option)
|
|
|
|
grantee.access.revokeGrantOption(query.access_rights_elements);
|
|
|
|
else
|
|
|
|
grantee.access.revoke(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
|
|
|
{
|
2020-02-17 02:59:56 +00:00
|
|
|
if (query.kind == Kind::GRANT)
|
2020-10-12 18:29:02 +00:00
|
|
|
{
|
|
|
|
if (query.admin_option)
|
|
|
|
grantee.granted_roles.grantWithAdminOption(roles_to_grant_or_revoke);
|
|
|
|
else
|
|
|
|
grantee.granted_roles.grant(roles_to_grant_or_revoke);
|
|
|
|
}
|
2020-02-17 02:59:56 +00:00
|
|
|
else
|
|
|
|
{
|
2020-10-12 18:29:02 +00:00
|
|
|
if (query.admin_option)
|
|
|
|
grantee.granted_roles.revokeAdminOption(roles_to_grant_or_revoke);
|
|
|
|
else
|
|
|
|
grantee.granted_roles.revoke(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
|
|
|
}
|
2020-02-21 19:27:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BlockIO InterpreterGrantQuery::execute()
|
|
|
|
{
|
2020-04-05 23:03:20 +00:00
|
|
|
auto & query = query_ptr->as<ASTGrantQuery &>();
|
2020-06-20 22:44:52 +00:00
|
|
|
query.replaceCurrentUserTagWithName(context.getUserName());
|
2020-07-02 00:09:57 +00:00
|
|
|
|
|
|
|
if (!query.cluster.empty())
|
|
|
|
return executeDDLQueryOnCluster(query_ptr, context, query.access_rights_elements, true);
|
|
|
|
|
2020-03-07 17:37:38 +00:00
|
|
|
auto access = context.getAccess();
|
2020-06-20 22:44:52 +00:00
|
|
|
auto & access_control = context.getAccessControlManager();
|
2020-07-02 00:09:57 +00:00
|
|
|
query.replaceEmptyDatabaseWithCurrent(context.getCurrentDatabase());
|
2020-02-21 19:27:12 +00:00
|
|
|
|
2020-10-12 18:29:02 +00:00
|
|
|
RolesOrUsersSet roles_set;
|
2020-02-21 19:27:12 +00:00
|
|
|
if (query.roles)
|
2020-10-12 18:29:02 +00:00
|
|
|
roles_set = RolesOrUsersSet{*query.roles, access_control};
|
2020-07-02 00:09:57 +00:00
|
|
|
|
|
|
|
std::vector<UUID> to_roles = RolesOrUsersSet{*query.to_roles, access_control, context.getUserID()}.getMatchingIDs(access_control);
|
|
|
|
|
2020-10-12 18:29:02 +00:00
|
|
|
/// Check if the current user has corresponding access rights with grant option.
|
|
|
|
if (!query.access_rights_elements.empty())
|
2020-02-21 19:27:12 +00:00
|
|
|
{
|
2020-10-12 18:29:02 +00:00
|
|
|
query.access_rights_elements.removeNonGrantableFlags();
|
|
|
|
|
|
|
|
/// Special case for REVOKE: it's possible that the current user doesn't have the grant option for all
|
|
|
|
/// the specified access rights and that's ok because the roles or users which the access rights
|
|
|
|
/// will be revoked from don't have the specified access rights either.
|
|
|
|
///
|
|
|
|
/// For example, to execute
|
|
|
|
/// GRANT ALL ON mydb.* TO role1
|
|
|
|
/// REVOKE ALL ON *.* FROM role1
|
|
|
|
/// the current user needs to have access rights only for the 'mydb' database.
|
|
|
|
if ((query.kind == Kind::REVOKE) && !access->hasGrantOption(query.access_rights_elements))
|
2020-07-02 00:09:57 +00:00
|
|
|
{
|
2020-10-12 18:29:02 +00:00
|
|
|
AccessRights max_access;
|
|
|
|
for (const auto & id : to_roles)
|
|
|
|
{
|
|
|
|
auto entity = access_control.tryRead(id);
|
|
|
|
if (auto role = typeid_cast<RolePtr>(entity))
|
|
|
|
max_access.makeUnion(role->access);
|
|
|
|
else if (auto user = typeid_cast<UserPtr>(entity))
|
|
|
|
max_access.makeUnion(user->access);
|
|
|
|
}
|
|
|
|
AccessRights access_to_revoke;
|
|
|
|
if (query.grant_option)
|
|
|
|
access_to_revoke.grantWithGrantOption(query.access_rights_elements);
|
|
|
|
else
|
|
|
|
access_to_revoke.grant(query.access_rights_elements);
|
|
|
|
access_to_revoke.makeIntersection(max_access);
|
|
|
|
AccessRightsElements filtered_access_to_revoke;
|
|
|
|
for (auto & element : access_to_revoke.getElements())
|
|
|
|
{
|
|
|
|
if ((element.kind == Kind::GRANT) && (element.grant_option || !query.grant_option))
|
|
|
|
filtered_access_to_revoke.emplace_back(std::move(element));
|
|
|
|
}
|
|
|
|
query.access_rights_elements = std::move(filtered_access_to_revoke);
|
2020-07-02 00:09:57 +00:00
|
|
|
}
|
2020-10-12 18:29:02 +00:00
|
|
|
|
|
|
|
access->checkGrantOption(query.access_rights_elements);
|
2020-02-21 19:27:12 +00:00
|
|
|
}
|
|
|
|
|
2020-10-12 18:29:02 +00:00
|
|
|
/// Check if the current user has corresponding roles granted with admin option.
|
|
|
|
std::vector<UUID> roles_to_grant_or_revoke;
|
|
|
|
if (!roles_set.empty())
|
2020-07-02 00:09:57 +00:00
|
|
|
{
|
2020-10-12 18:29:02 +00:00
|
|
|
bool all = roles_set.all;
|
|
|
|
if (!all)
|
|
|
|
roles_to_grant_or_revoke = roles_set.getMatchingIDs();
|
|
|
|
|
|
|
|
/// Special case for REVOKE: it's possible that the current user doesn't have the admin option for all
|
|
|
|
/// the specified roles and that's ok because the roles or users which the roles will be revoked from
|
|
|
|
/// don't have the specified roles granted either.
|
|
|
|
///
|
|
|
|
/// 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).
|
|
|
|
if ((query.kind == Kind::REVOKE) && (roles_set.all || !access->hasAdminOption(roles_to_grant_or_revoke)))
|
|
|
|
{
|
|
|
|
auto & roles_to_revoke = roles_to_grant_or_revoke;
|
|
|
|
boost::container::flat_set<UUID> max_roles;
|
|
|
|
for (const auto & id : to_roles)
|
|
|
|
{
|
|
|
|
auto entity = access_control.tryRead(id);
|
|
|
|
auto add_to_max_roles = [&](const GrantedRoles & granted_roles)
|
|
|
|
{
|
|
|
|
if (query.admin_option)
|
|
|
|
max_roles.insert(granted_roles.roles_with_admin_option.begin(), granted_roles.roles_with_admin_option.end());
|
|
|
|
else
|
|
|
|
max_roles.insert(granted_roles.roles.begin(), granted_roles.roles.end());
|
|
|
|
};
|
|
|
|
if (auto role = typeid_cast<RolePtr>(entity))
|
|
|
|
add_to_max_roles(role->granted_roles);
|
|
|
|
else if (auto user = typeid_cast<UserPtr>(entity))
|
|
|
|
add_to_max_roles(user->granted_roles);
|
|
|
|
}
|
|
|
|
if (roles_set.all)
|
|
|
|
boost::range::set_difference(max_roles, roles_set.except_ids, std::back_inserter(roles_to_revoke));
|
|
|
|
else
|
|
|
|
boost::range::remove_erase_if(roles_to_revoke, [&](const UUID & id) { return !max_roles.count(id); });
|
|
|
|
}
|
2020-04-05 23:03:20 +00:00
|
|
|
|
2020-10-12 18:29:02 +00:00
|
|
|
access->checkAdminOption(roles_to_grant_or_revoke);
|
2020-07-02 00:09:57 +00:00
|
|
|
}
|
2020-02-21 19:27:12 +00:00
|
|
|
|
2020-10-12 18:29:02 +00:00
|
|
|
/// Update roles and users listed in `to_roles`.
|
2020-02-21 19:27:12 +00:00
|
|
|
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
|
|
|
{
|
|
|
|
auto clone = entity->clone();
|
2020-10-12 18:29:02 +00:00
|
|
|
updateFromQueryImpl(*clone, query, roles_to_grant_or_revoke);
|
2020-07-02 00:09:57 +00:00
|
|
|
return clone;
|
2020-02-04 22:37:04 +00:00
|
|
|
};
|
|
|
|
|
2020-02-10 02:26:56 +00:00
|
|
|
access_control.update(to_roles, update_func);
|
|
|
|
|
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 &>();
|
|
|
|
if (query.kind == Kind::GRANT)
|
|
|
|
elem.query_kind = "Grant";
|
|
|
|
else if (query.kind == Kind::REVOKE)
|
|
|
|
elem.query_kind = "Revoke";
|
|
|
|
}
|
|
|
|
|
2020-02-04 22:37:04 +00:00
|
|
|
}
|