Better auth user/role handling (#1699)

* Stop auth module from creating users
* Explicit about auth policy (check if no users defined OR auth module used)
* Role supports database access definition
* Authenticate() returns user or role
* AuthChecker generates QueryUserOrRole (can be empty)
* QueryUserOrRole actually authorizes
* Add auth cache invalidation
* Better database access queries (GRANT, DENY, REVOKE DATABASE)
This commit is contained in:
andrejtonev
2024-02-22 15:00:39 +01:00
committed by GitHub
parent 98727e0fa0
commit 6a4ef55e90
60 changed files with 1870 additions and 880 deletions

View File

@@ -27,6 +27,7 @@ std::filesystem::path data_directory{std::filesystem::temp_directory_path() / "e
class ExpansionBenchFixture : public benchmark::Fixture {
protected:
std::optional<memgraph::system::System> system;
std::optional<memgraph::query::AllowEverythingAuthChecker> auth_checker;
std::optional<memgraph::query::InterpreterContext> interpreter_context;
std::optional<memgraph::query::Interpreter> interpreter;
std::optional<memgraph::utils::Gatekeeper<memgraph::dbms::Database>> db_gk;
@@ -43,6 +44,7 @@ class ExpansionBenchFixture : public benchmark::Fixture {
auto &db_acc = *db_acc_opt;
system.emplace();
auth_checker.emplace();
interpreter_context.emplace(memgraph::query::InterpreterConfig{}, nullptr, &repl_state.value(), *system
#ifdef MG_ENTERPRISE
,
@@ -73,13 +75,15 @@ class ExpansionBenchFixture : public benchmark::Fixture {
}
interpreter.emplace(&*interpreter_context, std::move(db_acc));
interpreter->SetUser(auth_checker->GenQueryUser(std::nullopt, std::nullopt));
}
void TearDown(const benchmark::State &) override {
interpreter = std::nullopt;
interpreter_context = std::nullopt;
system.reset();
db_gk.reset();
auth_checker.reset();
system.reset();
std::filesystem::remove_all(data_directory);
}
};

View File

@@ -14,14 +14,7 @@
# If you wish to modify these, update the startup_config_dict and workloads.yaml !
startup_config_dict = {
"auth_module_create_missing_role": ("true", "true", "Set to false to disable creation of missing roles."),
"auth_module_create_missing_user": ("true", "true", "Set to false to disable creation of missing users."),
"auth_module_executable": ("", "", "Absolute path to the auth module executable that should be used."),
"auth_module_manage_roles": (
"true",
"true",
"Set to false to disable management of roles through the auth module.",
),
"auth_module_timeout_ms": (
"10000",
"10000",

View File

@@ -19,10 +19,10 @@ from mgclient import DatabaseError
@pytest.mark.parametrize("switch", [False, True])
def test_create_node_all_labels_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
results = common.execute_and_fetch_all(user_connection.cursor(), "CREATE (n:label1) RETURN n;")
@@ -33,10 +33,10 @@ def test_create_node_all_labels_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_create_node_all_labels_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -47,10 +47,10 @@ def test_create_node_all_labels_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_create_node_specific_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS :label1 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
results = common.execute_and_fetch_all(user_connection.cursor(), "CREATE (n:label1) RETURN n;")
@@ -61,10 +61,10 @@ def test_create_node_specific_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_create_node_specific_label_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS :label1 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -75,10 +75,10 @@ def test_create_node_specific_label_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_delete_node_all_labels_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
common.execute_and_fetch_all(user_connection.cursor(), "MATCH (n:test_delete) DELETE n;")
@@ -91,10 +91,10 @@ def test_delete_node_all_labels_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_delete_node_all_labels_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -105,10 +105,10 @@ def test_delete_node_all_labels_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_delete_node_specific_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS :test_delete TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
results = common.execute_and_fetch_all(user_connection.cursor(), "MATCH (n:test_delete) DELETE n;")
@@ -123,10 +123,10 @@ def test_delete_node_specific_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_delete_node_specific_label_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS :test_delete TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -137,11 +137,11 @@ def test_delete_node_specific_label_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_create_edge_all_labels_all_edge_types_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -156,11 +156,11 @@ def test_create_edge_all_labels_all_edge_types_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_create_edge_all_labels_all_edge_types_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -174,11 +174,11 @@ def test_create_edge_all_labels_all_edge_types_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_create_edge_all_labels_denied_all_edge_types_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -192,11 +192,11 @@ def test_create_edge_all_labels_denied_all_edge_types_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_create_edge_all_labels_granted_all_edge_types_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -210,7 +210,6 @@ def test_create_edge_all_labels_granted_all_edge_types_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_create_edge_all_labels_granted_specific_edge_types_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
@@ -218,6 +217,7 @@ def test_create_edge_all_labels_granted_specific_edge_types_denied(switch):
admin_connection.cursor(),
"GRANT UPDATE ON EDGE_TYPES :edge_type TO user;",
)
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -231,7 +231,6 @@ def test_create_edge_all_labels_granted_specific_edge_types_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_create_edge_first_node_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS :label1 TO user;")
@@ -240,6 +239,7 @@ def test_create_edge_first_node_label_granted(switch):
admin_connection.cursor(),
"GRANT CREATE_DELETE ON EDGE_TYPES :edge_type TO user;",
)
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -253,7 +253,6 @@ def test_create_edge_first_node_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_create_edge_second_node_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS :label2 TO user;")
@@ -262,6 +261,7 @@ def test_create_edge_second_node_label_granted(switch):
admin_connection.cursor(),
"GRANT CREATE_DELETE ON EDGE_TYPES :edge_type TO user;",
)
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -275,11 +275,11 @@ def test_create_edge_second_node_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_delete_edge_all_labels_denied_all_edge_types_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -293,11 +293,11 @@ def test_delete_edge_all_labels_denied_all_edge_types_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_delete_edge_all_labels_granted_all_edge_types_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -311,7 +311,6 @@ def test_delete_edge_all_labels_granted_all_edge_types_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_delete_edge_all_labels_granted_specific_edge_types_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
@@ -319,6 +318,7 @@ def test_delete_edge_all_labels_granted_specific_edge_types_denied(switch):
admin_connection.cursor(),
"GRANT UPDATE ON EDGE_TYPES :edge_type_delete TO user;",
)
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -332,7 +332,6 @@ def test_delete_edge_all_labels_granted_specific_edge_types_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_delete_edge_first_node_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS :test_delete_1 TO user;")
@@ -341,6 +340,7 @@ def test_delete_edge_first_node_label_granted(switch):
admin_connection.cursor(),
"GRANT CREATE_DELETE ON EDGE_TYPES :edge_type_delete TO user;",
)
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -354,7 +354,6 @@ def test_delete_edge_first_node_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_delete_edge_second_node_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS :test_delete_2 TO user;")
@@ -363,6 +362,7 @@ def test_delete_edge_second_node_label_granted(switch):
admin_connection.cursor(),
"GRANT CREATE_DELETE ON EDGE_TYPES :edge_type_delete TO user;",
)
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -376,13 +376,13 @@ def test_delete_edge_second_node_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_delete_node_with_edge_label_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(
admin_connection.cursor(),
"GRANT UPDATE ON LABELS :test_delete_1 TO user;",
)
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -393,13 +393,13 @@ def test_delete_node_with_edge_label_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_delete_node_with_edge_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(
admin_connection.cursor(),
"GRANT CREATE_DELETE ON LABELS :test_delete_1 TO user;",
)
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -415,10 +415,10 @@ def test_delete_node_with_edge_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_node_all_labels_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
results = common.execute_and_fetch_all(user_connection.cursor(), "MERGE (n:label1) RETURN n;")
@@ -429,10 +429,10 @@ def test_merge_node_all_labels_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_node_all_labels_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -443,10 +443,10 @@ def test_merge_node_all_labels_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_node_specific_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS :label1 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
results = common.execute_and_fetch_all(user_connection.cursor(), "MERGE (n:label1) RETURN n;")
@@ -457,10 +457,10 @@ def test_merge_node_specific_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_node_specific_label_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS :label1 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -471,11 +471,11 @@ def test_merge_node_specific_label_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_edge_all_labels_all_edge_types_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
results = common.execute_and_fetch_all(
@@ -489,11 +489,11 @@ def test_merge_edge_all_labels_all_edge_types_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_edge_all_labels_all_edge_types_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -507,11 +507,11 @@ def test_merge_edge_all_labels_all_edge_types_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_edge_all_labels_denied_all_edge_types_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -525,11 +525,11 @@ def test_merge_edge_all_labels_denied_all_edge_types_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_edge_all_labels_granted_all_edge_types_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -543,7 +543,6 @@ def test_merge_edge_all_labels_granted_all_edge_types_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_edge_all_labels_granted_specific_edge_types_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
@@ -551,6 +550,7 @@ def test_merge_edge_all_labels_granted_specific_edge_types_denied(switch):
admin_connection.cursor(),
"GRANT UPDATE ON EDGE_TYPES :edge_type TO user;",
)
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -564,7 +564,6 @@ def test_merge_edge_all_labels_granted_specific_edge_types_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_edge_first_node_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS :label1 TO user;")
@@ -573,6 +572,7 @@ def test_merge_edge_first_node_label_granted(switch):
admin_connection.cursor(),
"GRANT CREATE_DELETE ON EDGE_TYPES :edge_type TO user;",
)
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -586,7 +586,6 @@ def test_merge_edge_first_node_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_edge_second_node_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS :label2 TO user;")
@@ -595,6 +594,7 @@ def test_merge_edge_second_node_label_granted(switch):
admin_connection.cursor(),
"GRANT CREATE_DELETE ON EDGE_TYPES :edge_type TO user;",
)
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -608,10 +608,10 @@ def test_merge_edge_second_node_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_set_label_when_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS :update_label_2 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -621,12 +621,12 @@ def test_set_label_when_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_set_label_when_label_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS :update_label_2 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS :test_delete TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -637,11 +637,11 @@ def test_set_label_when_label_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_remove_label_when_label_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS :test_delete TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -651,12 +651,12 @@ def test_remove_label_when_label_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_remove_label_when_label_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT UPDATE ON LABELS :update_label_2 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS :test_delete TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -667,12 +667,12 @@ def test_remove_label_when_label_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_merge_nodes_pass_when_having_create_delete(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.reset_and_prepare(admin_connection.cursor())
common.create_multi_db(admin_connection.cursor(), switch)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())

View File

@@ -7,9 +7,9 @@ import pytest
@pytest.mark.parametrize("switch", [False, True])
def test_all_edge_types_all_labels_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -21,9 +21,9 @@ def test_all_edge_types_all_labels_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_deny_all_edge_types_and_all_labels(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -35,9 +35,9 @@ def test_deny_all_edge_types_and_all_labels(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_revoke_all_edge_types_and_all_labels(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -49,10 +49,10 @@ def test_revoke_all_edge_types_and_all_labels(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_deny_edge_type(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS :label1, :label2, :label3 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES :edgeType2 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES :edgeType1 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -64,10 +64,10 @@ def test_deny_edge_type(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_denied_node_label(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS :label1,:label3 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES :edgeType1, :edgeType2 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label2 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -79,10 +79,10 @@ def test_denied_node_label(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_denied_one_of_node_label(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS :label1,:label2 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES :edgeType1, :edgeType2 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label3 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -94,8 +94,8 @@ def test_denied_one_of_node_label(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_revoke_all_labels(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
results = common.execute_and_fetch_all(user_connection.cursor(), "MATCH (n)-[r]->(m) RETURN n,r,m;")
@@ -106,8 +106,8 @@ def test_revoke_all_labels(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_revoke_all_edge_types(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
results = common.execute_and_fetch_all(user_connection.cursor(), "MATCH (n)-[r]->(m) RETURN n,r,m;")

View File

@@ -7,11 +7,11 @@ import pytest
@pytest.mark.parametrize("switch", [False, True])
def test_weighted_shortest_path_all_edge_types_all_labels_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -54,11 +54,11 @@ def test_weighted_shortest_path_all_edge_types_all_labels_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_weighted_shortest_path_all_edge_types_all_labels_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -72,7 +72,6 @@ def test_weighted_shortest_path_all_edge_types_all_labels_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_weighted_shortest_path_denied_start(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -80,6 +79,7 @@ def test_weighted_shortest_path_denied_start(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label0 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -94,7 +94,6 @@ def test_weighted_shortest_path_denied_start(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_weighted_shortest_path_denied_destination(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -102,6 +101,7 @@ def test_weighted_shortest_path_denied_destination(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label4 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -116,7 +116,6 @@ def test_weighted_shortest_path_denied_destination(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_weighted_shortest_path_denied_label_1(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -124,6 +123,7 @@ def test_weighted_shortest_path_denied_label_1(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label1 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -162,7 +162,6 @@ def test_weighted_shortest_path_denied_label_1(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_weighted_shortest_path_denied_edge_type_3(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
@@ -170,6 +169,7 @@ def test_weighted_shortest_path_denied_edge_type_3(switch):
admin_connection.cursor(), "GRANT READ ON EDGE_TYPES :edge_type_1, :edge_type_2, :edge_type_4 TO user;"
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES :edge_type_3 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -213,11 +213,11 @@ def test_weighted_shortest_path_denied_edge_type_3(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_dfs_all_edge_types_all_labels_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -235,11 +235,11 @@ def test_dfs_all_edge_types_all_labels_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_dfs_all_edge_types_all_labels_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -251,7 +251,6 @@ def test_dfs_all_edge_types_all_labels_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_dfs_denied_start(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -259,6 +258,7 @@ def test_dfs_denied_start(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label0 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -272,7 +272,6 @@ def test_dfs_denied_start(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_dfs_denied_destination(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -280,6 +279,7 @@ def test_dfs_denied_destination(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label4 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -293,7 +293,6 @@ def test_dfs_denied_destination(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_dfs_denied_label_1(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -301,6 +300,7 @@ def test_dfs_denied_label_1(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label1 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -318,7 +318,6 @@ def test_dfs_denied_label_1(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_dfs_denied_edge_type_3(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
@@ -327,6 +326,7 @@ def test_dfs_denied_edge_type_3(switch):
admin_connection.cursor(), "GRANT READ ON EDGE_TYPES :edge_type_1, :edge_type_2, :edge_type_4 TO user;"
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES :edge_type_3 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -344,11 +344,11 @@ def test_dfs_denied_edge_type_3(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_sts_all_edge_types_all_labels_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -366,11 +366,11 @@ def test_bfs_sts_all_edge_types_all_labels_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_sts_all_edge_types_all_labels_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -384,7 +384,6 @@ def test_bfs_sts_all_edge_types_all_labels_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_sts_denied_start(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -392,6 +391,7 @@ def test_bfs_sts_denied_start(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label0 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -405,7 +405,6 @@ def test_bfs_sts_denied_start(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_sts_denied_destination(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -413,6 +412,7 @@ def test_bfs_sts_denied_destination(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label4 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -426,7 +426,6 @@ def test_bfs_sts_denied_destination(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_sts_denied_label_1(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -434,6 +433,7 @@ def test_bfs_sts_denied_label_1(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label1 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -450,7 +450,6 @@ def test_bfs_sts_denied_label_1(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_sts_denied_edge_type_3(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
@@ -458,6 +457,7 @@ def test_bfs_sts_denied_edge_type_3(switch):
admin_connection.cursor(), "GRANT READ ON EDGE_TYPES :edge_type_1, :edge_type_2, :edge_type_4 TO user;"
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES :edge_type_3 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -474,11 +474,11 @@ def test_bfs_sts_denied_edge_type_3(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_single_source_all_edge_types_all_labels_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -496,11 +496,11 @@ def test_bfs_single_source_all_edge_types_all_labels_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_single_source_all_edge_types_all_labels_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -512,7 +512,6 @@ def test_bfs_single_source_all_edge_types_all_labels_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_single_source_denied_start(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -520,6 +519,7 @@ def test_bfs_single_source_denied_start(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label0 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -533,7 +533,6 @@ def test_bfs_single_source_denied_start(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_single_source_denied_destination(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -541,6 +540,7 @@ def test_bfs_single_source_denied_destination(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label4 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -554,7 +554,6 @@ def test_bfs_single_source_denied_destination(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_single_source_denied_label_1(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -562,6 +561,7 @@ def test_bfs_single_source_denied_label_1(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label1 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -579,7 +579,6 @@ def test_bfs_single_source_denied_label_1(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_bfs_single_source_denied_edge_type_3(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
@@ -587,6 +586,7 @@ def test_bfs_single_source_denied_edge_type_3(switch):
admin_connection.cursor(), "GRANT READ ON EDGE_TYPES :edge_type_1, :edge_type_2, :edge_type_4 TO user;"
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES :edge_type_3 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -604,11 +604,11 @@ def test_bfs_single_source_denied_edge_type_3(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_all_shortest_paths_when_all_edge_types_all_labels_granted(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -651,11 +651,11 @@ def test_all_shortest_paths_when_all_edge_types_all_labels_granted(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_all_shortest_paths_when_all_edge_types_all_labels_denied(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -669,7 +669,6 @@ def test_all_shortest_paths_when_all_edge_types_all_labels_denied(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_all_shortest_paths_when_denied_start(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -677,6 +676,7 @@ def test_all_shortest_paths_when_denied_start(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label0 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -691,7 +691,6 @@ def test_all_shortest_paths_when_denied_start(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_all_shortest_paths_when_denied_destination(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -699,6 +698,7 @@ def test_all_shortest_paths_when_denied_destination(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label4 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -713,7 +713,6 @@ def test_all_shortest_paths_when_denied_destination(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_all_shortest_paths_when_denied_label_1(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(
@@ -721,6 +720,7 @@ def test_all_shortest_paths_when_denied_label_1(switch):
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON LABELS :label1 TO user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())
@@ -759,7 +759,6 @@ def test_all_shortest_paths_when_denied_label_1(switch):
@pytest.mark.parametrize("switch", [False, True])
def test_all_shortest_paths_when_denied_edge_type_3(switch):
admin_connection = common.connect(username="admin", password="test")
user_connection = common.connect(username="user", password="test")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
@@ -767,6 +766,7 @@ def test_all_shortest_paths_when_denied_edge_type_3(switch):
admin_connection.cursor(), "GRANT READ ON EDGE_TYPES :edge_type_1, :edge_type_2, :edge_type_4 TO user;"
)
common.execute_and_fetch_all(admin_connection.cursor(), "GRANT NOTHING ON EDGE_TYPES :edge_type_3 TO user;")
user_connection = common.connect(username="user", password="test")
if switch:
common.switch_db(user_connection.cursor())

View File

@@ -84,11 +84,12 @@ show_databases_w_user_setup_queries: &show_databases_w_user_setup_queries
- "GRANT DATABASE db1 TO user;"
- "GRANT ALL PRIVILEGES TO user2;"
- "GRANT DATABASE db2 TO user2;"
- "GRANT DATABASE memgraph TO user2;"
- "REVOKE DATABASE memgraph FROM user2;"
- "SET MAIN DATABASE db2 FOR user2"
- "GRANT ALL PRIVILEGES TO user3;"
- "GRANT DATABASE * TO user3;"
- "REVOKE DATABASE memgraph FROM user3;"
- "DENY DATABASE memgraph FROM user3;"
- "SET MAIN DATABASE db1 FOR user3"
create_delete_filtering_in_memory_cluster: &create_delete_filtering_in_memory_cluster

View File

@@ -107,18 +107,21 @@ def execute_read_node_assertion(
operation_case: List[str], queries: List[str], create_index: bool, expected_size: int, switch: bool
) -> None:
admin_cursor = get_admin_cursor()
user_cursor = get_user_cursor()
if switch:
create_multi_db(admin_cursor)
switch_db(admin_cursor)
switch_db(user_cursor)
reset_permissions(admin_cursor, create_index)
for operation in operation_case:
execute_and_fetch_all(admin_cursor, operation)
# Connect after possible auth changes
user_cursor = get_user_cursor()
if switch:
switch_db(user_cursor)
for mq in queries:
results = execute_and_fetch_all(user_cursor, mq)
assert len(results) == expected_size

View File

@@ -121,6 +121,7 @@ def only_main_queries(cursor):
n_exceptions += try_and_count(cursor, f"REVOKE EDGE_TYPES :e FROM user_name")
n_exceptions += try_and_count(cursor, f"GRANT DATABASE memgraph TO user_name;")
n_exceptions += try_and_count(cursor, f"SET MAIN DATABASE memgraph FOR user_name")
n_exceptions += try_and_count(cursor, f"DENY DATABASE memgraph FROM user_name;")
n_exceptions += try_and_count(cursor, f"REVOKE DATABASE memgraph FROM user_name;")
return n_exceptions
@@ -198,8 +199,8 @@ def test_auth_queries_on_replica(connection):
# 1/
assert only_main_queries(cursor_main) == 0
assert only_main_queries(cursor_replica_1) == 17
assert only_main_queries(cursor_replica_2) == 17
assert only_main_queries(cursor_replica_1) == 18
assert only_main_queries(cursor_replica_2) == 18
assert main_and_repl_queries(cursor_main) == 0
assert main_and_repl_queries(cursor_replica_1) == 0
assert main_and_repl_queries(cursor_replica_2) == 0
@@ -383,6 +384,7 @@ def test_manual_roles_recovery(connection):
"--log-level=TRACE",
"--data_directory",
TEMP_DIR + "/replica1",
"--also-log-to-stderr",
],
"log_file": "replica1.log",
"setup_queries": [
@@ -818,13 +820,15 @@ def test_auth_replication(connection):
{("LABEL :l3", "UPDATE", "LABEL PERMISSION GRANTED TO ROLE")},
)
# GRANT/REVOKE DATABASE
# GRANT/DENY DATABASE
execute_and_fetch_all(cursor_main, "CREATE DATABASE auth_test")
execute_and_fetch_all(cursor_main, "CREATE DATABASE auth_test2")
execute_and_fetch_all(cursor_main, "GRANT DATABASE auth_test TO user4")
check(partial(show_database_privileges_func, user="user4"), [(["auth_test", "memgraph"], [])])
execute_and_fetch_all(cursor_main, "REVOKE DATABASE auth_test2 FROM user4")
execute_and_fetch_all(cursor_main, "DENY DATABASE auth_test2 FROM user4")
check(partial(show_database_privileges_func, user="user4"), [(["auth_test", "memgraph"], ["auth_test2"])])
execute_and_fetch_all(cursor_main, "REVOKE DATABASE memgraph FROM user4")
check(partial(show_database_privileges_func, user="user4"), [(["auth_test"], ["auth_test2"])])
# SET MAIN DATABASE
execute_and_fetch_all(cursor_main, "GRANT ALL PRIVILEGES TO user4")

View File

@@ -70,21 +70,26 @@ def test_multitenant_transactions():
# TODO Add SHOW TRANSACTIONS ON * that should return all transactions
def test_admin_has_one_transaction():
def test_admin_has_one_transaction(request):
"""Creates admin and tests that he sees only one transaction."""
# a_cursor is used for creating admin user, simulates main thread
superadmin_cursor = connect().cursor()
execute_and_fetch_all(superadmin_cursor, "CREATE USER admin")
execute_and_fetch_all(superadmin_cursor, "GRANT TRANSACTION_MANAGEMENT TO admin")
execute_and_fetch_all(superadmin_cursor, "GRANT DATABASE * TO admin")
def on_exit():
execute_and_fetch_all(superadmin_cursor, "DROP USER admin")
request.addfinalizer(on_exit)
admin_cursor = connect(username="admin", password="").cursor()
process = multiprocessing.Process(target=show_transactions_test, args=(admin_cursor, 1))
process.start()
process.join()
execute_and_fetch_all(superadmin_cursor, "DROP USER admin")
def test_user_can_see_its_transaction():
def test_user_can_see_its_transaction(request):
"""Tests that user without privileges can see its own transaction"""
superadmin_cursor = connect().cursor()
execute_and_fetch_all(superadmin_cursor, "CREATE USER admin")
@@ -92,20 +97,31 @@ def test_user_can_see_its_transaction():
execute_and_fetch_all(superadmin_cursor, "GRANT DATABASE * TO admin")
execute_and_fetch_all(superadmin_cursor, "CREATE USER user")
execute_and_fetch_all(superadmin_cursor, "REVOKE ALL PRIVILEGES FROM user")
def on_exit():
execute_and_fetch_all(superadmin_cursor, "DROP USER admin")
execute_and_fetch_all(superadmin_cursor, "DROP USER user")
request.addfinalizer(on_exit)
user_cursor = connect(username="user", password="").cursor()
process = multiprocessing.Process(target=show_transactions_test, args=(user_cursor, 1))
process.start()
process.join()
admin_cursor = connect(username="admin", password="").cursor()
execute_and_fetch_all(admin_cursor, "DROP USER user")
execute_and_fetch_all(admin_cursor, "DROP USER admin")
def test_explicit_transaction_output():
def test_explicit_transaction_output(request):
superadmin_cursor = connect().cursor()
execute_and_fetch_all(superadmin_cursor, "CREATE USER admin")
execute_and_fetch_all(superadmin_cursor, "GRANT TRANSACTION_MANAGEMENT TO admin")
execute_and_fetch_all(superadmin_cursor, "GRANT DATABASE * TO admin")
def on_exit():
execute_and_fetch_all(superadmin_cursor, "DROP USER admin")
request.addfinalizer(on_exit)
admin_connection = connect(username="admin", password="")
admin_cursor = admin_connection.cursor()
# Admin starts running explicit transaction
@@ -123,10 +139,9 @@ def test_explicit_transaction_output():
assert show_results[1 - executing_index][2] == ["CREATE (n:Person {id_: 1})", "CREATE (n:Person {id_: 2})"]
execute_and_fetch_all(superadmin_cursor, "ROLLBACK")
execute_and_fetch_all(superadmin_cursor, "DROP USER admin")
def test_superadmin_cannot_see_admin_can_see_admin():
def test_superadmin_cannot_see_admin_can_see_admin(request):
"""Tests that superadmin cannot see the transaction created by admin but two admins can see and kill each other's transactions."""
superadmin_cursor = connect().cursor()
execute_and_fetch_all(superadmin_cursor, "CREATE USER admin1")
@@ -135,6 +150,13 @@ def test_superadmin_cannot_see_admin_can_see_admin():
execute_and_fetch_all(superadmin_cursor, "CREATE USER admin2")
execute_and_fetch_all(superadmin_cursor, "GRANT TRANSACTION_MANAGEMENT TO admin2")
execute_and_fetch_all(superadmin_cursor, "GRANT DATABASE * TO admin2")
def on_exit():
execute_and_fetch_all(superadmin_cursor, "DROP USER admin1")
execute_and_fetch_all(superadmin_cursor, "DROP USER admin2")
request.addfinalizer(on_exit)
# Admin starts running infinite query
admin_connection_1 = connect(username="admin1", password="")
admin_cursor_1 = admin_connection_1.cursor()
@@ -160,19 +182,23 @@ def test_superadmin_cannot_see_admin_can_see_admin():
# Kill transaction
long_transaction_id = show_results[1 - executing_index][1]
execute_and_fetch_all(admin_cursor_2, f"TERMINATE TRANSACTIONS '{long_transaction_id}'")
execute_and_fetch_all(superadmin_cursor, "DROP USER admin1")
execute_and_fetch_all(superadmin_cursor, "DROP USER admin2")
admin_connection_1.close()
admin_connection_2.close()
def test_admin_sees_superadmin():
def test_admin_sees_superadmin(request):
"""Tests that admin created by superadmin can see the superadmin's transaction."""
superadmin_connection = connect()
superadmin_cursor = superadmin_connection.cursor()
execute_and_fetch_all(superadmin_cursor, "CREATE USER admin")
execute_and_fetch_all(superadmin_cursor, "GRANT TRANSACTION_MANAGEMENT TO admin")
execute_and_fetch_all(superadmin_cursor, "GRANT DATABASE * TO admin")
def on_exit():
execute_and_fetch_all(admin_cursor, "DROP USER admin")
request.addfinalizer(on_exit)
# Admin starts running infinite query
process = multiprocessing.Process(
target=process_function, args=(superadmin_cursor, ["CALL infinite_query.long_query() YIELD my_id RETURN my_id"])
@@ -194,17 +220,23 @@ def test_admin_sees_superadmin():
# Kill transaction
long_transaction_id = show_results[1 - executing_index][1]
execute_and_fetch_all(admin_cursor, f"TERMINATE TRANSACTIONS '{long_transaction_id}'")
execute_and_fetch_all(admin_cursor, "DROP USER admin")
superadmin_connection.close()
def test_admin_can_see_user_transaction():
def test_admin_can_see_user_transaction(request):
"""Tests that admin can see user's transaction and kill it."""
superadmin_cursor = connect().cursor()
execute_and_fetch_all(superadmin_cursor, "CREATE USER admin")
execute_and_fetch_all(superadmin_cursor, "GRANT TRANSACTION_MANAGEMENT TO admin")
execute_and_fetch_all(superadmin_cursor, "GRANT DATABASE * TO admin")
execute_and_fetch_all(superadmin_cursor, "CREATE USER user")
def on_exit():
execute_and_fetch_all(superadmin_cursor, "DROP USER admin")
execute_and_fetch_all(superadmin_cursor, "DROP USER user")
request.addfinalizer(on_exit)
# Admin starts running infinite query
admin_connection = connect(username="admin", password="")
admin_cursor = admin_connection.cursor()
@@ -229,13 +261,11 @@ def test_admin_can_see_user_transaction():
# Kill transaction
long_transaction_id = show_results[1 - executing_index][1]
execute_and_fetch_all(admin_cursor, f"TERMINATE TRANSACTIONS '{long_transaction_id}'")
execute_and_fetch_all(superadmin_cursor, "DROP USER admin")
execute_and_fetch_all(superadmin_cursor, "DROP USER user")
admin_connection.close()
user_connection.close()
def test_user_cannot_see_admin_transaction():
def test_user_cannot_see_admin_transaction(request):
"""User cannot see admin's transaction but other admin can and he can kill it."""
# Superadmin creates two admins and one user
superadmin_cursor = connect().cursor()
@@ -246,6 +276,14 @@ def test_user_cannot_see_admin_transaction():
execute_and_fetch_all(superadmin_cursor, "GRANT TRANSACTION_MANAGEMENT TO admin2")
execute_and_fetch_all(superadmin_cursor, "GRANT DATABASE * TO admin2")
execute_and_fetch_all(superadmin_cursor, "CREATE USER user")
def on_exit():
execute_and_fetch_all(superadmin_cursor, "DROP USER admin1")
execute_and_fetch_all(superadmin_cursor, "DROP USER admin2")
execute_and_fetch_all(superadmin_cursor, "DROP USER user")
request.addfinalizer(on_exit)
admin_connection_1 = connect(username="admin1", password="")
admin_cursor_1 = admin_connection_1.cursor()
admin_connection_2 = connect(username="admin2", password="")
@@ -274,9 +312,6 @@ def test_user_cannot_see_admin_transaction():
# Kill transaction
long_transaction_id = show_results[1 - executing_index][1]
execute_and_fetch_all(admin_cursor_2, f"TERMINATE TRANSACTIONS '{long_transaction_id}'")
execute_and_fetch_all(superadmin_cursor, "DROP USER admin1")
execute_and_fetch_all(superadmin_cursor, "DROP USER admin2")
execute_and_fetch_all(superadmin_cursor, "DROP USER user")
admin_connection_1.close()
admin_connection_2.close()
user_connection.close()
@@ -300,12 +335,18 @@ def test_killing_multiple_non_existing_transactions():
assert results[i][1] == False # not killed
def test_admin_killing_multiple_non_existing_transactions():
def test_admin_killing_multiple_non_existing_transactions(request):
# Starting, superadmin admin
superadmin_cursor = connect().cursor()
execute_and_fetch_all(superadmin_cursor, "CREATE USER admin")
execute_and_fetch_all(superadmin_cursor, "GRANT TRANSACTION_MANAGEMENT TO admin")
execute_and_fetch_all(superadmin_cursor, "GRANT DATABASE * TO admin")
def on_exit():
execute_and_fetch_all(admin_cursor, "DROP USER admin")
request.addfinalizer(on_exit)
# Connect with admin
admin_cursor = connect(username="admin", password="").cursor()
transactions_id = ["'1'", "'2'", "'3'"]
@@ -314,7 +355,6 @@ def test_admin_killing_multiple_non_existing_transactions():
for i in range(len(results)):
assert results[i][0] == eval(transactions_id[i]) # transaction id
assert results[i][1] == False # not killed
execute_and_fetch_all(admin_cursor, "DROP USER admin")
def test_user_killing_some_transactions():

View File

@@ -193,12 +193,12 @@ def execute_test(memgraph_binary, tester_binary, checker_binary):
"GRANT DATABASE db2 TO user",
"CREATE USER useR2 IDENTIFIED BY 'user'",
"GRANT DATABASE db2 TO user2",
"REVOKE DATABASE memgraph FROM user2",
"DENY DATABASE memgraph FROM user2",
"SET MAIN DATABASE db2 FOR user2",
"CREATE USER user3 IDENTIFIED BY 'user'",
"GRANT ALL PRIVILEGES TO user3",
"GRANT DATABASE * TO user3",
"REVOKE DATABASE memgraph FROM user3",
"DENY DATABASE memgraph FROM user3",
]
)

View File

@@ -139,7 +139,7 @@ class Memgraph:
def initialize_test(memgraph, tester_binary, **kwargs):
memgraph.start(module_executable="")
execute_tester(tester_binary, ["CREATE USER root", "GRANT ALL PRIVILEGES TO root"])
execute_tester(tester_binary, ["CREATE ROLE root_role", "GRANT ALL PRIVILEGES TO root_role"])
check_login = kwargs.pop("check_login", True)
memgraph.restart(**kwargs)
if check_login:
@@ -149,20 +149,24 @@ def initialize_test(memgraph, tester_binary, **kwargs):
# Tests
def test_basic(memgraph, tester_binary):
def test_module_ux(memgraph, tester_binary):
initialize_test(memgraph, tester_binary)
execute_tester(tester_binary, [], "alice")
execute_tester(tester_binary, ["GRANT MATCH TO alice"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
execute_tester(tester_binary, ["CREATE USER user1"], "root", query_should_fail=True)
execute_tester(tester_binary, ["CREATE ROLE role1"], "root", query_should_fail=False)
execute_tester(tester_binary, ["DROP USER user1"], "root", query_should_fail=True)
execute_tester(tester_binary, ["DROP ROLE role1"], "root", query_should_fail=False)
execute_tester(tester_binary, ["SET ROLE FOR user1 TO role1"], "root", query_should_fail=True)
execute_tester(tester_binary, ["CLEAR ROLE FOR user1"], "root", query_should_fail=True)
memgraph.stop()
def test_only_existing_users(memgraph, tester_binary):
initialize_test(memgraph, tester_binary, create_missing_user=False)
def test_user_auth(memgraph, tester_binary):
initialize_test(memgraph, tester_binary)
execute_tester(tester_binary, [], "alice", auth_should_fail=True)
execute_tester(tester_binary, ["CREATE USER alice"], "root")
execute_tester(tester_binary, ["CREATE ROLE moderator"], "root")
execute_tester(tester_binary, [], "alice")
execute_tester(tester_binary, ["GRANT MATCH TO alice"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=True)
execute_tester(tester_binary, ["GRANT MATCH TO moderator"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
memgraph.stop()
@@ -170,77 +174,50 @@ def test_only_existing_users(memgraph, tester_binary):
def test_role_mapping(memgraph, tester_binary):
initialize_test(memgraph, tester_binary)
execute_tester(tester_binary, [], "alice")
execute_tester(tester_binary, [], "alice", auth_should_fail=True)
execute_tester(tester_binary, [], "bob", auth_should_fail=True)
execute_tester(tester_binary, [], "carol", auth_should_fail=True)
execute_tester(tester_binary, ["CREATE ROLE moderator"], "root")
execute_tester(tester_binary, ["CREATE ROLE admin"], "root")
execute_tester(tester_binary, [], "alice", auth_should_fail=False)
execute_tester(tester_binary, [], "bob", auth_should_fail=True)
execute_tester(tester_binary, [], "carol", auth_should_fail=False)
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=True)
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "carol", query_should_fail=True)
execute_tester(tester_binary, ["GRANT MATCH TO moderator"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=False)
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "carol", query_should_fail=True)
execute_tester(tester_binary, ["GRANT MATCH TO admin"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=False)
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "carol", query_should_fail=False)
execute_tester(tester_binary, [], "bob")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "bob", query_should_fail=True)
execute_tester(tester_binary, [], "carol")
execute_tester(tester_binary, ["CREATE (n) RETURN n"], "alice", query_should_fail=True)
execute_tester(tester_binary, ["CREATE (n) RETURN n"], "carol", query_should_fail=True)
execute_tester(tester_binary, ["GRANT CREATE TO admin"], "root")
execute_tester(tester_binary, ["CREATE (n) RETURN n"], "carol")
execute_tester(tester_binary, ["CREATE (n) RETURN n"], "dave")
execute_tester(tester_binary, ["CREATE (n) RETURN n"], "alice", query_should_fail=True)
execute_tester(tester_binary, ["CREATE (n) RETURN n"], "carol", query_should_fail=False)
memgraph.stop()
def test_instance_restart(memgraph, tester_binary):
initialize_test(memgraph, tester_binary)
execute_tester(tester_binary, ["CREATE ROLE moderator"], "root")
execute_tester(tester_binary, ["GRANT MATCH TO moderator"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
memgraph.restart()
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
memgraph.stop()
def test_role_removal(memgraph, tester_binary):
initialize_test(memgraph, tester_binary)
execute_tester(tester_binary, [], "alice")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=True)
execute_tester(tester_binary, ["CREATE ROLE moderator"], "root")
execute_tester(tester_binary, ["GRANT MATCH TO moderator"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
memgraph.restart(manage_roles=False)
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
execute_tester(tester_binary, ["CLEAR ROLE FOR alice"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=True)
memgraph.stop()
def test_only_existing_roles(memgraph, tester_binary):
initialize_test(memgraph, tester_binary, create_missing_role=False)
execute_tester(tester_binary, [], "bob")
execute_tester(tester_binary, ["DROP ROLE moderator"], "root")
execute_tester(tester_binary, [], "alice", auth_should_fail=True)
execute_tester(tester_binary, ["CREATE ROLE moderator"], "root")
execute_tester(tester_binary, [], "alice")
memgraph.stop()
def test_role_is_user(memgraph, tester_binary):
initialize_test(memgraph, tester_binary)
execute_tester(tester_binary, [], "admin")
execute_tester(tester_binary, [], "carol", auth_should_fail=True)
memgraph.stop()
def test_user_is_role(memgraph, tester_binary):
initialize_test(memgraph, tester_binary)
execute_tester(tester_binary, [], "carol")
execute_tester(tester_binary, [], "admin", auth_should_fail=True)
memgraph.stop()
def test_user_permissions_persistancy(memgraph, tester_binary):
initialize_test(memgraph, tester_binary)
execute_tester(tester_binary, ["CREATE USER alice", "GRANT MATCH TO alice"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
memgraph.stop()
def test_role_permissions_persistancy(memgraph, tester_binary):
initialize_test(memgraph, tester_binary)
execute_tester(tester_binary, ["CREATE ROLE moderator", "GRANT MATCH TO moderator"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
memgraph.stop()
def test_only_authentication(memgraph, tester_binary):
initialize_test(memgraph, tester_binary, manage_roles=False)
execute_tester(tester_binary, ["CREATE ROLE moderator", "GRANT MATCH TO moderator"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=True)
memgraph.stop()
@@ -258,36 +235,36 @@ def test_wrong_suffix(memgraph, tester_binary):
def test_suffix_with_spaces(memgraph, tester_binary):
initialize_test(memgraph, tester_binary, suffix=", ou= people, dc = memgraph, dc = com")
execute_tester(tester_binary, ["CREATE USER alice", "GRANT MATCH TO alice"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
memgraph.stop()
def test_role_mapping_wrong_root_dn(memgraph, tester_binary):
initialize_test(memgraph, tester_binary, root_dn="ou=invalid,dc=memgraph,dc=com")
execute_tester(tester_binary, ["CREATE ROLE moderator", "GRANT MATCH TO moderator"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=True)
memgraph.restart()
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
memgraph.stop()
def test_role_mapping_wrong_root_objectclass(memgraph, tester_binary):
initialize_test(memgraph, tester_binary, root_objectclass="person")
execute_tester(tester_binary, ["CREATE ROLE moderator", "GRANT MATCH TO moderator"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=True)
memgraph.restart()
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
memgraph.stop()
# def test_role_mapping_wrong_root_dn(memgraph, tester_binary):
# initialize_test(memgraph, tester_binary, root_dn="ou=invalid,dc=memgraph,dc=com")
# execute_tester(tester_binary, ["CREATE ROLE moderator", "GRANT MATCH TO moderator"], "root")
# execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=True)
# memgraph.restart()
# execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
# memgraph.stop()
def test_role_mapping_wrong_user_attribute(memgraph, tester_binary):
initialize_test(memgraph, tester_binary, user_attribute="cn")
execute_tester(tester_binary, ["CREATE ROLE moderator", "GRANT MATCH TO moderator"], "root")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=True)
memgraph.restart()
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
memgraph.stop()
# def test_role_mapping_wrong_root_objectclass(memgraph, tester_binary):
# initialize_test(memgraph, tester_binary, root_objectclass="person")
# execute_tester(tester_binary, ["CREATE ROLE moderator", "GRANT MATCH TO moderator"], "root")
# execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=True)
# memgraph.restart()
# execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
# memgraph.stop()
# def test_role_mapping_wrong_user_attribute(memgraph, tester_binary):
# initialize_test(memgraph, tester_binary, user_attribute="cn")
# execute_tester(tester_binary, ["CREATE ROLE moderator", "GRANT MATCH TO moderator"], "root")
# execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice", query_should_fail=True)
# memgraph.restart()
# execute_tester(tester_binary, ["MATCH (n) RETURN n"], "alice")
# memgraph.stop()
def test_wrong_password(memgraph, tester_binary):
@@ -297,31 +274,9 @@ def test_wrong_password(memgraph, tester_binary):
memgraph.stop()
def test_password_persistancy(memgraph, tester_binary):
initialize_test(memgraph, tester_binary, check_login=False)
memgraph.restart(module_executable="")
execute_tester(tester_binary, ["SHOW USERS"], "root", password="sudo")
execute_tester(tester_binary, ["SHOW USERS"], "root", password="root")
memgraph.restart()
execute_tester(tester_binary, [], "root", password="sudo", auth_should_fail=True)
execute_tester(tester_binary, ["SHOW USERS"], "root", password="root")
memgraph.restart(module_executable="")
execute_tester(tester_binary, [], "root", password="sudo", auth_should_fail=True)
execute_tester(tester_binary, ["SHOW USERS"], "root", password="root")
memgraph.stop()
def test_user_multiple_roles(memgraph, tester_binary):
initialize_test(memgraph, tester_binary, check_login=False)
memgraph.restart()
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "eve", query_should_fail=True)
execute_tester(tester_binary, ["GRANT MATCH TO moderator"], "root", query_should_fail=True)
memgraph.restart(manage_roles=False)
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "eve", query_should_fail=True)
execute_tester(tester_binary, ["GRANT MATCH TO moderator"], "root", query_should_fail=True)
memgraph.restart(manage_roles=False, root_dn="")
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "eve", query_should_fail=True)
execute_tester(tester_binary, ["GRANT MATCH TO moderator"], "root", query_should_fail=True)
initialize_test(memgraph, tester_binary)
execute_tester(tester_binary, ["MATCH (n) RETURN n"], "eve", auth_should_fail=True)
memgraph.stop()

View File

@@ -84,6 +84,13 @@ objectclass: organizationalUnit
objectclass: top
ou: roles
# Role root
dn: cn=root_role,ou=roles,dc=memgraph,dc=com
cn: root_role
member: cn=root,ou=people,dc=memgraph,dc=com
objectclass: groupOfNames
objectclass: top
# Role moderator
dn: cn=moderator,ou=roles,dc=memgraph,dc=com
cn: moderator

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2024 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -48,6 +48,7 @@ int main(int argc, char **argv) {
}
if (FLAGS_auth_should_fail) {
MG_ASSERT(!what.empty(), "The authentication should have failed!");
return 0; // Auth failed, nothing left to do
} else {
MG_ASSERT(what.empty(),
"The authentication should have succeeded, but "

View File

@@ -50,6 +50,8 @@ int main(int argc, char *argv[]) {
memgraph::query::Interpreter interpreter{&interpreter_context, db_acc};
ResultStreamFaker stream(db_acc->storage());
memgraph::query::AllowEverythingAuthChecker auth_checker;
interpreter.SetUser(auth_checker.GenQueryUser(std::nullopt, std::nullopt));
auto [header, _1, qid, _2] = interpreter.Prepare(argv[1], {}, {});
stream.Header(header);
auto summary = interpreter.PullAll(&stream);

View File

@@ -280,6 +280,8 @@ TEST_F(AuthWithStorage, RoleManipulations) {
}
{
const auto all = auth->AllUsernames();
for (const auto &user : all) std::cout << user << std::endl;
auto users = auth->AllUsers();
std::sort(users.begin(), users.end(), [](const User &a, const User &b) { return a.username() < b.username(); });
ASSERT_EQ(users.size(), 2);
@@ -774,14 +776,16 @@ TEST_F(AuthWithStorage, CaseInsensitivity) {
// Authenticate
{
auto user = auth->Authenticate("alice", "alice");
ASSERT_TRUE(user);
ASSERT_EQ(user->username(), "alice");
auto user_or_role = auth->Authenticate("alice", "alice");
ASSERT_TRUE(user_or_role);
const auto &user = std::get<memgraph::auth::User>(*user_or_role);
ASSERT_EQ(user.username(), "alice");
}
{
auto user = auth->Authenticate("alICe", "alice");
ASSERT_TRUE(user);
ASSERT_EQ(user->username(), "alice");
auto user_or_role = auth->Authenticate("alICe", "alice");
ASSERT_TRUE(user_or_role);
const auto &user = std::get<memgraph::auth::User>(*user_or_role);
ASSERT_EQ(user.username(), "alice");
}
// GetUser
@@ -809,6 +813,8 @@ TEST_F(AuthWithStorage, CaseInsensitivity) {
// AllUsers
{
const auto all = auth->AllUsernames();
for (const auto &user : all) std::cout << user << std::endl;
auto users = auth->AllUsers();
ASSERT_EQ(users.size(), 2);
std::sort(users.begin(), users.end(), [](const auto &a, const auto &b) { return a.username() < b.username(); });

View File

@@ -12,11 +12,14 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "auth/exceptions.hpp"
#include "auth/models.hpp"
#include "disk_test_utils.hpp"
#include "glue/auth_checker.hpp"
#include "license/license.hpp"
#include "query/frontend/ast/ast.hpp"
#include "query/query_user.hpp"
#include "query_plan_common.hpp"
#include "storage/v2/config.hpp"
#include "storage/v2/disk/storage.hpp"
@@ -225,4 +228,123 @@ TYPED_TEST(FineGrainedAuthCheckerFixture, GrantAndDenySpecificEdgeTypes) {
ASSERT_FALSE(auth_checker.Has(this->r3, memgraph::query::AuthQuery::FineGrainedPrivilege::READ));
ASSERT_FALSE(auth_checker.Has(this->r4, memgraph::query::AuthQuery::FineGrainedPrivilege::READ));
}
TEST(AuthChecker, Generate) {
std::filesystem::path auth_dir{std::filesystem::temp_directory_path() / "MG_auth_checker"};
memgraph::utils::OnScopeExit clean([&]() {
if (std::filesystem::exists(auth_dir)) {
std::filesystem::remove_all(auth_dir);
}
});
memgraph::auth::SynchedAuth auth(auth_dir, memgraph::auth::Auth::Config{/* default config */});
memgraph::glue::AuthChecker auth_checker(&auth);
auto empty_user = auth_checker.GenQueryUser(std::nullopt, std::nullopt);
ASSERT_THROW(auth_checker.GenQueryUser("does_not_exist", std::nullopt), memgraph::auth::AuthException);
EXPECT_FALSE(empty_user && *empty_user);
// Still empty auth, so the above should have su permissions
using enum memgraph::query::AuthQuery::Privilege;
EXPECT_TRUE(empty_user->IsAuthorized({AUTH, REMOVE, REPLICATION}, "", &memgraph::query::session_long_policy));
EXPECT_TRUE(empty_user->IsAuthorized({FREE_MEMORY, WEBSOCKET, MULTI_DATABASE_EDIT}, "memgraph",
&memgraph::query::session_long_policy));
EXPECT_TRUE(
empty_user->IsAuthorized({TRIGGER, DURABILITY, STORAGE_MODE}, "some_db", &memgraph::query::session_long_policy));
// Add user
auth->AddUser("new_user");
// ~Empty user should now fail~
// NOTE: Cache invalidation has been disabled, so this will pass; change if it is ever turned on
EXPECT_TRUE(empty_user->IsAuthorized({AUTH, REMOVE, REPLICATION}, "", &memgraph::query::session_long_policy));
EXPECT_TRUE(empty_user->IsAuthorized({FREE_MEMORY, WEBSOCKET, MULTI_DATABASE_EDIT}, "memgraph",
&memgraph::query::session_long_policy));
EXPECT_TRUE(
empty_user->IsAuthorized({TRIGGER, DURABILITY, STORAGE_MODE}, "some_db", &memgraph::query::session_long_policy));
// Add role and new user
auto new_role = *auth->AddRole("new_role");
auto new_user2 = *auth->AddUser("new_user2");
auto role = auth_checker.GenQueryUser("anyuser", "new_role");
auto user2 = auth_checker.GenQueryUser("new_user2", std::nullopt);
// Should be permission-less by default
EXPECT_FALSE(role->IsAuthorized({AUTH}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_FALSE(role->IsAuthorized({FREE_MEMORY}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_FALSE(role->IsAuthorized({TRIGGER}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_FALSE(user2->IsAuthorized({AUTH}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_FALSE(user2->IsAuthorized({FREE_MEMORY}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_FALSE(user2->IsAuthorized({TRIGGER}, "memgraph", &memgraph::query::session_long_policy));
// Update permissions and recheck
new_user2.permissions().Grant(memgraph::auth::Permission::AUTH);
new_role.permissions().Grant(memgraph::auth::Permission::TRIGGER);
auth->SaveUser(new_user2);
auth->SaveRole(new_role);
role = auth_checker.GenQueryUser("no check", "new_role");
user2 = auth_checker.GenQueryUser("new_user2", std::nullopt);
EXPECT_FALSE(role->IsAuthorized({AUTH}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_FALSE(role->IsAuthorized({FREE_MEMORY}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_TRUE(role->IsAuthorized({TRIGGER}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_TRUE(user2->IsAuthorized({AUTH}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_FALSE(user2->IsAuthorized({FREE_MEMORY}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_FALSE(user2->IsAuthorized({TRIGGER}, "memgraph", &memgraph::query::session_long_policy));
// Connect role and recheck
new_user2.SetRole(new_role);
auth->SaveUser(new_user2);
user2 = auth_checker.GenQueryUser("new_user2", std::nullopt);
EXPECT_TRUE(user2->IsAuthorized({AUTH}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_FALSE(user2->IsAuthorized({FREE_MEMORY}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_TRUE(user2->IsAuthorized({TRIGGER}, "memgraph", &memgraph::query::session_long_policy));
// Add database and recheck
EXPECT_FALSE(user2->IsAuthorized({AUTH}, "non_default", &memgraph::query::session_long_policy));
EXPECT_FALSE(user2->IsAuthorized({AUTH}, "another", &memgraph::query::session_long_policy));
EXPECT_TRUE(user2->IsAuthorized({AUTH}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_FALSE(role->IsAuthorized({TRIGGER}, "non_default", &memgraph::query::session_long_policy));
EXPECT_FALSE(role->IsAuthorized({TRIGGER}, "another", &memgraph::query::session_long_policy));
EXPECT_TRUE(role->IsAuthorized({TRIGGER}, "memgraph", &memgraph::query::session_long_policy));
new_user2.db_access().Grant("another");
new_role.db_access().Grant("non_default");
auth->SaveUser(new_user2);
auth->SaveRole(new_role);
// Session policy test
// Session long policy
EXPECT_FALSE(user2->IsAuthorized({AUTH}, "non_default", &memgraph::query::session_long_policy));
EXPECT_FALSE(user2->IsAuthorized({AUTH}, "another", &memgraph::query::session_long_policy));
EXPECT_TRUE(user2->IsAuthorized({AUTH}, "memgraph", &memgraph::query::session_long_policy));
EXPECT_FALSE(role->IsAuthorized({TRIGGER}, "non_default", &memgraph::query::session_long_policy));
EXPECT_FALSE(role->IsAuthorized({TRIGGER}, "another", &memgraph::query::session_long_policy));
EXPECT_TRUE(role->IsAuthorized({TRIGGER}, "memgraph", &memgraph::query::session_long_policy));
// Up to date policy
EXPECT_TRUE(user2->IsAuthorized({AUTH}, "non_default", &memgraph::query::up_to_date_policy));
EXPECT_TRUE(user2->IsAuthorized({AUTH}, "another", &memgraph::query::up_to_date_policy));
EXPECT_TRUE(user2->IsAuthorized({AUTH}, "memgraph", &memgraph::query::up_to_date_policy));
EXPECT_TRUE(role->IsAuthorized({TRIGGER}, "non_default", &memgraph::query::up_to_date_policy));
EXPECT_FALSE(role->IsAuthorized({TRIGGER}, "another", &memgraph::query::up_to_date_policy));
EXPECT_TRUE(role->IsAuthorized({TRIGGER}, "memgraph", &memgraph::query::up_to_date_policy));
new_user2.db_access().Deny("memgraph");
new_role.db_access().Deny("non_default");
auth->SaveUser(new_user2);
auth->SaveRole(new_role);
EXPECT_FALSE(user2->IsAuthorized({AUTH}, "non_default", &memgraph::query::up_to_date_policy));
EXPECT_TRUE(user2->IsAuthorized({AUTH}, "another", &memgraph::query::up_to_date_policy));
EXPECT_FALSE(user2->IsAuthorized({AUTH}, "memgraph", &memgraph::query::up_to_date_policy));
EXPECT_FALSE(role->IsAuthorized({TRIGGER}, "non_default", &memgraph::query::up_to_date_policy));
EXPECT_FALSE(role->IsAuthorized({TRIGGER}, "another", &memgraph::query::up_to_date_policy));
EXPECT_TRUE(role->IsAuthorized({TRIGGER}, "memgraph", &memgraph::query::up_to_date_policy));
new_user2.db_access().Revoke("memgraph");
new_role.db_access().Revoke("non_default");
auth->SaveUser(new_user2);
auth->SaveRole(new_role);
EXPECT_FALSE(user2->IsAuthorized({AUTH}, "non_default", &memgraph::query::up_to_date_policy));
EXPECT_TRUE(user2->IsAuthorized({AUTH}, "another", &memgraph::query::up_to_date_policy));
EXPECT_TRUE(user2->IsAuthorized({AUTH}, "memgraph", &memgraph::query::up_to_date_policy));
EXPECT_FALSE(role->IsAuthorized({TRIGGER}, "non_default", &memgraph::query::up_to_date_policy));
EXPECT_FALSE(role->IsAuthorized({TRIGGER}, "another", &memgraph::query::up_to_date_policy));
EXPECT_TRUE(role->IsAuthorized({TRIGGER}, "memgraph", &memgraph::query::up_to_date_policy));
}
#endif

View File

@@ -1,4 +1,4 @@
// Copyright 2023 Memgraph Ltd.
// Copyright 2024 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -18,6 +18,7 @@ struct InterpreterFaker {
: interpreter_context(interpreter_context), interpreter(interpreter_context, db) {
interpreter_context->auth_checker = &auth_checker;
interpreter_context->interpreters.WithLock([this](auto &interpreters) { interpreters.insert(&interpreter); });
interpreter.SetUser(auth_checker.GenQueryUser(std::nullopt, std::nullopt));
}
auto Prepare(const std::string &query, const std::map<std::string, memgraph::storage::PropertyValue> &params = {}) {

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2024 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -44,11 +44,9 @@ struct MockAuth : public memgraph::communication::websocket::AuthenticationInter
return authentication;
}
bool HasUserPermission(const std::string & /*username*/, memgraph::auth::Permission /*permission*/) const override {
return authorization;
}
bool HasPermission(memgraph::auth::Permission /*permission*/) const override { return authorization; }
bool HasAnyUsers() const override { return has_any_users; }
bool AccessControlled() const override { return has_any_users; }
bool authentication{true};
bool authorization{true};

View File

@@ -21,6 +21,8 @@
#include "communication/result_stream_faker.hpp"
#include "dbms/database.hpp"
#include "disk_test_utils.hpp"
#include "glue/auth_checker.hpp"
#include "query/auth_checker.hpp"
#include "query/config.hpp"
#include "query/dump.hpp"
#include "query/interpreter.hpp"
@@ -216,6 +218,8 @@ DatabaseState GetState(memgraph::storage::Storage *db) {
auto Execute(memgraph::query::InterpreterContext *context, memgraph::dbms::DatabaseAccess db,
const std::string &query) {
memgraph::query::Interpreter interpreter(context, db);
memgraph::query::AllowEverythingAuthChecker auth_checker;
interpreter.SetUser(auth_checker.GenQueryUser(std::nullopt, std::nullopt));
ResultStreamFaker stream(db->storage());
auto [header, _1, qid, _2] = interpreter.Prepare(query, {}, {});
@@ -915,7 +919,10 @@ TYPED_TEST(DumpTest, ExecuteDumpDatabase) {
class StatefulInterpreter {
public:
explicit StatefulInterpreter(memgraph::query::InterpreterContext *context, memgraph::dbms::DatabaseAccess db)
: context_(context), interpreter_(context_, db) {}
: context_(context), interpreter_(context_, db) {
memgraph::query::AllowEverythingAuthChecker auth_checker;
interpreter_.SetUser(auth_checker.GenQueryUser(std::nullopt, std::nullopt));
}
auto Execute(const std::string &query) {
ResultStreamFaker stream(interpreter_.current_db_.db_acc_->get()->storage());
@@ -1138,7 +1145,7 @@ TYPED_TEST(DumpTest, DumpDatabaseWithTriggers) {
memgraph::query::DbAccessor dba(acc.get());
const std::map<std::string, memgraph::storage::PropertyValue> props;
trigger_store->AddTrigger(trigger_name, trigger_statement, props, trigger_event_type, trigger_phase, &ast_cache,
&dba, query_config, std::nullopt, &auth_checker);
&dba, query_config, auth_checker.GenQueryUser(std::nullopt, std::nullopt));
}
{
ResultStreamFaker stream(this->db->storage());

View File

@@ -22,6 +22,7 @@
#include "gtest/gtest.h"
#include "communication/result_stream_faker.hpp"
#include "query/auth_checker.hpp"
#include "query/interpreter.hpp"
#include "query/interpreter_context.hpp"
#include "query/stream/streams.hpp"
@@ -36,6 +37,7 @@ class QueryExecution : public testing::Test {
const std::string testSuite = "query_plan_edge_cases";
std::optional<memgraph::dbms::DatabaseAccess> db_acc_;
std::optional<memgraph::query::InterpreterContext> interpreter_context_;
std::optional<memgraph::query::AllowEverythingAuthChecker> auth_checker_;
std::optional<memgraph::query::Interpreter> interpreter_;
std::filesystem::path data_directory{std::filesystem::temp_directory_path() / "MG_tests_unit_query_plan_edge_cases"};
@@ -73,11 +75,14 @@ class QueryExecution : public testing::Test {
nullptr
#endif
);
auth_checker_.emplace();
interpreter_.emplace(&*interpreter_context_, *db_acc_);
interpreter_->SetUser(auth_checker_->GenQueryUser(std::nullopt, std::nullopt));
}
void TearDown() override {
interpreter_ = std::nullopt;
auth_checker_.reset();
interpreter_context_ = std::nullopt;
system_state.reset();
db_acc_.reset();

View File

@@ -20,9 +20,11 @@
#include "integrations/constants.hpp"
#include "integrations/kafka/exceptions.hpp"
#include "kafka_mock.hpp"
#include "query/auth_checker.hpp"
#include "query/config.hpp"
#include "query/interpreter.hpp"
#include "query/interpreter_context.hpp"
#include "query/query_user.hpp"
#include "query/stream/streams.hpp"
#include "storage/v2/config.hpp"
#include "storage/v2/disk/storage.hpp"
@@ -35,11 +37,23 @@ using StreamStatus = memgraph::query::stream::StreamStatus<memgraph::query::stre
namespace {
const static std::string kTopicName{"TrialTopic"};
struct FakeUser : memgraph::query::QueryUserOrRole {
FakeUser() : memgraph::query::QueryUserOrRole{std::nullopt, std::nullopt} {}
bool IsAuthorized(const std::vector<memgraph::query::AuthQuery::Privilege> &privileges, const std::string &db_name,
memgraph::query::UserPolicy *policy) const {
return true;
}
#ifdef MG_ENTERPRISE
std::string GetDefaultDB() const { return "memgraph"; }
#endif
};
struct StreamCheckData {
std::string name;
StreamInfo info;
bool is_running;
std::optional<std::string> owner;
std::shared_ptr<memgraph::query::QueryUserOrRole> owner;
};
std::string GetDefaultStreamName() {
@@ -105,13 +119,16 @@ class StreamsTestFixture : public ::testing::Test {
}() // iile
};
memgraph::system::System system_state;
memgraph::query::InterpreterContext interpreter_context_{memgraph::query::InterpreterConfig{}, nullptr, &repl_state,
system_state
memgraph::query::AllowEverythingAuthChecker auth_checker;
memgraph::query::InterpreterContext interpreter_context_{memgraph::query::InterpreterConfig{},
nullptr,
&repl_state,
system_state,
#ifdef MG_ENTERPRISE
,
nullptr
nullptr,
#endif
};
nullptr,
&auth_checker};
std::filesystem::path streams_data_directory_{data_directory_ / "separate-dir-for-test"};
std::optional<StreamsTest> proxyStreams_;
@@ -173,7 +190,7 @@ class StreamsTestFixture : public ::testing::Test {
}
StreamCheckData CreateDefaultStreamCheckData() {
return {GetDefaultStreamName(), CreateDefaultStreamInfo(), false, std::nullopt};
return {GetDefaultStreamName(), CreateDefaultStreamInfo(), false, std::make_unique<FakeUser>()};
}
void Clear() {
@@ -215,11 +232,11 @@ TYPED_TEST(StreamsTestFixture, CreateAlreadyExisting) {
auto stream_info = this->CreateDefaultStreamInfo();
auto stream_name = GetDefaultStreamName();
this->proxyStreams_->streams_->template Create<memgraph::query::stream::KafkaStream>(
stream_name, stream_info, std::nullopt, this->db_, &this->interpreter_context_);
stream_name, stream_info, std::make_unique<FakeUser>(), this->db_, &this->interpreter_context_);
try {
this->proxyStreams_->streams_->template Create<memgraph::query::stream::KafkaStream>(
stream_name, stream_info, std::nullopt, this->db_, &this->interpreter_context_);
stream_name, stream_info, std::make_unique<FakeUser>(), this->db_, &this->interpreter_context_);
FAIL() << "Creating already existing stream should throw\n";
} catch (memgraph::query::stream::StreamsException &exception) {
EXPECT_EQ(exception.what(), fmt::format("Stream already exists with name '{}'", stream_name));
@@ -231,7 +248,7 @@ TYPED_TEST(StreamsTestFixture, DropNotExistingStream) {
const auto stream_name = GetDefaultStreamName();
const std::string not_existing_stream_name{"ThisDoesn'tExists"};
this->proxyStreams_->streams_->template Create<memgraph::query::stream::KafkaStream>(
stream_name, stream_info, std::nullopt, this->db_, &this->interpreter_context_);
stream_name, stream_info, std::make_unique<FakeUser>(), this->db_, &this->interpreter_context_);
try {
this->proxyStreams_->streams_->Drop(not_existing_stream_name);
@@ -262,7 +279,7 @@ TYPED_TEST(StreamsTestFixture, RestoreStreams) {
if (i > 0) {
stream_info.common_info.batch_interval = std::chrono::milliseconds((i + 1) * 10);
stream_info.common_info.batch_size = 1000 + i;
stream_check_data.owner = std::string{"owner"} + iteration_postfix;
stream_check_data.owner = std::make_unique<FakeUser>();
// These are just random numbers to make the CONFIGS and CREDENTIALS map vary between consumers:
// - 0 means no config, no credential
@@ -280,7 +297,7 @@ TYPED_TEST(StreamsTestFixture, RestoreStreams) {
this->mock_cluster_.CreateTopic(stream_info.topics[0]);
}
stream_check_datas[3].owner = {};
stream_check_datas[3].owner = std::make_unique<FakeUser>();
const auto check_restore_logic = [&stream_check_datas, this]() {
// Reset the Streams object to trigger reloading
@@ -336,7 +353,7 @@ TYPED_TEST(StreamsTestFixture, CheckWithTimeout) {
const auto stream_info = this->CreateDefaultStreamInfo();
const auto stream_name = GetDefaultStreamName();
this->proxyStreams_->streams_->template Create<memgraph::query::stream::KafkaStream>(
stream_name, stream_info, std::nullopt, this->db_, &this->interpreter_context_);
stream_name, stream_info, std::make_unique<FakeUser>(), this->db_, &this->interpreter_context_);
std::chrono::milliseconds timeout{3000};
@@ -360,9 +377,10 @@ TYPED_TEST(StreamsTestFixture, CheckInvalidConfig) {
EXPECT_TRUE(message.find(kInvalidConfigName) != std::string::npos) << message;
EXPECT_TRUE(message.find(kConfigValue) != std::string::npos) << message;
};
EXPECT_THROW_WITH_MSG(this->proxyStreams_->streams_->template Create<memgraph::query::stream::KafkaStream>(
stream_name, stream_info, std::nullopt, this->db_, &this->interpreter_context_),
memgraph::integrations::kafka::SettingCustomConfigFailed, checker);
EXPECT_THROW_WITH_MSG(
this->proxyStreams_->streams_->template Create<memgraph::query::stream::KafkaStream>(
stream_name, stream_info, std::make_unique<FakeUser>(), this->db_, &this->interpreter_context_),
memgraph::integrations::kafka::SettingCustomConfigFailed, checker);
}
TYPED_TEST(StreamsTestFixture, CheckInvalidCredentials) {
@@ -376,7 +394,8 @@ TYPED_TEST(StreamsTestFixture, CheckInvalidCredentials) {
EXPECT_TRUE(message.find(memgraph::integrations::kReducted) != std::string::npos) << message;
EXPECT_TRUE(message.find(kCredentialValue) == std::string::npos) << message;
};
EXPECT_THROW_WITH_MSG(this->proxyStreams_->streams_->template Create<memgraph::query::stream::KafkaStream>(
stream_name, stream_info, std::nullopt, this->db_, &this->interpreter_context_),
memgraph::integrations::kafka::SettingCustomConfigFailed, checker);
EXPECT_THROW_WITH_MSG(
this->proxyStreams_->streams_->template Create<memgraph::query::stream::KafkaStream>(
stream_name, stream_info, std::make_unique<FakeUser>(), this->db_, &this->interpreter_context_),
memgraph::integrations::kafka::SettingCustomConfigFailed, checker);
}

View File

@@ -21,6 +21,7 @@
#include "query/db_accessor.hpp"
#include "query/frontend/ast/ast.hpp"
#include "query/interpreter.hpp"
#include "query/query_user.hpp"
#include "query/trigger.hpp"
#include "query/typed_value.hpp"
#include "storage/v2/config.hpp"
@@ -42,16 +43,27 @@ const std::unordered_set<memgraph::query::TriggerEventType> kAllEventTypes{
class MockAuthChecker : public memgraph::query::AuthChecker {
public:
MOCK_CONST_METHOD3(IsUserAuthorized,
bool(const std::optional<std::string> &username,
const std::vector<memgraph::query::AuthQuery::Privilege> &privileges, const std::string &db));
MOCK_CONST_METHOD2(GenQueryUser,
std::shared_ptr<memgraph::query::QueryUserOrRole>(const std::optional<std::string> &username,
const std::optional<std::string> &rolename));
#ifdef MG_ENTERPRISE
MOCK_CONST_METHOD2(GetFineGrainedAuthChecker,
std::unique_ptr<memgraph::query::FineGrainedAuthChecker>(
const std::string &username, const memgraph::query::DbAccessor *db_accessor));
MOCK_CONST_METHOD2(GetFineGrainedAuthChecker, std::unique_ptr<memgraph::query::FineGrainedAuthChecker>(
std::shared_ptr<memgraph::query::QueryUserOrRole> user,
const memgraph::query::DbAccessor *db_accessor));
MOCK_CONST_METHOD0(ClearCache, void());
#endif
};
class MockQueryUser : public memgraph::query::QueryUserOrRole {
public:
MockQueryUser(std::optional<std::string> name) : memgraph::query::QueryUserOrRole(std::move(name), std::nullopt) {}
MOCK_CONST_METHOD3(IsAuthorized, bool(const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::string &db_name, memgraph::query::UserPolicy *policy));
#ifdef MG_ENTERPRISE
MOCK_CONST_METHOD0(GetDefaultDB, std::string());
#endif
};
} // namespace
const std::string testSuite = "query_trigger";
@@ -966,12 +978,12 @@ TYPED_TEST(TriggerStoreTest, Restore) {
trigger_name_before, trigger_statement,
std::map<std::string, memgraph::storage::PropertyValue>{{"parameter", memgraph::storage::PropertyValue{1}}},
event_type, memgraph::query::TriggerPhase::BEFORE_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &this->auth_checker);
memgraph::query::InterpreterConfig::Query{}, this->auth_checker.GenQueryUser(std::nullopt, std::nullopt));
store->AddTrigger(
trigger_name_after, trigger_statement,
std::map<std::string, memgraph::storage::PropertyValue>{{"parameter", memgraph::storage::PropertyValue{"value"}}},
event_type, memgraph::query::TriggerPhase::AFTER_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, {owner}, &this->auth_checker);
memgraph::query::InterpreterConfig::Query{}, this->auth_checker.GenQueryUser(owner, std::nullopt));
const auto check_triggers = [&] {
ASSERT_EQ(store->GetTriggerInfo().size(), 2);
@@ -981,9 +993,9 @@ TYPED_TEST(TriggerStoreTest, Restore) {
ASSERT_EQ(trigger.OriginalStatement(), trigger_statement);
ASSERT_EQ(trigger.EventType(), event_type);
if (owner != nullptr) {
ASSERT_EQ(*trigger.Owner(), *owner);
ASSERT_EQ(trigger.Owner()->username(), *owner);
} else {
ASSERT_FALSE(trigger.Owner().has_value());
ASSERT_FALSE(trigger.Owner()->username());
}
};
@@ -1022,32 +1034,38 @@ TYPED_TEST(TriggerStoreTest, AddTrigger) {
// Invalid query in statements
ASSERT_THROW(store.AddTrigger("trigger", "RETUR 1", {}, memgraph::query::TriggerEventType::VERTEX_CREATE,
memgraph::query::TriggerPhase::BEFORE_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &this->auth_checker),
memgraph::query::InterpreterConfig::Query{},
this->auth_checker.GenQueryUser(std::nullopt, std::nullopt)),
memgraph::utils::BasicException);
ASSERT_THROW(store.AddTrigger("trigger", "RETURN createdEdges", {}, memgraph::query::TriggerEventType::VERTEX_CREATE,
memgraph::query::TriggerPhase::BEFORE_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &this->auth_checker),
memgraph::query::InterpreterConfig::Query{},
this->auth_checker.GenQueryUser(std::nullopt, std::nullopt)),
memgraph::utils::BasicException);
ASSERT_THROW(store.AddTrigger("trigger", "RETURN $parameter", {}, memgraph::query::TriggerEventType::VERTEX_CREATE,
memgraph::query::TriggerPhase::BEFORE_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &this->auth_checker),
memgraph::query::InterpreterConfig::Query{},
this->auth_checker.GenQueryUser(std::nullopt, std::nullopt)),
memgraph::utils::BasicException);
ASSERT_NO_THROW(store.AddTrigger(
"trigger", "RETURN $parameter",
std::map<std::string, memgraph::storage::PropertyValue>{{"parameter", memgraph::storage::PropertyValue{1}}},
memgraph::query::TriggerEventType::VERTEX_CREATE, memgraph::query::TriggerPhase::BEFORE_COMMIT, &this->ast_cache,
&*this->dba, memgraph::query::InterpreterConfig::Query{}, std::nullopt, &this->auth_checker));
&*this->dba, memgraph::query::InterpreterConfig::Query{},
this->auth_checker.GenQueryUser(std::nullopt, std::nullopt)));
// Inserting with the same name
ASSERT_THROW(store.AddTrigger("trigger", "RETURN 1", {}, memgraph::query::TriggerEventType::VERTEX_CREATE,
memgraph::query::TriggerPhase::BEFORE_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &this->auth_checker),
memgraph::query::InterpreterConfig::Query{},
this->auth_checker.GenQueryUser(std::nullopt, std::nullopt)),
memgraph::utils::BasicException);
ASSERT_THROW(store.AddTrigger("trigger", "RETURN 1", {}, memgraph::query::TriggerEventType::VERTEX_CREATE,
memgraph::query::TriggerPhase::AFTER_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &this->auth_checker),
memgraph::query::InterpreterConfig::Query{},
this->auth_checker.GenQueryUser(std::nullopt, std::nullopt)),
memgraph::utils::BasicException);
ASSERT_EQ(store.GetTriggerInfo().size(), 1);
@@ -1063,7 +1081,8 @@ TYPED_TEST(TriggerStoreTest, DropTrigger) {
const auto *trigger_name = "trigger";
store.AddTrigger(trigger_name, "RETURN 1", {}, memgraph::query::TriggerEventType::VERTEX_CREATE,
memgraph::query::TriggerPhase::BEFORE_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &this->auth_checker);
memgraph::query::InterpreterConfig::Query{},
this->auth_checker.GenQueryUser(std::nullopt, std::nullopt));
ASSERT_THROW(store.DropTrigger("Unknown"), memgraph::utils::BasicException);
ASSERT_NO_THROW(store.DropTrigger(trigger_name));
@@ -1076,7 +1095,8 @@ TYPED_TEST(TriggerStoreTest, TriggerInfo) {
std::vector<memgraph::query::TriggerStore::TriggerInfo> expected_info;
store.AddTrigger("trigger", "RETURN 1", {}, memgraph::query::TriggerEventType::VERTEX_CREATE,
memgraph::query::TriggerPhase::BEFORE_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &this->auth_checker);
memgraph::query::InterpreterConfig::Query{},
this->auth_checker.GenQueryUser(std::nullopt, std::nullopt));
expected_info.push_back({"trigger",
"RETURN 1",
memgraph::query::TriggerEventType::VERTEX_CREATE,
@@ -1099,7 +1119,8 @@ TYPED_TEST(TriggerStoreTest, TriggerInfo) {
store.AddTrigger("edge_update_trigger", "RETURN 1", {}, memgraph::query::TriggerEventType::EDGE_UPDATE,
memgraph::query::TriggerPhase::AFTER_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &this->auth_checker);
memgraph::query::InterpreterConfig::Query{},
this->auth_checker.GenQueryUser(std::nullopt, std::nullopt));
expected_info.push_back({"edge_update_trigger",
"RETURN 1",
memgraph::query::TriggerEventType::EDGE_UPDATE,
@@ -1216,7 +1237,8 @@ TYPED_TEST(TriggerStoreTest, AnyTriggerAllKeywords) {
SCOPED_TRACE(keyword);
EXPECT_NO_THROW(store.AddTrigger(trigger_name, fmt::format("RETURN {}", keyword), {}, event_type,
memgraph::query::TriggerPhase::BEFORE_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &this->auth_checker));
memgraph::query::InterpreterConfig::Query{},
this->auth_checker.GenQueryUser(std::nullopt, std::nullopt)));
store.DropTrigger(trigger_name);
}
}
@@ -1228,45 +1250,50 @@ TYPED_TEST(TriggerStoreTest, AuthCheckerUsage) {
using ::testing::ElementsAre;
using ::testing::Return;
std::optional<memgraph::query::TriggerStore> store{this->testing_directory};
const std::optional<std::string> owner{"testing_owner"};
MockAuthChecker mock_checker;
const std::optional<std::string> owner{"mock_user"};
MockQueryUser mock_user(owner);
std::shared_ptr<memgraph::query::QueryUserOrRole> mock_user_ptr(
&mock_user, [](memgraph::query::QueryUserOrRole *) { /* do nothing */ });
MockQueryUser mock_userless(std::nullopt);
std::shared_ptr<memgraph::query::QueryUserOrRole> mock_userless_ptr(
&mock_userless, [](memgraph::query::QueryUserOrRole *) { /* do nothing */ });
::testing::InSequence s;
EXPECT_CALL(mock_checker, IsUserAuthorized(std::optional<std::string>{}, ElementsAre(Privilege::CREATE), ""))
.Times(1)
// TODO Userless
EXPECT_CALL(mock_user, IsAuthorized(ElementsAre(Privilege::CREATE), "", &memgraph::query::up_to_date_policy))
.WillOnce(Return(true));
EXPECT_CALL(mock_checker, IsUserAuthorized(owner, ElementsAre(Privilege::CREATE), ""))
.Times(1)
.WillOnce(Return(true));
ASSERT_NO_THROW(store->AddTrigger("successfull_trigger_1", "CREATE (n:VERTEX) RETURN n", {},
memgraph::query::TriggerEventType::EDGE_UPDATE,
memgraph::query::TriggerPhase::AFTER_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &mock_checker));
memgraph::query::InterpreterConfig::Query{}, mock_user_ptr));
EXPECT_CALL(mock_userless, IsAuthorized(ElementsAre(Privilege::CREATE), "", &memgraph::query::up_to_date_policy))
.WillOnce(Return(true));
ASSERT_NO_THROW(store->AddTrigger("successfull_trigger_2", "CREATE (n:VERTEX) RETURN n", {},
memgraph::query::TriggerEventType::EDGE_UPDATE,
memgraph::query::TriggerPhase::AFTER_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, owner, &mock_checker));
memgraph::query::InterpreterConfig::Query{}, mock_userless_ptr));
EXPECT_CALL(mock_checker, IsUserAuthorized(std::optional<std::string>{}, ElementsAre(Privilege::MATCH), ""))
.Times(1)
EXPECT_CALL(mock_user, IsAuthorized(ElementsAre(Privilege::MATCH), "", &memgraph::query::up_to_date_policy))
.WillOnce(Return(false));
ASSERT_THROW(
store->AddTrigger("unprivileged_trigger", "MATCH (n:VERTEX) RETURN n", {},
memgraph::query::TriggerEventType::EDGE_UPDATE, memgraph::query::TriggerPhase::AFTER_COMMIT,
&this->ast_cache, &*this->dba, memgraph::query::InterpreterConfig::Query{}, mock_user_ptr);
, memgraph::utils::BasicException);
ASSERT_THROW(store->AddTrigger("unprivileged_trigger", "MATCH (n:VERTEX) RETURN n", {},
memgraph::query::TriggerEventType::EDGE_UPDATE,
memgraph::query::TriggerPhase::AFTER_COMMIT, &this->ast_cache, &*this->dba,
memgraph::query::InterpreterConfig::Query{}, std::nullopt, &mock_checker);
, memgraph::utils::BasicException);
// Restore
store.emplace(this->testing_directory);
EXPECT_CALL(mock_checker, IsUserAuthorized(std::optional<std::string>{}, ElementsAre(Privilege::CREATE), ""))
.Times(1)
.WillOnce(Return(false));
EXPECT_CALL(mock_checker, IsUserAuthorized(owner, ElementsAre(Privilege::CREATE), ""))
.Times(1)
std::optional<std::string> nopt{};
EXPECT_CALL(mock_checker, GenQueryUser(owner, nopt)).WillOnce(Return(mock_user_ptr));
EXPECT_CALL(mock_user, IsAuthorized(ElementsAre(Privilege::CREATE), "", &memgraph::query::up_to_date_policy))
.WillOnce(Return(true));
EXPECT_CALL(mock_checker, GenQueryUser(nopt, nopt)).WillOnce(Return(mock_userless_ptr));
EXPECT_CALL(mock_userless, IsAuthorized(ElementsAre(Privilege::CREATE), "", &memgraph::query::up_to_date_policy))
.WillOnce(Return(false));
ASSERT_NO_THROW(store->RestoreTriggers(&this->ast_cache, &*this->dba, memgraph::query::InterpreterConfig::Query{},
&mock_checker));