The cache is covered already with general auth dtests but some cases are more tricky and easier to express directly as calls to cache class. For such tests boost test file was added.
154 lines
6.0 KiB
C++
154 lines
6.0 KiB
C++
/*
|
|
* Copyright (C) 2026-present ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
|
|
*/
|
|
|
|
#include <seastar/core/future.hh>
|
|
|
|
#undef SEASTAR_TESTING_MAIN
|
|
#include <seastar/testing/test_case.hh>
|
|
|
|
#include "auth/cache.hh"
|
|
#include "auth/permission.hh"
|
|
#include "auth/resource.hh"
|
|
#include "auth/role_or_anonymous.hh"
|
|
#include "auth/service.hh"
|
|
#include "db/config.hh"
|
|
#include "test/lib/cql_test_env.hh"
|
|
|
|
BOOST_AUTO_TEST_SUITE(auth_cache_test)
|
|
|
|
static cql_test_config auth_on_config() {
|
|
cql_test_config cfg;
|
|
cfg.db_config->authorizer("CassandraAuthorizer");
|
|
cfg.db_config->authenticator("PasswordAuthenticator");
|
|
return cfg;
|
|
}
|
|
|
|
// Tests whether removing role drops it from cache.
|
|
SEASTAR_TEST_CASE(test_update_cache_for_dropped_role) {
|
|
return do_with_cql_env([](cql_test_env& env) -> future<> {
|
|
co_await env.execute_cql("CREATE ROLE to_drop WITH LOGIN = false AND PASSWORD = 'x'");
|
|
|
|
auto& cache = env.auth_cache().local();
|
|
co_await cache.load_all();
|
|
|
|
BOOST_REQUIRE(cache.get("to_drop"));
|
|
|
|
co_await env.execute_cql("DROP ROLE to_drop");
|
|
co_await cache.load_roles({"to_drop"});
|
|
|
|
BOOST_REQUIRE(!cache.get("to_drop"));
|
|
}, auth_on_config());
|
|
}
|
|
|
|
// Tests whether altering base role's permission refreshes
|
|
// all descendant roles permissions. And then if dropping
|
|
// base role also drops permissions for descendants.
|
|
SEASTAR_TEST_CASE(test_three_level_role_hierarchy) {
|
|
return do_with_cql_env([](cql_test_env& env) -> future<> {
|
|
co_await env.execute_cql("CREATE TABLE ks.tbl_a (pk int PRIMARY KEY, v int)");
|
|
co_await env.execute_cql("CREATE TABLE ks.tbl_b (pk int PRIMARY KEY, v int)");
|
|
|
|
co_await env.execute_cql("CREATE ROLE r_base WITH LOGIN = false");
|
|
co_await env.execute_cql("CREATE ROLE r_mid WITH LOGIN = false");
|
|
co_await env.execute_cql("CREATE ROLE r_bottom WITH LOGIN = true AND PASSWORD = 'x'");
|
|
|
|
co_await env.execute_cql("GRANT r_base TO r_mid");
|
|
co_await env.execute_cql("GRANT r_mid TO r_bottom");
|
|
|
|
co_await env.execute_cql("GRANT SELECT ON ks.tbl_a TO r_base");
|
|
co_await env.execute_cql("GRANT MODIFY ON ks.tbl_b TO r_mid");
|
|
co_await env.execute_cql("GRANT CREATE ON KEYSPACE ks TO r_bottom");
|
|
co_await env.execute_cql("GRANT MODIFY ON ks.tbl_a TO r_bottom");
|
|
|
|
auto& cache = env.auth_cache().local();
|
|
co_await cache.load_all();
|
|
|
|
auto base = auth::role_or_anonymous("r_base");
|
|
auto mid = auth::role_or_anonymous("r_mid");
|
|
auto bottom = auth::role_or_anonymous("r_bottom");
|
|
auto res_tbl_a = auth::make_data_resource("ks", "tbl_a");
|
|
auto res_tbl_b = auth::make_data_resource("ks", "tbl_b");
|
|
|
|
// Initial check of relationships.
|
|
BOOST_REQUIRE(cache.get("r_base")->member_of.empty());
|
|
BOOST_REQUIRE(cache.get("r_mid")->member_of.contains("r_base"));
|
|
BOOST_REQUIRE(cache.get("r_bottom")->member_of.contains("r_mid"));
|
|
|
|
// Update base permissions.
|
|
co_await env.execute_cql("REVOKE SELECT ON ks.tbl_a FROM r_base");
|
|
co_await env.execute_cql("GRANT ALTER ON ks.tbl_a TO r_base");
|
|
co_await cache.load_roles({"r_base"});
|
|
|
|
auto perms_mid_a = co_await cache.get_permissions(mid, res_tbl_a);
|
|
BOOST_REQUIRE(!perms_mid_a.contains(auth::permission::SELECT));
|
|
BOOST_REQUIRE(perms_mid_a.contains(auth::permission::ALTER));
|
|
|
|
auto perms_bottom_a = co_await cache.get_permissions(bottom, res_tbl_a);
|
|
BOOST_REQUIRE(!perms_bottom_a.contains(auth::permission::SELECT));
|
|
BOOST_REQUIRE(perms_bottom_a.contains(auth::permission::ALTER));
|
|
|
|
// Drop base role.
|
|
co_await env.execute_cql("DROP ROLE r_base");
|
|
co_await cache.load_roles({"r_base"});
|
|
|
|
perms_mid_a = co_await cache.get_permissions(mid, res_tbl_a);
|
|
BOOST_REQUIRE_EQUAL(perms_mid_a.mask(), auth::permissions::NONE.mask());
|
|
|
|
perms_bottom_a = co_await cache.get_permissions(bottom, res_tbl_a);
|
|
auth::permission_set expected;
|
|
expected.set(auth::permission::MODIFY);
|
|
BOOST_REQUIRE(perms_bottom_a.mask() == expected.mask());
|
|
}, auth_on_config());
|
|
}
|
|
|
|
// Tests whether resource drop properly removes permissions.
|
|
SEASTAR_TEST_CASE(test_invalidate_permissions_via_drop) {
|
|
return do_with_cql_env([](cql_test_env& env) -> future<> {
|
|
co_await env.execute_cql("CREATE TABLE ks.t (pk int PRIMARY KEY)");
|
|
co_await env.execute_cql("CREATE ROLE user");
|
|
co_await env.execute_cql("GRANT SELECT ON ks.t TO user");
|
|
|
|
auto& cache = env.auth_cache().local();
|
|
co_await cache.load_all();
|
|
|
|
auto r = auth::make_data_resource("ks", "t");
|
|
auto role = auth::role_or_anonymous("user");
|
|
|
|
auto perms_before = co_await cache.get_permissions(role, r);
|
|
BOOST_REQUIRE(perms_before.contains(auth::permission::SELECT));
|
|
|
|
co_await env.execute_cql("DROP TABLE ks.t");
|
|
co_await cache.prune(r);
|
|
|
|
auto perms_after = co_await cache.get_permissions(role, r);
|
|
BOOST_REQUIRE(!perms_after.contains(auth::permission::SELECT));
|
|
}, auth_on_config());
|
|
}
|
|
|
|
// Checks if permissions are not accidentally added to anonymous role.
|
|
SEASTAR_TEST_CASE(test_anonymous_not_granted_other_roles_permissions) {
|
|
return do_with_cql_env([](cql_test_env& env) -> future<> {
|
|
co_await env.execute_cql("CREATE TABLE ks.t (pk int PRIMARY KEY)");
|
|
co_await env.execute_cql("CREATE ROLE granted_role");
|
|
co_await env.execute_cql("GRANT SELECT ON ks.t TO granted_role");
|
|
|
|
auto& cache = env.auth_cache().local();
|
|
co_await cache.load_all();
|
|
|
|
auto r = auth::make_data_resource("ks", "t");
|
|
|
|
auto role_perms = co_await cache.get_permissions(auth::role_or_anonymous("granted_role"), r);
|
|
BOOST_REQUIRE(role_perms.contains(auth::permission::SELECT));
|
|
|
|
auto anon_perms = co_await cache.get_permissions(auth::role_or_anonymous(), r);
|
|
BOOST_REQUIRE(!anon_perms.contains(auth::permission::SELECT));
|
|
}, auth_on_config());
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|