Add MG_ENTERPRISE and license checks (#547)

This commit is contained in:
niko4299 2022-09-14 01:10:28 +02:00 committed by GitHub
parent dc8dad9794
commit 201f75e809
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 703 additions and 208 deletions

View File

@ -101,6 +101,7 @@ std::string PermissionLevelToString(PermissionLevel level) {
}
}
#ifdef MG_ENTERPRISE
FineGrainedPermission PermissionToFineGrainedPermission(const uint64_t permission) {
if (permission & FineGrainedPermission::CREATE_DELETE) {
return FineGrainedPermission::CREATE_DELETE;
@ -147,6 +148,7 @@ FineGrainedAccessPermissions Merge(const FineGrainedAccessPermissions &first,
return FineGrainedAccessPermissions(permissions, global_permission);
}
#endif
Permissions::Permissions(uint64_t grants, uint64_t denies) {
// The deny bitmask has higher priority than the grant bitmask.
@ -233,12 +235,16 @@ bool operator==(const Permissions &first, const Permissions &second) {
bool operator!=(const Permissions &first, const Permissions &second) { return !(first == second); }
#ifdef MG_ENTERPRISE
FineGrainedAccessPermissions::FineGrainedAccessPermissions(const std::unordered_map<std::string, uint64_t> &permissions,
const std::optional<uint64_t> &global_permission)
: permissions_(permissions), global_permission_(global_permission) {}
PermissionLevel FineGrainedAccessPermissions::Has(const std::string &permission,
const FineGrainedPermission fine_grained_permission) const {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return PermissionLevel::GRANT;
}
const auto concrete_permission = std::invoke([&]() -> uint64_t {
if (permissions_.contains(permission)) {
return permissions_.at(permission);
@ -284,6 +290,9 @@ void FineGrainedAccessPermissions::Deny(const std::string &permission,
}
nlohmann::json FineGrainedAccessPermissions::Serialize() const {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return {};
}
nlohmann::json data = nlohmann::json::object();
data["permissions"] = permissions_;
data["global_permission"] = global_permission_.has_value() ? global_permission_.value() : -1;
@ -294,7 +303,9 @@ FineGrainedAccessPermissions FineGrainedAccessPermissions::Deserialize(const nlo
if (!data.is_object()) {
throw AuthException("Couldn't load permissions data!");
}
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return FineGrainedAccessPermissions{};
}
std::optional<uint64_t> global_permission;
if (data["global_permission"].empty() || data["global_permission"] == -1) {
@ -358,6 +369,9 @@ const FineGrainedAccessPermissions &FineGrainedAccessHandler::edge_type_permissi
FineGrainedAccessPermissions &FineGrainedAccessHandler::edge_type_permissions() { return edge_type_permissions_; }
nlohmann::json FineGrainedAccessHandler::Serialize() const {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return {};
}
nlohmann::json data = nlohmann::json::object();
data["label_permissions"] = label_permissions_.Serialize();
data["edge_type_permissions"] = edge_type_permissions_.Serialize();
@ -371,6 +385,9 @@ FineGrainedAccessHandler FineGrainedAccessHandler::Deserialize(const nlohmann::j
if (!data["label_permissions"].is_object() || !data["edge_type_permissions"].is_object()) {
throw AuthException("Couldn't load label_permissions or edge_type_permissions data!");
}
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return FineGrainedAccessHandler{};
}
auto label_permissions = FineGrainedAccessPermissions::Deserialize(data["label_permissions"]);
auto edge_type_permissions = FineGrainedAccessPermissions::Deserialize(data["edge_type_permissions"]);
@ -385,18 +402,23 @@ bool operator==(const FineGrainedAccessHandler &first, const FineGrainedAccessHa
bool operator!=(const FineGrainedAccessHandler &first, const FineGrainedAccessHandler &second) {
return !(first == second);
}
#endif
Role::Role(const std::string &rolename) : rolename_(utils::ToLowerCase(rolename)) {}
Role::Role(const std::string &rolename, const Permissions &permissions)
: rolename_(utils::ToLowerCase(rolename)), permissions_(permissions) {}
#ifdef MG_ENTERPRISE
Role::Role(const std::string &rolename, const Permissions &permissions,
FineGrainedAccessHandler fine_grained_access_handler)
: rolename_(utils::ToLowerCase(rolename)),
permissions_(permissions),
fine_grained_access_handler_(std::move(fine_grained_access_handler)) {}
#endif
const std::string &Role::rolename() const { return rolename_; }
const Permissions &Role::permissions() const { return permissions_; }
Permissions &Role::permissions() { return permissions_; }
#ifdef MG_ENTERPRISE
const FineGrainedAccessHandler &Role::fine_grained_access_handler() const { return fine_grained_access_handler_; }
FineGrainedAccessHandler &Role::fine_grained_access_handler() { return fine_grained_access_handler_; }
@ -407,12 +429,19 @@ const FineGrainedAccessPermissions &Role::GetFineGrainedAccessLabelPermissions()
const FineGrainedAccessPermissions &Role::GetFineGrainedAccessEdgeTypePermissions() const {
return fine_grained_access_handler_.edge_type_permissions();
}
#endif
nlohmann::json Role::Serialize() const {
nlohmann::json data = nlohmann::json::object();
data["rolename"] = rolename_;
data["permissions"] = permissions_.Serialize();
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
} else {
data["fine_grained_access_handler"] = {};
}
#endif
return data;
}
@ -420,30 +449,46 @@ Role Role::Deserialize(const nlohmann::json &data) {
if (!data.is_object()) {
throw AuthException("Couldn't load role data!");
}
if (!data["rolename"].is_string() || !data["permissions"].is_object() ||
!data["fine_grained_access_handler"].is_object()) {
if (!data["rolename"].is_string() || !data["permissions"].is_object()) {
throw AuthException("Couldn't load role data!");
}
auto permissions = Permissions::Deserialize(data["permissions"]);
auto fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
return {data["rolename"], permissions, std::move(fine_grained_access_handler)};
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
if (!data["fine_grained_access_handler"].is_object()) {
throw AuthException("Couldn't load user data!");
}
auto fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
return {data["rolename"], permissions, std::move(fine_grained_access_handler)};
}
#endif
return {data["rolename"], permissions};
}
bool operator==(const Role &first, const Role &second) {
return first.rolename_ == second.rolename_ && first.permissions_ == second.permissions_ &&
first.fine_grained_access_handler_ == second.fine_grained_access_handler_;
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return first.rolename_ == second.rolename_ && first.permissions_ == second.permissions_ &&
first.fine_grained_access_handler_ == second.fine_grained_access_handler_;
}
#endif
return first.rolename_ == second.rolename_ && first.permissions_ == second.permissions_;
}
User::User() {}
User::User(const std::string &username) : username_(utils::ToLowerCase(username)) {}
User::User(const std::string &username, const std::string &password_hash, const Permissions &permissions)
: username_(utils::ToLowerCase(username)), password_hash_(password_hash), permissions_(permissions) {}
#ifdef MG_ENTERPRISE
User::User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
FineGrainedAccessHandler fine_grained_access_handler)
: username_(utils::ToLowerCase(username)),
password_hash_(password_hash),
permissions_(permissions),
fine_grained_access_handler_(std::move(fine_grained_access_handler)) {}
#endif
bool User::CheckPassword(const std::string &password) {
if (password_hash_.empty()) return true;
@ -492,29 +537,41 @@ Permissions User::GetPermissions() const {
return permissions_;
}
#ifdef MG_ENTERPRISE
FineGrainedAccessPermissions User::GetFineGrainedAccessLabelPermissions() const {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return FineGrainedAccessPermissions{};
}
if (role_) {
return Merge(role()->fine_grained_access_handler().label_permissions(),
fine_grained_access_handler_.label_permissions());
}
return fine_grained_access_handler_.label_permissions();
}
FineGrainedAccessPermissions User::GetFineGrainedAccessEdgeTypePermissions() const {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return FineGrainedAccessPermissions{};
}
if (role_) {
return Merge(role()->fine_grained_access_handler().edge_type_permissions(),
fine_grained_access_handler_.edge_type_permissions());
}
return fine_grained_access_handler_.edge_type_permissions();
}
#endif
const std::string &User::username() const { return username_; }
const Permissions &User::permissions() const { return permissions_; }
Permissions &User::permissions() { return permissions_; }
#ifdef MG_ENTERPRISE
const FineGrainedAccessHandler &User::fine_grained_access_handler() const { return fine_grained_access_handler_; }
FineGrainedAccessHandler &User::fine_grained_access_handler() { return fine_grained_access_handler_; }
FineGrainedAccessHandler &User::fine_grained_access_handler() { return fine_grained_access_handler_; }
#endif
const Role *User::role() const {
if (role_.has_value()) {
return &role_.value();
@ -527,7 +584,13 @@ nlohmann::json User::Serialize() const {
data["username"] = username_;
data["password_hash"] = password_hash_;
data["permissions"] = permissions_.Serialize();
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
} else {
data["fine_grained_access_handler"] = {};
}
#endif
// The role shouldn't be serialized here, it is stored as a foreign key.
return data;
}
@ -536,19 +599,32 @@ User User::Deserialize(const nlohmann::json &data) {
if (!data.is_object()) {
throw AuthException("Couldn't load user data!");
}
if (!data["username"].is_string() || !data["password_hash"].is_string() || !data["permissions"].is_object() ||
!data["fine_grained_access_handler"].is_object()) {
if (!data["username"].is_string() || !data["password_hash"].is_string() || !data["permissions"].is_object()) {
throw AuthException("Couldn't load user data!");
}
auto permissions = Permissions::Deserialize(data["permissions"]);
auto fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
return {data["username"], data["password_hash"], permissions, fine_grained_access_handler};
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
if (!data["fine_grained_access_handler"].is_object()) {
throw AuthException("Couldn't load user data!");
}
auto fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
return {data["username"], data["password_hash"], permissions, fine_grained_access_handler};
}
#endif
return {data["username"], data["password_hash"], permissions};
}
bool operator==(const User &first, const User &second) {
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return first.username_ == second.username_ && first.password_hash_ == second.password_hash_ &&
first.permissions_ == second.permissions_ && first.role_ == second.role_ &&
first.fine_grained_access_handler_ == second.fine_grained_access_handler_;
}
#endif
return first.username_ == second.username_ && first.password_hash_ == second.password_hash_ &&
first.permissions_ == second.permissions_ && first.role_ == second.role_ &&
first.fine_grained_access_handler_ == second.fine_grained_access_handler_;
first.permissions_ == second.permissions_ && first.role_ == second.role_;
}
} // namespace memgraph::auth

View File

@ -44,6 +44,7 @@ enum class Permission : uint64_t {
};
// clang-format on
#ifdef MG_ENTERPRISE
// clang-format off
enum class FineGrainedPermission : uint64_t {
NO_PERMISSION = 0,
@ -70,6 +71,7 @@ constexpr uint64_t kLabelPermissionAll = memgraph::auth::FineGrainedPermission::
memgraph::auth::FineGrainedPermission::READ;
constexpr uint64_t kLabelPermissionMax = static_cast<uint64_t>(memgraph::auth::FineGrainedPermission::CREATE_DELETE);
constexpr uint64_t kLabelPermissionMin = static_cast<uint64_t>(memgraph::auth::FineGrainedPermission::READ);
#endif
// Function that converts a permission to its string representation.
std::string PermissionToString(Permission permission);
@ -80,11 +82,13 @@ enum class PermissionLevel : uint8_t { GRANT, NEUTRAL, DENY };
// Function that converts a permission level to its string representation.
std::string PermissionLevelToString(PermissionLevel level);
#ifdef MG_ENTERPRISE
// Function that converts a label permission level to its string representation.
std::string FineGrainedPermissionToString(FineGrainedPermission level);
// Constructs a label permission from a permission
FineGrainedPermission PermissionToFineGrainedPermission(uint64_t permission);
#endif
class Permissions final {
public:
@ -125,6 +129,7 @@ bool operator==(const Permissions &first, const Permissions &second);
bool operator!=(const Permissions &first, const Permissions &second);
#ifdef MG_ENTERPRISE
class FineGrainedAccessPermissions final {
public:
explicit FineGrainedAccessPermissions(const std::unordered_map<std::string, uint64_t> &permissions = {},
@ -192,14 +197,16 @@ class FineGrainedAccessHandler final {
};
bool operator==(const FineGrainedAccessHandler &first, const FineGrainedAccessHandler &second);
#endif
class Role final {
public:
explicit Role(const std::string &rolename);
Role(const std::string &rolename, const Permissions &permissions);
#ifdef MG_ENTERPRISE
Role(const std::string &rolename, const Permissions &permissions,
FineGrainedAccessHandler fine_grained_access_handler);
#endif
Role(const Role &) = default;
Role &operator=(const Role &) = default;
Role(Role &&) noexcept = default;
@ -209,11 +216,12 @@ class Role final {
const std::string &rolename() const;
const Permissions &permissions() const;
Permissions &permissions();
#ifdef MG_ENTERPRISE
const FineGrainedAccessHandler &fine_grained_access_handler() const;
FineGrainedAccessHandler &fine_grained_access_handler();
const FineGrainedAccessPermissions &GetFineGrainedAccessLabelPermissions() const;
const FineGrainedAccessPermissions &GetFineGrainedAccessEdgeTypePermissions() const;
#endif
nlohmann::json Serialize() const;
/// @throw AuthException if unable to deserialize.
@ -224,7 +232,9 @@ class Role final {
private:
std::string rolename_;
Permissions permissions_;
#ifdef MG_ENTERPRISE
FineGrainedAccessHandler fine_grained_access_handler_;
#endif
};
bool operator==(const Role &first, const Role &second);
@ -235,10 +245,11 @@ class User final {
User();
explicit User(const std::string &username);
User(const std::string &username, const std::string &password_hash, const Permissions &permissions);
#ifdef MG_ENTERPRISE
User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
FineGrainedAccessHandler fine_grained_access_handler);
#endif
User(const User &) = default;
User &operator=(const User &) = default;
User(User &&) noexcept = default;
@ -256,15 +267,17 @@ class User final {
void ClearRole();
Permissions GetPermissions() const;
#ifdef MG_ENTERPRISE
FineGrainedAccessPermissions GetFineGrainedAccessLabelPermissions() const;
FineGrainedAccessPermissions GetFineGrainedAccessEdgeTypePermissions() const;
const FineGrainedAccessHandler &fine_grained_access_handler() const;
FineGrainedAccessHandler &fine_grained_access_handler();
#endif
const std::string &username() const;
const Permissions &permissions() const;
Permissions &permissions();
const FineGrainedAccessHandler &fine_grained_access_handler() const;
FineGrainedAccessHandler &fine_grained_access_handler();
const Role *role() const;
@ -279,12 +292,16 @@ class User final {
std::string username_;
std::string password_hash_;
Permissions permissions_;
#ifdef MG_ENTERPRISE
FineGrainedAccessHandler fine_grained_access_handler_;
#endif
std::optional<Role> role_;
};
bool operator==(const User &first, const User &second);
#ifdef MG_ENTERPRISE
FineGrainedAccessPermissions Merge(const FineGrainedAccessPermissions &first,
const FineGrainedAccessPermissions &second);
#endif
} // namespace memgraph::auth

View File

@ -61,6 +61,7 @@ auth::Permission PrivilegeToPermission(query::AuthQuery::Privilege privilege) {
}
}
#ifdef MG_ENTERPRISE
auth::FineGrainedPermission FineGrainedPrivilegeToFineGrainedPermission(
const query::AuthQuery::FineGrainedPrivilege fine_grained_privilege) {
switch (fine_grained_privilege) {
@ -72,4 +73,5 @@ auth::FineGrainedPermission FineGrainedPrivilegeToFineGrainedPermission(
return auth::FineGrainedPermission::CREATE_DELETE;
}
}
#endif
} // namespace memgraph::glue

View File

@ -20,11 +20,12 @@ namespace memgraph::glue {
*/
auth::Permission PrivilegeToPermission(query::AuthQuery::Privilege privilege);
#ifdef MG_ENTERPRISE
/**
* Converts query::AuthQuery::FineGrainedPrivilege to its corresponding
* auth::EntityPermission.
*/
auth::FineGrainedPermission FineGrainedPrivilegeToFineGrainedPermission(
query::AuthQuery::FineGrainedPrivilege fine_grained_privilege);
#endif
} // namespace memgraph::glue

View File

@ -15,12 +15,17 @@
#include "auth/models.hpp"
#include "glue/auth.hpp"
#include "query/frontend/ast/ast.hpp"
#include "utils/license.hpp"
#include "utils/synchronized.hpp"
#ifdef MG_ENTERPRISE
namespace {
bool IsUserAuthorizedLabels(const memgraph::auth::User &user, const memgraph::query::DbAccessor *dba,
const std::vector<memgraph::storage::LabelId> &labels,
const memgraph::query::AuthQuery::FineGrainedPrivilege fine_grained_privilege) {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return true;
}
return std::all_of(labels.begin(), labels.end(), [dba, &user, fine_grained_privilege](const auto &label) {
return user.GetFineGrainedAccessLabelPermissions().Has(
dba->LabelToName(label), memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(
@ -30,12 +35,18 @@ bool IsUserAuthorizedLabels(const memgraph::auth::User &user, const memgraph::qu
bool IsUserAuthorizedGloballyLabels(const memgraph::auth::User &user,
const memgraph::auth::FineGrainedPermission fine_grained_permission) {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return true;
}
return user.GetFineGrainedAccessLabelPermissions().Has(memgraph::auth::kAsterisk, fine_grained_permission) ==
memgraph::auth::PermissionLevel::GRANT;
}
bool IsUserAuthorizedGloballyEdges(const memgraph::auth::User &user,
const memgraph::auth::FineGrainedPermission fine_grained_permission) {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return true;
}
return user.GetFineGrainedAccessEdgeTypePermissions().Has(memgraph::auth::kAsterisk, fine_grained_permission) ==
memgraph::auth::PermissionLevel::GRANT;
}
@ -43,12 +54,15 @@ bool IsUserAuthorizedGloballyEdges(const memgraph::auth::User &user,
bool IsUserAuthorizedEdgeType(const memgraph::auth::User &user, const memgraph::query::DbAccessor *dba,
const memgraph::storage::EdgeTypeId &edgeType,
const memgraph::query::AuthQuery::FineGrainedPrivilege fine_grained_privilege) {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return true;
}
return user.GetFineGrainedAccessEdgeTypePermissions().Has(
dba->EdgeTypeToName(edgeType), memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(
fine_grained_privilege)) == memgraph::auth::PermissionLevel::GRANT;
}
} // namespace
#endif
namespace memgraph::glue {
AuthChecker::AuthChecker(
@ -70,9 +84,12 @@ bool AuthChecker::IsUserAuthorized(const std::optional<std::string> &username,
return maybe_user.has_value() && IsUserAuthorized(*maybe_user, privileges);
}
#ifdef MG_ENTERPRISE
std::unique_ptr<memgraph::query::FineGrainedAuthChecker> AuthChecker::GetFineGrainedAuthChecker(
const std::string &username, const memgraph::query::DbAccessor *dba) const {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return {};
}
try {
auto locked_auth = auth_->Lock();
auto user = locked_auth->GetUser(username);
@ -86,6 +103,7 @@ std::unique_ptr<memgraph::query::FineGrainedAuthChecker> AuthChecker::GetFineGra
throw memgraph::query::QueryRuntimeException(e.what());
}
}
#endif
bool AuthChecker::IsUserAuthorized(const memgraph::auth::User &user,
const std::vector<memgraph::query::AuthQuery::Privilege> &privileges) {
@ -96,6 +114,7 @@ bool AuthChecker::IsUserAuthorized(const memgraph::auth::User &user,
});
}
#ifdef MG_ENTERPRISE
FineGrainedAuthChecker::FineGrainedAuthChecker(auth::User user, const memgraph::query::DbAccessor *dba)
: user_{std::move(user)}, dba_(dba){};
@ -135,11 +154,18 @@ bool FineGrainedAuthChecker::Has(const memgraph::storage::EdgeTypeId &edge_type,
bool FineGrainedAuthChecker::HasGlobalPrivilegeOnVertices(
const memgraph::query::AuthQuery::FineGrainedPrivilege fine_grained_privilege) const {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return true;
}
return IsUserAuthorizedGloballyLabels(user_, FineGrainedPrivilegeToFineGrainedPermission(fine_grained_privilege));
}
bool FineGrainedAuthChecker::HasGlobalPrivilegeOnEdges(
const memgraph::query::AuthQuery::FineGrainedPrivilege fine_grained_privilege) const {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return true;
}
return IsUserAuthorizedGloballyEdges(user_, FineGrainedPrivilegeToFineGrainedPermission(fine_grained_privilege));
};
#endif
} // namespace memgraph::glue

View File

@ -26,17 +26,17 @@ class AuthChecker : public query::AuthChecker {
bool IsUserAuthorized(const std::optional<std::string> &username,
const std::vector<query::AuthQuery::Privilege> &privileges) const override;
#ifdef MG_ENTERPRISE
std::unique_ptr<memgraph::query::FineGrainedAuthChecker> GetFineGrainedAuthChecker(
const std::string &username, const memgraph::query::DbAccessor *dba) const override;
#endif
[[nodiscard]] static bool IsUserAuthorized(const memgraph::auth::User &user,
const std::vector<memgraph::query::AuthQuery::Privilege> &privileges);
private:
memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth_;
};
#ifdef MG_ENTERPRISE
class FineGrainedAuthChecker : public query::FineGrainedAuthChecker {
public:
explicit FineGrainedAuthChecker(auth::User user, const memgraph::query::DbAccessor *dba);
@ -63,4 +63,5 @@ class FineGrainedAuthChecker : public query::FineGrainedAuthChecker {
auth::User user_;
const memgraph::query::DbAccessor *dba_;
};
#endif
} // namespace memgraph::glue

View File

@ -17,6 +17,7 @@
#include "auth/models.hpp"
#include "glue/auth.hpp"
#include "utils/license.hpp"
namespace {
@ -28,7 +29,9 @@ struct PermissionForPrivilegeResult {
struct FineGrainedPermissionForPrivilegeResult {
std::string permission;
#ifdef MG_ENTERPRISE
memgraph::auth::FineGrainedPermission permission_level;
#endif
std::string description;
};
@ -117,10 +120,14 @@ std::vector<std::vector<memgraph::query::TypedValue>> ShowRolePrivileges(
return ConstructPrivilegesResult(privilege_results);
}
#ifdef MG_ENTERPRISE
std::vector<FineGrainedPermissionForPrivilegeResult> GetFineGrainedPermissionForPrivilegeForUserOrRole(
const memgraph::auth::FineGrainedAccessPermissions &permissions, const std::string &permission_type,
const std::string &user_or_role) {
std::vector<FineGrainedPermissionForPrivilegeResult> fine_grained_permissions;
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return fine_grained_permissions;
}
const auto global_permission = permissions.GetGlobalPermission();
if (global_permission.has_value()) {
const auto &permission_level = memgraph::auth::PermissionToFineGrainedPermission(global_permission.value());
@ -159,7 +166,9 @@ std::vector<FineGrainedPermissionForPrivilegeResult> GetFineGrainedPermissionFor
std::vector<std::vector<memgraph::query::TypedValue>> ConstructFineGrainedPrivilegesResult(
const std::vector<FineGrainedPermissionForPrivilegeResult> &privileges) {
std::vector<std::vector<memgraph::query::TypedValue>> grants;
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return {};
}
grants.reserve(privileges.size());
for (const auto &permission : privileges) {
grants.push_back(
@ -173,6 +182,9 @@ std::vector<std::vector<memgraph::query::TypedValue>> ConstructFineGrainedPrivil
std::vector<std::vector<memgraph::query::TypedValue>> ShowFineGrainedUserPrivileges(
const std::optional<memgraph::auth::User> &user) {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return {};
}
const auto &label_permissions = user->GetFineGrainedAccessLabelPermissions();
const auto &edge_type_permissions = user->GetFineGrainedAccessEdgeTypePermissions();
@ -189,6 +201,9 @@ std::vector<std::vector<memgraph::query::TypedValue>> ShowFineGrainedUserPrivile
std::vector<std::vector<memgraph::query::TypedValue>> ShowFineGrainedRolePrivileges(
const std::optional<memgraph::auth::Role> &role) {
if (!memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
return {};
}
const auto &label_permissions = role->GetFineGrainedAccessLabelPermissions();
const auto &edge_type_permissions = role->GetFineGrainedAccessEdgeTypePermissions();
@ -202,6 +217,8 @@ std::vector<std::vector<memgraph::query::TypedValue>> ShowFineGrainedRolePrivile
return ConstructFineGrainedPrivilegesResult(all_fine_grained_permissions);
}
#endif
} // namespace
namespace memgraph::glue {
@ -236,10 +253,21 @@ bool AuthQueryHandler::CreateUser(const std::string &username, const std::option
if (first_user) {
spdlog::info("{} is first created user. Granting all privileges.", username);
GrantPrivilege(
username, memgraph::query::kPrivilegesAll,
{{{memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {memgraph::auth::kAsterisk}}}},
{{{memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {memgraph::auth::kAsterisk}}}});
GrantPrivilege(username, memgraph::query::kPrivilegesAll
#ifdef MG_ENTERPRISE
,
{{{memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {memgraph::auth::kAsterisk}}}},
{
{
{
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {
memgraph::auth::kAsterisk
}
}
}
}
#endif
);
}
return user_added;
@ -433,7 +461,9 @@ std::vector<std::vector<memgraph::query::TypedValue>> AuthQueryHandler::GetPrivi
try {
auto locked_auth = auth_->ReadLock();
std::vector<std::vector<memgraph::query::TypedValue>> grants;
#ifdef MG_ENTERPRISE
std::vector<std::vector<memgraph::query::TypedValue>> fine_grained_grants;
#endif
auto user = locked_auth->GetUser(user_or_role);
auto role = locked_auth->GetRole(user_or_role);
if (!user && !role) {
@ -442,14 +472,24 @@ std::vector<std::vector<memgraph::query::TypedValue>> AuthQueryHandler::GetPrivi
if (user) {
grants = ShowUserPrivileges(user);
fine_grained_grants = ShowFineGrainedUserPrivileges(user);
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
fine_grained_grants = ShowFineGrainedUserPrivileges(user);
}
#endif
} else {
grants = ShowRolePrivileges(role);
fine_grained_grants = ShowFineGrainedRolePrivileges(role);
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
fine_grained_grants = ShowFineGrainedRolePrivileges(role);
}
#endif
}
grants.insert(grants.end(), fine_grained_grants.begin(), fine_grained_grants.end());
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
grants.insert(grants.end(), fine_grained_grants.begin(), fine_grained_grants.end());
}
#endif
return grants;
} catch (const memgraph::auth::AuthException &e) {
throw memgraph::query::QueryRuntimeException(e.what());
@ -457,19 +497,28 @@ std::vector<std::vector<memgraph::query::TypedValue>> AuthQueryHandler::GetPrivi
}
void AuthQueryHandler::GrantPrivilege(
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges
#ifdef MG_ENTERPRISE
,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&label_privileges,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges) {
&edge_type_privileges
#endif
) {
EditPermissions(
user_or_role, privileges, label_privileges, edge_type_privileges,
user_or_role, privileges,
#ifdef MG_ENTERPRISE
label_privileges, edge_type_privileges,
#endif
[](auto &permissions, const auto &permission) {
// TODO (mferencevic): should we first check that the
// privilege is granted/denied/revoked before
// unconditionally granting/denying/revoking it?
permissions.Grant(permission);
},
}
#ifdef MG_ENTERPRISE
,
[](auto &fine_grained_permissions, const auto &privilege_collection) {
for (const auto &[privilege, entities] : privilege_collection) {
const auto &permission = memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(privilege);
@ -477,23 +526,34 @@ void AuthQueryHandler::GrantPrivilege(
fine_grained_permissions.Grant(entity, permission);
}
}
});
}
}
#endif
);
} // namespace memgraph::glue
void AuthQueryHandler::DenyPrivilege(
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges
#ifdef MG_ENTERPRISE
,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&label_privileges,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges) {
&edge_type_privileges
#endif
) {
EditPermissions(
user_or_role, privileges, label_privileges, edge_type_privileges,
user_or_role, privileges,
#ifdef MG_ENTERPRISE
label_privileges, edge_type_privileges,
#endif
[](auto &permissions, const auto &permission) {
// TODO (mferencevic): should we first check that the
// privilege is granted/denied/revoked before
// unconditionally granting/denying/revoking it?
permissions.Deny(permission);
},
}
#ifdef MG_ENTERPRISE
,
[](auto &fine_grained_permissions, const auto &privilege_collection) {
for (const auto &[privilege, entities] : privilege_collection) {
const auto &permission = memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(privilege);
@ -501,41 +561,67 @@ void AuthQueryHandler::DenyPrivilege(
fine_grained_permissions.Deny(entity, permission);
}
}
});
}
}
#endif
);
} // namespace memgraph::glue
void AuthQueryHandler::RevokePrivilege(
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges
#ifdef MG_ENTERPRISE
,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&label_privileges,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges) {
&edge_type_privileges
#endif
) {
EditPermissions(
user_or_role, privileges, label_privileges, edge_type_privileges,
user_or_role, privileges,
#ifdef MG_ENTERPRISE
label_privileges, edge_type_privileges,
#endif
[](auto &permissions, const auto &permission) {
// TODO (mferencevic): should we first check that the
// privilege is granted/denied/revoked before
// unconditionally granting/denying/revoking it?
permissions.Revoke(permission);
},
}
#ifdef MG_ENTERPRISE
,
[](auto &fine_grained_permissions, const auto &privilege_collection) {
for ([[maybe_unused]] const auto &[privilege, entities] : privilege_collection) {
for (const auto &entity : entities) {
fine_grained_permissions.Revoke(entity);
}
}
});
}
}
#endif
);
} // namespace memgraph::glue
template <class TEditPermissionsFun, class TEditFineGrainedPermissionsFun>
template <class TEditPermissionsFun
#ifdef MG_ENTERPRISE
,
class TEditFineGrainedPermissionsFun
#endif
>
void AuthQueryHandler::EditPermissions(
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges
#ifdef MG_ENTERPRISE
,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&label_privileges,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges,
const TEditPermissionsFun &edit_permissions_fun,
const TEditFineGrainedPermissionsFun &edit_fine_grained_permissions_fun) {
&edge_type_privileges
#endif
,
const TEditPermissionsFun &edit_permissions_fun
#ifdef MG_ENTERPRISE
,
const TEditFineGrainedPermissionsFun &edit_fine_grained_permissions_fun
#endif
) {
if (!std::regex_match(user_or_role, name_regex_)) {
throw memgraph::query::QueryRuntimeException("Invalid user or role name.");
}
@ -555,28 +641,34 @@ void AuthQueryHandler::EditPermissions(
for (const auto &permission : permissions) {
edit_permissions_fun(user->permissions(), permission);
}
for (const auto &label_privilege_collection : label_privileges) {
edit_fine_grained_permissions_fun(user->fine_grained_access_handler().label_permissions(),
label_privilege_collection);
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
for (const auto &label_privilege_collection : label_privileges) {
edit_fine_grained_permissions_fun(user->fine_grained_access_handler().label_permissions(),
label_privilege_collection);
}
for (const auto &edge_type_privilege_collection : edge_type_privileges) {
edit_fine_grained_permissions_fun(user->fine_grained_access_handler().edge_type_permissions(),
edge_type_privilege_collection);
}
}
for (const auto &edge_type_privilege_collection : edge_type_privileges) {
edit_fine_grained_permissions_fun(user->fine_grained_access_handler().edge_type_permissions(),
edge_type_privilege_collection);
}
#endif
locked_auth->SaveUser(*user);
} else {
for (const auto &permission : permissions) {
edit_permissions_fun(role->permissions(), permission);
}
for (const auto &label_privilege : label_privileges) {
edit_fine_grained_permissions_fun(user->fine_grained_access_handler().label_permissions(), label_privilege);
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
for (const auto &label_privilege : label_privileges) {
edit_fine_grained_permissions_fun(user->fine_grained_access_handler().label_permissions(), label_privilege);
}
for (const auto &edge_type_privilege : edge_type_privileges) {
edit_fine_grained_permissions_fun(role->fine_grained_access_handler().edge_type_permissions(),
edge_type_privilege);
}
}
for (const auto &edge_type_privilege : edge_type_privileges) {
edit_fine_grained_permissions_fun(role->fine_grained_access_handler().edge_type_permissions(),
edge_type_privilege);
}
#endif
locked_auth->SaveRole(*role);
}
} catch (const memgraph::auth::AuthException &e) {

View File

@ -57,35 +57,62 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
std::vector<std::vector<memgraph::query::TypedValue>> GetPrivileges(const std::string &user_or_role) override;
void GrantPrivilege(
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges
#ifdef MG_ENTERPRISE
,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&label_privileges,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges) override;
&edge_type_privileges
#endif
) override;
void DenyPrivilege(
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges
#ifdef MG_ENTERPRISE
,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&label_privileges,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges) override;
&edge_type_privileges
#endif
) override;
void RevokePrivilege(
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges
#ifdef MG_ENTERPRISE
,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&label_privileges,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges) override;
&edge_type_privileges
#endif
) override;
private:
template <class TEditPermissionsFun, class TEditFineGrainedPermissionsFun>
template <class TEditPermissionsFun
#ifdef MG_ENTERPRISE
,
class TEditFineGrainedPermissionsFun
#endif
>
void EditPermissions(
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges
#ifdef MG_ENTERPRISE
,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&label_privileges,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges,
const TEditPermissionsFun &edit_permissions_fun,
const TEditFineGrainedPermissionsFun &edit_fine_grained_permissions_fun);
&edge_type_privileges
#endif
,
const TEditPermissionsFun &edit_permissions_fun
#ifdef MG_ENTERPRISE
,
const TEditFineGrainedPermissionsFun &edit_fine_grained_permissions_fun
#endif
);
};
} // namespace memgraph::glue

View File

@ -26,10 +26,12 @@ class AuthChecker {
[[nodiscard]] virtual bool IsUserAuthorized(const std::optional<std::string> &username,
const std::vector<query::AuthQuery::Privilege> &privileges) const = 0;
#ifdef MG_ENTERPRISE
[[nodiscard]] virtual std::unique_ptr<FineGrainedAuthChecker> GetFineGrainedAuthChecker(
const std::string &username, const memgraph::query::DbAccessor *db_accessor) const = 0;
#endif
};
#ifdef MG_ENTERPRISE
class FineGrainedAuthChecker {
public:
virtual ~FineGrainedAuthChecker() = default;
@ -85,6 +87,7 @@ class AllowEverythingFineGrainedAuthChecker final : public query::FineGrainedAut
return true;
}
}; // namespace memgraph::query
#endif
class AllowEverythingAuthChecker final : public query::AuthChecker {
public:
@ -93,10 +96,12 @@ class AllowEverythingAuthChecker final : public query::AuthChecker {
return true;
}
#ifdef MG_ENTERPRISE
std::unique_ptr<FineGrainedAuthChecker> GetFineGrainedAuthChecker(const std::string & /*username*/,
const query::DbAccessor * /*dba*/) const override {
return std::make_unique<AllowEverythingFineGrainedAuthChecker>();
}
};
#endif
}; // namespace memgraph::query
} // namespace memgraph::query

View File

@ -73,7 +73,9 @@ struct ExecutionContext {
ExecutionStats execution_stats;
TriggerContextCollector *trigger_context_collector{nullptr};
utils::AsyncTimer timer;
#ifdef MG_ENTERPRISE
std::unique_ptr<FineGrainedAuthChecker> auth_checker{nullptr};
#endif
};
static_assert(std::is_move_assignable_v<ExecutionContext>, "ExecutionContext must be move assignable!");

View File

@ -289,10 +289,12 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa
std::string rolename = auth_query->role_;
std::string user_or_role = auth_query->user_or_role_;
std::vector<AuthQuery::Privilege> privileges = auth_query->privileges_;
#ifdef MG_ENTERPRISE
std::vector<std::unordered_map<AuthQuery::FineGrainedPrivilege, std::vector<std::string>>> label_privileges =
auth_query->label_privileges_;
std::vector<std::unordered_map<AuthQuery::FineGrainedPrivilege, std::vector<std::string>>> edge_type_privileges =
auth_query->edge_type_privileges_;
#endif
auto password = EvaluateOptionalExpression(auth_query->password_, &evaluator);
Callback callback;
@ -322,9 +324,19 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa
// If the license is not valid we create users with admin access
if (!valid_enterprise_license) {
spdlog::warn("Granting all the privileges to {}.", username);
auth->GrantPrivilege(username, kPrivilegesAll,
auth->GrantPrivilege(username, kPrivilegesAll
#ifdef MG_ENTERPRISE
,
{{{AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {auth::kAsterisk}}}},
{{{AuthQuery::FineGrainedPrivilege::CREATE_DELETE, {auth::kAsterisk}}}});
{
{
{
AuthQuery::FineGrainedPrivilege::CREATE_DELETE, { auth::kAsterisk }
}
}
}
#endif
);
}
return std::vector<std::vector<TypedValue>>();
@ -399,20 +411,50 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa
};
return callback;
case AuthQuery::Action::GRANT_PRIVILEGE:
callback.fn = [auth, user_or_role, privileges, label_privileges, edge_type_privileges] {
auth->GrantPrivilege(user_or_role, privileges, label_privileges, edge_type_privileges);
callback.fn = [auth, user_or_role, privileges
#ifdef MG_ENTERPRISE
,
label_privileges, edge_type_privileges
#endif
] {
auth->GrantPrivilege(user_or_role, privileges
#ifdef MG_ENTERPRISE
,
label_privileges, edge_type_privileges
#endif
);
return std::vector<std::vector<TypedValue>>();
};
return callback;
case AuthQuery::Action::DENY_PRIVILEGE:
callback.fn = [auth, user_or_role, privileges, label_privileges, edge_type_privileges] {
auth->DenyPrivilege(user_or_role, privileges, label_privileges, edge_type_privileges);
callback.fn = [auth, user_or_role, privileges
#ifdef MG_ENTERPRISE
,
label_privileges, edge_type_privileges
#endif
] {
auth->DenyPrivilege(user_or_role, privileges
#ifdef MG_ENTERPRISE
,
label_privileges, edge_type_privileges
#endif
);
return std::vector<std::vector<TypedValue>>();
};
return callback;
case AuthQuery::Action::REVOKE_PRIVILEGE: {
callback.fn = [auth, user_or_role, privileges, label_privileges, edge_type_privileges] {
auth->RevokePrivilege(user_or_role, privileges, label_privileges, edge_type_privileges);
callback.fn = [auth, user_or_role, privileges
#ifdef MG_ENTERPRISE
,
label_privileges, edge_type_privileges
#endif
] {
auth->RevokePrivilege(user_or_role, privileges
#ifdef MG_ENTERPRISE
,
label_privileges, edge_type_privileges
#endif
);
return std::vector<std::vector<TypedValue>>();
};
return callback;
@ -444,7 +486,7 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa
default:
break;
}
}
} // namespace
Callback HandleReplicationQuery(ReplicationQuery *repl_query, const Parameters &parameters,
InterpreterContext *interpreter_context, DbAccessor *db_accessor,
@ -985,7 +1027,7 @@ PullPlan::PullPlan(const std::shared_ptr<CachedPlan> plan, const Parameters &par
ctx_.evaluation_context.properties = NamesToProperties(plan->ast_storage().properties_, dba);
ctx_.evaluation_context.labels = NamesToLabels(plan->ast_storage().labels_, dba);
#ifdef MG_ENTERPRISE
if (username.has_value() && dba) {
if (utils::license::global_license_checker.IsValidLicenseFast() && username.has_value() && dba) {
ctx_.auth_checker = interpreter_context->auth_checker->GetFineGrainedAuthChecker(*username, dba);
}
#endif

View File

@ -100,27 +100,42 @@ class AuthQueryHandler {
/// @throw QueryRuntimeException if an error ocurred.
virtual void GrantPrivilege(
const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges,
const std::vector<std::unordered_map<AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges
#ifdef MG_ENTERPRISE
,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&label_privileges,
const std::vector<std::unordered_map<AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges) = 0;
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges
#endif
) = 0;
/// @throw QueryRuntimeException if an error ocurred.
virtual void DenyPrivilege(
const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges,
const std::vector<std::unordered_map<AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges
#ifdef MG_ENTERPRISE
,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&label_privileges,
const std::vector<std::unordered_map<AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges) = 0;
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges
#endif
) = 0;
/// @throw QueryRuntimeException if an error ocurred.
virtual void RevokePrivilege(
const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges,
const std::vector<std::unordered_map<AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges
#ifdef MG_ENTERPRISE
,
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&label_privileges,
const std::vector<std::unordered_map<AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges) = 0;
const std::vector<std::unordered_map<memgraph::query::AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>
&edge_type_privileges
#endif
) = 0;
};
enum class QueryHandlerResult { COMMIT, ABORT, NOTHING };

View File

@ -46,6 +46,7 @@
#include "utils/event_counter.hpp"
#include "utils/exceptions.hpp"
#include "utils/fnv.hpp"
#include "utils/license.hpp"
#include "utils/likely.hpp"
#include "utils/logging.hpp"
#include "utils/memory.hpp"
@ -239,12 +240,13 @@ CreateNode::CreateNodeCursor::CreateNodeCursor(const CreateNode &self, utils::Me
bool CreateNode::CreateNodeCursor::Pull(Frame &frame, ExecutionContext &context) {
SCOPED_PROFILE_OP("CreateNode");
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(self_.node_info_.labels,
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
throw QueryRuntimeException("Vertex not created due to not having enough permission!");
}
#endif
if (input_cursor_->Pull(frame, context)) {
auto created_vertex = CreateLocalVertex(self_.node_info_, &frame, context);
@ -330,15 +332,21 @@ bool CreateExpand::CreateExpandCursor::Pull(Frame &frame, ExecutionContext &cont
if (!input_cursor_->Pull(frame, context)) return false;
const auto fine_grained_permission = self_.existing_node_
? memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE
: memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE;
if (context.auth_checker &&
!(context.auth_checker->Has(self_.edge_info_.edge_type,
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE) &&
context.auth_checker->Has(self_.node_info_.labels, fine_grained_permission))) {
throw QueryRuntimeException("Edge not created due to not having enough permission!");
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast()) {
const auto fine_grained_permission = self_.existing_node_
? memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE
: memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE;
if (context.auth_checker &&
!(context.auth_checker->Has(self_.edge_info_.edge_type,
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE) &&
context.auth_checker->Has(self_.node_info_.labels, fine_grained_permission))) {
throw QueryRuntimeException("Edge not created due to not having enough permission!");
}
}
#endif
// get the origin vertex
TypedValue &vertex_value = frame[self_.input_symbol_];
ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex);
@ -423,16 +431,19 @@ class ScanAllCursor : public Cursor {
vertices_.emplace(std::move(next_vertices.value()));
vertices_it_.emplace(vertices_.value().begin());
}
if (context.auth_checker && !FindNextVertex(context)) {
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!FindNextVertex(context)) {
return false;
}
#endif
frame[output_symbol_] = *vertices_it_.value();
++vertices_it_.value();
return true;
}
#ifdef MG_ENTERPRISE
bool FindNextVertex(const ExecutionContext &context) {
while (vertices_it_.value() != vertices_.value().end()) {
if (context.auth_checker->Has(*vertices_it_.value(), memgraph::storage::View::OLD,
@ -441,9 +452,9 @@ class ScanAllCursor : public Cursor {
}
++vertices_it_.value();
}
return false;
}
#endif
void Shutdown() override { input_cursor_->Shutdown(); }
@ -718,12 +729,14 @@ bool Expand::ExpandCursor::Pull(Frame &frame, ExecutionContext &context) {
// attempt to get a value from the incoming edges
if (in_edges_ && *in_edges_it_ != in_edges_->end()) {
auto edge = *(*in_edges_it_)++;
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
context.auth_checker->Has(edge.From(), self_.view_,
memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
continue;
}
#endif
frame[self_.common_.edge_symbol] = edge;
pull_node(edge, EdgeAtom::Direction::IN);
@ -737,13 +750,14 @@ bool Expand::ExpandCursor::Pull(Frame &frame, ExecutionContext &context) {
// we should do only one expansion for cycles, and it was
// already done in the block above
if (self_.common_.direction == EdgeAtom::Direction::BOTH && edge.IsCycle()) continue;
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
context.auth_checker->Has(edge.To(), self_.view_,
memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
continue;
}
#endif
frame[self_.common_.edge_symbol] = edge;
pull_node(edge, EdgeAtom::Direction::OUT);
return true;
@ -1073,13 +1087,14 @@ class ExpandVariableCursor : public Cursor {
VertexAccessor current_vertex =
current_edge.second == EdgeAtom::Direction::IN ? current_edge.first.From() : current_edge.first.To();
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(current_edge.first, memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
context.auth_checker->Has(current_vertex, storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
continue;
}
#endif
AppendEdge(current_edge.first, &edges_on_frame);
if (!self_.common_.existing_node) {
@ -1241,12 +1256,14 @@ class STShortestPathCursor : public query::plan::Cursor {
if (self_.common_.direction != EdgeAtom::Direction::IN) {
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
for (const auto &edge : out_edges) {
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
context.auth_checker->Has(edge.To(), storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
continue;
}
#endif
if (ShouldExpand(edge.To(), edge, frame, evaluator) && !Contains(in_edge, edge.To())) {
in_edge.emplace(edge.To(), edge);
@ -1265,12 +1282,14 @@ class STShortestPathCursor : public query::plan::Cursor {
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
for (const auto &edge : in_edges) {
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
context.auth_checker->Has(edge.From(), storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
continue;
}
#endif
if (ShouldExpand(edge.From(), edge, frame, evaluator) && !Contains(in_edge, edge.From())) {
in_edge.emplace(edge.From(), edge);
@ -1303,12 +1322,14 @@ class STShortestPathCursor : public query::plan::Cursor {
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
for (const auto &edge : out_edges) {
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
context.auth_checker->Has(edge.To(), storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
continue;
}
#endif
if (ShouldExpand(vertex, edge, frame, evaluator) && !Contains(out_edge, edge.To())) {
out_edge.emplace(edge.To(), edge);
if (Contains(in_edge, edge.To())) {
@ -1326,12 +1347,14 @@ class STShortestPathCursor : public query::plan::Cursor {
if (self_.common_.direction != EdgeAtom::Direction::IN) {
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
for (const auto &edge : in_edges) {
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
context.auth_checker->Has(edge.From(), storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
continue;
}
#endif
if (ShouldExpand(vertex, edge, frame, evaluator) && !Contains(out_edge, edge.From())) {
out_edge.emplace(edge.From(), edge);
if (Contains(in_edge, edge.From())) {
@ -1381,13 +1404,14 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
auto expand_pair = [this, &evaluator, &frame, &context](EdgeAccessor edge, VertexAccessor vertex) {
// if we already processed the given vertex it doesn't get expanded
if (processed_.find(vertex) != processed_.end()) return;
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(vertex, storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
return;
}
#endif
frame[self_.filter_lambda_.inner_edge_symbol] = edge;
frame[self_.filter_lambda_.inner_node_symbol] = vertex;
@ -1566,13 +1590,14 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
const EdgeAccessor &edge, const VertexAccessor &vertex, const TypedValue &total_weight,
int64_t depth) {
auto *memory = evaluator.GetMemoryResource();
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(vertex, storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
return;
}
#endif
if (self_.filter_lambda_.expression) {
frame[self_.filter_lambda_.inner_edge_symbol] = edge;
frame[self_.filter_lambda_.inner_node_symbol] = vertex;
@ -1875,24 +1900,28 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
if (self_.common_.direction != EdgeAtom::Direction::IN) {
auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
for (const auto &edge : out_edges) {
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(edge.To(), storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
continue;
}
#endif
expand_vertex(edge, EdgeAtom::Direction::OUT, weight, depth);
}
}
if (self_.common_.direction != EdgeAtom::Direction::OUT) {
auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
for (const auto &edge : in_edges) {
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(edge.From(), storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
continue;
}
#endif
expand_vertex(edge, EdgeAtom::Direction::IN, weight, depth);
}
}
@ -1915,8 +1944,8 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
// Check if there is an external error.
if (MustAbort(context)) throw HintedAbortError();
// If traversal stack if filled, the DFS traversal tree is created. Traverse the tree iteratively by preserving
// the traversal state on stack.
// If traversal stack if filled, the DFS traversal tree is created. Traverse the tree iteratively by
// preserving the traversal state on stack.
while (!traversal_stack_.empty()) {
auto &current_level = traversal_stack_.back();
auto &edges_on_frame = frame[self_.common_.edge_symbol].ValueList();
@ -2335,12 +2364,14 @@ bool Delete::DeleteCursor::Pull(Frame &frame, ExecutionContext &context) {
if (MustAbort(context)) throw HintedAbortError();
if (expression_result.type() == TypedValue::Type::Edge) {
auto &ea = expression_result.ValueEdge();
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!(context.auth_checker->Has(ea, query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE) &&
context.auth_checker->Has(ea.To(), storage::View::NEW, query::AuthQuery::FineGrainedPrivilege::UPDATE) &&
context.auth_checker->Has(ea.From(), storage::View::NEW, query::AuthQuery::FineGrainedPrivilege::UPDATE))) {
throw QueryRuntimeException("Edge not deleted due to not having enough permission!");
}
#endif
auto maybe_value = dba.RemoveEdge(&ea);
if (maybe_value.HasError()) {
switch (maybe_value.GetError()) {
@ -2366,10 +2397,12 @@ bool Delete::DeleteCursor::Pull(Frame &frame, ExecutionContext &context) {
switch (expression_result.type()) {
case TypedValue::Type::Vertex: {
auto &va = expression_result.ValueVertex();
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(va, storage::View::NEW, query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
throw QueryRuntimeException("Vertex not deleted due to not having enough permission!");
}
#endif
if (self_.detach_) {
auto res = dba.DetachRemoveVertex(&va);
if (res.HasError()) {
@ -2473,12 +2506,13 @@ bool SetProperty::SetPropertyCursor::Pull(Frame &frame, ExecutionContext &contex
switch (lhs.type()) {
case TypedValue::Type::Vertex: {
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(lhs.ValueVertex(), storage::View::NEW,
memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
throw QueryRuntimeException("Vertex property not set due to not having enough permission!");
}
#endif
auto old_value = PropsSetChecked(&lhs.ValueVertex(), self_.property_, rhs);
context.execution_stats[ExecutionStats::Key::UPDATED_PROPERTIES] += 1;
if (context.trigger_context_collector) {
@ -2489,15 +2523,17 @@ bool SetProperty::SetPropertyCursor::Pull(Frame &frame, ExecutionContext &contex
break;
}
case TypedValue::Type::Edge: {
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(lhs.ValueEdge(), memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
throw QueryRuntimeException("Edge property not set due to not having enough permission!");
}
#endif
auto old_value = PropsSetChecked(&lhs.ValueEdge(), self_.property_, rhs);
context.execution_stats[ExecutionStats::Key::UPDATED_PROPERTIES] += 1;
if (context.trigger_context_collector) {
// rhs cannot be moved because it was created with the allocator that is only valid during current pull
// rhs cannot be moved because it was created with the allocator that is only valid
// during current pull
context.trigger_context_collector->RegisterSetObjectProperty(lhs.ValueEdge(), self_.property_,
TypedValue{std::move(old_value)}, TypedValue{rhs});
}
@ -2686,20 +2722,23 @@ bool SetProperties::SetPropertiesCursor::Pull(Frame &frame, ExecutionContext &co
switch (lhs.type()) {
case TypedValue::Type::Vertex:
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(lhs.ValueVertex(), storage::View::NEW,
memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
throw QueryRuntimeException("Vertex properties not set due to not having enough permission!");
}
#endif
SetPropertiesOnRecord(&lhs.ValueVertex(), rhs, self_.op_, &context);
break;
case TypedValue::Type::Edge:
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(lhs.ValueEdge(), memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
throw QueryRuntimeException("Edge properties not set due to not having enough permission!");
}
#endif
SetPropertiesOnRecord(&lhs.ValueEdge(), rhs, self_.op_, &context);
break;
case TypedValue::Type::Null:
@ -2737,10 +2776,12 @@ SetLabels::SetLabelsCursor::SetLabelsCursor(const SetLabels &self, utils::Memory
bool SetLabels::SetLabelsCursor::Pull(Frame &frame, ExecutionContext &context) {
SCOPED_PROFILE_OP("SetLabels");
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(self_.labels_, memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
throw QueryRuntimeException("Couldn't set label due to not having enough permission!");
}
#endif
if (!input_cursor_->Pull(frame, context)) return false;
@ -2750,10 +2791,13 @@ bool SetLabels::SetLabelsCursor::Pull(Frame &frame, ExecutionContext &context) {
ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex);
auto &vertex = vertex_value.ValueVertex();
if (context.auth_checker && !context.auth_checker->Has(vertex, storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(vertex, storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
throw QueryRuntimeException("Couldn't set label due to not having enough permission!");
}
#endif
for (auto label : self_.labels_) {
auto maybe_value = vertex.AddLabel(label);
@ -2837,20 +2881,22 @@ bool RemoveProperty::RemovePropertyCursor::Pull(Frame &frame, ExecutionContext &
switch (lhs.type()) {
case TypedValue::Type::Vertex:
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(lhs.ValueVertex(), storage::View::NEW,
memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
throw QueryRuntimeException("Vertex property not removed due to not having enough permission!");
}
#endif
remove_prop(&lhs.ValueVertex());
break;
case TypedValue::Type::Edge:
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(lhs.ValueEdge(), memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
throw QueryRuntimeException("Edge property not removed due to not having enough permission!");
}
#endif
remove_prop(&lhs.ValueEdge());
break;
case TypedValue::Type::Null:
@ -2888,10 +2934,12 @@ RemoveLabels::RemoveLabelsCursor::RemoveLabelsCursor(const RemoveLabels &self, u
bool RemoveLabels::RemoveLabelsCursor::Pull(Frame &frame, ExecutionContext &context) {
SCOPED_PROFILE_OP("RemoveLabels");
if (context.auth_checker &&
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(self_.labels_, memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
throw QueryRuntimeException("Couldn't remove label due to not having enough permission!");
}
#endif
if (!input_cursor_->Pull(frame, context)) return false;
@ -2900,10 +2948,14 @@ bool RemoveLabels::RemoveLabelsCursor::Pull(Frame &frame, ExecutionContext &cont
if (vertex_value.IsNull()) return true;
ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex);
auto &vertex = vertex_value.ValueVertex();
if (context.auth_checker && !context.auth_checker->Has(vertex, storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
#ifdef MG_ENTERPRISE
if (utils::license::global_license_checker.IsValidLicenseFast() && context.auth_checker &&
!context.auth_checker->Has(vertex, storage::View::OLD,
memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
throw QueryRuntimeException("Couldn't remove label due to not having enough permission!");
}
#endif
for (auto label : self_.labels_) {
auto maybe_value = vertex.RemoveLabel(label);

View File

@ -32,6 +32,7 @@
#include "storage/v2/view.hpp"
#include "utils/algorithm.hpp"
#include "utils/concepts.hpp"
#include "utils/license.hpp"
#include "utils/logging.hpp"
#include "utils/math.hpp"
#include "utils/memory.hpp"
@ -1589,11 +1590,12 @@ mgp_error mgp_vertex_set_property(struct mgp_vertex *v, const char *property_nam
return WrapExceptions([=] {
auto *ctx = v->graph->ctx;
if (ctx && ctx->auth_checker &&
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast() && ctx && ctx->auth_checker &&
!ctx->auth_checker->Has(v->impl, v->graph->view, memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
throw AuthorizationException{"Insufficient permissions for setting a property on vertex!"};
}
#endif
if (!MgpVertexIsMutable(*v)) {
throw ImmutableObjectException{"Cannot set a property on an immutable vertex!"};
}
@ -1635,12 +1637,14 @@ mgp_error mgp_vertex_add_label(struct mgp_vertex *v, mgp_label label) {
return WrapExceptions([=] {
auto *ctx = v->graph->ctx;
if (ctx && ctx->auth_checker &&
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast() && ctx && ctx->auth_checker &&
!(ctx->auth_checker->Has(v->impl, v->graph->view, memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE) &&
ctx->auth_checker->Has({v->graph->impl->NameToLabel(label.name)},
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE))) {
throw AuthorizationException{"Insufficient permissions for adding a label to vertex!"};
}
#endif
if (!MgpVertexIsMutable(*v)) {
throw ImmutableObjectException{"Cannot add a label to an immutable vertex!"};
@ -1674,13 +1678,14 @@ mgp_error mgp_vertex_remove_label(struct mgp_vertex *v, mgp_label label) {
return WrapExceptions([=] {
auto *ctx = v->graph->ctx;
if (ctx && ctx->auth_checker &&
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast() && ctx && ctx->auth_checker &&
!(ctx->auth_checker->Has(v->impl, v->graph->view, memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE) &&
ctx->auth_checker->Has({v->graph->impl->NameToLabel(label.name)},
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE))) {
throw AuthorizationException{"Insufficient permissions for removing a label from vertex!"};
}
#endif
if (!MgpVertexIsMutable(*v)) {
throw ImmutableObjectException{"Cannot remove a label from an immutable vertex!"};
}
@ -1856,6 +1861,7 @@ mgp_error mgp_vertex_iter_properties(mgp_vertex *v, mgp_memory *memory, mgp_prop
void mgp_edges_iterator_destroy(mgp_edges_iterator *it) { DeleteRawMgpObject(it); }
#ifdef MG_ENTERPRISE
namespace {
void NextPermittedEdge(mgp_edges_iterator &it, const bool for_in) {
if (const auto *ctx = it.source_vertex.graph->ctx; !ctx || !ctx->auth_checker) return;
@ -1879,6 +1885,7 @@ void NextPermittedEdge(mgp_edges_iterator &it, const bool for_in) {
}
};
} // namespace
#endif
mgp_error mgp_vertex_iter_in_edges(mgp_vertex *v, mgp_memory *memory, mgp_edges_iterator **result) {
return WrapExceptions(
@ -1903,8 +1910,11 @@ mgp_error mgp_vertex_iter_in_edges(mgp_vertex *v, mgp_memory *memory, mgp_edges_
}
it->in.emplace(std::move(*maybe_edges));
it->in_it.emplace(it->in->begin());
NextPermittedEdge(*it, true);
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
NextPermittedEdge(*it, true);
}
#endif
if (*it->in_it != it->in->end()) {
it->current_e.emplace(**it->in_it, v->graph, it->GetMemoryResource());
@ -1939,7 +1949,11 @@ mgp_error mgp_vertex_iter_out_edges(mgp_vertex *v, mgp_memory *memory, mgp_edges
it->out.emplace(std::move(*maybe_edges));
it->out_it.emplace(it->out->begin());
NextPermittedEdge(*it, false);
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
NextPermittedEdge(*it, false);
}
#endif
if (*it->out_it != it->out->end()) {
it->current_e.emplace(**it->out_it, v->graph, it->GetMemoryResource());
@ -1981,7 +1995,11 @@ mgp_error mgp_edges_iterator_next(mgp_edges_iterator *it, mgp_edge **result) {
++*impl_it;
NextPermittedEdge(*it, for_in);
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
NextPermittedEdge(*it, for_in);
}
#endif
if (*impl_it == end) {
it->current_e = std::nullopt;
@ -2073,10 +2091,12 @@ mgp_error mgp_edge_set_property(struct mgp_edge *e, const char *property_name, m
return WrapExceptions([=] {
auto *ctx = e->from.graph->ctx;
if (ctx && ctx->auth_checker &&
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast() && ctx && ctx->auth_checker &&
!ctx->auth_checker->Has(e->impl, memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
throw AuthorizationException{"Insufficient permissions for setting a property on edge!"};
}
#endif
if (!MgpEdgeIsMutable(*e)) {
throw ImmutableObjectException{"Cannot set a property on an immutable edge!"};
@ -2164,11 +2184,15 @@ mgp_error mgp_graph_is_mutable(mgp_graph *graph, int *result) {
mgp_error mgp_graph_create_vertex(struct mgp_graph *graph, mgp_memory *memory, mgp_vertex **result) {
return WrapExceptions(
[=]() -> mgp_vertex * {
if (graph->ctx && graph->ctx->auth_checker &&
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast() && graph->ctx &&
graph->ctx->auth_checker &&
!graph->ctx->auth_checker->HasGlobalPrivilegeOnVertices(
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
throw AuthorizationException{"Insufficient permissions for creating vertices!"};
}
#endif
if (!MgpGraphIsMutable(*graph)) {
throw ImmutableObjectException{"Cannot create a vertex in an immutable graph!"};
@ -2190,11 +2214,13 @@ mgp_error mgp_graph_delete_vertex(struct mgp_graph *graph, mgp_vertex *vertex) {
return WrapExceptions([=] {
auto *ctx = graph->ctx;
if (ctx && ctx->auth_checker &&
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast() && ctx && ctx->auth_checker &&
!ctx->auth_checker->Has(vertex->impl, graph->view,
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
throw AuthorizationException{"Insufficient permissions for deleting a vertex!"};
}
#endif
if (!MgpGraphIsMutable(*graph)) {
throw ImmutableObjectException{"Cannot remove a vertex from an immutable graph!"};
@ -2230,12 +2256,13 @@ mgp_error mgp_graph_delete_vertex(struct mgp_graph *graph, mgp_vertex *vertex) {
mgp_error mgp_graph_detach_delete_vertex(struct mgp_graph *graph, mgp_vertex *vertex) {
return WrapExceptions([=] {
auto *ctx = graph->ctx;
if (ctx && ctx->auth_checker &&
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast() && ctx && ctx->auth_checker &&
!ctx->auth_checker->Has(vertex->impl, graph->view,
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
throw AuthorizationException{"Insufficient permissions for deleting a vertex!"};
}
#endif
if (!MgpGraphIsMutable(*graph)) {
throw ImmutableObjectException{"Cannot remove a vertex from an immutable graph!"};
@ -2283,13 +2310,13 @@ mgp_error mgp_graph_create_edge(mgp_graph *graph, mgp_vertex *from, mgp_vertex *
return WrapExceptions(
[=]() -> mgp_edge * {
auto *ctx = graph->ctx;
if (ctx && ctx->auth_checker &&
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast() && ctx && ctx->auth_checker &&
!ctx->auth_checker->Has(from->graph->impl->NameToEdgeType(type.name),
memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
throw AuthorizationException{"Insufficient permissions for creating edges!"};
}
#endif
if (!MgpGraphIsMutable(*graph)) {
throw ImmutableObjectException{"Cannot create an edge in an immutable graph!"};
}
@ -2322,11 +2349,12 @@ mgp_error mgp_graph_create_edge(mgp_graph *graph, mgp_vertex *from, mgp_vertex *
mgp_error mgp_graph_delete_edge(struct mgp_graph *graph, mgp_edge *edge) {
return WrapExceptions([=] {
auto *ctx = graph->ctx;
if (ctx && ctx->auth_checker &&
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast() && ctx && ctx->auth_checker &&
!ctx->auth_checker->Has(edge->impl, memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
throw AuthorizationException{"Insufficient permissions for deleting an edge!"};
}
#endif
if (!MgpGraphIsMutable(*graph)) {
throw ImmutableObjectException{"Cannot remove an edge from an immutable graph!"};
}
@ -2356,6 +2384,7 @@ mgp_error mgp_graph_delete_edge(struct mgp_graph *graph, mgp_edge *edge) {
});
}
#ifdef MG_ENTERPRISE
namespace {
void NextPermitted(mgp_vertices_iterator &it) {
const auto *ctx = it.graph->ctx;
@ -2374,11 +2403,16 @@ void NextPermitted(mgp_vertices_iterator &it) {
}
};
} // namespace
#endif
/// @throw anything VerticesIterable may throw
mgp_vertices_iterator::mgp_vertices_iterator(mgp_graph *graph, memgraph::utils::MemoryResource *memory)
: memory(memory), graph(graph), vertices(graph->impl->Vertices(graph->view)), current_it(vertices.begin()) {
NextPermitted(*this);
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
NextPermitted(*this);
}
#endif
if (current_it != vertices.end()) {
current_v.emplace(*current_it, graph, memory);
@ -2417,9 +2451,11 @@ mgp_error mgp_vertices_iterator_next(mgp_vertices_iterator *it, mgp_vertex **res
}
++it->current_it;
NextPermitted(*it);
#ifdef MG_ENTERPRISE
if (memgraph::utils::license::global_license_checker.IsValidLicenseFast()) {
NextPermitted(*it);
}
#endif
if (it->current_it == it->vertices.end()) {
it->current_v = std::nullopt;
return nullptr;

View File

@ -161,6 +161,7 @@ TEST_F(AuthWithStorage, UserRolePermissions) {
}
}
#ifdef MG_ENTERPRISE
TEST_F(AuthWithStorage, UserRoleFineGrainedAccessHandler) {
ASSERT_FALSE(auth.HasUsers());
ASSERT_TRUE(auth.AddUser("test"));
@ -239,6 +240,7 @@ TEST_F(AuthWithStorage, UserRoleFineGrainedAccessHandler) {
PermissionLevel::DENY);
}
}
#endif
TEST_F(AuthWithStorage, RoleManipulations) {
{
@ -488,6 +490,7 @@ TEST(AuthWithoutStorage, PermissionsMaskTest) {
ASSERT_EQ(p4.denies(), 2);
}
#ifdef MG_ENTERPRISE
TEST(AuthWithoutStorage, FineGrainedAccessPermissions) {
const std::string any_label = "AnyString";
const std::string check_label = "Label";
@ -776,6 +779,7 @@ TEST(AuthWithoutStorage, FineGrainedAccessPermissions) {
ASSERT_EQ(fga_permissions.Has(non_check_label, FineGrainedPermission::READ), PermissionLevel::DENY);
}
}
TEST_F(AuthWithStorage, FineGrainedAccessCheckerMerge) {
auto any_label = "AnyString";
auto check_label = "Label";
@ -842,6 +846,7 @@ TEST_F(AuthWithStorage, FineGrainedAccessCheckerMerge) {
ASSERT_EQ(fga_permissions3.Has(check_label, FineGrainedPermission::READ), PermissionLevel::GRANT);
}
}
#endif
TEST(AuthWithoutStorage, UserSerializeDeserialize) {
auto user = User("test");

View File

@ -17,7 +17,9 @@
#include "query_plan_common.hpp"
#include "storage/v2/view.hpp"
#include "utils/license.hpp"
#ifdef MG_ENTERPRISE
class FineGrainedAuthCheckerFixture : public testing::Test {
protected:
memgraph::storage::Storage db;
@ -37,6 +39,7 @@ class FineGrainedAuthCheckerFixture : public testing::Test {
memgraph::query::EdgeAccessor r4{*dba.InsertEdge(&v1, &v3, edge_type_two)};
void SetUp() override {
memgraph::utils::license::global_license_checker.EnableTesting();
ASSERT_TRUE(v1.AddLabel(dba.NameToLabel("l1")).HasValue());
ASSERT_TRUE(v2.AddLabel(dba.NameToLabel("l2")).HasValue());
ASSERT_TRUE(v3.AddLabel(dba.NameToLabel("l3")).HasValue());
@ -205,3 +208,4 @@ TEST_F(FineGrainedAuthCheckerFixture, GrantAndDenySpecificEdgeTypes) {
ASSERT_FALSE(auth_checker.Has(r3, memgraph::query::AuthQuery::FineGrainedPrivilege::READ));
ASSERT_FALSE(auth_checker.Has(r4, memgraph::query::AuthQuery::FineGrainedPrivilege::READ));
}
#endif

View File

@ -32,8 +32,9 @@ class AuthQueryHandlerFixture : public testing::Test {
std::string edge_type_repr = "EdgeType1";
std::string label_repr = "Label1";
memgraph::auth::Permissions perms{};
#ifdef MG_ENTERPRISE
memgraph::auth::FineGrainedAccessHandler handler{};
#endif
virtual void SetUp() {
memgraph::utils::EnsureDir(test_folder_);
memgraph::utils::license::global_license_checker.EnableTesting();
@ -42,7 +43,9 @@ class AuthQueryHandlerFixture : public testing::Test {
virtual void TearDown() {
std::filesystem::remove_all(test_folder_);
perms = memgraph::auth::Permissions{};
#ifdef MG_ENTERPRISE
handler = memgraph::auth::FineGrainedAccessHandler{};
#endif
}
};
@ -52,7 +55,7 @@ TEST_F(AuthQueryHandlerFixture, GivenAuthQueryHandlerWhenInitializedHaveNoUserna
}
TEST_F(AuthQueryHandlerFixture, GivenUserWhenNoDeniesOrGrantsThenNothingIsReturned) {
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms};
auth->SaveUser(user);
{ ASSERT_EQ(auth_handler.GetUsernames().size(), 1); }
@ -66,7 +69,7 @@ TEST_F(AuthQueryHandlerFixture, GivenUserWhenNoDeniesOrGrantsThenNothingIsReturn
TEST_F(AuthQueryHandlerFixture, GivenUserWhenAddedGrantPermissionThenItIsReturned) {
perms.Grant(memgraph::auth::Permission::MATCH);
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms};
auth->SaveUser(user);
auto privileges = auth_handler.GetPrivileges(user_name);
@ -87,7 +90,7 @@ TEST_F(AuthQueryHandlerFixture, GivenUserWhenAddedGrantPermissionThenItIsReturne
TEST_F(AuthQueryHandlerFixture, GivenUserWhenAddedDenyPermissionThenItIsReturned) {
perms.Deny(memgraph::auth::Permission::MATCH);
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms};
auth->SaveUser(user);
auto privileges = auth_handler.GetPrivileges(user_name);
@ -109,7 +112,7 @@ TEST_F(AuthQueryHandlerFixture, GivenUserWhenAddedDenyPermissionThenItIsReturned
TEST_F(AuthQueryHandlerFixture, GivenUserWhenPrivilegeRevokedThenNothingIsReturned) {
perms.Deny(memgraph::auth::Permission::MATCH);
perms.Revoke(memgraph::auth::Permission::MATCH);
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms};
auth->SaveUser(user);
auto privileges = auth_handler.GetPrivileges(user_name);
@ -118,7 +121,7 @@ TEST_F(AuthQueryHandlerFixture, GivenUserWhenPrivilegeRevokedThenNothingIsReturn
TEST_F(AuthQueryHandlerFixture, GivenRoleWhenPrivilegeGrantedThenItIsReturned) {
perms.Grant(memgraph::auth::Permission::MATCH);
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms};
auth->SaveRole(role);
{ ASSERT_EQ(auth_handler.GetRolenames().size(), 1); }
@ -143,7 +146,7 @@ TEST_F(AuthQueryHandlerFixture, GivenRoleWhenPrivilegeGrantedThenItIsReturned) {
TEST_F(AuthQueryHandlerFixture, GivenRoleWhenPrivilegeDeniedThenItIsReturned) {
perms.Deny(memgraph::auth::Permission::MATCH);
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms};
auth->SaveRole(role);
auto privileges = auth_handler.GetPrivileges("Mates_role");
@ -165,7 +168,7 @@ TEST_F(AuthQueryHandlerFixture, GivenRoleWhenPrivilegeDeniedThenItIsReturned) {
TEST_F(AuthQueryHandlerFixture, GivenRoleWhenPrivilegeRevokedThenNothingIsReturned) {
perms.Deny(memgraph::auth::Permission::MATCH);
perms.Revoke(memgraph::auth::Permission::MATCH);
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms};
auth->SaveRole(role);
auto privileges = auth_handler.GetPrivileges("Mates_role");
@ -175,7 +178,7 @@ TEST_F(AuthQueryHandlerFixture, GivenRoleWhenPrivilegeRevokedThenNothingIsReturn
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedTwoPrivilegesThenBothAreReturned) {
perms.Grant(memgraph::auth::Permission::MATCH);
perms.Grant(memgraph::auth::Permission::CREATE);
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms};
auth->SaveUser(user);
auto privileges = auth_handler.GetPrivileges(user_name);
@ -184,9 +187,9 @@ TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedTwoPrivilegesThenBothAreRetu
TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneGrantedAndOtherGrantedThenBothArePrinted) {
perms.Grant(memgraph::auth::Permission::MATCH);
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms};
auth->SaveRole(role);
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms};
user.SetRole(role);
auth->SaveUser(user);
@ -208,9 +211,9 @@ TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneGrantedAndOtherGrantedThe
TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneDeniedAndOtherDeniedThenBothArePrinted) {
perms.Deny(memgraph::auth::Permission::MATCH);
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms};
auth->SaveRole(role);
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms};
user.SetRole(role);
auth->SaveUser(user);
@ -233,12 +236,16 @@ TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneDeniedAndOtherDeniedThenB
TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneGrantedAndOtherDeniedThenBothArePrinted) {
memgraph::auth::Permissions role_perms{};
role_perms.Deny(memgraph::auth::Permission::MATCH);
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", role_perms, handler};
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", role_perms};
auth->SaveRole(role);
memgraph::auth::Permissions user_perms{};
user_perms.Grant(memgraph::auth::Permission::MATCH);
memgraph::auth::User user = memgraph::auth::User{user_name, "", user_perms, handler};
memgraph::auth::User user = memgraph::auth::User{
user_name,
"",
user_perms,
};
user.SetRole(role);
auth->SaveUser(user);
@ -261,12 +268,12 @@ TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneGrantedAndOtherDeniedThen
TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneDeniedAndOtherGrantedThenBothArePrinted) {
memgraph::auth::Permissions role_perms{};
role_perms.Grant(memgraph::auth::Permission::MATCH);
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", role_perms, handler};
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", role_perms};
auth->SaveRole(role);
memgraph::auth::Permissions user_perms{};
user_perms.Deny(memgraph::auth::Permission::MATCH);
memgraph::auth::User user = memgraph::auth::User{user_name, "", user_perms, handler};
memgraph::auth::User user = memgraph::auth::User{user_name, "", user_perms};
user.SetRole(role);
auth->SaveUser(user);
@ -286,6 +293,7 @@ TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneDeniedAndOtherGrantedThen
ASSERT_EQ(result[2].ValueString(), "DENIED TO USER, GRANTED TO ROLE");
}
#ifdef MG_ENTERPRISE
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedPrivilegeOnLabelThenIsDisplayed) {
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::READ);
@ -722,3 +730,4 @@ TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedReadAndDeniedUpdateThenOneIs
ASSERT_TRUE(result[2].IsString());
ASSERT_EQ(result[2].ValueString(), "EDGE_TYPE PERMISSION GRANTED TO USER");
}
#endif

View File

@ -451,6 +451,7 @@ void BfsTest(Database *db, int lower_bound, int upper_bound, memgraph::query::Ed
dba.Abort();
}
#ifdef MG_ENTERPRISE
void BfsTestWithFineGrainedFiltering(Database *db, int lower_bound, int upper_bound,
memgraph::query::EdgeAtom::Direction direction,
std::vector<std::string> edge_types, bool known_sink,
@ -718,3 +719,4 @@ void BfsTestWithFineGrainedFiltering(Database *db, int lower_bound, int upper_bo
db_accessor.Abort();
}
#endif

View File

@ -18,6 +18,7 @@
#include <gtest/internal/gtest-param-util-generated.h>
#include "auth/models.hpp"
#include "utils/license.hpp"
using namespace memgraph::query;
using namespace memgraph::query::plan;
@ -73,11 +74,15 @@ class VertexDb : public Database {
memgraph::storage::Storage db_;
};
#ifdef MG_ENTERPRISE
class FineGrainedBfsTest
: public ::testing::TestWithParam<
std::tuple<int, int, EdgeAtom::Direction, std::vector<std::string>, bool, FineGrainedTestType>> {
public:
static void SetUpTestCase() { db_ = std::make_unique<VertexDb>(); }
static void SetUpTestCase() {
memgraph::utils::license::global_license_checker.EnableTesting();
db_ = std::make_unique<VertexDb>();
}
static void TearDownTestCase() { db_ = nullptr; }
protected:
@ -99,7 +104,6 @@ TEST_P(FineGrainedBfsTest, All) {
}
std::unique_ptr<VertexDb> FineGrainedBfsTest::db_{nullptr};
INSTANTIATE_TEST_CASE_P(
FineGrained, FineGrainedBfsTest,
testing::Combine(testing::Values(3), testing::Values(-1),
@ -108,3 +112,4 @@ INSTANTIATE_TEST_CASE_P(
testing::Values(FineGrainedTestType::ALL_GRANTED, FineGrainedTestType::ALL_DENIED,
FineGrainedTestType::EDGE_TYPE_A_DENIED, FineGrainedTestType::EDGE_TYPE_B_DENIED,
FineGrainedTestType::LABEL_0_DENIED, FineGrainedTestType::LABEL_3_DENIED)));
#endif

View File

@ -41,7 +41,7 @@ ExecutionContext MakeContext(const AstStorage &storage, const SymbolTable &symbo
context.evaluation_context.labels = NamesToLabels(storage.labels_, dba);
return context;
}
#ifdef MG_ENTERPRISE
ExecutionContext MakeContextWithFineGrainedChecker(const AstStorage &storage, const SymbolTable &symbol_table,
memgraph::query::DbAccessor *dba,
memgraph::glue::FineGrainedAuthChecker *auth_checker) {
@ -53,6 +53,7 @@ ExecutionContext MakeContextWithFineGrainedChecker(const AstStorage &storage, co
return context;
}
#endif
/** Helper function that collects all the results from the given Produce. */
std::vector<std::vector<TypedValue>> CollectProduce(const Produce &produce, ExecutionContext *context) {

View File

@ -24,6 +24,7 @@
#include "query/exceptions.hpp"
#include "query/interpret/frame.hpp"
#include "query/plan/operator.hpp"
#include "utils/license.hpp"
#include "query_plan_common.hpp"
#include "storage/v2/id_types.hpp"
@ -77,7 +78,9 @@ TEST(QueryPlan, CreateNodeWithAttributes) {
EXPECT_EQ(vertex_count, 1);
}
#ifdef MG_ENTERPRISE
TEST(QueryPlan, FineGrainedCreateNodeWithAttributes) {
memgraph::utils::license::global_license_checker.EnableTesting();
memgraph::query::AstStorage ast;
memgraph::query::SymbolTable symbol_table;
memgraph::storage::Storage db;
@ -117,6 +120,7 @@ TEST(QueryPlan, FineGrainedCreateNodeWithAttributes) {
ASSERT_THROW(test_create(user), QueryRuntimeException);
}
}
#endif
TEST(QueryPlan, CreateReturn) {
// test CREATE (n:Person {age: 42}) RETURN n, n.age
@ -158,7 +162,10 @@ TEST(QueryPlan, CreateReturn) {
EXPECT_EQ(1, CountIterable(dba.Vertices(memgraph::storage::View::OLD)));
}
#ifdef MG_ENTERPRISE
TEST(QueryPlan, FineGrainedCreateReturn) {
memgraph::utils::license::global_license_checker.EnableTesting();
// test CREATE (n:Person {age: 42}) RETURN n, n.age
memgraph::storage::Storage db;
auto storage_dba = db.Access();
@ -215,6 +222,7 @@ TEST(QueryPlan, FineGrainedCreateReturn) {
ASSERT_THROW(CollectProduce(*produce, &context), QueryRuntimeException);
}
}
#endif
TEST(QueryPlan, CreateExpand) {
memgraph::storage::Storage db;
@ -293,6 +301,7 @@ TEST(QueryPlan, CreateExpand) {
}
}
#ifdef MG_ENTERPRISE
class CreateExpandWithAuthFixture : public testing::Test {
protected:
memgraph::storage::Storage db;
@ -301,6 +310,8 @@ class CreateExpandWithAuthFixture : public testing::Test {
AstStorage storage;
SymbolTable symbol_table;
void SetUp() override { memgraph::utils::license::global_license_checker.EnableTesting(); }
void ExecuteCreateExpand(bool cycle, memgraph::auth::User &user) {
const auto label_node_1 = dba.NameToLabel("Node1");
const auto label_node_2 = dba.NameToLabel("Node2");
@ -465,6 +476,8 @@ class MatchCreateNodeWithAuthFixture : public testing::Test {
AstStorage storage;
SymbolTable symbol_table;
void SetUp() override { memgraph::utils::license::global_license_checker.EnableTesting(); }
void InitGraph() {
// add three nodes we'll match and expand-create from
memgraph::query::VertexAccessor v1{dba.InsertVertex()};
@ -536,6 +549,7 @@ TEST_F(MatchCreateNodeWithAuthFixture, MatchCreateWithOneLabelDeniedThrows) {
ASSERT_THROW(ExecuteMatchCreateTestSuite(user, 3), QueryRuntimeException);
}
#endif
TEST(QueryPlan, MatchCreateExpand) {
memgraph::storage::Storage db;
@ -585,6 +599,7 @@ TEST(QueryPlan, MatchCreateExpand) {
test_create_path(true, 0, 6);
}
#ifdef MG_ENTERPRISE
class MatchCreateExpandWithAuthFixture : public testing::Test {
protected:
memgraph::storage::Storage db;
@ -593,6 +608,8 @@ class MatchCreateExpandWithAuthFixture : public testing::Test {
AstStorage storage;
SymbolTable symbol_table;
void SetUp() override { memgraph::utils::license::global_license_checker.EnableTesting(); }
void InitGraph() {
// add three nodes we'll match and expand-create from
memgraph::query::VertexAccessor v1{dba.InsertVertex()};
@ -730,6 +747,7 @@ TEST_F(MatchCreateExpandWithAuthFixture, MatchCreateExpandWithCycleExecutesWhenG
ExecuteMatchCreateExpandTestSuite(true, 3, 3, user);
}
#endif
TEST(QueryPlan, Delete) {
memgraph::storage::Storage db;
@ -802,6 +820,7 @@ TEST(QueryPlan, Delete) {
}
}
#ifdef MG_ENTERPRISE
class DeleteOperatorWithAuthFixture : public testing::Test {
protected:
memgraph::storage::Storage db;
@ -810,6 +829,8 @@ class DeleteOperatorWithAuthFixture : public testing::Test {
AstStorage storage;
SymbolTable symbol_table;
void SetUp() override { memgraph::utils::license::global_license_checker.EnableTesting(); }
void InitGraph() {
std::vector<memgraph::query::VertexAccessor> vertices;
for (int i = 0; i < 4; ++i) {
@ -949,6 +970,7 @@ TEST_F(DeleteOperatorWithAuthFixture, DeleteNodeAndDeleteEdgePerformWhenGranted)
TestDeleteNodesHypothesis(0);
TestDeleteEdgesHypothesis(0);
}
#endif
TEST(QueryPlan, DeleteTwiceDeleteBlockingEdge) {
// test deleting the same vertex and edge multiple times
@ -1242,7 +1264,9 @@ TEST(QueryPlan, SetLabels) {
}
}
#ifdef MG_ENTERPRISE
TEST(QueryPlan, SetLabelsWithFineGrained) {
memgraph::utils::license::global_license_checker.EnableTesting();
auto set_labels = [&](memgraph::auth::User user, memgraph::query::DbAccessor dba,
std::vector<memgraph::storage::LabelId> labels) {
ASSERT_TRUE(dba.InsertVertex().AddLabel(labels[0]).HasValue());
@ -1315,6 +1339,7 @@ TEST(QueryPlan, SetLabelsWithFineGrained) {
QueryRuntimeException);
}
}
#endif
TEST(QueryPlan, RemoveProperty) {
memgraph::storage::Storage db;
@ -1413,7 +1438,9 @@ TEST(QueryPlan, RemoveLabels) {
}
}
#ifdef MG_ENTERPRISE
TEST(QueryPlan, RemoveLabelsFineGrainedFiltering) {
memgraph::utils::license::global_license_checker.EnableTesting();
auto remove_labels = [&](memgraph::auth::User user, memgraph::query::DbAccessor dba,
std::vector<memgraph::storage::LabelId> labels) {
auto v1 = dba.InsertVertex();
@ -1492,6 +1519,7 @@ TEST(QueryPlan, RemoveLabelsFineGrainedFiltering) {
QueryRuntimeException);
}
}
#endif
TEST(QueryPlan, NodeFilterSet) {
memgraph::storage::Storage db;
@ -1858,6 +1886,7 @@ TEST(QueryPlan, DeleteRemoveProperty) {
//////////////////////////////////////////////
//// FINE GRAINED AUTHORIZATION /////
//////////////////////////////////////////////
#ifdef MG_ENTERPRISE
class UpdatePropertiesWithAuthFixture : public testing::Test {
protected:
memgraph::storage::Storage db;
@ -1882,6 +1911,8 @@ class UpdatePropertiesWithAuthFixture : public testing::Test {
const memgraph::storage::PropertyId edge_prop{dba.NameToProperty(edge_prop_name)};
const memgraph::storage::PropertyValue edge_prop_value{1};
void SetUp() override { memgraph::utils::license::global_license_checker.EnableTesting(); }
void SetVertexProperty(memgraph::query::VertexAccessor vertex) {
static_cast<void>(vertex.SetProperty(entity_prop, entity_prop_value));
}
@ -2484,3 +2515,4 @@ TEST_F(UpdatePropertiesWithAuthFixture, SetPropertyExpandWithAuthChecker) {
test_remove_hypothesis(1);
}
}
#endif

View File

@ -33,6 +33,7 @@
#include "query/context.hpp"
#include "query/exceptions.hpp"
#include "query/plan/operator.hpp"
#include "utils/license.hpp"
#include "utils/synchronized.hpp"
using namespace memgraph::query;
@ -49,6 +50,7 @@ class MatchReturnFixture : public testing::Test {
void AddVertices(int count) {
for (int i = 0; i < count; i++) dba.InsertVertex();
}
void SetUp() override { memgraph::utils::license::global_license_checker.EnableTesting(); }
std::vector<Path> PathResults(std::shared_ptr<Produce> &op) {
std::vector<Path> res;
@ -58,12 +60,15 @@ class MatchReturnFixture : public testing::Test {
}
int PullCountAuthorized(ScanAllTuple scan_all, memgraph::auth::User user) {
#ifdef MG_ENTERPRISE
auto output =
NEXPR("n", IDENT("n")->MapTo(scan_all.sym_))->MapTo(symbol_table.CreateSymbol("named_expression_1", true));
auto produce = MakeProduce(scan_all.op_, output);
memgraph::glue::FineGrainedAuthChecker auth_checker{user, &dba};
auto context = MakeContextWithFineGrainedChecker(storage, symbol_table, &dba, &auth_checker);
return PullAll(*produce, &context);
#endif
return 0;
}
};
@ -107,6 +112,7 @@ TEST_F(MatchReturnFixture, MatchReturnPath) {
EXPECT_TRUE(std::is_permutation(expected_paths.begin(), expected_paths.end(), results.begin()));
}
#ifdef MG_ENTERPRISE
TEST_F(MatchReturnFixture, ScanAllWithAuthChecker) {
std::string labelName = "l1";
const auto label = dba.NameToLabel(labelName);
@ -192,6 +198,7 @@ TEST_F(MatchReturnFixture, ScanAllWithAuthChecker) {
test_hypothesis(user, memgraph::storage::View::NEW, 0);
}
}
#endif
TEST(QueryPlan, MatchReturnCartesian) {
memgraph::storage::Storage db;
@ -474,6 +481,8 @@ class ExpandFixture : public testing::Test {
ASSERT_TRUE(v1.AddLabel(dba.NameToLabel("l1")).HasValue());
ASSERT_TRUE(v2.AddLabel(dba.NameToLabel("l2")).HasValue());
ASSERT_TRUE(v3.AddLabel(dba.NameToLabel("l3")).HasValue());
memgraph::utils::license::global_license_checker.EnableTesting();
dba.AdvanceCommand();
}
};
@ -506,6 +515,7 @@ TEST_F(ExpandFixture, Expand) {
EXPECT_EQ(8, test_expand(EdgeAtom::Direction::BOTH, memgraph::storage::View::OLD));
}
#ifdef MG_ENTERPRISE
TEST_F(ExpandFixture, ExpandWithEdgeFiltering) {
auto test_expand = [&](memgraph::auth::User user, EdgeAtom::Direction direction, memgraph::storage::View view) {
auto n = MakeScanAll(storage, symbol_table, "n");
@ -560,6 +570,7 @@ TEST_F(ExpandFixture, ExpandWithEdgeFiltering) {
EXPECT_EQ(4, test_expand(user, EdgeAtom::Direction::IN, memgraph::storage::View::OLD));
EXPECT_EQ(8, test_expand(user, EdgeAtom::Direction::BOTH, memgraph::storage::View::OLD));
}
#endif
TEST_F(ExpandFixture, ExpandPath) {
auto n = MakeScanAll(storage, symbol_table, "n");
@ -613,6 +624,8 @@ class QueryPlanExpandVariable : public testing::Test {
std::nullopt_t nullopt = std::nullopt;
void SetUp() {
memgraph::utils::license::global_license_checker.EnableTesting();
// create the graph
int chain_length = 3;
std::vector<memgraph::query::VertexAccessor> layer;
@ -703,8 +716,10 @@ class QueryPlanExpandVariable : public testing::Test {
auto cursor = input_op->MakeCursor(memgraph::utils::NewDeleteResource());
ExecutionContext context;
if (user) {
#ifdef MG_ENTERPRISE
memgraph::glue::FineGrainedAuthChecker auth_checker{*user, &dba};
context = MakeContextWithFineGrainedChecker(storage, symbol_table, &dba, &auth_checker);
#endif
} else {
context = MakeContext(storage, symbol_table, &dba);
}
@ -721,8 +736,10 @@ class QueryPlanExpandVariable : public testing::Test {
auto cursor = input_op->MakeCursor(memgraph::utils::NewDeleteResource());
ExecutionContext context;
if (user) {
#ifdef MG_ENTERPRISE
memgraph::glue::FineGrainedAuthChecker auth_checker{*user, &dba};
context = MakeContextWithFineGrainedChecker(storage, symbol_table, &dba, &auth_checker);
#endif
} else {
context = MakeContext(storage, symbol_table, &dba);
}
@ -788,6 +805,7 @@ TEST_F(QueryPlanExpandVariable, OneVariableExpansion) {
}
}
#ifdef MG_ENTERPRISE
TEST_F(QueryPlanExpandVariable, FineGrainedOneVariableExpansion) {
auto test_expand = [&](int layer, EdgeAtom::Direction direction, std::optional<size_t> lower,
std::optional<size_t> upper, bool reverse, memgraph::auth::User &user) {
@ -989,6 +1007,7 @@ TEST_F(QueryPlanExpandVariable, FineGrainedOneVariableExpansion) {
}
}
}
#endif
TEST_F(QueryPlanExpandVariable, EdgeUniquenessSingleAndVariableExpansion) {
auto test_expand = [&](int layer, EdgeAtom::Direction direction, std::optional<size_t> lower,
@ -1049,6 +1068,7 @@ TEST_F(QueryPlanExpandVariable, EdgeUniquenessTwoVariableExpansions) {
EXPECT_EQ(test_expand(0, EdgeAtom::Direction::OUT, 2, 2, true), (map_int{{2, 5 * 8}}));
}
#ifdef MG_ENTERPRISE
TEST_F(QueryPlanExpandVariable, FineGrainedEdgeUniquenessTwoVariableExpansions) {
auto test_expand = [&](int layer, EdgeAtom::Direction direction, std::optional<size_t> lower,
std::optional<size_t> upper, bool add_uniqueness_check, memgraph::auth::User &user) {
@ -1139,6 +1159,7 @@ TEST_F(QueryPlanExpandVariable, FineGrainedEdgeUniquenessTwoVariableExpansions)
EXPECT_EQ(test_expand(1, EdgeAtom::Direction::OUT, 0, 2, true, user), (map_int{{0, 4}}));
}
}
#endif
TEST_F(QueryPlanExpandVariable, NamedPath) {
auto e = Edge("r", EdgeAtom::Direction::OUT);
@ -1172,6 +1193,7 @@ TEST_F(QueryPlanExpandVariable, NamedPath) {
EXPECT_TRUE(std::is_permutation(results.begin(), results.end(), expected_paths.begin()));
}
#ifdef MG_ENTERPRISE
TEST_F(QueryPlanExpandVariable, FineGrainedFilterNamedPath) {
auto e = Edge("r", EdgeAtom::Direction::OUT);
auto expand = AddMatch<ExpandVariable>(nullptr, "n", 0, EdgeAtom::Direction::OUT, {}, 0, 2, e, "m",
@ -1310,6 +1332,7 @@ TEST_F(QueryPlanExpandVariable, FineGrainedFilterNamedPath) {
EXPECT_TRUE(std::is_permutation(results.begin(), results.end(), expected_paths.begin()));
}
}
#endif
TEST_F(QueryPlanExpandVariable, ExpandToSameSymbol) {
auto test_expand = [&](int layer, EdgeAtom::Direction direction, std::optional<size_t> lower,
@ -1501,6 +1524,7 @@ TEST_F(QueryPlanExpandVariable, ExpandToSameSymbol) {
}
}
#ifdef MG_ENTERPRISE
TEST_F(QueryPlanExpandVariable, FineGrainedExpandToSameSymbol) {
auto test_expand = [&](int layer, EdgeAtom::Direction direction, std::optional<size_t> lower,
std::optional<size_t> upper, bool reverse, memgraph::auth::User &user) {
@ -1699,6 +1723,7 @@ TEST_F(QueryPlanExpandVariable, FineGrainedExpandToSameSymbol) {
}
}
}
#endif
namespace std {
template <>
@ -1743,6 +1768,8 @@ class QueryPlanExpandWeightedShortestPath : public testing::Test {
Symbol total_weight = symbol_table.CreateSymbol("total_weight", true);
void SetUp() {
memgraph::utils::license::global_license_checker.EnableTesting();
for (int i = 0; i < 5; i++) {
v.push_back(dba.InsertVertex());
ASSERT_TRUE(v.back().SetProperty(prop.second, memgraph::storage::PropertyValue(i)).HasValue());
@ -1796,8 +1823,10 @@ class QueryPlanExpandWeightedShortestPath : public testing::Test {
std::vector<ResultType> results;
memgraph::query::ExecutionContext context;
if (user) {
#ifdef MG_ENTERPRISE
memgraph::glue::FineGrainedAuthChecker auth_checker{*user, &dba};
context = MakeContextWithFineGrainedChecker(storage, symbol_table, &dba, &auth_checker);
#endif
} else {
context = MakeContext(storage, symbol_table, &dba);
}
@ -2030,6 +2059,7 @@ TEST_F(QueryPlanExpandWeightedShortestPath, NegativeUpperBound) {
EXPECT_THROW(ExpandWShortest(EdgeAtom::Direction::BOTH, -1, LITERAL(true)), QueryRuntimeException);
}
#if MG_ENTERPRISE
TEST_F(QueryPlanExpandWeightedShortestPath, FineGrainedFiltering) {
// All edge_types and labels allowed
{
@ -2129,6 +2159,7 @@ TEST_F(QueryPlanExpandWeightedShortestPath, FineGrainedFiltering) {
ASSERT_EQ(filtered_results.size(), 4);
}
}
#endif
/** A test fixture for all shortest paths expansion */
class QueryPlanExpandAllShortestPaths : public testing::Test {
@ -2166,6 +2197,8 @@ class QueryPlanExpandAllShortestPaths : public testing::Test {
Symbol total_weight = symbol_table.CreateSymbol("total_weight", true);
void SetUp() {
memgraph::utils::license::global_license_checker.EnableTesting();
for (int i = 0; i < 5; i++) {
v.push_back(dba.InsertVertex());
ASSERT_TRUE(v.back().SetProperty(prop.second, memgraph::storage::PropertyValue(i)).HasValue());
@ -2219,8 +2252,10 @@ class QueryPlanExpandAllShortestPaths : public testing::Test {
std::vector<ResultType> results;
ExecutionContext context;
if (user) {
#ifdef MG_ENTERPRISE
memgraph::glue::FineGrainedAuthChecker auth_checker{*user, &dba};
context = MakeContextWithFineGrainedChecker(storage, symbol_table, &dba, &auth_checker);
#endif
} else {
context = MakeContext(storage, symbol_table, &dba);
}
@ -2492,6 +2527,7 @@ TEST_F(QueryPlanExpandAllShortestPaths, MultiEdge) {
EXPECT_EQ(results[5].total_weight, 9);
}
#ifdef MG_ENTERPRISE
TEST_F(QueryPlanExpandAllShortestPaths, BasicWithFineGrainedFiltering) {
// All edge_types and labels allowed
{
@ -2571,6 +2607,7 @@ TEST_F(QueryPlanExpandAllShortestPaths, BasicWithFineGrainedFiltering) {
ASSERT_EQ(filtered_results.size(), 4);
}
}
#endif
TEST(QueryPlan, ExpandOptional) {
memgraph::storage::Storage db;

View File

@ -17,6 +17,7 @@
#include "query/frontend/ast/ast_visitor.hpp"
#include "query/frontend/semantic/required_privileges.hpp"
#include "storage/v2/id_types.hpp"
#include "utils/license.hpp"
#include "query_common.hpp"
@ -97,8 +98,9 @@ TEST_F(TestPrivilegeExtractor, CreateIndex) {
auto *query = CREATE_INDEX_ON(storage.GetLabelIx(LABEL_0), storage.GetPropertyIx(PROP_0));
EXPECT_THAT(GetRequiredPrivileges(query), UnorderedElementsAre(AuthQuery::Privilege::INDEX));
}
#ifdef MG_ENTERPRISE
TEST_F(TestPrivilegeExtractor, AuthQuery) {
memgraph::utils::license::global_license_checker.EnableTesting();
auto label_privileges = std::vector<std::unordered_map<AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>{};
auto edge_type_privileges =
std::vector<std::unordered_map<AuthQuery::FineGrainedPrivilege, std::vector<std::string>>>{};
@ -106,6 +108,7 @@ TEST_F(TestPrivilegeExtractor, AuthQuery) {
label_privileges, edge_type_privileges);
EXPECT_THAT(GetRequiredPrivileges(query), UnorderedElementsAre(AuthQuery::Privilege::AUTH));
}
#endif
TEST_F(TestPrivilegeExtractor, ShowIndexInfo) {
auto *query = storage.Create<InfoQuery>();

View File

@ -39,9 +39,12 @@ class MockAuthChecker : public memgraph::query::AuthChecker {
public:
MOCK_CONST_METHOD2(IsUserAuthorized, bool(const std::optional<std::string> &username,
const std::vector<memgraph::query::AuthQuery::Privilege> &privileges));
#ifdef MG_ENTERPRISE
MOCK_CONST_METHOD2(GetFineGrainedAuthChecker,
std::unique_ptr<memgraph::query::FineGrainedAuthChecker>(
const std::string &username, const memgraph::query::DbAccessor *db_accessor));
#endif
};
} // namespace