Added integration test for lba

This commit is contained in:
niko4299
2022-08-03 14:04:36 +02:00
parent 633214baa8
commit f385e080ab
8 changed files with 300 additions and 53 deletions

View File

@@ -21,7 +21,7 @@
namespace memgraph::auth {
/**
* This class serves as the main Authentication/Authorization storage.
* It provides functions for managing Users, Roles and Permissions.
* It provides functions for managing Users, Roles, Permissions and FineGrainedAccessPermissions.
* NOTE: The non-const functions in this class aren't thread safe.
* TODO (mferencevic): Disable user/role modification functions when they are
* being managed by the auth module.

View File

@@ -38,6 +38,7 @@
#include "query/procedure/mg_procedure_impl.hpp"
#include "query/procedure/module.hpp"
#include "storage/v2/property_value.hpp"
#include "storage/v2/view.hpp"
#include "utils/algorithm.hpp"
#include "utils/csv_parsing.hpp"
#include "utils/event_counter.hpp"
@@ -684,7 +685,11 @@ bool Expand::ExpandCursor::Pull(Frame &frame, ExecutionContext &context) {
if (in_edges_ && *in_edges_it_ != in_edges_->end()) {
auto edge = *(*in_edges_it_)++;
if (context.auth_checker &&
!context.auth_checker->IsUserAuthorizedEdgeType(context.user, context.db_accessor, edge.EdgeType()))
(!context.auth_checker->IsUserAuthorizedEdgeType(context.user, context.db_accessor, edge.EdgeType()) ||
!context.auth_checker->IsUserAuthorizedLabels(context.user, context.db_accessor,
edge.To().Labels(storage::View::OLD).GetValue()) ||
!context.auth_checker->IsUserAuthorizedLabels(context.user, context.db_accessor,
edge.From().Labels(storage::View::OLD).GetValue())))
continue;
frame[self_.common_.edge_symbol] = edge;
pull_node(edge, EdgeAtom::Direction::IN);
@@ -699,7 +704,11 @@ bool Expand::ExpandCursor::Pull(Frame &frame, ExecutionContext &context) {
// already done in the block above
if (self_.common_.direction == EdgeAtom::Direction::BOTH && edge.IsCycle()) continue;
if (context.auth_checker &&
!context.auth_checker->IsUserAuthorizedEdgeType(context.user, context.db_accessor, edge.EdgeType()))
(!context.auth_checker->IsUserAuthorizedEdgeType(context.user, context.db_accessor, edge.EdgeType()) ||
!context.auth_checker->IsUserAuthorizedLabels(context.user, context.db_accessor,
edge.To().Labels(storage::View::OLD).GetValue()) ||
!context.auth_checker->IsUserAuthorizedLabels(context.user, context.db_accessor,
edge.From().Labels(storage::View::OLD).GetValue())))
continue;
frame[self_.common_.edge_symbol] = edge;
pull_node(edge, EdgeAtom::Direction::OUT);

View File

@@ -10,6 +10,9 @@ add_subdirectory(transactions)
# auth test binaries
add_subdirectory(auth)
# lba test binaries
add_subdirectory(lba)
## distributed ha/basic binaries
#add_subdirectory(ha/basic)
#

View File

@@ -0,0 +1,13 @@
set(target_name memgraph__integration__lba)
set(tester_target_name ${target_name}__tester)
set(filtering_target_name ${target_name}__filtering)
add_executable(${tester_target_name} tester.cpp)
set_target_properties(${tester_target_name} PROPERTIES OUTPUT_NAME tester)
target_link_libraries(${tester_target_name} mg-communication)
add_executable(${filtering_target_name} filtering.cpp)
set_target_properties(${filtering_target_name} PROPERTIES OUTPUT_NAME filtering)
target_link_libraries(${filtering_target_name} mg-communication)

View File

@@ -0,0 +1,59 @@
// Copyright 2022 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 <gflags/gflags.h>
#include <cstdlib>
#include "communication/bolt/client.hpp"
#include "io/network/endpoint.hpp"
#include "io/network/utils.hpp"
#include "utils/logging.hpp"
DEFINE_string(address, "127.0.0.1", "Server address");
DEFINE_int32(port, 7687, "Server port");
DEFINE_string(username, "admin", "Username for the database");
DEFINE_string(password, "admin", "Password for the database");
DEFINE_bool(use_ssl, false, "Set to true to connect with SSL to the server.");
/**
* Verifies that user 'user' has privileges that are given as positional
* arguments.
*/
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
memgraph::communication::SSLInit sslInit;
memgraph::io::network::Endpoint endpoint(memgraph::io::network::ResolveHostname(FLAGS_address), FLAGS_port);
memgraph::communication::ClientContext context(FLAGS_use_ssl);
memgraph::communication::bolt::Client client(&context);
client.Connect(endpoint, FLAGS_username, FLAGS_password);
try {
std::string query(argv[1]);
auto ret = client.Execute(query, {});
uint64_t count_got = ret.records.size();
if (count_got != std::atoi(argv[2])) {
LOG_FATAL("Expected the record to have {} entries but they had {} entries!", argv[2], count_got);
}
} catch (const memgraph::communication::bolt::ClientQueryException &e) {
LOG_FATAL(
"The query shoudn't have failed but it failed with an "
"error message '{}', {}",
e.what(), argv[0]);
}
return 0;
}

View File

@@ -0,0 +1,129 @@
#!/usr/bin/python3 -u
# 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.
import argparse
import atexit
import os
import subprocess
import sys
import tempfile
import time
from typing import List
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
PROJECT_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, "..", "..", ".."))
UNAUTHORIZED_ERROR = "You are not authorized to execute this query! Please " "contact your database administrator."
def wait_for_server(port, delay=0.1):
cmd = ["nc", "-z", "-w", "1", "127.0.0.1", str(port)]
while subprocess.call(cmd) != 0:
time.sleep(0.01)
time.sleep(delay)
def execute_tester(
binary, queries, should_fail=False, failure_message="", username="", password="", check_failure=True
):
args = [binary, "--username", username, "--password", password]
if should_fail:
args.append("--should-fail")
if failure_message:
args.extend(["--failure-message", failure_message])
if check_failure:
args.append("--check-failure")
args.extend(queries)
subprocess.run(args).check_returncode()
def execute_filtering(binary: str, queries: List[str], expected: int, username: str = "", password: str = "") -> None:
args = [binary, "--username", username, "--password", password]
args.extend(queries)
args.append(str(expected))
subprocess.run(args).check_returncode()
def execute_test(memgraph_binary: str, tester_binary: str, filtering_binary: str) -> None:
storage_directory = tempfile.TemporaryDirectory()
memgraph_args = [memgraph_binary, "--data-directory", storage_directory.name]
def execute_admin_queries(queries):
return execute_tester(
tester_binary, queries, should_fail=False, check_failure=True, username="admin", password="admin"
)
def execute_user_queries(queries, should_fail=False, failure_message="", check_failure=True):
return execute_tester(tester_binary, queries, should_fail, failure_message, "user", "user", check_failure)
# Start the memgraph binary
memgraph = subprocess.Popen(list(map(str, memgraph_args)))
time.sleep(0.1)
assert memgraph.poll() is None, "Memgraph process died prematurely!"
wait_for_server(7687)
# Register cleanup function
@atexit.register
def cleanup():
if memgraph.poll() is None:
memgraph.terminate()
assert memgraph.wait() == 0, "Memgraph process didn't exit cleanly!"
# Prepare all users
execute_admin_queries(
[
"CREATE USER admin IDENTIFIED BY 'admin'",
"GRANT ALL PRIVILEGES TO admin",
"CREATE USER user IDENTIFIED BY 'user'",
"GRANT LABELS :label1, :label2, :label3 TO user",
"GRANT EDGE_TYPES :edgeType1, :edgeType2 TO user",
"MERGE (l1:label1 {name: 'test1'})",
"MERGE (l2:label2 {name: 'test2'})",
"MATCH (l1:label1),(l2:label2) WHERE l1.name = 'test1' AND l2.name = 'test2' CREATE (l1)-[r:edgeType1]->(l2)",
"MERGE (l3:label3 {name: 'test3'})",
"MATCH (l1:label1),(l3:label3) WHERE l1.name = 'test1' AND l3.name = 'test3' CREATE (l1)-[r:edgeType2]->(l3)",
]
)
# Run the test with all combinations of permissions
print("\033[1;36m~~ Starting edge filtering test ~~\033[0m")
execute_filtering(filtering_binary, ["MATCH (n)-[r]->(m) RETURN n,r,m"], 2, "user", "user")
execute_admin_queries(["DENY EDGE_TYPES :edgeType1 TO user"])
execute_filtering(filtering_binary, ["MATCH (n)-[r]->(m) RETURN n,r,m"], 1, "user", "user")
execute_admin_queries(["GRANT EDGE_TYPES :edgeType1 TO user", "DENY LABELS :label3 TO user"])
execute_filtering(filtering_binary, ["MATCH (n)-[r]->(m) RETURN n,r,m"], 1, "user", "user")
execute_admin_queries(["REVOKE LABELS * FROM user", "REVOKE EDGE_TYPES * FROM user"])
execute_filtering(filtering_binary, ["MATCH (n)-[r]->(m) RETURN n,r,m"], 0, "user", "user")
print("\033[1;36m~~ Finished edge filtering test ~~\033[0m\n")
# Shutdown the memgraph binary
memgraph.terminate()
assert memgraph.wait() == 0, "Memgraph process didn't exit cleanly!"
if __name__ == "__main__":
memgraph_binary = os.path.join(PROJECT_DIR, "build", "memgraph")
tester_binary = os.path.join(PROJECT_DIR, "build", "tests", "integration", "lba", "tester")
filtering_binary = os.path.join(PROJECT_DIR, "build", "tests", "integration", "lba", "filtering")
parser = argparse.ArgumentParser()
parser.add_argument("--memgraph", default=memgraph_binary)
parser.add_argument("--tester", default=tester_binary)
parser.add_argument("--filtering", default=filtering_binary)
args = parser.parse_args()
execute_test(args.memgraph, args.tester, args.filtering)
sys.exit(0)

View File

@@ -0,0 +1,84 @@
// Copyright 2022 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 <gflags/gflags.h>
#include "communication/bolt/client.hpp"
#include "io/network/endpoint.hpp"
#include "io/network/utils.hpp"
DEFINE_string(address, "127.0.0.1", "Server address");
DEFINE_int32(port, 7687, "Server port");
DEFINE_string(username, "", "Username for the database");
DEFINE_string(password, "", "Password for the database");
DEFINE_bool(use_ssl, false, "Set to true to connect with SSL to the server.");
DEFINE_bool(check_failure, false, "Set to true to enable failure checking.");
DEFINE_bool(should_fail, false, "Set to true to expect a failure.");
DEFINE_string(failure_message, "", "Set to the expected failure message.");
/**
* Executes queries passed as positional arguments and verifies whether they
* succeeded, failed, failed with a specific error message or executed without a
* specific error occurring.
*/
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
memgraph::communication::SSLInit sslInit;
memgraph::io::network::Endpoint endpoint(memgraph::io::network::ResolveHostname(FLAGS_address), FLAGS_port);
memgraph::communication::ClientContext context(FLAGS_use_ssl);
memgraph::communication::bolt::Client client(&context);
client.Connect(endpoint, FLAGS_username, FLAGS_password);
for (int i = 1; i < argc; ++i) {
std::string query(argv[i]);
try {
client.Execute(query, {});
} catch (const memgraph::communication::bolt::ClientQueryException &e) {
if (!FLAGS_check_failure) {
if (!FLAGS_failure_message.empty() && e.what() == FLAGS_failure_message) {
LOG_FATAL(
"The query should have succeeded or failed with an error "
"message that isn't equal to '{}' but it failed with that error "
"message",
FLAGS_failure_message);
}
continue;
}
if (FLAGS_should_fail) {
if (!FLAGS_failure_message.empty() && e.what() != FLAGS_failure_message) {
LOG_FATAL(
"The query should have failed with an error message of '{}'' but "
"instead it failed with '{}'",
FLAGS_failure_message, e.what());
}
return 0;
} else {
LOG_FATAL(
"The query shoudn't have failed but it failed with an "
"error message '{}'",
e.what());
}
}
if (!FLAGS_check_failure) continue;
if (FLAGS_should_fail) {
LOG_FATAL(
"The query should have failed but instead it executed "
"successfully!");
}
}
return 0;
}

View File

@@ -1,50 +0,0 @@
// Copyright 2022 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 <algorithm>
#include <iostream>
#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include "auth/auth.hpp"
#include "auth/crypto.hpp"
#include "auth/models.hpp"
#include "utils/cast.hpp"
#include "utils/file.hpp"
#include "utils/license.hpp"
using namespace memgraph::auth;
namespace fs = std::filesystem;
DECLARE_bool(auth_password_permit_null);
DECLARE_string(auth_password_strength_regex);
class AuthWithStorage : public ::testing::Test {
protected:
virtual void SetUp() {
memgraph::utils::EnsureDir(test_folder_);
FLAGS_auth_password_permit_null = true;
FLAGS_auth_password_strength_regex = ".+";
memgraph::utils::license::global_license_checker.EnableTesting();
}
virtual void TearDown() { fs::remove_all(test_folder_); }
fs::path test_folder_{fs::temp_directory_path() / "MG_tests_unit_auth"};
Auth auth{test_folder_ / ("unit_auth_test_" + std::to_string(static_cast<int>(getpid())))};
};
TEST_F(AuthWithStorage, IsUserAuthorizedLabels) { ASSERT_TRUE(true); }
TEST_F(AuthWithStorage, IsUserAuthorizedEdgeType) { ASSERT_TRUE(true); }