[E129-MG < T997-MG] Show label privileges (#506)
Added showing of label privileges functionality to fine grained access control.
This commit is contained in:
parent
05f120b7d4
commit
7478300762
@ -101,6 +101,35 @@ std::string PermissionLevelToString(PermissionLevel level) {
|
||||
}
|
||||
}
|
||||
|
||||
FineGrainedPermission PermissionToFineGrainedPermission(const uint64_t permission) {
|
||||
if (permission & FineGrainedPermission::CREATE_DELETE) {
|
||||
return FineGrainedPermission::CREATE_DELETE;
|
||||
}
|
||||
|
||||
if (permission & FineGrainedPermission::UPDATE) {
|
||||
return FineGrainedPermission::UPDATE;
|
||||
}
|
||||
|
||||
if (permission & FineGrainedPermission::READ) {
|
||||
return FineGrainedPermission::READ;
|
||||
}
|
||||
|
||||
return FineGrainedPermission::NO_PERMISSION;
|
||||
}
|
||||
|
||||
std::string FineGrainedPermissionToString(const FineGrainedPermission level) {
|
||||
switch (level) {
|
||||
case FineGrainedPermission::CREATE_DELETE:
|
||||
return "CREATE_DELETE";
|
||||
case FineGrainedPermission::UPDATE:
|
||||
return "UPDATE";
|
||||
case FineGrainedPermission::READ:
|
||||
return "READ";
|
||||
case FineGrainedPermission::NO_PERMISSION:
|
||||
return "NO_PERMISSION";
|
||||
}
|
||||
}
|
||||
|
||||
FineGrainedAccessPermissions Merge(const FineGrainedAccessPermissions &first,
|
||||
const FineGrainedAccessPermissions &second) {
|
||||
std::unordered_map<std::string, uint64_t> permissions{first.GetPermissions()};
|
||||
@ -370,6 +399,14 @@ Permissions &Role::permissions() { return permissions_; }
|
||||
const FineGrainedAccessHandler &Role::fine_grained_access_handler() const { return fine_grained_access_handler_; }
|
||||
FineGrainedAccessHandler &Role::fine_grained_access_handler() { return fine_grained_access_handler_; }
|
||||
|
||||
const FineGrainedAccessPermissions &Role::GetFineGrainedAccessLabelPermissions() const {
|
||||
return fine_grained_access_handler_.label_permissions();
|
||||
}
|
||||
|
||||
const FineGrainedAccessPermissions &Role::GetFineGrainedAccessEdgeTypePermissions() const {
|
||||
return fine_grained_access_handler_.edge_type_permissions();
|
||||
}
|
||||
|
||||
nlohmann::json Role::Serialize() const {
|
||||
nlohmann::json data = nlohmann::json::object();
|
||||
data["rolename"] = rolename_;
|
||||
|
@ -46,6 +46,7 @@ enum class Permission : uint64_t {
|
||||
|
||||
// clang-format off
|
||||
enum class FineGrainedPermission : uint64_t {
|
||||
NO_PERMISSION = 0,
|
||||
READ = 1,
|
||||
UPDATE = 1U << 1U,
|
||||
CREATE_DELETE = 1U << 2U
|
||||
@ -79,6 +80,12 @@ enum class PermissionLevel : uint8_t { GRANT, NEUTRAL, DENY };
|
||||
// Function that converts a permission level to its string representation.
|
||||
std::string PermissionLevelToString(PermissionLevel level);
|
||||
|
||||
// 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);
|
||||
|
||||
class Permissions final {
|
||||
public:
|
||||
explicit Permissions(uint64_t grants = 0, uint64_t denies = 0);
|
||||
@ -205,6 +212,8 @@ class Role final {
|
||||
Permissions &permissions();
|
||||
const FineGrainedAccessHandler &fine_grained_access_handler() const;
|
||||
FineGrainedAccessHandler &fine_grained_access_handler();
|
||||
const FineGrainedAccessPermissions &GetFineGrainedAccessLabelPermissions() const;
|
||||
const FineGrainedAccessPermissions &GetFineGrainedAccessEdgeTypePermissions() const;
|
||||
|
||||
nlohmann::json Serialize() const;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
set(mg_glue_sources auth.cpp auth_checker.cpp communication.cpp)
|
||||
set(mg_glue_sources auth.cpp auth_checker.cpp auth_handler.cpp communication.cpp)
|
||||
|
||||
add_library(mg-glue STATIC ${mg_glue_sources})
|
||||
target_link_libraries(mg-glue mg-query mg-auth)
|
||||
|
587
src/glue/auth_handler.cpp
Normal file
587
src/glue/auth_handler.cpp
Normal file
@ -0,0 +1,587 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
// License, and you may not use this file except in compliance with the Business Source License.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
#include "glue/auth_handler.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "auth/models.hpp"
|
||||
#include "glue/auth.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
struct PermissionForPrivilegeResult {
|
||||
std::string permission;
|
||||
memgraph::auth::PermissionLevel permission_level;
|
||||
std::string description;
|
||||
};
|
||||
|
||||
struct FineGrainedPermissionForPrivilegeResult {
|
||||
std::string permission;
|
||||
memgraph::auth::FineGrainedPermission permission_level;
|
||||
std::string description;
|
||||
};
|
||||
|
||||
PermissionForPrivilegeResult GetPermissionForPrivilegeForUserOrRole(
|
||||
const memgraph::auth::Permissions &permissions, const memgraph::query::AuthQuery::Privilege &privilege,
|
||||
const std::string &user_or_role) {
|
||||
PermissionForPrivilegeResult container;
|
||||
|
||||
const auto permission = memgraph::glue::PrivilegeToPermission(privilege);
|
||||
container.permission = memgraph::auth::PermissionToString(permission);
|
||||
container.permission_level = permissions.Has(permission);
|
||||
|
||||
switch (container.permission_level) {
|
||||
case memgraph::auth::PermissionLevel::GRANT:
|
||||
container.description = "GRANTED TO " + user_or_role;
|
||||
break;
|
||||
case memgraph::auth::PermissionLevel::DENY:
|
||||
container.description = "DENIED TO " + user_or_role;
|
||||
break;
|
||||
case memgraph::auth::PermissionLevel::NEUTRAL:
|
||||
break;
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> ConstructPrivilegesResult(
|
||||
const std::vector<PermissionForPrivilegeResult> &privileges) {
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> grants;
|
||||
|
||||
grants.reserve(privileges.size());
|
||||
for (const auto &permission : privileges) {
|
||||
grants.push_back({memgraph::query::TypedValue(permission.permission),
|
||||
memgraph::query::TypedValue(memgraph::auth::PermissionLevelToString(permission.permission_level)),
|
||||
memgraph::query::TypedValue(permission.description)});
|
||||
}
|
||||
|
||||
return grants;
|
||||
}
|
||||
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> ShowUserPrivileges(
|
||||
const std::optional<memgraph::auth::User> &user) {
|
||||
std::vector<PermissionForPrivilegeResult> privilege_results;
|
||||
|
||||
const auto &permissions = user->GetPermissions();
|
||||
const auto &user_level_permissions = user->permissions();
|
||||
|
||||
for (const auto &privilege : memgraph::query::kPrivilegesAll) {
|
||||
auto user_permission_result = GetPermissionForPrivilegeForUserOrRole(permissions, privilege, "USER");
|
||||
auto user_only_permissions_result =
|
||||
GetPermissionForPrivilegeForUserOrRole(user_level_permissions, privilege, "USER");
|
||||
|
||||
if (user_permission_result.permission_level != memgraph::auth::PermissionLevel::NEUTRAL) {
|
||||
std::vector<std::string> full_description;
|
||||
if (user_only_permissions_result.permission_level != memgraph::auth::PermissionLevel::NEUTRAL) {
|
||||
full_description.emplace_back(user_only_permissions_result.description);
|
||||
}
|
||||
|
||||
if (const auto *role = user->role(); role != nullptr) {
|
||||
auto role_permission_result = GetPermissionForPrivilegeForUserOrRole(role->permissions(), privilege, "ROLE");
|
||||
if (role_permission_result.permission_level != memgraph::auth::PermissionLevel::NEUTRAL) {
|
||||
full_description.emplace_back(role_permission_result.description);
|
||||
}
|
||||
}
|
||||
|
||||
privilege_results.push_back(PermissionForPrivilegeResult{user_permission_result.permission,
|
||||
user_permission_result.permission_level,
|
||||
memgraph::utils::Join(full_description, ", ")});
|
||||
}
|
||||
}
|
||||
|
||||
return ConstructPrivilegesResult(privilege_results);
|
||||
}
|
||||
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> ShowRolePrivileges(
|
||||
const std::optional<memgraph::auth::Role> &role) {
|
||||
std::vector<PermissionForPrivilegeResult> privilege_results;
|
||||
const auto &permissions = role->permissions();
|
||||
for (const auto &privilege : memgraph::query::kPrivilegesAll) {
|
||||
auto role_permission_result = GetPermissionForPrivilegeForUserOrRole(permissions, privilege, "ROLE");
|
||||
if (role_permission_result.permission_level != memgraph::auth::PermissionLevel::NEUTRAL) {
|
||||
privilege_results.push_back(role_permission_result);
|
||||
}
|
||||
}
|
||||
|
||||
return ConstructPrivilegesResult(privilege_results);
|
||||
}
|
||||
|
||||
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;
|
||||
const auto global_permission = permissions.GetGlobalPermission();
|
||||
if (global_permission.has_value()) {
|
||||
const auto &permission_level = memgraph::auth::PermissionToFineGrainedPermission(global_permission.value());
|
||||
|
||||
std::stringstream permission_representation;
|
||||
permission_representation << "ALL " << permission_type << "S";
|
||||
const auto &permission_level_representation =
|
||||
permission_level == memgraph::auth::FineGrainedPermission::NO_PERMISSION ? "DENIED" : "GRANTED";
|
||||
|
||||
const auto permission_description =
|
||||
fmt::format("GLOBAL {0} PERMISSION {1} TO {2}", permission_type, permission_level_representation, user_or_role);
|
||||
|
||||
fine_grained_permissions.push_back(FineGrainedPermissionForPrivilegeResult{
|
||||
permission_representation.str(), permission_level, permission_description});
|
||||
}
|
||||
|
||||
for (const auto &[label, permission] : permissions.GetPermissions()) {
|
||||
auto permission_level = memgraph::auth::PermissionToFineGrainedPermission(permission);
|
||||
|
||||
std::stringstream permission_representation;
|
||||
permission_representation << permission_type << " :" << label;
|
||||
|
||||
const auto &permission_level_representation =
|
||||
permission_level == memgraph::auth::FineGrainedPermission::NO_PERMISSION ? "DENIED" : "GRANTED";
|
||||
|
||||
const auto permission_description =
|
||||
fmt::format("{0} PERMISSION {1} TO {2}", permission_type, permission_level_representation, user_or_role);
|
||||
|
||||
fine_grained_permissions.push_back(FineGrainedPermissionForPrivilegeResult{
|
||||
permission_representation.str(), permission_level, permission_description});
|
||||
}
|
||||
|
||||
return fine_grained_permissions;
|
||||
}
|
||||
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> ConstructFineGrainedPrivilegesResult(
|
||||
const std::vector<FineGrainedPermissionForPrivilegeResult> &privileges) {
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> grants;
|
||||
|
||||
grants.reserve(privileges.size());
|
||||
for (const auto &permission : privileges) {
|
||||
grants.push_back(
|
||||
{memgraph::query::TypedValue(permission.permission),
|
||||
memgraph::query::TypedValue(memgraph::auth::FineGrainedPermissionToString(permission.permission_level)),
|
||||
memgraph::query::TypedValue(permission.description)});
|
||||
}
|
||||
|
||||
return grants;
|
||||
}
|
||||
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> ShowFineGrainedUserPrivileges(
|
||||
const std::optional<memgraph::auth::User> &user) {
|
||||
const auto &label_permissions = user->GetFineGrainedAccessLabelPermissions();
|
||||
const auto &edge_type_permissions = user->GetFineGrainedAccessEdgeTypePermissions();
|
||||
|
||||
auto all_fine_grained_permissions =
|
||||
GetFineGrainedPermissionForPrivilegeForUserOrRole(label_permissions, "LABEL", "USER");
|
||||
auto edge_type_fine_grained_permissions =
|
||||
GetFineGrainedPermissionForPrivilegeForUserOrRole(edge_type_permissions, "EDGE_TYPE", "USER");
|
||||
|
||||
all_fine_grained_permissions.insert(all_fine_grained_permissions.end(), edge_type_fine_grained_permissions.begin(),
|
||||
edge_type_fine_grained_permissions.end());
|
||||
|
||||
return ConstructFineGrainedPrivilegesResult(all_fine_grained_permissions);
|
||||
}
|
||||
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> ShowFineGrainedRolePrivileges(
|
||||
const std::optional<memgraph::auth::Role> &role) {
|
||||
const auto &label_permissions = role->GetFineGrainedAccessLabelPermissions();
|
||||
const auto &edge_type_permissions = role->GetFineGrainedAccessEdgeTypePermissions();
|
||||
|
||||
auto all_fine_grained_permissions =
|
||||
GetFineGrainedPermissionForPrivilegeForUserOrRole(label_permissions, "LABEL", "USER");
|
||||
auto edge_type_fine_grained_permissions =
|
||||
GetFineGrainedPermissionForPrivilegeForUserOrRole(edge_type_permissions, "EDGE_TYPE", "USER");
|
||||
|
||||
all_fine_grained_permissions.insert(all_fine_grained_permissions.end(), edge_type_fine_grained_permissions.begin(),
|
||||
edge_type_fine_grained_permissions.end());
|
||||
|
||||
return ConstructFineGrainedPrivilegesResult(all_fine_grained_permissions);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace memgraph::glue {
|
||||
|
||||
AuthQueryHandler::AuthQueryHandler(
|
||||
memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth,
|
||||
std::string name_regex_string)
|
||||
: auth_(auth), name_regex_string_(std::move(name_regex_string)), name_regex_(name_regex_string_) {}
|
||||
|
||||
bool AuthQueryHandler::CreateUser(const std::string &username, const std::optional<std::string> &password) {
|
||||
if (name_regex_string_ != kDefaultUserRoleRegex) {
|
||||
if (const auto license_check_result =
|
||||
memgraph::utils::license::global_license_checker.IsValidLicense(memgraph::utils::global_settings);
|
||||
license_check_result.HasError()) {
|
||||
throw memgraph::auth::AuthException(
|
||||
"Custom user/role regex is a Memgraph Enterprise feature. Please set the config "
|
||||
"(\"--auth-user-or-role-name-regex\") to its default value (\"{}\") or remove the flag.\n{}",
|
||||
kDefaultUserRoleRegex,
|
||||
memgraph::utils::license::LicenseCheckErrorToString(license_check_result.GetError(), "user/role regex"));
|
||||
}
|
||||
}
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
try {
|
||||
const auto [first_user, user_added] = std::invoke([&, this] {
|
||||
auto locked_auth = auth_->Lock();
|
||||
const auto first_user = !locked_auth->HasUsers();
|
||||
const auto user_added = locked_auth->AddUser(username, password).has_value();
|
||||
return std::make_pair(first_user, user_added);
|
||||
});
|
||||
|
||||
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}}}});
|
||||
}
|
||||
|
||||
return user_added;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool AuthQueryHandler::DropUser(const std::string &username) {
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto user = locked_auth->GetUser(username);
|
||||
if (!user) return false;
|
||||
return locked_auth->RemoveUser(username);
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void AuthQueryHandler::SetPassword(const std::string &username, const std::optional<std::string> &password) {
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto user = locked_auth->GetUser(username);
|
||||
if (!user) {
|
||||
throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist.", username);
|
||||
}
|
||||
user->UpdatePassword(password);
|
||||
locked_auth->SaveUser(*user);
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool AuthQueryHandler::CreateRole(const std::string &rolename) {
|
||||
if (!std::regex_match(rolename, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid role name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
return locked_auth->AddRole(rolename).has_value();
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool AuthQueryHandler::DropRole(const std::string &rolename) {
|
||||
if (!std::regex_match(rolename, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid role name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto role = locked_auth->GetRole(rolename);
|
||||
|
||||
if (!role) {
|
||||
return false;
|
||||
};
|
||||
|
||||
return locked_auth->RemoveRole(rolename);
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<memgraph::query::TypedValue> AuthQueryHandler::GetUsernames() {
|
||||
try {
|
||||
auto locked_auth = auth_->ReadLock();
|
||||
std::vector<memgraph::query::TypedValue> usernames;
|
||||
const auto &users = locked_auth->AllUsers();
|
||||
usernames.reserve(users.size());
|
||||
for (const auto &user : users) {
|
||||
usernames.emplace_back(user.username());
|
||||
}
|
||||
return usernames;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<memgraph::query::TypedValue> AuthQueryHandler::GetRolenames() {
|
||||
try {
|
||||
auto locked_auth = auth_->ReadLock();
|
||||
std::vector<memgraph::query::TypedValue> rolenames;
|
||||
const auto &roles = locked_auth->AllRoles();
|
||||
rolenames.reserve(roles.size());
|
||||
for (const auto &role : roles) {
|
||||
rolenames.emplace_back(role.rolename());
|
||||
}
|
||||
return rolenames;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> AuthQueryHandler::GetRolenameForUser(const std::string &username) {
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->ReadLock();
|
||||
auto user = locked_auth->GetUser(username);
|
||||
if (!user) {
|
||||
throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
|
||||
}
|
||||
|
||||
if (const auto *role = user->role(); role != nullptr) {
|
||||
return role->rolename();
|
||||
}
|
||||
return std::nullopt;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<memgraph::query::TypedValue> AuthQueryHandler::GetUsernamesForRole(const std::string &rolename) {
|
||||
if (!std::regex_match(rolename, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid role name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->ReadLock();
|
||||
auto role = locked_auth->GetRole(rolename);
|
||||
if (!role) {
|
||||
throw memgraph::query::QueryRuntimeException("Role '{}' doesn't exist.", rolename);
|
||||
}
|
||||
std::vector<memgraph::query::TypedValue> usernames;
|
||||
const auto &users = locked_auth->AllUsersForRole(rolename);
|
||||
usernames.reserve(users.size());
|
||||
for (const auto &user : users) {
|
||||
usernames.emplace_back(user.username());
|
||||
}
|
||||
return usernames;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void AuthQueryHandler::SetRole(const std::string &username, const std::string &rolename) {
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
if (!std::regex_match(rolename, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid role name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto user = locked_auth->GetUser(username);
|
||||
if (!user) {
|
||||
throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
|
||||
}
|
||||
auto role = locked_auth->GetRole(rolename);
|
||||
if (!role) {
|
||||
throw memgraph::query::QueryRuntimeException("Role '{}' doesn't exist .", rolename);
|
||||
}
|
||||
if (const auto *current_role = user->role(); current_role != nullptr) {
|
||||
throw memgraph::query::QueryRuntimeException("User '{}' is already a member of role '{}'.", username,
|
||||
current_role->rolename());
|
||||
}
|
||||
user->SetRole(*role);
|
||||
locked_auth->SaveUser(*user);
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void AuthQueryHandler::ClearRole(const std::string &username) {
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto user = locked_auth->GetUser(username);
|
||||
if (!user) {
|
||||
throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
|
||||
}
|
||||
user->ClearRole();
|
||||
locked_auth->SaveUser(*user);
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> AuthQueryHandler::GetPrivileges(const std::string &user_or_role) {
|
||||
if (!std::regex_match(user_or_role, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user or role name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->ReadLock();
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> grants;
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> fine_grained_grants;
|
||||
auto user = locked_auth->GetUser(user_or_role);
|
||||
auto role = locked_auth->GetRole(user_or_role);
|
||||
if (!user && !role) {
|
||||
throw memgraph::query::QueryRuntimeException("User or role '{}' doesn't exist.", user_or_role);
|
||||
}
|
||||
|
||||
if (user) {
|
||||
grants = ShowUserPrivileges(user);
|
||||
fine_grained_grants = ShowFineGrainedUserPrivileges(user);
|
||||
} else {
|
||||
grants = ShowRolePrivileges(role);
|
||||
fine_grained_grants = ShowFineGrainedRolePrivileges(role);
|
||||
}
|
||||
|
||||
grants.insert(grants.end(), fine_grained_grants.begin(), fine_grained_grants.end());
|
||||
|
||||
return grants;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void AuthQueryHandler::GrantPrivilege(
|
||||
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
|
||||
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) {
|
||||
EditPermissions(
|
||||
user_or_role, privileges, label_privileges, edge_type_privileges,
|
||||
[](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);
|
||||
},
|
||||
[](auto &fine_grained_permissions, const auto &privilege_collection) {
|
||||
for (const auto &[privilege, entities] : privilege_collection) {
|
||||
const auto &permission = memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(privilege);
|
||||
for (const auto &entity : entities) {
|
||||
fine_grained_permissions.Grant(entity, permission);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AuthQueryHandler::DenyPrivilege(
|
||||
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
|
||||
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) {
|
||||
EditPermissions(
|
||||
user_or_role, privileges, label_privileges, edge_type_privileges,
|
||||
[](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);
|
||||
},
|
||||
[](auto &fine_grained_permissions, const auto &privilege_collection) {
|
||||
for (const auto &[privilege, entities] : privilege_collection) {
|
||||
const auto &permission = memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(privilege);
|
||||
for (const auto &entity : entities) {
|
||||
fine_grained_permissions.Deny(entity, permission);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AuthQueryHandler::RevokePrivilege(
|
||||
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
|
||||
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) {
|
||||
EditPermissions(
|
||||
user_or_role, privileges, label_privileges, edge_type_privileges,
|
||||
[](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);
|
||||
},
|
||||
[](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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <class TEditPermissionsFun, class TEditFineGrainedPermissionsFun>
|
||||
void AuthQueryHandler::EditPermissions(
|
||||
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
|
||||
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) {
|
||||
if (!std::regex_match(user_or_role, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user or role name.");
|
||||
}
|
||||
try {
|
||||
std::vector<memgraph::auth::Permission> permissions;
|
||||
permissions.reserve(privileges.size());
|
||||
for (const auto &privilege : privileges) {
|
||||
permissions.push_back(memgraph::glue::PrivilegeToPermission(privilege));
|
||||
}
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto user = locked_auth->GetUser(user_or_role);
|
||||
auto role = locked_auth->GetRole(user_or_role);
|
||||
if (!user && !role) {
|
||||
throw memgraph::query::QueryRuntimeException("User or role '{}' doesn't exist.", user_or_role);
|
||||
}
|
||||
if (user) {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
locked_auth->SaveRole(*role);
|
||||
}
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace memgraph::glue
|
91
src/glue/auth_handler.hpp
Normal file
91
src/glue/auth_handler.hpp
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
// License, and you may not use this file except in compliance with the Business Source License.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "auth/auth.hpp"
|
||||
#include "glue/auth.hpp"
|
||||
#include "query/interpreter.hpp"
|
||||
#include "utils/license.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace memgraph::glue {
|
||||
|
||||
inline constexpr std::string_view kDefaultUserRoleRegex = "[a-zA-Z0-9_.+-@]+";
|
||||
|
||||
class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
|
||||
memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth_;
|
||||
std::string name_regex_string_;
|
||||
std::regex name_regex_;
|
||||
|
||||
public:
|
||||
AuthQueryHandler(memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth,
|
||||
std::string name_regex_string);
|
||||
|
||||
bool CreateUser(const std::string &username, const std::optional<std::string> &password) override;
|
||||
|
||||
bool DropUser(const std::string &username) override;
|
||||
|
||||
void SetPassword(const std::string &username, const std::optional<std::string> &password) override;
|
||||
|
||||
bool CreateRole(const std::string &rolename) override;
|
||||
|
||||
bool DropRole(const std::string &rolename) override;
|
||||
|
||||
std::vector<memgraph::query::TypedValue> GetUsernames() override;
|
||||
|
||||
std::vector<memgraph::query::TypedValue> GetRolenames() override;
|
||||
|
||||
std::optional<std::string> GetRolenameForUser(const std::string &username) override;
|
||||
|
||||
std::vector<memgraph::query::TypedValue> GetUsernamesForRole(const std::string &rolename) override;
|
||||
|
||||
void SetRole(const std::string &username, const std::string &rolename) override;
|
||||
|
||||
void ClearRole(const std::string &username) override;
|
||||
|
||||
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::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;
|
||||
|
||||
void DenyPrivilege(
|
||||
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
|
||||
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;
|
||||
|
||||
void RevokePrivilege(
|
||||
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
|
||||
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;
|
||||
|
||||
private:
|
||||
template <class TEditPermissionsFun, class TEditFineGrainedPermissionsFun>
|
||||
void EditPermissions(
|
||||
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
|
||||
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);
|
||||
};
|
||||
} // namespace memgraph::glue
|
419
src/memgraph.cpp
419
src/memgraph.cpp
@ -38,6 +38,7 @@
|
||||
#include "communication/websocket/auth.hpp"
|
||||
#include "communication/websocket/server.hpp"
|
||||
#include "glue/auth_checker.hpp"
|
||||
#include "glue/auth_handler.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "py/py.hpp"
|
||||
#include "query/auth_checker.hpp"
|
||||
@ -469,424 +470,10 @@ struct SessionData {
|
||||
#endif
|
||||
};
|
||||
|
||||
inline constexpr std::string_view default_user_role_regex = "[a-zA-Z0-9_.+-@]+";
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
DEFINE_string(auth_user_or_role_name_regex, default_user_role_regex.data(),
|
||||
DEFINE_string(auth_user_or_role_name_regex, memgraph::glue::kDefaultUserRoleRegex.data(),
|
||||
"Set to the regular expression that each user or role name must fulfill.");
|
||||
|
||||
class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
|
||||
memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth_;
|
||||
std::string name_regex_string_;
|
||||
std::regex name_regex_;
|
||||
|
||||
public:
|
||||
AuthQueryHandler(memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> *auth,
|
||||
std::string name_regex_string)
|
||||
: auth_(auth), name_regex_string_(std::move(name_regex_string)), name_regex_(name_regex_string_) {}
|
||||
|
||||
bool CreateUser(const std::string &username, const std::optional<std::string> &password) override {
|
||||
if (name_regex_string_ != default_user_role_regex) {
|
||||
if (const auto license_check_result =
|
||||
memgraph::utils::license::global_license_checker.IsValidLicense(memgraph::utils::global_settings);
|
||||
license_check_result.HasError()) {
|
||||
throw memgraph::auth::AuthException(
|
||||
"Custom user/role regex is a Memgraph Enterprise feature. Please set the config "
|
||||
"(\"--auth-user-or-role-name-regex\") to its default value (\"{}\") or remove the flag.\n{}",
|
||||
default_user_role_regex,
|
||||
memgraph::utils::license::LicenseCheckErrorToString(license_check_result.GetError(), "user/role regex"));
|
||||
}
|
||||
}
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
try {
|
||||
const auto [first_user, user_added] = std::invoke([&, this] {
|
||||
auto locked_auth = auth_->Lock();
|
||||
const auto first_user = !locked_auth->HasUsers();
|
||||
const auto user_added = locked_auth->AddUser(username, password).has_value();
|
||||
return std::make_pair(first_user, user_added);
|
||||
});
|
||||
|
||||
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}}}});
|
||||
}
|
||||
|
||||
return user_added;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool DropUser(const std::string &username) override {
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto user = locked_auth->GetUser(username);
|
||||
if (!user) return false;
|
||||
return locked_auth->RemoveUser(username);
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void SetPassword(const std::string &username, const std::optional<std::string> &password) override {
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto user = locked_auth->GetUser(username);
|
||||
if (!user) {
|
||||
throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist.", username);
|
||||
}
|
||||
user->UpdatePassword(password);
|
||||
locked_auth->SaveUser(*user);
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool CreateRole(const std::string &rolename) override {
|
||||
if (!std::regex_match(rolename, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid role name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
return locked_auth->AddRole(rolename).has_value();
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool DropRole(const std::string &rolename) override {
|
||||
if (!std::regex_match(rolename, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid role name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto role = locked_auth->GetRole(rolename);
|
||||
if (!role) return false;
|
||||
return locked_auth->RemoveRole(rolename);
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<memgraph::query::TypedValue> GetUsernames() override {
|
||||
try {
|
||||
auto locked_auth = auth_->ReadLock();
|
||||
std::vector<memgraph::query::TypedValue> usernames;
|
||||
const auto &users = locked_auth->AllUsers();
|
||||
usernames.reserve(users.size());
|
||||
for (const auto &user : users) {
|
||||
usernames.emplace_back(user.username());
|
||||
}
|
||||
return usernames;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<memgraph::query::TypedValue> GetRolenames() override {
|
||||
try {
|
||||
auto locked_auth = auth_->ReadLock();
|
||||
std::vector<memgraph::query::TypedValue> rolenames;
|
||||
const auto &roles = locked_auth->AllRoles();
|
||||
rolenames.reserve(roles.size());
|
||||
for (const auto &role : roles) {
|
||||
rolenames.emplace_back(role.rolename());
|
||||
}
|
||||
return rolenames;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> GetRolenameForUser(const std::string &username) override {
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->ReadLock();
|
||||
auto user = locked_auth->GetUser(username);
|
||||
if (!user) {
|
||||
throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
|
||||
}
|
||||
|
||||
if (const auto *role = user->role(); role != nullptr) {
|
||||
return role->rolename();
|
||||
}
|
||||
return std::nullopt;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<memgraph::query::TypedValue> GetUsernamesForRole(const std::string &rolename) override {
|
||||
if (!std::regex_match(rolename, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid role name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->ReadLock();
|
||||
auto role = locked_auth->GetRole(rolename);
|
||||
if (!role) {
|
||||
throw memgraph::query::QueryRuntimeException("Role '{}' doesn't exist.", rolename);
|
||||
}
|
||||
std::vector<memgraph::query::TypedValue> usernames;
|
||||
const auto &users = locked_auth->AllUsersForRole(rolename);
|
||||
usernames.reserve(users.size());
|
||||
for (const auto &user : users) {
|
||||
usernames.emplace_back(user.username());
|
||||
}
|
||||
return usernames;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void SetRole(const std::string &username, const std::string &rolename) override {
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
if (!std::regex_match(rolename, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid role name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto user = locked_auth->GetUser(username);
|
||||
if (!user) {
|
||||
throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
|
||||
}
|
||||
auto role = locked_auth->GetRole(rolename);
|
||||
if (!role) {
|
||||
throw memgraph::query::QueryRuntimeException("Role '{}' doesn't exist .", rolename);
|
||||
}
|
||||
if (const auto *current_role = user->role(); current_role != nullptr) {
|
||||
throw memgraph::query::QueryRuntimeException("User '{}' is already a member of role '{}'.", username,
|
||||
current_role->rolename());
|
||||
}
|
||||
user->SetRole(*role);
|
||||
locked_auth->SaveUser(*user);
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void ClearRole(const std::string &username) override {
|
||||
if (!std::regex_match(username, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto user = locked_auth->GetUser(username);
|
||||
if (!user) {
|
||||
throw memgraph::query::QueryRuntimeException("User '{}' doesn't exist .", username);
|
||||
}
|
||||
user->ClearRole();
|
||||
locked_auth->SaveUser(*user);
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> GetPrivileges(const std::string &user_or_role) override {
|
||||
if (!std::regex_match(user_or_role, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user or role name.");
|
||||
}
|
||||
try {
|
||||
auto locked_auth = auth_->ReadLock();
|
||||
std::vector<std::vector<memgraph::query::TypedValue>> grants;
|
||||
auto user = locked_auth->GetUser(user_or_role);
|
||||
auto role = locked_auth->GetRole(user_or_role);
|
||||
if (!user && !role) {
|
||||
throw memgraph::query::QueryRuntimeException("User or role '{}' doesn't exist.", user_or_role);
|
||||
}
|
||||
if (user) {
|
||||
const auto &permissions = user->GetPermissions();
|
||||
for (const auto &privilege : memgraph::query::kPrivilegesAll) {
|
||||
auto permission = memgraph::glue::PrivilegeToPermission(privilege);
|
||||
auto effective = permissions.Has(permission);
|
||||
if (permissions.Has(permission) != memgraph::auth::PermissionLevel::NEUTRAL) {
|
||||
std::vector<std::string> description;
|
||||
auto user_level = user->permissions().Has(permission);
|
||||
if (user_level == memgraph::auth::PermissionLevel::GRANT) {
|
||||
description.emplace_back("GRANTED TO USER");
|
||||
} else if (user_level == memgraph::auth::PermissionLevel::DENY) {
|
||||
description.emplace_back("DENIED TO USER");
|
||||
}
|
||||
if (const auto *role = user->role(); role != nullptr) {
|
||||
auto role_level = role->permissions().Has(permission);
|
||||
if (role_level == memgraph::auth::PermissionLevel::GRANT) {
|
||||
description.emplace_back("GRANTED TO ROLE");
|
||||
} else if (role_level == memgraph::auth::PermissionLevel::DENY) {
|
||||
description.emplace_back("DENIED TO ROLE");
|
||||
}
|
||||
}
|
||||
grants.push_back({memgraph::query::TypedValue(memgraph::auth::PermissionToString(permission)),
|
||||
memgraph::query::TypedValue(memgraph::auth::PermissionLevelToString(effective)),
|
||||
memgraph::query::TypedValue(memgraph::utils::Join(description, ", "))});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const auto &permissions = role->permissions();
|
||||
for (const auto &privilege : memgraph::query::kPrivilegesAll) {
|
||||
auto permission = memgraph::glue::PrivilegeToPermission(privilege);
|
||||
auto effective = permissions.Has(permission);
|
||||
if (effective != memgraph::auth::PermissionLevel::NEUTRAL) {
|
||||
std::string description;
|
||||
if (effective == memgraph::auth::PermissionLevel::GRANT) {
|
||||
description = "GRANTED TO ROLE";
|
||||
} else if (effective == memgraph::auth::PermissionLevel::DENY) {
|
||||
description = "DENIED TO ROLE";
|
||||
}
|
||||
grants.push_back({memgraph::query::TypedValue(memgraph::auth::PermissionToString(permission)),
|
||||
memgraph::query::TypedValue(memgraph::auth::PermissionLevelToString(effective)),
|
||||
memgraph::query::TypedValue(description)});
|
||||
}
|
||||
}
|
||||
}
|
||||
return grants;
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void GrantPrivilege(
|
||||
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
|
||||
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 {
|
||||
EditPermissions(
|
||||
user_or_role, privileges, label_privileges, edge_type_privileges,
|
||||
[](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);
|
||||
},
|
||||
[](auto &fine_grained_permissions, const auto &privilege_collection) {
|
||||
for (const auto &[privilege, entities] : privilege_collection) {
|
||||
const auto &permission = memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(privilege);
|
||||
for (const auto &entity : entities) {
|
||||
fine_grained_permissions.Grant(entity, permission);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void DenyPrivilege(
|
||||
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
|
||||
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 {
|
||||
EditPermissions(
|
||||
user_or_role, privileges, label_privileges, edge_type_privileges,
|
||||
[](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);
|
||||
},
|
||||
[](auto &fine_grained_permissions, const auto &privilege_collection) {
|
||||
for (const auto &[privilege, entities] : privilege_collection) {
|
||||
const auto &permission = memgraph::glue::FineGrainedPrivilegeToFineGrainedPermission(privilege);
|
||||
for (const auto &entity : entities) {
|
||||
fine_grained_permissions.Deny(entity, permission);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RevokePrivilege(
|
||||
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
|
||||
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 {
|
||||
EditPermissions(
|
||||
user_or_role, privileges, label_privileges, edge_type_privileges,
|
||||
[](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);
|
||||
},
|
||||
[](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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
template <class TEditPermissionsFun, class TEditFineGrainedPermissionsFun>
|
||||
void EditPermissions(
|
||||
const std::string &user_or_role, const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
|
||||
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) {
|
||||
if (!std::regex_match(user_or_role, name_regex_)) {
|
||||
throw memgraph::query::QueryRuntimeException("Invalid user or role name.");
|
||||
}
|
||||
try {
|
||||
std::vector<memgraph::auth::Permission> permissions;
|
||||
permissions.reserve(privileges.size());
|
||||
for (const auto &privilege : privileges) {
|
||||
permissions.push_back(memgraph::glue::PrivilegeToPermission(privilege));
|
||||
}
|
||||
auto locked_auth = auth_->Lock();
|
||||
auto user = locked_auth->GetUser(user_or_role);
|
||||
auto role = locked_auth->GetRole(user_or_role);
|
||||
if (!user && !role) {
|
||||
throw memgraph::query::QueryRuntimeException("User or role '{}' doesn't exist.", user_or_role);
|
||||
}
|
||||
if (user) {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
locked_auth->SaveRole(*role);
|
||||
}
|
||||
} catch (const memgraph::auth::AuthException &e) {
|
||||
throw memgraph::query::QueryRuntimeException(e.what());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class BoltSession final : public memgraph::communication::bolt::Session<memgraph::communication::v2::InputStream,
|
||||
memgraph::communication::v2::OutputStream> {
|
||||
public:
|
||||
@ -1277,7 +864,7 @@ int main(int argc, char **argv) {
|
||||
memgraph::query::procedure::gModuleRegistry.SetModulesDirectory(query_modules_directories, FLAGS_data_directory);
|
||||
memgraph::query::procedure::gModuleRegistry.UnloadAndLoadModulesFromDirectories();
|
||||
|
||||
AuthQueryHandler auth_handler(&auth, FLAGS_auth_user_or_role_name_regex);
|
||||
memgraph::glue::AuthQueryHandler auth_handler(&auth, FLAGS_auth_user_or_role_name_regex);
|
||||
memgraph::glue::AuthChecker auth_checker{&auth};
|
||||
interpreter_context.auth = &auth_handler;
|
||||
interpreter_context.auth_checker = &auth_checker;
|
||||
|
@ -4,5 +4,6 @@ endfunction()
|
||||
|
||||
copy_lba_procedures_e2e_python_files(common.py)
|
||||
copy_lba_procedures_e2e_python_files(lba_procedures.py)
|
||||
copy_lba_procedures_e2e_python_files(show_privileges.py)
|
||||
|
||||
add_subdirectory(procedures)
|
||||
|
117
tests/e2e/lba_procedures/show_privileges.py
Normal file
117
tests/e2e/lba_procedures/show_privileges.py
Normal file
@ -0,0 +1,117 @@
|
||||
# Copyright 2022 Memgraph Ltd.
|
||||
#
|
||||
# Use of this software is governed by the Business Source License
|
||||
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
# License, and you may not use this file except in compliance with the Business Source License.
|
||||
#
|
||||
# As of the Change Date specified in that file, in accordance with
|
||||
# the Business Source License, use of this software will be governed
|
||||
# by the Apache License, Version 2.0, included in the file
|
||||
# licenses/APL.txt.
|
||||
|
||||
import sys
|
||||
import pytest
|
||||
from common import connect, execute_and_fetch_all
|
||||
|
||||
BASIC_PRIVILEGES = [
|
||||
"CREATE",
|
||||
"DELETE",
|
||||
"MATCH",
|
||||
"MERGE",
|
||||
"SET",
|
||||
"REMOVE",
|
||||
"INDEX",
|
||||
"STATS",
|
||||
"AUTH",
|
||||
"REPLICATION",
|
||||
"READ_FILE",
|
||||
"DURABILITY",
|
||||
"FREE_MEMORY",
|
||||
"TRIGGER",
|
||||
"STREAM",
|
||||
"CONFIG",
|
||||
"CONSTRAINT",
|
||||
"DUMP",
|
||||
"MODULE_READ",
|
||||
"WEBSOCKET",
|
||||
"MODULE_WRITE",
|
||||
]
|
||||
|
||||
|
||||
def test_lba_procedures_show_privileges_first_user():
|
||||
expected_assertions_josip = [
|
||||
("ALL LABELS", "CREATE_DELETE", "GLOBAL LABEL PERMISSION GRANTED TO USER"),
|
||||
(
|
||||
"ALL EDGE_TYPES",
|
||||
"CREATE_DELETE",
|
||||
"GLOBAL EDGE_TYPE PERMISSION GRANTED TO USER",
|
||||
),
|
||||
("LABEL :Label1", "READ", "LABEL PERMISSION GRANTED TO USER"),
|
||||
("LABEL :Label2", "NO_PERMISSION", "LABEL PERMISSION DENIED TO USER"),
|
||||
("LABEL :Label3", "UPDATE", "LABEL PERMISSION GRANTED TO USER"),
|
||||
("LABEL :Label4", "READ", "LABEL PERMISSION GRANTED TO USER"),
|
||||
("LABEL :Label5", "CREATE_DELETE", "LABEL PERMISSION GRANTED TO USER"),
|
||||
("LABEL :Label6", "UPDATE", "LABEL PERMISSION GRANTED TO USER"),
|
||||
("LABEL :Label7", "NO_PERMISSION", "LABEL PERMISSION DENIED TO USER"),
|
||||
]
|
||||
|
||||
cursor = connect(username="Josip", password="").cursor()
|
||||
result = execute_and_fetch_all(cursor, "SHOW PRIVILEGES FOR Josip;")
|
||||
|
||||
assert len(result) == 30
|
||||
|
||||
fine_privilege_results = [res for res in result if res[0] not in BASIC_PRIVILEGES]
|
||||
|
||||
assert len(fine_privilege_results) == len(expected_assertions_josip)
|
||||
assert set(expected_assertions_josip) == set(fine_privilege_results)
|
||||
|
||||
|
||||
def test_lba_procedures_show_privileges_second_user():
|
||||
expected_assertions_boris = [
|
||||
("AUTH", "GRANT", "GRANTED TO USER"),
|
||||
("LABEL :Label1", "READ", "LABEL PERMISSION GRANTED TO USER"),
|
||||
("LABEL :Label2", "NO_PERMISSION", "LABEL PERMISSION DENIED TO USER"),
|
||||
("LABEL :Label3", "UPDATE", "LABEL PERMISSION GRANTED TO USER"),
|
||||
("LABEL :Label4", "READ", "LABEL PERMISSION GRANTED TO USER"),
|
||||
("LABEL :Label5", "CREATE_DELETE", "LABEL PERMISSION GRANTED TO USER"),
|
||||
("LABEL :Label6", "UPDATE", "LABEL PERMISSION GRANTED TO USER"),
|
||||
("LABEL :Label7", "NO_PERMISSION", "LABEL PERMISSION DENIED TO USER"),
|
||||
]
|
||||
|
||||
cursor = connect(username="Boris", password="").cursor()
|
||||
result = execute_and_fetch_all(cursor, "SHOW PRIVILEGES FOR Boris;")
|
||||
|
||||
assert len(result) == len(expected_assertions_boris)
|
||||
assert set(result) == set(expected_assertions_boris)
|
||||
|
||||
|
||||
def test_lba_procedures_show_privileges_third_user():
|
||||
expected_assertions_niko = [
|
||||
("AUTH", "GRANT", "GRANTED TO USER"),
|
||||
("ALL LABELS", "READ", "GLOBAL LABEL PERMISSION GRANTED TO USER"),
|
||||
]
|
||||
|
||||
cursor = connect(username="Niko", password="").cursor()
|
||||
result = execute_and_fetch_all(cursor, "SHOW PRIVILEGES FOR Niko;")
|
||||
|
||||
assert len(result) == len(expected_assertions_niko)
|
||||
assert set(result) == set(expected_assertions_niko)
|
||||
|
||||
|
||||
def test_lba_procedures_show_privileges_fourth_user():
|
||||
expected_assertions_bruno = [
|
||||
("AUTH", "GRANT", "GRANTED TO USER"),
|
||||
("ALL LABELS", "UPDATE", "GLOBAL LABEL PERMISSION GRANTED TO USER"),
|
||||
]
|
||||
|
||||
# TODO: Revisit behaviour of this test
|
||||
|
||||
cursor = connect(username="Bruno", password="").cursor()
|
||||
result = execute_and_fetch_all(cursor, "SHOW PRIVILEGES FOR Bruno;")
|
||||
|
||||
assert len(result) == len(expected_assertions_bruno)
|
||||
assert set(result) == set(expected_assertions_bruno)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main([__file__, "-rA"]))
|
@ -20,9 +20,52 @@ template_cluster: &template_cluster
|
||||
]
|
||||
validation_queries: []
|
||||
|
||||
show_privileges_cluster: &show_privileges_cluster
|
||||
cluster:
|
||||
main:
|
||||
args: ["--bolt-port", "7687", "--log-level=TRACE"]
|
||||
log_file: "lba-e2e.log"
|
||||
setup_queries: [
|
||||
"Create User Josip;",
|
||||
"Grant Read On Labels :Label1 to Josip;",
|
||||
"Deny Read On Labels :Label2 to Josip;",
|
||||
"Grant Update On Labels :Label3 to Josip;",
|
||||
"Deny Update On Labels :Label4 to Josip;",
|
||||
"Grant Create_Delete On Labels :Label5 to Josip;",
|
||||
"Deny Create_Delete On Labels :Label6 to Josip;",
|
||||
"Grant Create_Delete On Labels :Label7 to Josip;",
|
||||
"Deny Read On Labels :Label7 to Josip;",
|
||||
|
||||
"Create User Boris;",
|
||||
"Grant Auth to Boris;",
|
||||
"Grant Read On Labels :Label1 to Boris;",
|
||||
"Deny Read On Labels :Label2 to Boris;",
|
||||
"Grant Update On Labels :Label3 to Boris;",
|
||||
"Deny Update On Labels :Label4 to Boris;",
|
||||
"Grant Create_Delete On Labels :Label5 to Boris;",
|
||||
"Deny Create_Delete On Labels :Label6 to Boris;",
|
||||
"Grant Create_Delete On Labels :Label7 to Boris;",
|
||||
"Deny Read On Labels :Label7 to Boris;",
|
||||
|
||||
"Create User Niko;",
|
||||
"Grant Auth to Niko;",
|
||||
"Grant Create_Delete On Labels * to Niko",
|
||||
"Deny Update On Labels * to Niko",
|
||||
|
||||
"Create User Bruno;",
|
||||
"Grant Auth to Bruno;",
|
||||
"Deny Create_Delete On Labels * to Bruno"
|
||||
]
|
||||
|
||||
workloads:
|
||||
- name: "Label-based auth"
|
||||
binary: "tests/e2e/pytest_runner.sh"
|
||||
proc: "tests/e2e/lba_procedures/procedures/"
|
||||
args: ["lba_procedures/lba_procedures.py"]
|
||||
<<: *template_cluster
|
||||
|
||||
- name: "show-privileges"
|
||||
binary: "tests/e2e/pytest_runner.sh"
|
||||
proc: "tests/e2e/lba_procedures/procedures/"
|
||||
args: ["lba_procedures/show_privileges.py"]
|
||||
<<: *show_privileges_cluster
|
||||
|
@ -324,6 +324,9 @@ target_link_libraries(${test_prefix}replication_persistence_helper mg-storage-v2
|
||||
add_unit_test(auth_checker.cpp)
|
||||
target_link_libraries(${test_prefix}auth_checker mg-glue mg-auth)
|
||||
|
||||
add_unit_test(auth_handler.cpp)
|
||||
target_link_libraries(${test_prefix}auth_handler mg-glue mg-auth)
|
||||
|
||||
# Test mg-auth
|
||||
if(MG_ENTERPRISE)
|
||||
add_unit_test(auth.cpp)
|
||||
|
724
tests/unit/auth_handler.cpp
Normal file
724
tests/unit/auth_handler.cpp
Normal file
@ -0,0 +1,724 @@
|
||||
// Copyright 2022 Memgraph Ltd.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License
|
||||
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
// License, and you may not use this file except in compliance with the Business Source License.
|
||||
//
|
||||
// As of the Change Date specified in that file, in accordance with
|
||||
// the Business Source License, use of this software will be governed
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "auth/auth.hpp"
|
||||
#include "auth/models.hpp"
|
||||
#include "glue/auth_handler.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
#include "utils/file.hpp"
|
||||
#include "utils/rw_lock.hpp"
|
||||
#include "utils/synchronized.hpp"
|
||||
|
||||
class AuthQueryHandlerFixture : public testing::Test {
|
||||
protected:
|
||||
std::filesystem::path test_folder_{std::filesystem::temp_directory_path() / "MG_tests_unit_auth_handler"};
|
||||
memgraph::utils::Synchronized<memgraph::auth::Auth, memgraph::utils::WritePrioritizedRWLock> auth{
|
||||
test_folder_ / ("unit_auth_handler_test_" + std::to_string(static_cast<int>(getpid())))};
|
||||
memgraph::glue::AuthQueryHandler auth_handler{&auth, memgraph::glue::kDefaultUserRoleRegex.data()};
|
||||
|
||||
std::string user_name = "Mate";
|
||||
std::string edge_type_repr = "EdgeType1";
|
||||
std::string label_repr = "Label1";
|
||||
memgraph::auth::Permissions perms{};
|
||||
memgraph::auth::FineGrainedAccessHandler handler{};
|
||||
|
||||
virtual void SetUp() {
|
||||
memgraph::utils::EnsureDir(test_folder_);
|
||||
memgraph::utils::license::global_license_checker.EnableTesting();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
std::filesystem::remove_all(test_folder_);
|
||||
perms = memgraph::auth::Permissions{};
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{};
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenAuthQueryHandlerWhenInitializedHaveNoUsernamesOrRolenames) {
|
||||
ASSERT_EQ(auth_handler.GetUsernames().size(), 0);
|
||||
ASSERT_EQ(auth_handler.GetRolenames().size(), 0);
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenNoDeniesOrGrantsThenNothingIsReturned) {
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
{ ASSERT_EQ(auth_handler.GetUsernames().size(), 1); }
|
||||
|
||||
{
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
|
||||
ASSERT_EQ(privileges.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenAddedGrantPermissionThenItIsReturned) {
|
||||
perms.Grant(memgraph::auth::Permission::MATCH);
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "MATCH");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "GRANT");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenAddedDenyPermissionThenItIsReturned) {
|
||||
perms.Deny(memgraph::auth::Permission::MATCH);
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "MATCH");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "DENY");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "DENIED TO USER");
|
||||
}
|
||||
|
||||
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};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 0);
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenRoleWhenPrivilegeGrantedThenItIsReturned) {
|
||||
perms.Grant(memgraph::auth::Permission::MATCH);
|
||||
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
|
||||
auth->SaveRole(role);
|
||||
|
||||
{ ASSERT_EQ(auth_handler.GetRolenames().size(), 1); }
|
||||
|
||||
{
|
||||
auto privileges = auth_handler.GetPrivileges("Mates_role");
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "MATCH");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "GRANT");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "GRANTED TO ROLE");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenRoleWhenPrivilegeDeniedThenItIsReturned) {
|
||||
perms.Deny(memgraph::auth::Permission::MATCH);
|
||||
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
|
||||
auth->SaveRole(role);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges("Mates_role");
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "MATCH");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "DENY");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "DENIED TO ROLE");
|
||||
}
|
||||
|
||||
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};
|
||||
auth->SaveRole(role);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges("Mates_role");
|
||||
ASSERT_EQ(privileges.size(), 0);
|
||||
}
|
||||
|
||||
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};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 2);
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneGrantedAndOtherGrantedThenBothArePrinted) {
|
||||
perms.Grant(memgraph::auth::Permission::MATCH);
|
||||
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
|
||||
auth->SaveRole(role);
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
user.SetRole(role);
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "MATCH");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "GRANT");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "GRANTED TO USER, GRANTED TO ROLE");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserAndRoleWhenOneDeniedAndOtherDeniedThenBothArePrinted) {
|
||||
perms.Deny(memgraph::auth::Permission::MATCH);
|
||||
memgraph::auth::Role role = memgraph::auth::Role{"Mates_role", perms, handler};
|
||||
auth->SaveRole(role);
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
user.SetRole(role);
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "MATCH");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "DENY");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "DENIED TO USER, DENIED TO ROLE");
|
||||
}
|
||||
|
||||
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};
|
||||
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};
|
||||
user.SetRole(role);
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "MATCH");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "DENY");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "GRANTED TO USER, DENIED TO ROLE");
|
||||
}
|
||||
|
||||
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};
|
||||
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};
|
||||
user.SetRole(role);
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "MATCH");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "DENY");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "DENIED TO USER, GRANTED TO ROLE");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedPrivilegeOnLabelThenIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::READ);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "LABEL :Label1");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "READ");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "LABEL PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedMultiplePrivilegesOnLabelThenTopOneIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::READ);
|
||||
read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::UPDATE);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "LABEL :Label1");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "UPDATE");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "LABEL PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedAllPrivilegesOnLabelThenTopOneIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::READ);
|
||||
read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::UPDATE);
|
||||
read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::CREATE_DELETE);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "LABEL :Label1");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "CREATE_DELETE");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "LABEL PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalPrivilegeOnLabelThenIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "ALL LABELS");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "READ");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "GLOBAL LABEL PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalMultiplePrivilegesOnLabelThenTopOneIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::UPDATE);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "ALL LABELS");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "UPDATE");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "GLOBAL LABEL PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalAllPrivilegesOnLabelThenTopOneIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::UPDATE);
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::CREATE_DELETE);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "ALL LABELS");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "CREATE_DELETE");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "GLOBAL LABEL PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
// EDGE_TYPES
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedPrivilegeOnEdgeTypeThenIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "EDGE_TYPE :EdgeType1");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "READ");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "EDGE_TYPE PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedMultiplePrivilegesOnEdgeTypeThenTopOneIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
|
||||
read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::UPDATE);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "EDGE_TYPE :EdgeType1");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "UPDATE");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "EDGE_TYPE PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedAllPrivilegesOnEdgeTypeThenTopOneIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
|
||||
read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::UPDATE);
|
||||
read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::CREATE_DELETE);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "EDGE_TYPE :EdgeType1");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "CREATE_DELETE");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "EDGE_TYPE PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalPrivilegeOnEdgeTypeThenIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "ALL EDGE_TYPES");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "READ");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "GLOBAL EDGE_TYPE PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalMultiplePrivilegesOnEdgeTypeThenTopOneIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::UPDATE);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "ALL EDGE_TYPES");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "UPDATE");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "GLOBAL EDGE_TYPE PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedGlobalAllPrivilegesOnEdgeTypeThenTopOneIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::READ);
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::UPDATE);
|
||||
read_permission.Grant("*", memgraph::auth::FineGrainedPermission::CREATE_DELETE);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "ALL EDGE_TYPES");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "CREATE_DELETE");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "GLOBAL EDGE_TYPE PERMISSION GRANTED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedAndDeniedOnLabelThenNoPermission) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant(label_repr, memgraph::auth::FineGrainedPermission::READ);
|
||||
read_permission.Deny(label_repr, memgraph::auth::FineGrainedPermission::READ);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "LABEL :Label1");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "NO_PERMISSION");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "LABEL PERMISSION DENIED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedAndDeniedOnEdgeTypeThenNoPermission) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
|
||||
read_permission.Deny(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "EDGE_TYPE :EdgeType1");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "NO_PERMISSION");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "EDGE_TYPE PERMISSION DENIED TO USER");
|
||||
}
|
||||
|
||||
TEST_F(AuthQueryHandlerFixture, GivenUserWhenGrantedReadAndDeniedUpdateThenOneIsDisplayed) {
|
||||
auto read_permission = memgraph::auth::FineGrainedAccessPermissions();
|
||||
read_permission.Grant(edge_type_repr, memgraph::auth::FineGrainedPermission::READ);
|
||||
read_permission.Deny(edge_type_repr, memgraph::auth::FineGrainedPermission::UPDATE);
|
||||
|
||||
handler = memgraph::auth::FineGrainedAccessHandler{
|
||||
memgraph::auth::FineGrainedAccessPermissions{},
|
||||
memgraph::auth::FineGrainedAccessPermissions{read_permission},
|
||||
};
|
||||
|
||||
memgraph::auth::User user = memgraph::auth::User{user_name, "", perms, handler};
|
||||
auth->SaveUser(user);
|
||||
|
||||
auto privileges = auth_handler.GetPrivileges(user_name);
|
||||
ASSERT_EQ(privileges.size(), 1);
|
||||
|
||||
auto result = *privileges.begin();
|
||||
ASSERT_EQ(result.size(), 3);
|
||||
|
||||
ASSERT_TRUE(result[0].IsString());
|
||||
ASSERT_EQ(result[0].ValueString(), "EDGE_TYPE :EdgeType1");
|
||||
|
||||
ASSERT_TRUE(result[1].IsString());
|
||||
ASSERT_EQ(result[1].ValueString(), "READ");
|
||||
|
||||
ASSERT_TRUE(result[2].IsString());
|
||||
ASSERT_EQ(result[2].ValueString(), "EDGE_TYPE PERMISSION GRANTED TO USER");
|
||||
}
|
Loading…
Reference in New Issue
Block a user