mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-25 17:12:03 +00:00
Implement SQL queries for creating and controlling roles.
This commit is contained in:
parent
6671ca67eb
commit
e017bacc48
@ -483,6 +483,7 @@ namespace ErrorCodes
|
||||
extern const int INVALID_GRANT = 509;
|
||||
extern const int CACHE_DICTIONARY_UPDATE_FAIL = 510;
|
||||
extern const int UNKNOWN_ROLE = 511;
|
||||
extern const int SET_NON_GRANTED_ROLE = 512;
|
||||
|
||||
extern const int KEEPER_EXCEPTION = 999;
|
||||
extern const int POCO_EXCEPTION = 1000;
|
||||
|
62
dbms/src/Interpreters/InterpreterCreateRoleQuery.cpp
Normal file
62
dbms/src/Interpreters/InterpreterCreateRoleQuery.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include <Interpreters/InterpreterCreateRoleQuery.h>
|
||||
#include <Parsers/ASTCreateRoleQuery.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/Role.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
BlockIO InterpreterCreateRoleQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTCreateRoleQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
if (query.alter)
|
||||
context.checkAccess(AccessType::CREATE_ROLE | AccessType::DROP_ROLE);
|
||||
else
|
||||
context.checkAccess(AccessType::CREATE_ROLE);
|
||||
|
||||
if (query.alter)
|
||||
{
|
||||
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
||||
{
|
||||
auto updated_role = typeid_cast<std::shared_ptr<Role>>(entity->clone());
|
||||
updateRoleFromQuery(*updated_role, query);
|
||||
return updated_role;
|
||||
};
|
||||
if (query.if_exists)
|
||||
{
|
||||
if (auto id = access_control.find<Role>(query.name))
|
||||
access_control.tryUpdate(*id, update_func);
|
||||
}
|
||||
else
|
||||
access_control.update(access_control.getID<Role>(query.name), update_func);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto new_role = std::make_shared<Role>();
|
||||
updateRoleFromQuery(*new_role, query);
|
||||
|
||||
if (query.if_not_exists)
|
||||
access_control.tryInsert(new_role);
|
||||
else if (query.or_replace)
|
||||
access_control.insertOrReplace(new_role);
|
||||
else
|
||||
access_control.insert(new_role);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
void InterpreterCreateRoleQuery::updateRoleFromQuery(Role & role, const ASTCreateRoleQuery & query)
|
||||
{
|
||||
if (query.alter)
|
||||
{
|
||||
if (!query.new_name.empty())
|
||||
role.setName(query.new_name);
|
||||
}
|
||||
else
|
||||
role.setName(query.name);
|
||||
}
|
||||
}
|
26
dbms/src/Interpreters/InterpreterCreateRoleQuery.h
Normal file
26
dbms/src/Interpreters/InterpreterCreateRoleQuery.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <Interpreters/IInterpreter.h>
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTCreateRoleQuery;
|
||||
struct Role;
|
||||
|
||||
|
||||
class InterpreterCreateRoleQuery : public IInterpreter
|
||||
{
|
||||
public:
|
||||
InterpreterCreateRoleQuery(const ASTPtr & query_ptr_, Context & context_) : query_ptr(query_ptr_), context(context_) {}
|
||||
|
||||
BlockIO execute() override;
|
||||
|
||||
private:
|
||||
void updateRoleFromQuery(Role & role, const ASTCreateRoleQuery & query);
|
||||
|
||||
ASTPtr query_ptr;
|
||||
Context & context;
|
||||
};
|
||||
}
|
@ -1,24 +1,47 @@
|
||||
#include <Interpreters/InterpreterCreateUserQuery.h>
|
||||
#include <Parsers/ASTCreateUserQuery.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/InterpreterSetRoleQuery.h>
|
||||
#include <Parsers/ASTCreateUserQuery.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/User.h>
|
||||
#include <Access/GenericRoleSet.h>
|
||||
#include <Access/AccessRightsContext.h>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int SET_NON_GRANTED_ROLE;
|
||||
}
|
||||
|
||||
|
||||
BlockIO InterpreterCreateUserQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTCreateUserQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
context.checkAccess(query.alter ? AccessType::ALTER_USER : AccessType::CREATE_USER);
|
||||
|
||||
GenericRoleSet * default_roles_from_query = nullptr;
|
||||
GenericRoleSet temp_role_set;
|
||||
if (query.default_roles)
|
||||
{
|
||||
default_roles_from_query = &temp_role_set;
|
||||
*default_roles_from_query = GenericRoleSet{*query.default_roles, access_control};
|
||||
if (!query.alter && !default_roles_from_query->all)
|
||||
{
|
||||
for (const UUID & role : default_roles_from_query->getMatchingIDs())
|
||||
context.getAccessRights()->checkAdminOption(role);
|
||||
}
|
||||
}
|
||||
|
||||
if (query.alter)
|
||||
{
|
||||
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
||||
{
|
||||
auto updated_user = typeid_cast<std::shared_ptr<User>>(entity->clone());
|
||||
updateUserFromQuery(*updated_user, query);
|
||||
updateUserFromQuery(*updated_user, query, default_roles_from_query);
|
||||
return updated_user;
|
||||
};
|
||||
if (query.if_exists)
|
||||
@ -32,7 +55,7 @@ BlockIO InterpreterCreateUserQuery::execute()
|
||||
else
|
||||
{
|
||||
auto new_user = std::make_shared<User>();
|
||||
updateUserFromQuery(*new_user, query);
|
||||
updateUserFromQuery(*new_user, query, default_roles_from_query);
|
||||
|
||||
if (query.if_not_exists)
|
||||
access_control.tryInsert(new_user);
|
||||
@ -46,7 +69,7 @@ BlockIO InterpreterCreateUserQuery::execute()
|
||||
}
|
||||
|
||||
|
||||
void InterpreterCreateUserQuery::updateUserFromQuery(User & user, const ASTCreateUserQuery & query)
|
||||
void InterpreterCreateUserQuery::updateUserFromQuery(User & user, const ASTCreateUserQuery & query, const GenericRoleSet * default_roles_from_query)
|
||||
{
|
||||
if (query.alter)
|
||||
{
|
||||
@ -66,7 +89,16 @@ void InterpreterCreateUserQuery::updateUserFromQuery(User & user, const ASTCreat
|
||||
if (query.add_hosts)
|
||||
user.allowed_client_hosts.add(*query.add_hosts);
|
||||
|
||||
if (default_roles_from_query)
|
||||
{
|
||||
if (!query.alter && !default_roles_from_query->all)
|
||||
boost::range::copy(default_roles_from_query->getMatchingIDs(), std::inserter(user.granted_roles, user.granted_roles.end()));
|
||||
|
||||
InterpreterSetRoleQuery::updateUserSetDefaultRoles(user, *default_roles_from_query);
|
||||
}
|
||||
|
||||
if (query.profile)
|
||||
user.profile = *query.profile;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
namespace DB
|
||||
{
|
||||
class ASTCreateUserQuery;
|
||||
class GenericRoleSet;
|
||||
struct User;
|
||||
|
||||
|
||||
@ -18,7 +19,7 @@ public:
|
||||
BlockIO execute() override;
|
||||
|
||||
private:
|
||||
void updateUserFromQuery(User & user, const ASTCreateUserQuery & query);
|
||||
void updateUserFromQuery(User & user, const ASTCreateUserQuery & query, const GenericRoleSet * default_roles_from_query);
|
||||
|
||||
ASTPtr query_ptr;
|
||||
Context & context;
|
||||
|
@ -3,9 +3,10 @@
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <Access/User.h>
|
||||
#include <Access/Role.h>
|
||||
#include <Access/Quota.h>
|
||||
#include <Access/RowPolicy.h>
|
||||
#include <Access/User.h>
|
||||
#include <boost/range/algorithm/transform.hpp>
|
||||
|
||||
|
||||
@ -29,6 +30,16 @@ BlockIO InterpreterDropAccessEntityQuery::execute()
|
||||
return {};
|
||||
}
|
||||
|
||||
case Kind::ROLE:
|
||||
{
|
||||
context.checkAccess(AccessType::DROP_ROLE);
|
||||
if (query.if_exists)
|
||||
access_control.tryRemove(access_control.find<Role>(query.names));
|
||||
else
|
||||
access_control.remove(access_control.getIDs<Role>(query.names));
|
||||
return {};
|
||||
}
|
||||
|
||||
case Kind::QUOTA:
|
||||
{
|
||||
context.checkAccess(AccessType::DROP_QUOTA);
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <Parsers/ASTCheckQuery.h>
|
||||
#include <Parsers/ASTCreateQuery.h>
|
||||
#include <Parsers/ASTCreateUserQuery.h>
|
||||
#include <Parsers/ASTCreateRoleQuery.h>
|
||||
#include <Parsers/ASTCreateQuotaQuery.h>
|
||||
#include <Parsers/ASTCreateRowPolicyQuery.h>
|
||||
#include <Parsers/ASTDropAccessEntityQuery.h>
|
||||
@ -13,6 +14,7 @@
|
||||
#include <Parsers/ASTSelectQuery.h>
|
||||
#include <Parsers/ASTSelectWithUnionQuery.h>
|
||||
#include <Parsers/ASTSetQuery.h>
|
||||
#include <Parsers/ASTSetRoleQuery.h>
|
||||
#include <Parsers/ASTShowCreateAccessEntityQuery.h>
|
||||
#include <Parsers/ASTShowProcesslistQuery.h>
|
||||
#include <Parsers/ASTShowGrantsQuery.h>
|
||||
@ -29,6 +31,7 @@
|
||||
#include <Interpreters/InterpreterCheckQuery.h>
|
||||
#include <Interpreters/InterpreterCreateQuery.h>
|
||||
#include <Interpreters/InterpreterCreateUserQuery.h>
|
||||
#include <Interpreters/InterpreterCreateRoleQuery.h>
|
||||
#include <Interpreters/InterpreterCreateQuotaQuery.h>
|
||||
#include <Interpreters/InterpreterCreateRowPolicyQuery.h>
|
||||
#include <Interpreters/InterpreterDescribeQuery.h>
|
||||
@ -44,6 +47,7 @@
|
||||
#include <Interpreters/InterpreterSelectQuery.h>
|
||||
#include <Interpreters/InterpreterSelectWithUnionQuery.h>
|
||||
#include <Interpreters/InterpreterSetQuery.h>
|
||||
#include <Interpreters/InterpreterSetRoleQuery.h>
|
||||
#include <Interpreters/InterpreterShowCreateAccessEntityQuery.h>
|
||||
#include <Interpreters/InterpreterShowCreateQuery.h>
|
||||
#include <Interpreters/InterpreterShowProcesslistQuery.h>
|
||||
@ -126,6 +130,10 @@ std::unique_ptr<IInterpreter> InterpreterFactory::get(ASTPtr & query, Context &
|
||||
/// readonly is checked inside InterpreterSetQuery
|
||||
return std::make_unique<InterpreterSetQuery>(query, context);
|
||||
}
|
||||
else if (query->as<ASTSetRoleQuery>())
|
||||
{
|
||||
return std::make_unique<InterpreterSetRoleQuery>(query, context);
|
||||
}
|
||||
else if (query->as<ASTOptimizeQuery>())
|
||||
{
|
||||
return std::make_unique<InterpreterOptimizeQuery>(query, context);
|
||||
@ -186,6 +194,10 @@ std::unique_ptr<IInterpreter> InterpreterFactory::get(ASTPtr & query, Context &
|
||||
{
|
||||
return std::make_unique<InterpreterCreateUserQuery>(query, context);
|
||||
}
|
||||
else if (query->as<ASTCreateRoleQuery>())
|
||||
{
|
||||
return std::make_unique<InterpreterCreateRoleQuery>(query, context);
|
||||
}
|
||||
else if (query->as<ASTCreateQuotaQuery>())
|
||||
{
|
||||
return std::make_unique<InterpreterCreateQuotaQuery>(query, context);
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <Access/AccessRightsContext.h>
|
||||
#include <Access/GenericRoleSet.h>
|
||||
#include <Access/User.h>
|
||||
#include <Access/Role.h>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -16,32 +18,89 @@ BlockIO InterpreterGrantQuery::execute()
|
||||
context.getAccessRights()->checkGrantOption(query.access_rights_elements);
|
||||
|
||||
using Kind = ASTGrantQuery::Kind;
|
||||
std::vector<UUID> to_roles = GenericRoleSet{*query.to_roles, access_control, context.getUserID()}.getMatchingUsers(access_control);
|
||||
std::vector<UUID> roles;
|
||||
if (query.roles)
|
||||
{
|
||||
roles = GenericRoleSet{*query.roles, access_control}.getMatchingRoles(access_control);
|
||||
for (const UUID & role : roles)
|
||||
context.getAccessRights()->checkAdminOption(role);
|
||||
}
|
||||
|
||||
std::vector<UUID> to_roles = GenericRoleSet{*query.to_roles, access_control, context.getUserID()}.getMatchingUsersAndRoles(access_control);
|
||||
String current_database = context.getCurrentDatabase();
|
||||
using Kind = ASTGrantQuery::Kind;
|
||||
|
||||
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
||||
{
|
||||
auto updated_user = typeid_cast<std::shared_ptr<User>>(entity->clone());
|
||||
if (query.kind == Kind::GRANT)
|
||||
auto clone = entity->clone();
|
||||
AccessRights * access = nullptr;
|
||||
AccessRights * access_with_grant_option = nullptr;
|
||||
boost::container::flat_set<UUID> * granted_roles = nullptr;
|
||||
boost::container::flat_set<UUID> * granted_roles_with_admin_option = nullptr;
|
||||
GenericRoleSet * default_roles = nullptr;
|
||||
if (auto user = typeid_cast<std::shared_ptr<User>>(clone))
|
||||
{
|
||||
updated_user->access.grant(query.access_rights_elements, current_database);
|
||||
if (query.grant_option)
|
||||
updated_user->access_with_grant_option.grant(query.access_rights_elements, current_database);
|
||||
access = &user->access;
|
||||
access_with_grant_option = &user->access_with_grant_option;
|
||||
granted_roles = &user->granted_roles;
|
||||
granted_roles_with_admin_option = &user->granted_roles_with_admin_option;
|
||||
default_roles = &user->default_roles;
|
||||
}
|
||||
else if (context.getSettingsRef().partial_revokes)
|
||||
else if (auto role = typeid_cast<std::shared_ptr<Role>>(clone))
|
||||
{
|
||||
updated_user->access_with_grant_option.partialRevoke(query.access_rights_elements, current_database);
|
||||
if (!query.grant_option)
|
||||
updated_user->access.partialRevoke(query.access_rights_elements, current_database);
|
||||
access = &role->access;
|
||||
access_with_grant_option = &role->access_with_grant_option;
|
||||
granted_roles = &role->granted_roles;
|
||||
granted_roles_with_admin_option = &role->granted_roles_with_admin_option;
|
||||
}
|
||||
else
|
||||
return entity;
|
||||
|
||||
if (!query.access_rights_elements.empty())
|
||||
{
|
||||
updated_user->access_with_grant_option.revoke(query.access_rights_elements, current_database);
|
||||
if (!query.grant_option)
|
||||
updated_user->access.revoke(query.access_rights_elements, current_database);
|
||||
if (query.kind == Kind::GRANT)
|
||||
{
|
||||
access->grant(query.access_rights_elements, current_database);
|
||||
if (query.grant_option)
|
||||
access_with_grant_option->grant(query.access_rights_elements, current_database);
|
||||
}
|
||||
else if (context.getSettingsRef().partial_revokes)
|
||||
{
|
||||
access_with_grant_option->partialRevoke(query.access_rights_elements, current_database);
|
||||
if (!query.grant_option)
|
||||
access->partialRevoke(query.access_rights_elements, current_database);
|
||||
}
|
||||
else
|
||||
{
|
||||
access_with_grant_option->revoke(query.access_rights_elements, current_database);
|
||||
if (!query.grant_option)
|
||||
access->revoke(query.access_rights_elements, current_database);
|
||||
}
|
||||
}
|
||||
return updated_user;
|
||||
|
||||
if (!roles.empty())
|
||||
{
|
||||
if (query.kind == Kind::GRANT)
|
||||
{
|
||||
boost::range::copy(roles, std::inserter(*granted_roles, granted_roles->end()));
|
||||
if (query.admin_option)
|
||||
boost::range::copy(roles, std::inserter(*granted_roles_with_admin_option, granted_roles_with_admin_option->end()));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const UUID & role : roles)
|
||||
{
|
||||
granted_roles_with_admin_option->erase(role);
|
||||
if (!query.admin_option)
|
||||
{
|
||||
granted_roles->erase(role);
|
||||
if (default_roles)
|
||||
default_roles->ids.erase(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
};
|
||||
|
||||
access_control.update(to_roles, update_func);
|
||||
|
95
dbms/src/Interpreters/InterpreterSetRoleQuery.cpp
Normal file
95
dbms/src/Interpreters/InterpreterSetRoleQuery.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include <Interpreters/InterpreterSetRoleQuery.h>
|
||||
#include <Parsers/ASTSetRoleQuery.h>
|
||||
#include <Parsers/ASTGenericRoleSet.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Access/GenericRoleSet.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/User.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int SET_NON_GRANTED_ROLE;
|
||||
}
|
||||
|
||||
|
||||
BlockIO InterpreterSetRoleQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTSetRoleQuery &>();
|
||||
if (query.kind == ASTSetRoleQuery::Kind::SET_DEFAULT_ROLE)
|
||||
setDefaultRole(query);
|
||||
else
|
||||
setRole(query);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
void InterpreterSetRoleQuery::setRole(const ASTSetRoleQuery & query)
|
||||
{
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
auto & session_context = context.getSessionContext();
|
||||
auto user = session_context.getUser();
|
||||
|
||||
if (query.kind == ASTSetRoleQuery::Kind::SET_ROLE_DEFAULT)
|
||||
{
|
||||
session_context.setCurrentRolesDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
GenericRoleSet roles_from_query{*query.roles, access_control};
|
||||
std::vector<UUID> new_current_roles;
|
||||
if (roles_from_query.all)
|
||||
{
|
||||
for (const auto & id : user->granted_roles)
|
||||
if (roles_from_query.match(id))
|
||||
new_current_roles.push_back(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto & id : roles_from_query.getMatchingIDs())
|
||||
{
|
||||
if (!user->granted_roles.contains(id))
|
||||
throw Exception("Role should be granted to set current", ErrorCodes::SET_NON_GRANTED_ROLE);
|
||||
new_current_roles.push_back(id);
|
||||
}
|
||||
}
|
||||
session_context.setCurrentRoles(new_current_roles);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InterpreterSetRoleQuery::setDefaultRole(const ASTSetRoleQuery & query)
|
||||
{
|
||||
context.checkAccess(AccessType::CREATE_USER | AccessType::DROP_USER);
|
||||
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
std::vector<UUID> to_users = GenericRoleSet{*query.to_users, access_control, context.getUserID()}.getMatchingUsers(access_control);
|
||||
GenericRoleSet roles_from_query{*query.roles, access_control};
|
||||
|
||||
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
||||
{
|
||||
auto updated_user = typeid_cast<std::shared_ptr<User>>(entity->clone());
|
||||
updateUserSetDefaultRoles(*updated_user, roles_from_query);
|
||||
return updated_user;
|
||||
};
|
||||
|
||||
access_control.update(to_users, update_func);
|
||||
}
|
||||
|
||||
|
||||
void InterpreterSetRoleQuery::updateUserSetDefaultRoles(User & user, const GenericRoleSet & roles_from_query)
|
||||
{
|
||||
if (!roles_from_query.all)
|
||||
{
|
||||
for (const auto & id : roles_from_query.getMatchingIDs())
|
||||
{
|
||||
if (!user.granted_roles.contains(id))
|
||||
throw Exception("Role should be granted to set default", ErrorCodes::SET_NON_GRANTED_ROLE);
|
||||
}
|
||||
}
|
||||
user.default_roles = roles_from_query;
|
||||
}
|
||||
|
||||
}
|
30
dbms/src/Interpreters/InterpreterSetRoleQuery.h
Normal file
30
dbms/src/Interpreters/InterpreterSetRoleQuery.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <Interpreters/IInterpreter.h>
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTSetRoleQuery;
|
||||
class GenericRoleSet;
|
||||
struct User;
|
||||
|
||||
|
||||
class InterpreterSetRoleQuery : public IInterpreter
|
||||
{
|
||||
public:
|
||||
InterpreterSetRoleQuery(const ASTPtr & query_ptr_, Context & context_) : query_ptr(query_ptr_), context(context_) {}
|
||||
|
||||
BlockIO execute() override;
|
||||
|
||||
static void updateUserSetDefaultRoles(User & user, const GenericRoleSet & roles_from_query);
|
||||
|
||||
private:
|
||||
void setRole(const ASTSetRoleQuery & query);
|
||||
void setDefaultRole(const ASTSetRoleQuery & query);
|
||||
|
||||
ASTPtr query_ptr;
|
||||
Context & context;
|
||||
};
|
||||
}
|
@ -85,6 +85,9 @@ ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateUserQuery(const ASTShowC
|
||||
if (!user->profile.empty())
|
||||
create_query->profile = user->profile;
|
||||
|
||||
if (user->default_roles != GenericRoleSet::AllTag{})
|
||||
create_query->default_roles = GenericRoleSet{user->default_roles}.toAST(context.getAccessControlManager());
|
||||
|
||||
return create_query;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <DataTypes/DataTypeString.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/User.h>
|
||||
#include <Access/Role.h>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
@ -88,19 +89,44 @@ BlockInputStreamPtr InterpreterShowGrantsQuery::executeImpl()
|
||||
|
||||
ASTs InterpreterShowGrantsQuery::getGrantQueries(const ASTShowGrantsQuery & show_query) const
|
||||
{
|
||||
const auto & access_control = context.getAccessControlManager();
|
||||
UserPtr user;
|
||||
RolePtr role;
|
||||
if (show_query.current_user)
|
||||
user = context.getUser();
|
||||
else
|
||||
user = context.getAccessControlManager().read<User>(show_query.name);
|
||||
{
|
||||
user = access_control.tryRead<User>(show_query.name);
|
||||
if (!user)
|
||||
role = access_control.read<Role>(show_query.name);
|
||||
}
|
||||
|
||||
const AccessRights * access = nullptr;
|
||||
const AccessRights * access_with_grant_option = nullptr;
|
||||
const boost::container::flat_set<UUID> * granted_roles = nullptr;
|
||||
const boost::container::flat_set<UUID> * granted_roles_with_admin_option = nullptr;
|
||||
if (user)
|
||||
{
|
||||
access = &user->access;
|
||||
access_with_grant_option = &user->access_with_grant_option;
|
||||
granted_roles = &user->granted_roles;
|
||||
granted_roles_with_admin_option = &user->granted_roles_with_admin_option;
|
||||
}
|
||||
else
|
||||
{
|
||||
access = &role->access;
|
||||
access_with_grant_option = &role->access_with_grant_option;
|
||||
granted_roles = &role->granted_roles;
|
||||
granted_roles_with_admin_option = &role->granted_roles_with_admin_option;
|
||||
}
|
||||
|
||||
ASTs res;
|
||||
|
||||
for (bool grant_option : {true, false})
|
||||
{
|
||||
if (!grant_option && (user->access == user->access_with_grant_option))
|
||||
if (!grant_option && (*access == *access_with_grant_option))
|
||||
continue;
|
||||
const auto & access_rights = grant_option ? user->access_with_grant_option : user->access;
|
||||
const auto & access_rights = grant_option ? *access_with_grant_option : *access;
|
||||
const auto grouped_elements = groupByTable(access_rights.getElements());
|
||||
|
||||
using Kind = ASTGrantQuery::Kind;
|
||||
@ -112,13 +138,32 @@ ASTs InterpreterShowGrantsQuery::getGrantQueries(const ASTShowGrantsQuery & show
|
||||
grant_query->kind = kind;
|
||||
grant_query->grant_option = grant_option;
|
||||
grant_query->to_roles = std::make_shared<ASTGenericRoleSet>();
|
||||
grant_query->to_roles->names.push_back(user->getName());
|
||||
grant_query->to_roles->names.push_back(show_query.name);
|
||||
grant_query->access_rights_elements = elements;
|
||||
res.push_back(std::move(grant_query));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (bool admin_option : {true, false})
|
||||
{
|
||||
if (!admin_option && (*granted_roles == *granted_roles_with_admin_option))
|
||||
continue;
|
||||
|
||||
const auto & roles = admin_option ? *granted_roles_with_admin_option : *granted_roles;
|
||||
if (roles.empty())
|
||||
continue;
|
||||
|
||||
auto grant_query = std::make_shared<ASTGrantQuery>();
|
||||
using Kind = ASTGrantQuery::Kind;
|
||||
grant_query->kind = Kind::GRANT;
|
||||
grant_query->admin_option = admin_option;
|
||||
grant_query->to_roles = std::make_shared<ASTGenericRoleSet>();
|
||||
grant_query->to_roles->names.push_back(show_query.name);
|
||||
grant_query->roles = GenericRoleSet{roles}.toAST(access_control);
|
||||
res.push_back(std::move(grant_query));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
46
dbms/src/Parsers/ASTCreateRoleQuery.cpp
Normal file
46
dbms/src/Parsers/ASTCreateRoleQuery.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <Parsers/ASTCreateRoleQuery.h>
|
||||
#include <Common/quoteString.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void formatRenameTo(const String & new_name, const IAST::FormatSettings & settings)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " RENAME TO " << (settings.hilite ? IAST::hilite_none : "")
|
||||
<< quoteString(new_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String ASTCreateRoleQuery::getID(char) const
|
||||
{
|
||||
return "CreateRoleQuery";
|
||||
}
|
||||
|
||||
|
||||
ASTPtr ASTCreateRoleQuery::clone() const
|
||||
{
|
||||
return std::make_shared<ASTCreateRoleQuery>(*this);
|
||||
}
|
||||
|
||||
|
||||
void ASTCreateRoleQuery::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << (alter ? "ALTER ROLE" : "CREATE ROLE")
|
||||
<< (settings.hilite ? hilite_none : "");
|
||||
|
||||
if (if_exists)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " IF EXISTS" << (settings.hilite ? hilite_none : "");
|
||||
else if (if_not_exists)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " IF NOT EXISTS" << (settings.hilite ? hilite_none : "");
|
||||
else if (or_replace)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " OR REPLACE" << (settings.hilite ? hilite_none : "");
|
||||
|
||||
settings.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
if (!new_name.empty())
|
||||
formatRenameTo(new_name, settings);
|
||||
}
|
||||
}
|
29
dbms/src/Parsers/ASTCreateRoleQuery.h
Normal file
29
dbms/src/Parsers/ASTCreateRoleQuery.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
/** CREATE ROLE [IF NOT EXISTS | OR REPLACE] name
|
||||
*
|
||||
* ALTER ROLE [IF EXISTS] name
|
||||
* [RENAME TO new_name]
|
||||
*/
|
||||
class ASTCreateRoleQuery : public IAST
|
||||
{
|
||||
public:
|
||||
bool alter = false;
|
||||
|
||||
bool if_exists = false;
|
||||
bool if_not_exists = false;
|
||||
bool or_replace = false;
|
||||
|
||||
String name;
|
||||
String new_name;
|
||||
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
};
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
#include <Parsers/ASTCreateUserQuery.h>
|
||||
#include <Parsers/ASTGenericRoleSet.h>
|
||||
#include <Common/quoteString.h>
|
||||
|
||||
|
||||
@ -134,6 +135,13 @@ namespace
|
||||
}
|
||||
|
||||
|
||||
void formatDefaultRoles(const ASTGenericRoleSet & default_roles, const IAST::FormatSettings & settings)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " DEFAULT ROLE " << (settings.hilite ? IAST::hilite_none : "");
|
||||
default_roles.format(settings);
|
||||
}
|
||||
|
||||
|
||||
void formatProfile(const String & profile_name, const IAST::FormatSettings & settings)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " PROFILE " << (settings.hilite ? IAST::hilite_none : "")
|
||||
@ -181,6 +189,9 @@ void ASTCreateUserQuery::formatImpl(const FormatSettings & settings, FormatState
|
||||
if (remove_hosts)
|
||||
formatHosts("REMOVE", *remove_hosts, settings);
|
||||
|
||||
if (default_roles)
|
||||
formatDefaultRoles(*default_roles, settings);
|
||||
|
||||
if (profile)
|
||||
formatProfile(*profile, settings);
|
||||
}
|
||||
|
@ -7,15 +7,19 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTGenericRoleSet;
|
||||
|
||||
/** CREATE USER [IF NOT EXISTS | OR REPLACE] name
|
||||
* [IDENTIFIED [WITH {NO_PASSWORD|PLAINTEXT_PASSWORD|SHA256_PASSWORD|SHA256_HASH|DOUBLE_SHA1_PASSWORD|DOUBLE_SHA1_HASH}] BY {'password'|'hash'}]
|
||||
* [HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
|
||||
* [DEFAULT ROLE role [,...]]
|
||||
* [PROFILE 'profile_name']
|
||||
*
|
||||
* ALTER USER [IF EXISTS] name
|
||||
* [RENAME TO new_name]
|
||||
* [IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}]
|
||||
* [[ADD|REMOVE] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
|
||||
* [DEFAULT ROLE role [,...] | ALL | ALL EXCEPT role [,...] ]
|
||||
* [PROFILE 'profile_name']
|
||||
*/
|
||||
class ASTCreateUserQuery : public IAST
|
||||
@ -36,6 +40,8 @@ public:
|
||||
std::optional<AllowedClientHosts> add_hosts;
|
||||
std::optional<AllowedClientHosts> remove_hosts;
|
||||
|
||||
std::shared_ptr<ASTGenericRoleSet> default_roles;
|
||||
|
||||
std::optional<String> profile;
|
||||
|
||||
String getID(char) const override;
|
||||
|
@ -13,6 +13,7 @@ namespace
|
||||
switch (kind)
|
||||
{
|
||||
case Kind::USER: return "USER";
|
||||
case Kind::ROLE: return "ROLE";
|
||||
case Kind::QUOTA: return "QUOTA";
|
||||
case Kind::ROW_POLICY: return "POLICY";
|
||||
}
|
||||
|
@ -7,9 +7,10 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** DROP QUOTA [IF EXISTS] name [,...]
|
||||
/** DROP USER [IF EXISTS] name [,...]
|
||||
* DROP ROLE [IF EXISTS] name [,...]
|
||||
* DROP QUOTA [IF EXISTS] name [,...]
|
||||
* DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...]
|
||||
* DROP USER [IF EXISTS] name [,...]
|
||||
*/
|
||||
class ASTDropAccessEntityQuery : public IAST
|
||||
{
|
||||
@ -17,6 +18,7 @@ public:
|
||||
enum class Kind
|
||||
{
|
||||
USER,
|
||||
ROLE,
|
||||
QUOTA,
|
||||
ROW_POLICY,
|
||||
};
|
||||
|
@ -9,6 +9,11 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using KeywordToColumnsMap = std::map<std::string_view /* keyword */, std::vector<std::string_view> /* columns */>;
|
||||
@ -119,13 +124,30 @@ void ASTGrantQuery::formatImpl(const FormatSettings & settings, FormatState &, F
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << ((kind == Kind::GRANT) ? "GRANT" : "REVOKE")
|
||||
<< (settings.hilite ? IAST::hilite_none : "") << " ";
|
||||
|
||||
if (grant_option && (kind == Kind::REVOKE))
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "GRANT OPTION FOR " << (settings.hilite ? hilite_none : "");
|
||||
if (kind == Kind::REVOKE)
|
||||
{
|
||||
if (grant_option)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "GRANT OPTION FOR " << (settings.hilite ? hilite_none : "");
|
||||
else if (admin_option)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "ADMIN OPTION FOR " << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
|
||||
if ((!!roles + !access_rights_elements.empty()) != 1)
|
||||
throw Exception("Either roles or access rights elements should be set", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
if (roles)
|
||||
roles->format(settings);
|
||||
else
|
||||
formatAccessRightsElements(access_rights_elements, settings);
|
||||
|
||||
formatAccessRightsElements(access_rights_elements, settings);
|
||||
formatToRoles(*to_roles, kind, settings);
|
||||
|
||||
if (grant_option && (kind == Kind::GRANT))
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " WITH GRANT OPTION" << (settings.hilite ? hilite_none : "");
|
||||
if (kind == Kind::GRANT)
|
||||
{
|
||||
if (grant_option)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " WITH GRANT OPTION" << (settings.hilite ? hilite_none : "");
|
||||
else if (admin_option)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " WITH ADMIN OPTION" << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ class ASTGenericRoleSet;
|
||||
|
||||
/** GRANT access_type[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user_name | CURRENT_USER} [,...] [WITH GRANT OPTION]
|
||||
* REVOKE access_type[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} FROM {user_name | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | CURRENT_USER} [,...]
|
||||
*
|
||||
* GRANT role [,...] TO {user_name | role_name | CURRENT_USER} [,...] [WITH ADMIN OPTION]
|
||||
* REVOKE [ADMIN OPTION FOR] role [,...] FROM {user_name | role_name | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...]
|
||||
*/
|
||||
class ASTGrantQuery : public IAST
|
||||
{
|
||||
@ -22,8 +25,10 @@ public:
|
||||
};
|
||||
Kind kind = Kind::GRANT;
|
||||
AccessRightsElements access_rights_elements;
|
||||
std::shared_ptr<ASTGenericRoleSet> roles;
|
||||
std::shared_ptr<ASTGenericRoleSet> to_roles;
|
||||
bool grant_option = false;
|
||||
bool admin_option = false;
|
||||
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
|
43
dbms/src/Parsers/ASTSetRoleQuery.cpp
Normal file
43
dbms/src/Parsers/ASTSetRoleQuery.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include <Parsers/ASTSetRoleQuery.h>
|
||||
#include <Parsers/ASTGenericRoleSet.h>
|
||||
#include <Common/quoteString.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
String ASTSetRoleQuery::getID(char) const
|
||||
{
|
||||
return "SetRoleQuery";
|
||||
}
|
||||
|
||||
|
||||
ASTPtr ASTSetRoleQuery::clone() const
|
||||
{
|
||||
return std::make_shared<ASTSetRoleQuery>(*this);
|
||||
}
|
||||
|
||||
|
||||
void ASTSetRoleQuery::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "");
|
||||
switch (kind)
|
||||
{
|
||||
case Kind::SET_ROLE: settings.ostr << "SET ROLE"; break;
|
||||
case Kind::SET_ROLE_DEFAULT: settings.ostr << "SET ROLE DEFAULT"; break;
|
||||
case Kind::SET_DEFAULT_ROLE: settings.ostr << "SET DEFAULT ROLE"; break;
|
||||
}
|
||||
settings.ostr << (settings.hilite ? hilite_none : "");
|
||||
|
||||
if (kind == Kind::SET_ROLE_DEFAULT)
|
||||
return;
|
||||
|
||||
settings.ostr << " ";
|
||||
roles->format(settings);
|
||||
|
||||
if (kind == Kind::SET_ROLE)
|
||||
return;
|
||||
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " TO " << (settings.hilite ? hilite_none : "");
|
||||
to_users->format(settings);
|
||||
}
|
||||
}
|
31
dbms/src/Parsers/ASTSetRoleQuery.h
Normal file
31
dbms/src/Parsers/ASTSetRoleQuery.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTGenericRoleSet;
|
||||
|
||||
/** SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]}
|
||||
* SET DEFAULT ROLE {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} TO {user|CURRENT_USER} [,...]
|
||||
*/
|
||||
class ASTSetRoleQuery : public IAST
|
||||
{
|
||||
public:
|
||||
enum class Kind
|
||||
{
|
||||
SET_ROLE,
|
||||
SET_ROLE_DEFAULT,
|
||||
SET_DEFAULT_ROLE,
|
||||
};
|
||||
Kind kind = Kind::SET_ROLE;
|
||||
|
||||
std::shared_ptr<ASTGenericRoleSet> roles;
|
||||
std::shared_ptr<ASTGenericRoleSet> to_users;
|
||||
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
};
|
||||
}
|
70
dbms/src/Parsers/ParserCreateRoleQuery.cpp
Normal file
70
dbms/src/Parsers/ParserCreateRoleQuery.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include <Parsers/ParserCreateRoleQuery.h>
|
||||
#include <Parsers/ASTCreateRoleQuery.h>
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <Parsers/parseUserName.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace
|
||||
{
|
||||
bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_name)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
if (!ParserKeyword{"RENAME TO"}.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
return parseRoleName(pos, expected, new_name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
bool alter;
|
||||
if (ParserKeyword{"CREATE ROLE"}.ignore(pos, expected))
|
||||
alter = false;
|
||||
else if (ParserKeyword{"ALTER ROLE"}.ignore(pos, expected))
|
||||
alter = true;
|
||||
else
|
||||
return false;
|
||||
|
||||
bool if_exists = false;
|
||||
bool if_not_exists = false;
|
||||
bool or_replace = false;
|
||||
if (alter)
|
||||
{
|
||||
if (ParserKeyword{"IF EXISTS"}.ignore(pos, expected))
|
||||
if_exists = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ParserKeyword{"IF NOT EXISTS"}.ignore(pos, expected))
|
||||
if_not_exists = true;
|
||||
else if (ParserKeyword{"OR REPLACE"}.ignore(pos, expected))
|
||||
or_replace = true;
|
||||
}
|
||||
|
||||
String name;
|
||||
if (!parseRoleName(pos, expected, name))
|
||||
return false;
|
||||
|
||||
String new_name;
|
||||
if (alter)
|
||||
parseRenameTo(pos, expected, new_name);
|
||||
|
||||
auto query = std::make_shared<ASTCreateRoleQuery>();
|
||||
node = query;
|
||||
|
||||
query->alter = alter;
|
||||
query->if_exists = if_exists;
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->name = std::move(name);
|
||||
query->new_name = std::move(new_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
20
dbms/src/Parsers/ParserCreateRoleQuery.h
Normal file
20
dbms/src/Parsers/ParserCreateRoleQuery.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IParserBase.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
/** Parses queries like
|
||||
* CREATE ROLE [IF NOT EXISTS | OR REPLACE] name
|
||||
*
|
||||
* ALTER ROLE [IF EXISTS] name
|
||||
* [RENAME TO new_name]
|
||||
*/
|
||||
class ParserCreateRoleQuery : public IParserBase
|
||||
{
|
||||
protected:
|
||||
const char * getName() const override { return "CREATE ROLE or ALTER ROLE query"; }
|
||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||
};
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
#include <Parsers/ExpressionElementParsers.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTGenericRoleSet.h>
|
||||
#include <Parsers/ParserGenericRoleSet.h>
|
||||
#include <ext/range.h>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
@ -208,6 +209,23 @@ namespace
|
||||
}
|
||||
|
||||
|
||||
bool parseDefaultRoles(IParserBase::Pos & pos, Expected & expected, std::shared_ptr<ASTGenericRoleSet> & default_roles)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
if (!ParserKeyword{"DEFAULT ROLE"}.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
ASTPtr ast;
|
||||
if (!ParserGenericRoleSet{}.allowCurrentUser(false).parse(pos, ast, expected))
|
||||
return false;
|
||||
|
||||
default_roles = typeid_cast<std::shared_ptr<ASTGenericRoleSet>>(ast);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool parseProfileName(IParserBase::Pos & pos, Expected & expected, std::optional<String> & profile)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
@ -263,6 +281,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<ASTGenericRoleSet> default_roles;
|
||||
std::optional<String> profile;
|
||||
|
||||
while (true)
|
||||
@ -276,6 +295,9 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
if (!profile && parseProfileName(pos, expected, profile))
|
||||
continue;
|
||||
|
||||
if (!default_roles && parseDefaultRoles(pos, expected, default_roles))
|
||||
continue;
|
||||
|
||||
if (alter)
|
||||
{
|
||||
if (new_name.empty() && parseRenameTo(pos, expected, new_name, new_host_pattern))
|
||||
|
@ -82,12 +82,14 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
|
||||
using Kind = ASTDropAccessEntityQuery::Kind;
|
||||
Kind kind;
|
||||
if (ParserKeyword{"QUOTA"}.ignore(pos, expected))
|
||||
if (ParserKeyword{"USER"}.ignore(pos, expected))
|
||||
kind = Kind::USER;
|
||||
else if (ParserKeyword{"ROLE"}.ignore(pos, expected))
|
||||
kind = Kind::ROLE;
|
||||
else if (ParserKeyword{"QUOTA"}.ignore(pos, expected))
|
||||
kind = Kind::QUOTA;
|
||||
else if (ParserKeyword{"POLICY"}.ignore(pos, expected) || ParserKeyword{"ROW POLICY"}.ignore(pos, expected))
|
||||
kind = Kind::ROW_POLICY;
|
||||
else if (ParserKeyword{"USER"}.ignore(pos, expected))
|
||||
kind = Kind::USER;
|
||||
else
|
||||
return false;
|
||||
|
||||
@ -98,7 +100,7 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
Strings names;
|
||||
std::vector<RowPolicy::FullNameParts> row_policies_names;
|
||||
|
||||
if (kind == Kind::USER)
|
||||
if ((kind == Kind::USER) || (kind == Kind::ROLE))
|
||||
{
|
||||
if (!parseUserNames(pos, expected, names))
|
||||
return false;
|
||||
|
@ -6,9 +6,10 @@
|
||||
namespace DB
|
||||
{
|
||||
/** Parses queries like
|
||||
* DROP USER [IF EXISTS] name [,...]
|
||||
* DROP ROLE [IF EXISTS] name [,...]
|
||||
* DROP QUOTA [IF EXISTS] name [,...]
|
||||
* DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...]
|
||||
* DROP USER [IF EXISTS] name [,...]
|
||||
*/
|
||||
class ParserDropAccessEntityQuery : public IParserBase
|
||||
{
|
||||
|
@ -10,6 +10,11 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool parseRoundBrackets(IParser::Pos & pos, Expected & expected)
|
||||
@ -206,6 +211,20 @@ namespace
|
||||
}
|
||||
|
||||
|
||||
bool parseRoles(IParser::Pos & pos, Expected & expected, std::shared_ptr<ASTGenericRoleSet> & roles)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
ASTPtr ast;
|
||||
if (!ParserGenericRoleSet{}.allowAll(false).allowCurrentUser(false).parse(pos, ast, expected))
|
||||
return false;
|
||||
|
||||
roles = typeid_cast<std::shared_ptr<ASTGenericRoleSet>>(ast);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool parseToRoles(IParser::Pos & pos, Expected & expected, ASTGrantQuery::Kind kind, std::shared_ptr<ASTGenericRoleSet> & to_roles)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
@ -245,30 +264,46 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
return false;
|
||||
|
||||
bool grant_option = false;
|
||||
bool admin_option = false;
|
||||
if (kind == Kind::REVOKE)
|
||||
{
|
||||
if (ParserKeyword{"GRANT OPTION FOR"}.ignore(pos, expected))
|
||||
grant_option = true;
|
||||
else if (ParserKeyword{"ADMIN OPTION FOR"}.ignore(pos, expected))
|
||||
admin_option = true;
|
||||
}
|
||||
|
||||
AccessRightsElements elements;
|
||||
std::shared_ptr<ASTGenericRoleSet> roles;
|
||||
if (!parseAccessRightsElements(pos, expected, elements) && !parseRoles(pos, expected, roles))
|
||||
return false;
|
||||
|
||||
std::shared_ptr<ASTGenericRoleSet> to_roles;
|
||||
if (!parseAccessRightsElements(pos, expected, elements) && !parseToRoles(pos, expected, kind, to_roles))
|
||||
if (!parseToRoles(pos, expected, kind, to_roles))
|
||||
return false;
|
||||
|
||||
if (kind == Kind::GRANT)
|
||||
{
|
||||
if (ParserKeyword{"WITH GRANT OPTION"}.ignore(pos, expected))
|
||||
grant_option = true;
|
||||
else if (ParserKeyword{"WITH ADMIN OPTION"}.ignore(pos, expected))
|
||||
admin_option = true;
|
||||
}
|
||||
|
||||
if (grant_option && roles)
|
||||
throw Exception("GRANT OPTION should be specified for access types", ErrorCodes::SYNTAX_ERROR);
|
||||
if (admin_option && !elements.empty())
|
||||
throw Exception("ADMIN OPTION should be specified for roles", ErrorCodes::SYNTAX_ERROR);
|
||||
|
||||
auto query = std::make_shared<ASTGrantQuery>();
|
||||
node = query;
|
||||
|
||||
query->kind = kind;
|
||||
query->access_rights_elements = std::move(elements);
|
||||
query->roles = std::move(roles);
|
||||
query->to_roles = std::move(to_roles);
|
||||
query->grant_option = grant_option;
|
||||
query->admin_option = admin_option;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -7,9 +7,11 @@
|
||||
#include <Parsers/ParserOptimizeQuery.h>
|
||||
#include <Parsers/ParserUseQuery.h>
|
||||
#include <Parsers/ParserSetQuery.h>
|
||||
#include <Parsers/ParserSetRoleQuery.h>
|
||||
#include <Parsers/ParserAlterQuery.h>
|
||||
#include <Parsers/ParserSystemQuery.h>
|
||||
#include <Parsers/ParserCreateUserQuery.h>
|
||||
#include <Parsers/ParserCreateRoleQuery.h>
|
||||
#include <Parsers/ParserCreateQuotaQuery.h>
|
||||
#include <Parsers/ParserCreateRowPolicyQuery.h>
|
||||
#include <Parsers/ParserDropAccessEntityQuery.h>
|
||||
@ -28,17 +30,21 @@ bool ParserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
ParserSetQuery set_p;
|
||||
ParserSystemQuery system_p;
|
||||
ParserCreateUserQuery create_user_p;
|
||||
ParserCreateRoleQuery create_role_p;
|
||||
ParserCreateQuotaQuery create_quota_p;
|
||||
ParserCreateRowPolicyQuery create_row_policy_p;
|
||||
ParserDropAccessEntityQuery drop_access_entity_p;
|
||||
ParserGrantQuery grant_p;
|
||||
ParserSetRoleQuery set_role_p;
|
||||
|
||||
bool res = query_with_output_p.parse(pos, node, expected)
|
||||
|| insert_p.parse(pos, node, expected)
|
||||
|| use_p.parse(pos, node, expected)
|
||||
|| set_role_p.parse(pos, node, expected)
|
||||
|| set_p.parse(pos, node, expected)
|
||||
|| system_p.parse(pos, node, expected)
|
||||
|| create_user_p.parse(pos, node, expected)
|
||||
|| create_role_p.parse(pos, node, expected)
|
||||
|| create_quota_p.parse(pos, node, expected)
|
||||
|| create_row_policy_p.parse(pos, node, expected)
|
||||
|| drop_access_entity_p.parse(pos, node, expected)
|
||||
|
80
dbms/src/Parsers/ParserSetRoleQuery.cpp
Normal file
80
dbms/src/Parsers/ParserSetRoleQuery.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
#include <Parsers/ParserSetRoleQuery.h>
|
||||
#include <Parsers/ASTSetRoleQuery.h>
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <Parsers/ASTGenericRoleSet.h>
|
||||
#include <Parsers/ParserGenericRoleSet.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace
|
||||
{
|
||||
bool parseRoles(IParserBase::Pos & pos, Expected & expected, std::shared_ptr<ASTGenericRoleSet> & roles)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
ASTPtr ast;
|
||||
if (!ParserGenericRoleSet{}.allowCurrentUser(false).parse(pos, ast, expected))
|
||||
return false;
|
||||
|
||||
roles = typeid_cast<std::shared_ptr<ASTGenericRoleSet>>(ast);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
bool parseToUsers(IParserBase::Pos & pos, Expected & expected, std::shared_ptr<ASTGenericRoleSet> & to_users)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
if (!ParserKeyword{"TO"}.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
ASTPtr ast;
|
||||
if (!ParserGenericRoleSet{}.allowAll(false).parse(pos, ast, expected))
|
||||
return false;
|
||||
|
||||
to_users = typeid_cast<std::shared_ptr<ASTGenericRoleSet>>(ast);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ParserSetRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
using Kind = ASTSetRoleQuery::Kind;
|
||||
Kind kind;
|
||||
if (ParserKeyword{"SET ROLE DEFAULT"}.ignore(pos, expected))
|
||||
kind = Kind::SET_ROLE_DEFAULT;
|
||||
else if (ParserKeyword{"SET ROLE"}.ignore(pos, expected))
|
||||
kind = Kind::SET_ROLE;
|
||||
else if (ParserKeyword{"SET DEFAULT ROLE"}.ignore(pos, expected))
|
||||
kind = Kind::SET_DEFAULT_ROLE;
|
||||
else
|
||||
return false;
|
||||
|
||||
std::shared_ptr<ASTGenericRoleSet> roles;
|
||||
std::shared_ptr<ASTGenericRoleSet> to_users;
|
||||
|
||||
if ((kind == Kind::SET_ROLE) || (kind == Kind::SET_DEFAULT_ROLE))
|
||||
{
|
||||
if (!parseRoles(pos, expected, roles))
|
||||
return false;
|
||||
|
||||
if (kind == Kind::SET_DEFAULT_ROLE)
|
||||
{
|
||||
if (!parseToUsers(pos, expected, to_users))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto query = std::make_shared<ASTSetRoleQuery>();
|
||||
node = query;
|
||||
|
||||
query->kind = kind;
|
||||
query->roles = std::move(roles);
|
||||
query->to_users = std::move(to_users);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
18
dbms/src/Parsers/ParserSetRoleQuery.h
Normal file
18
dbms/src/Parsers/ParserSetRoleQuery.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IParserBase.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
/** Parses queries like
|
||||
* SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]}
|
||||
* SET DEFAULT ROLE {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} TO {user|CURRENT_USER} [,...]
|
||||
*/
|
||||
class ParserSetRoleQuery : public IParserBase
|
||||
{
|
||||
protected:
|
||||
const char * getName() const override { return "SET ROLE or SET DEFAULT ROLE query"; }
|
||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user