[E129-MG < T997-MG] Show label privileges (#506)

Added showing of label privileges functionality to fine grained access control.
This commit is contained in:
Josipmrden 2022-08-31 12:14:16 +02:00 committed by GitHub
parent 05f120b7d4
commit 7478300762
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1616 additions and 417 deletions

View File

@ -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_;

View File

@ -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;

View File

@ -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
View 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
View 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

View File

@ -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;

View File

@ -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)

View 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"]))

View File

@ -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

View File

@ -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
View 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");
}