memgraph/tests/e2e/triggers/privilige_check.cpp
2021-10-26 08:53:56 +02:00

173 lines
6.8 KiB
C++

// Copyright 2021 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
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include <string>
#include <string_view>
#include <gflags/gflags.h>
#include <spdlog/fmt/bundled/core.h>
#include <mgclient.hpp>
#include "common.hpp"
#include "utils/logging.hpp"
constexpr std::string_view kTriggerPrefix{"CreatedVerticesTrigger"};
int main(int argc, char **argv) {
gflags::SetUsageMessage("Memgraph E2E Triggers privilege check");
gflags::ParseCommandLineFlags(&argc, &argv, true);
logging::RedirectToStderr();
constexpr int kVertexId{42};
constexpr std::string_view kUserlessLabel{"USERLESS"};
constexpr std::string_view kAdminUser{"ADMIN"};
constexpr std::string_view kUserWithCreate{"USER_WITH_CREATE"};
constexpr std::string_view kUserWithoutCreate{"USER_WITHOUT_CREATE"};
mg::Client::Init();
auto userless_client = Connect();
const auto get_number_of_triggers = [&userless_client] {
userless_client->Execute("SHOW TRIGGERS");
auto result = userless_client->FetchAll();
MG_ASSERT(result.has_value());
return result->size();
};
auto create_trigger = [&get_number_of_triggers](mg::Client &client, const std::string_view vertexLabel,
bool should_succeed = true) {
const auto number_of_triggers_before = get_number_of_triggers();
client.Execute(
fmt::format("CREATE TRIGGER {}{} ON () CREATE "
"AFTER COMMIT "
"EXECUTE "
"UNWIND createdVertices as createdVertex "
"CREATE (n: {} {{ id: createdVertex.id }})",
kTriggerPrefix, vertexLabel, vertexLabel));
client.DiscardAll();
const auto number_of_triggers_after = get_number_of_triggers();
if (should_succeed) {
MG_ASSERT(number_of_triggers_after == number_of_triggers_before + 1);
} else {
MG_ASSERT(number_of_triggers_after == number_of_triggers_before);
}
};
auto delete_vertices = [&userless_client] {
userless_client->Execute("MATCH (n) DETACH DELETE n;");
userless_client->DiscardAll();
CheckNumberOfAllVertices(*userless_client, 0);
};
auto create_user = [&userless_client](const std::string_view username) {
userless_client->Execute(fmt::format("CREATE USER {};", username));
userless_client->DiscardAll();
userless_client->Execute(fmt::format("GRANT TRIGGER TO {};", username));
userless_client->DiscardAll();
};
auto drop_user = [&userless_client](const std::string_view username) {
userless_client->Execute(fmt::format("DROP USER {};", username));
userless_client->DiscardAll();
};
auto drop_trigger_of_user = [&userless_client](const std::string_view username) {
userless_client->Execute(fmt::format("DROP TRIGGER {}{};", kTriggerPrefix, username));
userless_client->DiscardAll();
};
// Single trigger created without user, there is no existing users
create_trigger(*userless_client, kUserlessLabel);
CreateVertex(*userless_client, kVertexId);
WaitForNumberOfAllVertices(*userless_client, 2);
CheckVertexExists(*userless_client, kVertexLabel, kVertexId);
CheckVertexExists(*userless_client, kUserlessLabel, kVertexId);
delete_vertices();
// Single trigger created without user, there is an existing user
// The trigger fails because there is no owner
create_user(kAdminUser);
CreateVertex(*userless_client, kVertexId);
CheckVertexExists(*userless_client, kVertexLabel, kVertexId);
CheckNumberOfAllVertices(*userless_client, 1);
delete_vertices();
// Three triggers: without an owner, an owner with CREATE privilege, an owner without CREATE privilege; there are
// existing users
// Only the trigger which owner has CREATE privilege will succeed
create_user(kUserWithCreate);
userless_client->Execute(fmt::format("GRANT CREATE TO {};", kUserWithCreate));
userless_client->DiscardAll();
create_user(kUserWithoutCreate);
auto client_with_create = ConnectWithUser(kUserWithCreate);
auto client_without_create = ConnectWithUser(kUserWithoutCreate);
create_trigger(*client_with_create, kUserWithCreate);
create_trigger(*client_without_create, kUserWithoutCreate, false);
// Grant CREATE to be able to create the trigger than revoke it
userless_client->Execute(fmt::format("GRANT CREATE TO {};", kUserWithoutCreate));
userless_client->DiscardAll();
create_trigger(*client_without_create, kUserWithoutCreate);
userless_client->Execute(fmt::format("REVOKE CREATE FROM {};", kUserWithoutCreate));
userless_client->DiscardAll();
CreateVertex(*userless_client, kVertexId);
WaitForNumberOfAllVertices(*userless_client, 2);
CheckVertexExists(*userless_client, kVertexLabel, kVertexId);
CheckVertexExists(*userless_client, kUserWithCreate, kVertexId);
delete_vertices();
// Three triggers: without an owner, an owner with CREATE privilege, an owner without CREATE privilege; there is no
// existing user
// All triggers will succeed, as there is no authorization is done when there are no users
drop_user(kAdminUser);
drop_user(kUserWithCreate);
drop_user(kUserWithoutCreate);
CreateVertex(*userless_client, kVertexId);
WaitForNumberOfAllVertices(*userless_client, 4);
CheckVertexExists(*userless_client, kVertexLabel, kVertexId);
CheckVertexExists(*userless_client, kUserlessLabel, kVertexId);
CheckVertexExists(*userless_client, kUserWithCreate, kVertexId);
CheckVertexExists(*userless_client, kUserWithoutCreate, kVertexId);
delete_vertices();
drop_trigger_of_user(kUserlessLabel);
drop_trigger_of_user(kUserWithCreate);
drop_trigger_of_user(kUserWithoutCreate);
// The BEFORE COMMIT trigger without proper privileges make the transaction fail
create_user(kUserWithoutCreate);
userless_client->Execute(fmt::format("GRANT CREATE TO {};", kUserWithoutCreate));
userless_client->DiscardAll();
client_without_create->Execute(
fmt::format("CREATE TRIGGER {}{} ON () CREATE "
"BEFORE COMMIT "
"EXECUTE "
"UNWIND createdVertices as createdVertex "
"CREATE (n: {} {{ id: createdVertex.id }})",
kTriggerPrefix, kUserWithoutCreate, kUserWithoutCreate));
client_without_create->DiscardAll();
userless_client->Execute(fmt::format("REVOKE CREATE FROM {};", kUserWithoutCreate));
userless_client->DiscardAll();
CreateVertex(*userless_client, kVertexId);
CheckNumberOfAllVertices(*userless_client, 0);
return 0;
}