mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-25 17:12:03 +00:00
Merge pull request #34225 from vitlibar/fix-checking-grants-for-show-grants
Fix checking grants for SHOW GRANTS
This commit is contained in:
commit
02c6cfba6a
44
src/Access/CachedAccessChecking.cpp
Normal file
44
src/Access/CachedAccessChecking.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <Access/CachedAccessChecking.h>
|
||||
#include <Access/ContextAccess.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
CachedAccessChecking::CachedAccessChecking(const std::shared_ptr<const ContextAccess> & access_, AccessFlags access_flags_)
|
||||
: CachedAccessChecking(access_, AccessRightsElement{access_flags_})
|
||||
{
|
||||
}
|
||||
|
||||
CachedAccessChecking::CachedAccessChecking(const std::shared_ptr<const ContextAccess> & access_, const AccessRightsElement & element_)
|
||||
: access(access_), element(element_)
|
||||
{
|
||||
}
|
||||
|
||||
CachedAccessChecking::~CachedAccessChecking() = default;
|
||||
|
||||
bool CachedAccessChecking::checkAccess(bool throw_if_denied)
|
||||
{
|
||||
if (checked)
|
||||
return result;
|
||||
if (throw_if_denied)
|
||||
{
|
||||
try
|
||||
{
|
||||
access->checkAccess(element);
|
||||
result = true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
result = false;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = access->isGranted(element);
|
||||
}
|
||||
checked = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
29
src/Access/CachedAccessChecking.h
Normal file
29
src/Access/CachedAccessChecking.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <Access/Common/AccessRightsElement.h>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ContextAccess;
|
||||
|
||||
/// Checks if the current user has a specified access type granted,
|
||||
/// and if it's checked another time later, it will just return the first result.
|
||||
class CachedAccessChecking
|
||||
{
|
||||
public:
|
||||
CachedAccessChecking(const std::shared_ptr<const ContextAccess> & access_, AccessFlags access_flags_);
|
||||
CachedAccessChecking(const std::shared_ptr<const ContextAccess> & access_, const AccessRightsElement & element_);
|
||||
~CachedAccessChecking();
|
||||
|
||||
bool checkAccess(bool throw_if_denied = true);
|
||||
|
||||
private:
|
||||
const std::shared_ptr<const ContextAccess> access;
|
||||
const AccessRightsElement element;
|
||||
bool checked = false;
|
||||
bool result = false;
|
||||
};
|
||||
|
||||
}
|
@ -4,6 +4,8 @@
|
||||
#include <Parsers/Access/ASTShowGrantsQuery.h>
|
||||
#include <Parsers/formatAST.h>
|
||||
#include <Access/AccessControl.h>
|
||||
#include <Access/CachedAccessChecking.h>
|
||||
#include <Access/ContextAccess.h>
|
||||
#include <Access/Role.h>
|
||||
#include <Access/RolesOrUsersSet.h>
|
||||
#include <Access/User.h>
|
||||
@ -135,15 +137,25 @@ QueryPipeline InterpreterShowGrantsQuery::executeImpl()
|
||||
|
||||
std::vector<AccessEntityPtr> InterpreterShowGrantsQuery::getEntities() const
|
||||
{
|
||||
const auto & show_query = query_ptr->as<ASTShowGrantsQuery &>();
|
||||
const auto & access = getContext()->getAccess();
|
||||
const auto & access_control = getContext()->getAccessControl();
|
||||
|
||||
const auto & show_query = query_ptr->as<ASTShowGrantsQuery &>();
|
||||
auto ids = RolesOrUsersSet{*show_query.for_roles, access_control, getContext()->getUserID()}.getMatchingIDs(access_control);
|
||||
|
||||
CachedAccessChecking show_users(access, AccessType::SHOW_USERS);
|
||||
CachedAccessChecking show_roles(access, AccessType::SHOW_ROLES);
|
||||
bool throw_if_access_denied = !show_query.for_roles->all;
|
||||
|
||||
std::vector<AccessEntityPtr> entities;
|
||||
for (const auto & id : ids)
|
||||
{
|
||||
auto entity = access_control.tryRead(id);
|
||||
if (entity)
|
||||
if (!entity)
|
||||
continue;
|
||||
if ((id == access->getUserID() /* Any user can see his own grants */)
|
||||
|| (entity->isTypeOf<User>() && show_users.checkAccess(throw_if_access_denied))
|
||||
|| (entity->isTypeOf<Role>() && show_roles.checkAccess(throw_if_access_denied)))
|
||||
entities.push_back(entity);
|
||||
}
|
||||
|
||||
|
@ -250,6 +250,15 @@ def test_introspection():
|
||||
assert instance.query("SHOW GRANTS", user='A') == TSV(["GRANT SELECT ON test.table TO A"])
|
||||
assert instance.query("SHOW GRANTS", user='B') == TSV(["GRANT CREATE ON *.* TO B WITH GRANT OPTION"])
|
||||
|
||||
assert instance.query("SHOW GRANTS FOR ALL", user='A') == TSV(["GRANT SELECT ON test.table TO A"])
|
||||
assert instance.query("SHOW GRANTS FOR ALL", user='B') == TSV(["GRANT CREATE ON *.* TO B WITH GRANT OPTION"])
|
||||
assert instance.query("SHOW GRANTS FOR ALL") == TSV(["GRANT SELECT ON test.table TO A",
|
||||
"GRANT CREATE ON *.* TO B WITH GRANT OPTION",
|
||||
"GRANT ALL ON *.* TO default WITH GRANT OPTION"])
|
||||
|
||||
expected_error = "necessary to have grant SHOW USERS"
|
||||
assert expected_error in instance.query_and_get_error("SHOW GRANTS FOR B", user='A')
|
||||
|
||||
expected_access1 = "CREATE USER A\n" \
|
||||
"CREATE USER B\n" \
|
||||
"CREATE USER default IDENTIFIED WITH plaintext_password SETTINGS PROFILE default"
|
||||
|
Loading…
Reference in New Issue
Block a user