Merge pull request #34225 from vitlibar/fix-checking-grants-for-show-grants

Fix checking grants for SHOW GRANTS
This commit is contained in:
Maksim Kita 2022-02-02 22:51:51 +01:00 committed by GitHub
commit 02c6cfba6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 2 deletions

View 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;
}
}

View 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;
};
}

View File

@ -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);
}

View File

@ -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"