mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-29 02:52:13 +00:00
Add WITH IMPLICIT
, fix error with implicit grants
This commit is contained in:
parent
229ead5f91
commit
2a107e3429
@ -351,7 +351,7 @@ Shows privileges for a user.
|
|||||||
**Syntax**
|
**Syntax**
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
SHOW GRANTS [FOR user1 [, user2 ...]]
|
SHOW GRANTS [FOR user1 [, user2 ...]] [WITH IMPLICIT]
|
||||||
```
|
```
|
||||||
|
|
||||||
If user is not specified, the query returns privileges for the current user.
|
If user is not specified, the query returns privileges for the current user.
|
||||||
|
@ -234,7 +234,7 @@ SHOW DICTIONARIES FROM db LIKE '%reg%' LIMIT 2
|
|||||||
### Синтаксис {#show-grants-syntax}
|
### Синтаксис {#show-grants-syntax}
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
SHOW GRANTS [FOR user]
|
SHOW GRANTS [FOR user1 [, user2 ...]] [WITH IMPLICIT]
|
||||||
```
|
```
|
||||||
|
|
||||||
Если пользователь не задан, запрос возвращает привилегии текущего пользователя.
|
Если пользователь не задан, запрос возвращает привилегии текущего пользователя.
|
||||||
|
@ -110,7 +110,7 @@ SHOW DICTIONARIES FROM db LIKE '%reg%' LIMIT 2
|
|||||||
### 语法 {#show-grants-syntax}
|
### 语法 {#show-grants-syntax}
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
SHOW GRANTS [FOR user]
|
SHOW GRANTS [FOR user1 [, user2 ...]] [WITH IMPLICIT]
|
||||||
```
|
```
|
||||||
|
|
||||||
如果未指定用户,输出当前用户的权限
|
如果未指定用户,输出当前用户的权限
|
||||||
|
@ -1155,9 +1155,6 @@ private:
|
|||||||
|
|
||||||
calculateMinMaxFlags();
|
calculateMinMaxFlags();
|
||||||
|
|
||||||
if (!isLeaf())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto new_flags = function(flags, min_flags_with_children, max_flags_with_children, level, grant_option);
|
auto new_flags = function(flags, min_flags_with_children, max_flags_with_children, level, grant_option);
|
||||||
|
|
||||||
if (new_flags != flags)
|
if (new_flags != flags)
|
||||||
|
@ -64,8 +64,28 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AccessRights addImplicitAccessRights(const AccessRights & access, const AccessControl & access_control)
|
std::array<UUID, 1> to_array(const UUID & id)
|
||||||
{
|
{
|
||||||
|
std::array<UUID, 1> ids;
|
||||||
|
ids[0] = id;
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper for using in templates.
|
||||||
|
std::string_view getDatabase() { return {}; }
|
||||||
|
|
||||||
|
template <typename... OtherArgs>
|
||||||
|
std::string_view getDatabase(std::string_view arg1, const OtherArgs &...) { return arg1; }
|
||||||
|
|
||||||
|
std::string_view getTableEngine() { return {}; }
|
||||||
|
|
||||||
|
template <typename... OtherArgs>
|
||||||
|
std::string_view getTableEngine(std::string_view arg1, const OtherArgs &...) { return arg1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AccessRights ContextAccess::addImplicitAccessRights(const AccessRights & access, const AccessControl & access_control)
|
||||||
|
{
|
||||||
AccessFlags max_flags;
|
AccessFlags max_flags;
|
||||||
|
|
||||||
auto modifier = [&](const AccessFlags & flags,
|
auto modifier = [&](const AccessFlags & flags,
|
||||||
@ -251,26 +271,6 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::array<UUID, 1> to_array(const UUID & id)
|
|
||||||
{
|
|
||||||
std::array<UUID, 1> ids;
|
|
||||||
ids[0] = id;
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper for using in templates.
|
|
||||||
std::string_view getDatabase() { return {}; }
|
|
||||||
|
|
||||||
template <typename... OtherArgs>
|
|
||||||
std::string_view getDatabase(std::string_view arg1, const OtherArgs &...) { return arg1; }
|
|
||||||
|
|
||||||
std::string_view getTableEngine() { return {}; }
|
|
||||||
|
|
||||||
template <typename... OtherArgs>
|
|
||||||
std::string_view getTableEngine(std::string_view arg1, const OtherArgs &...) { return arg1; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,6 +133,8 @@ public:
|
|||||||
/// Checks if grantees are allowed for the current user, throws an exception if not.
|
/// Checks if grantees are allowed for the current user, throws an exception if not.
|
||||||
void checkGranteesAreAllowed(const std::vector<UUID> & grantee_ids) const;
|
void checkGranteesAreAllowed(const std::vector<UUID> & grantee_ids) const;
|
||||||
|
|
||||||
|
static AccessRights addImplicitAccessRights(const AccessRights & access, const AccessControl & access_control);
|
||||||
|
|
||||||
ContextAccess(const AccessControl & access_control_, const Params & params_);
|
ContextAccess(const AccessControl & access_control_, const Params & params_);
|
||||||
~ContextAccess();
|
~ContextAccess();
|
||||||
|
|
||||||
|
@ -32,7 +32,8 @@ namespace
|
|||||||
ASTs getGrantQueriesImpl(
|
ASTs getGrantQueriesImpl(
|
||||||
const T & grantee,
|
const T & grantee,
|
||||||
const AccessControl * access_control /* not used if attach_mode == true */,
|
const AccessControl * access_control /* not used if attach_mode == true */,
|
||||||
bool attach_mode = false)
|
bool attach_mode = false,
|
||||||
|
bool with_implicit = false)
|
||||||
{
|
{
|
||||||
ASTs res;
|
ASTs res;
|
||||||
|
|
||||||
@ -41,7 +42,13 @@ namespace
|
|||||||
|
|
||||||
std::shared_ptr<ASTGrantQuery> current_query = nullptr;
|
std::shared_ptr<ASTGrantQuery> current_query = nullptr;
|
||||||
|
|
||||||
for (const auto & element : grantee.access.getElements())
|
AccessRightsElements elements;
|
||||||
|
if (with_implicit)
|
||||||
|
elements = ContextAccess::addImplicitAccessRights(grantee.access, *access_control).getElements();
|
||||||
|
else
|
||||||
|
elements = grantee.access.getElements();
|
||||||
|
|
||||||
|
for (const auto & element : elements)
|
||||||
{
|
{
|
||||||
if (element.empty())
|
if (element.empty())
|
||||||
continue;
|
continue;
|
||||||
@ -89,12 +96,13 @@ namespace
|
|||||||
ASTs getGrantQueriesImpl(
|
ASTs getGrantQueriesImpl(
|
||||||
const IAccessEntity & entity,
|
const IAccessEntity & entity,
|
||||||
const AccessControl * access_control /* not used if attach_mode == true */,
|
const AccessControl * access_control /* not used if attach_mode == true */,
|
||||||
bool attach_mode = false)
|
bool attach_mode = false,
|
||||||
|
bool with_implicit = false)
|
||||||
{
|
{
|
||||||
if (const User * user = typeid_cast<const User *>(&entity))
|
if (const User * user = typeid_cast<const User *>(&entity))
|
||||||
return getGrantQueriesImpl(*user, access_control, attach_mode);
|
return getGrantQueriesImpl(*user, access_control, attach_mode, with_implicit);
|
||||||
if (const Role * role = typeid_cast<const Role *>(&entity))
|
if (const Role * role = typeid_cast<const Role *>(&entity))
|
||||||
return getGrantQueriesImpl(*role, access_control, attach_mode);
|
return getGrantQueriesImpl(*role, access_control, attach_mode, with_implicit);
|
||||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "{} is expected to be user or role", entity.formatTypeWithName());
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "{} is expected to be user or role", entity.formatTypeWithName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,23 +188,24 @@ ASTs InterpreterShowGrantsQuery::getGrantQueries() const
|
|||||||
auto entities = getEntities();
|
auto entities = getEntities();
|
||||||
const auto & access_control = getContext()->getAccessControl();
|
const auto & access_control = getContext()->getAccessControl();
|
||||||
|
|
||||||
|
const auto & show_query = query_ptr->as<const ASTShowGrantsQuery &>();
|
||||||
ASTs grant_queries;
|
ASTs grant_queries;
|
||||||
for (const auto & entity : entities)
|
for (const auto & entity : entities)
|
||||||
boost::range::push_back(grant_queries, getGrantQueries(*entity, access_control));
|
boost::range::push_back(grant_queries, getGrantQueries(*entity, access_control, show_query.with_implicit));
|
||||||
|
|
||||||
return grant_queries;
|
return grant_queries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ASTs InterpreterShowGrantsQuery::getGrantQueries(const IAccessEntity & user_or_role, const AccessControl & access_control)
|
ASTs InterpreterShowGrantsQuery::getGrantQueries(const IAccessEntity & user_or_role, const AccessControl & access_control, bool with_implicit)
|
||||||
{
|
{
|
||||||
return getGrantQueriesImpl(user_or_role, &access_control, false);
|
return getGrantQueriesImpl(user_or_role, &access_control, false, with_implicit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ASTs InterpreterShowGrantsQuery::getAttachGrantQueries(const IAccessEntity & user_or_role)
|
ASTs InterpreterShowGrantsQuery::getAttachGrantQueries(const IAccessEntity & user_or_role)
|
||||||
{
|
{
|
||||||
return getGrantQueriesImpl(user_or_role, nullptr, true);
|
return getGrantQueriesImpl(user_or_role, nullptr, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerInterpreterShowGrantsQuery(InterpreterFactory & factory)
|
void registerInterpreterShowGrantsQuery(InterpreterFactory & factory)
|
||||||
|
@ -20,7 +20,7 @@ public:
|
|||||||
|
|
||||||
BlockIO execute() override;
|
BlockIO execute() override;
|
||||||
|
|
||||||
static ASTs getGrantQueries(const IAccessEntity & user_or_role, const AccessControl & access_control);
|
static ASTs getGrantQueries(const IAccessEntity & user_or_role, const AccessControl & access_control, bool with_implicit = false);
|
||||||
static ASTs getAttachGrantQueries(const IAccessEntity & user_or_role);
|
static ASTs getAttachGrantQueries(const IAccessEntity & user_or_role);
|
||||||
|
|
||||||
bool ignoreQuota() const override { return true; }
|
bool ignoreQuota() const override { return true; }
|
||||||
|
@ -38,5 +38,11 @@ void ASTShowGrantsQuery::formatQueryImpl(const FormatSettings & settings, Format
|
|||||||
<< (settings.hilite ? hilite_none : "");
|
<< (settings.hilite ? hilite_none : "");
|
||||||
for_roles->format(settings);
|
for_roles->format(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (with_implicit)
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << " WITH IMPLICIT"
|
||||||
|
<< (settings.hilite ? hilite_none : "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,13 @@ namespace DB
|
|||||||
{
|
{
|
||||||
class ASTRolesOrUsersSet;
|
class ASTRolesOrUsersSet;
|
||||||
|
|
||||||
/** SHOW GRANTS [FOR user_name]
|
/** SHOW GRANTS [FOR user1 [, user2 ...]] [WITH IMPLICIT]
|
||||||
*/
|
*/
|
||||||
class ASTShowGrantsQuery : public ASTQueryWithOutput
|
class ASTShowGrantsQuery : public ASTQueryWithOutput
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<ASTRolesOrUsersSet> for_roles;
|
std::shared_ptr<ASTRolesOrUsersSet> for_roles;
|
||||||
|
bool with_implicit = false;
|
||||||
|
|
||||||
String getID(char) const override;
|
String getID(char) const override;
|
||||||
ASTPtr clone() const override;
|
ASTPtr clone() const override;
|
||||||
|
@ -31,8 +31,13 @@ bool ParserShowGrantsQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
|||||||
for_roles->current_user = true;
|
for_roles->current_user = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool with_implicit = false;
|
||||||
|
if (ParserKeyword{Keyword::WITH_IMPLICIT}.ignore(pos, expected))
|
||||||
|
with_implicit = true;
|
||||||
|
|
||||||
auto query = std::make_shared<ASTShowGrantsQuery>();
|
auto query = std::make_shared<ASTShowGrantsQuery>();
|
||||||
query->for_roles = std::move(for_roles);
|
query->for_roles = std::move(for_roles);
|
||||||
|
query->with_implicit = with_implicit;
|
||||||
node = query;
|
node = query;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -530,6 +530,7 @@ namespace DB
|
|||||||
MR_MACROS(WITH_NAME, "WITH NAME") \
|
MR_MACROS(WITH_NAME, "WITH NAME") \
|
||||||
MR_MACROS(WITH_REPLACE_OPTION, "WITH REPLACE OPTION") \
|
MR_MACROS(WITH_REPLACE_OPTION, "WITH REPLACE OPTION") \
|
||||||
MR_MACROS(WITH_TIES, "WITH TIES") \
|
MR_MACROS(WITH_TIES, "WITH TIES") \
|
||||||
|
MR_MACROS(WITH_IMPLICIT, "WITH IMPLICIT") \
|
||||||
MR_MACROS(WITH, "WITH") \
|
MR_MACROS(WITH, "WITH") \
|
||||||
MR_MACROS(RECURSIVE, "RECURSIVE") \
|
MR_MACROS(RECURSIVE, "RECURSIVE") \
|
||||||
MR_MACROS(WK, "WK") \
|
MR_MACROS(WK, "WK") \
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
Empty grants
|
||||||
|
GRANT SOURCES ON *.*
|
||||||
|
GRANT TABLE ENGINE ON *
|
||||||
|
GRANT SELECT ON system.aggregate_function_combinators
|
||||||
|
GRANT SELECT ON system.collations
|
||||||
|
GRANT SELECT ON system.columns
|
||||||
|
GRANT SELECT ON system.contributors
|
||||||
|
GRANT SELECT ON system.current_roles
|
||||||
|
GRANT SELECT ON system.data_type_families
|
||||||
|
GRANT SELECT ON system.database_engines
|
||||||
|
GRANT SELECT ON system.databases
|
||||||
|
GRANT SELECT ON system.enabled_roles
|
||||||
|
GRANT SELECT ON system.formats
|
||||||
|
GRANT SELECT ON system.functions
|
||||||
|
GRANT SELECT ON system.licenses
|
||||||
|
GRANT SELECT ON system.one
|
||||||
|
GRANT SELECT ON system.privileges
|
||||||
|
GRANT SELECT ON system.quota_usage
|
||||||
|
GRANT SELECT ON system.settings
|
||||||
|
GRANT SELECT ON system.table_engines
|
||||||
|
GRANT SELECT ON system.table_functions
|
||||||
|
GRANT SELECT ON system.tables
|
||||||
|
GRANT SELECT ON system.time_zones
|
||||||
|
Revoke grants
|
||||||
|
GRANT SHOW DATABASES, SHOW TABLES, SHOW COLUMNS, SELECT, SOURCES ON *.*
|
||||||
|
GRANT TABLE ENGINE ON *
|
||||||
|
REVOKE SHOW TABLES, SHOW COLUMNS, SELECT ON test_03247.`table`
|
||||||
|
OK
|
||||||
|
0
|
25
tests/queries/0_stateless/03247_show_grants_with_implicit.sh
Executable file
25
tests/queries/0_stateless/03247_show_grants_with_implicit.sh
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
# shellcheck source=../shell_config.sh
|
||||||
|
. "$CURDIR"/../shell_config.sh
|
||||||
|
|
||||||
|
user="user03247_${CLICKHOUSE_DATABASE}_$RANDOM"
|
||||||
|
|
||||||
|
${CLICKHOUSE_CLIENT} --query "DROP USER IF EXISTS $user;";
|
||||||
|
${CLICKHOUSE_CLIENT} --query "CREATE USER $user;";
|
||||||
|
|
||||||
|
${CLICKHOUSE_CLIENT} --query "GRANT SOURCES ON *.* TO $user;";
|
||||||
|
|
||||||
|
echo "Empty grants";
|
||||||
|
${CLICKHOUSE_CLIENT} --query "SHOW GRANTS FOR $user WITH IMPLICIT;" | sed 's/ TO.*//';
|
||||||
|
|
||||||
|
echo "Revoke grants";
|
||||||
|
${CLICKHOUSE_CLIENT} --query "GRANT SELECT ON *.* TO $user ;";
|
||||||
|
${CLICKHOUSE_CLIENT} --query "REVOKE SELECT ON test_03247.table FROM $user;";
|
||||||
|
${CLICKHOUSE_CLIENT} --query "SHOW GRANTS FOR $user WITH IMPLICIT;" | sed 's/ TO.*//' | sed 's/ FROM.*//';
|
||||||
|
|
||||||
|
(( $(${CLICKHOUSE_CLIENT} --user $user --query "EXISTS test_03247.table;" 2>&1 | grep -c "Not enough privileges") >= 1 )) && echo "OK" || echo "UNEXPECTED";
|
||||||
|
${CLICKHOUSE_CLIENT} --query "EXISTS test_03247.table2;" --user $user;
|
||||||
|
|
||||||
|
${CLICKHOUSE_CLIENT} --query "DROP USER IF EXISTS $user;";
|
Loading…
Reference in New Issue
Block a user