Added filtering

This commit is contained in:
niko4299
2022-07-22 11:19:56 +02:00
parent 5e87ce9f65
commit 17cb59d75a
8 changed files with 288 additions and 195 deletions

View File

@@ -101,8 +101,6 @@ std::string PermissionLevelToString(PermissionLevel level) {
}
}
const std::string ASTERISK = "*";
Permissions::Permissions(uint64_t grants, uint64_t denies) : grants_(grants & (~denies)), denies_(denies) {}
PermissionLevel Permissions::Has(Permission permission) const {
@@ -293,30 +291,64 @@ bool operator!=(const FineGrainedAccessPermissions &first, const FineGrainedAcce
return !(first == second);
}
FineGrainedAccessHandler::FineGrainedAccessHandler(const FineGrainedAccessPermissions &labelPermissions,
const FineGrainedAccessPermissions &edgeTypePermissions)
: label_permissions_(labelPermissions), edge_type_permissions_(edgeTypePermissions) {}
const FineGrainedAccessPermissions &FineGrainedAccessHandler::label_permissions() const { return label_permissions_; }
const FineGrainedAccessPermissions &FineGrainedAccessHandler::edge_type_permissions() const {
return edge_type_permissions_;
}
nlohmann::json FineGrainedAccessHandler::Serialize() const {
nlohmann::json data = nlohmann::json::object();
data["label_permissions"] = label_permissions_.Serialize();
data["edge_type_permissions"] = edge_type_permissions_.Serialize();
return data;
}
FineGrainedAccessHandler FineGrainedAccessHandler::Deserialize(const nlohmann::json &data) {
if (!data.is_object()) {
throw AuthException("Couldn't load role data!");
}
if (!data["fine_grained_access_handler"].is_object()) {
throw AuthException("Couldn't load FineGrainedAccessHandler data!");
}
auto label_permissions = FineGrainedAccessPermissions::Deserialize(data["label_permissions"]);
auto edge_type_permissions = FineGrainedAccessPermissions::Deserialize(data["edge_type_permissions"]);
return {label_permissions, edge_type_permissions};
}
bool operator==(const FineGrainedAccessHandler &first, const FineGrainedAccessHandler &second) {
return first.label_permissions_ == second.label_permissions_ &&
first.edge_type_permissions_ == second.edge_type_permissions_;
}
bool operator!=(const FineGrainedAccessHandler &first, const FineGrainedAccessHandler &second) {
return !(first == second);
}
Role::Role(const std::string &rolename) : rolename_(utils::ToLowerCase(rolename)) {}
Role::Role(const std::string &rolename, const Permissions &permissions,
const FineGrainedAccessPermissions &fine_grained_access_permissions)
const FineGrainedAccessHandler &fine_grained_access_handler)
: rolename_(utils::ToLowerCase(rolename)),
permissions_(permissions),
fine_grained_access_permissions_(fine_grained_access_permissions) {}
fine_grained_access_handler_(fine_grained_access_handler) {}
const std::string &Role::rolename() const { return rolename_; }
const Permissions &Role::permissions() const { return permissions_; }
Permissions &Role::permissions() { return permissions_; }
const FineGrainedAccessPermissions &Role::fine_grained_access_permissions() const {
return fine_grained_access_permissions_;
}
FineGrainedAccessPermissions &Role::fine_grained_access_permissions() { return fine_grained_access_permissions_; }
const AccessPermissions &Role::edgeTypePermissions() const { return edgeTypePermissions_; }
AccessPermissions &Role::edgeTypePermissions() { return edgeTypePermissions_; }
const FineGrainedAccessHandler &Role::fine_grained_access_handler() const { return fine_grained_access_handler_; }
FineGrainedAccessHandler &Role::fine_grained_access_handler() { return fine_grained_access_handler_; }
nlohmann::json Role::Serialize() const {
nlohmann::json data = nlohmann::json::object();
data["rolename"] = rolename_;
data["permissions"] = permissions_.Serialize();
data["fine_grained_access_permissions"] = fine_grained_access_permissions_.Serialize();
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
return data;
}
@@ -325,28 +357,27 @@ Role Role::Deserialize(const nlohmann::json &data) {
throw AuthException("Couldn't load role data!");
}
if (!data["rolename"].is_string() || !data["permissions"].is_object() ||
!data["fine_grained_access_permissions"].is_object()) {
!data["fine_grained_access_handler"].is_object()) {
throw AuthException("Couldn't load role data!");
}
auto permissions = Permissions::Deserialize(data["permissions"]);
auto fine_grained_access_permissions =
FineGrainedAccessPermissions::Deserialize(data["fine_grained_access_permissions"]);
return {data["rolename"], permissions, fine_grained_access_permissions};
auto fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
return {data["rolename"], permissions, fine_grained_access_handler};
}
bool operator==(const Role &first, const Role &second) {
return first.rolename_ == second.rolename_ && first.permissions_ == second.permissions_ &&
first.edgeTypePermissions_ == second.edgeTypePermissions_;
first.fine_grained_access_handler_ == second.fine_grained_access_handler_;
}
User::User(const std::string &username) : username_(utils::ToLowerCase(username)) {}
User::User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
const FineGrainedAccessPermissions &fine_grained_access_permissions)
const FineGrainedAccessHandler &fine_grained_access_handler)
: username_(utils::ToLowerCase(username)),
password_hash_(password_hash),
permissions_(permissions),
fine_grained_access_permissions_(fine_grained_access_permissions) {}
fine_grained_access_handler_(fine_grained_access_handler) {}
bool User::CheckPassword(const std::string &password) {
if (password_hash_.empty()) return true;
@@ -395,38 +426,58 @@ Permissions User::GetPermissions() const {
return permissions_;
}
FineGrainedAccessPermissions User::GetFineGrainedAccessPermissions() const {
FineGrainedAccessPermissions User::GetFineGrainedAccessLabelPermissions() const {
if (role_) {
std::unordered_set<std::string> resultGrants;
std::set_union(fine_grained_access_permissions_.grants().begin(), fine_grained_access_permissions_.grants().end(),
role_->fine_grained_access_permissions().grants().begin(),
role_->fine_grained_access_permissions().grants().end(),
std::set_union(fine_grained_access_handler_.label_permissions().grants().begin(),
fine_grained_access_handler_.label_permissions().grants().end(),
role_->fine_grained_access_handler().label_permissions().grants().begin(),
role_->fine_grained_access_handler().label_permissions().grants().end(),
std::inserter(resultGrants, resultGrants.begin()));
std::unordered_set<std::string> resultDenies;
std::set_union(fine_grained_access_permissions_.denies().begin(), fine_grained_access_permissions_.denies().end(),
role_->fine_grained_access_permissions().denies().begin(),
role_->fine_grained_access_permissions().denies().end(),
std::set_union(fine_grained_access_handler_.label_permissions().denies().begin(),
fine_grained_access_handler_.label_permissions().denies().end(),
role_->fine_grained_access_handler().label_permissions().denies().begin(),
role_->fine_grained_access_handler().label_permissions().denies().end(),
std::inserter(resultDenies, resultDenies.begin()));
return {resultGrants, resultDenies};
}
return fine_grained_access_permissions_;
return fine_grained_access_handler_.label_permissions();
}
FineGrainedAccessPermissions User::GetFineGrainedAccessEdgeTypePermissions() const {
if (role_) {
std::unordered_set<std::string> resultGrants;
std::set_union(fine_grained_access_handler_.edge_type_permissions().grants().begin(),
fine_grained_access_handler_.edge_type_permissions().grants().end(),
role_->fine_grained_access_handler().edge_type_permissions().grants().begin(),
role_->fine_grained_access_handler().edge_type_permissions().grants().end(),
std::inserter(resultGrants, resultGrants.begin()));
std::unordered_set<std::string> resultDenies;
std::set_union(fine_grained_access_handler_.edge_type_permissions().denies().begin(),
fine_grained_access_handler_.edge_type_permissions().denies().end(),
role_->fine_grained_access_handler().edge_type_permissions().denies().begin(),
role_->fine_grained_access_handler().edge_type_permissions().denies().end(),
std::inserter(resultDenies, resultDenies.begin()));
return {resultGrants, resultDenies};
}
return fine_grained_access_handler_.edge_type_permissions();
}
const std::string &User::username() const { return username_; }
const Permissions &User::permissions() const { return permissions_; }
Permissions &User::permissions() { return permissions_; }
const FineGrainedAccessPermissions &User::fine_grained_access_permissions() const {
return fine_grained_access_permissions_;
}
FineGrainedAccessPermissions &User::fine_grained_access_permissions() { return fine_grained_access_permissions_; }
const AccessPermissions &User::edgeTypePermissions() const { return edgeTypePermissions_; }
AccessPermissions &User::edgeTypePermissions() { return edgeTypePermissions_; }
const FineGrainedAccessHandler &User::fine_grained_access_handler() const { return fine_grained_access_handler_; }
FineGrainedAccessHandler &User::fine_grained_access_handler() { return fine_grained_access_handler_; }
const Role *User::role() const {
if (role_.has_value()) {
@@ -440,7 +491,7 @@ nlohmann::json User::Serialize() const {
data["username"] = username_;
data["password_hash"] = password_hash_;
data["permissions"] = permissions_.Serialize();
data["fine_grained_access_permissions"] = fine_grained_access_permissions_.Serialize();
data["fine_grained_access_handler"] = fine_grained_access_handler_.Serialize();
// The role shouldn't be serialized here, it is stored as a foreign key.
return data;
}
@@ -449,19 +500,19 @@ User User::Deserialize(const nlohmann::json &data) {
if (!data.is_object()) {
throw AuthException("Couldn't load user data!");
}
if (!data["username"].is_string() || !data["password_hash"].is_string() || !data["permissions"].is_object()) {
if (!data["username"].is_string() || !data["password_hash"].is_string() || !data["permissions"].is_object() ||
!data["fine_grained_access_handler"].is_object()) {
throw AuthException("Couldn't load user data!");
}
auto permissions = Permissions::Deserialize(data["permissions"]);
auto fine_grained_access_permissions =
FineGrainedAccessPermissions::Deserialize(data["fine_grained_access_permissions"]);
return {data["username"], data["password_hash"], permissions, fine_grained_access_permissions};
auto fine_grained_access_handler = FineGrainedAccessHandler::Deserialize(data["fine_grained_access_handler"]);
return {data["username"], data["password_hash"], permissions, fine_grained_access_handler};
}
bool operator==(const User &first, const User &second) {
return first.username_ == second.username_ && first.password_hash_ == second.password_hash_ &&
first.permissions_ == second.permissions_ && first.edgeTypePermissions_ == second.edgeTypePermissions_ &&
first.role_ == second.role_;
first.permissions_ == second.permissions_ && first.role_ == second.role_ &&
first.fine_grained_access_handler_ == second.fine_grained_access_handler_;
}
} // namespace memgraph::auth

View File

@@ -120,21 +120,43 @@ bool operator==(const FineGrainedAccessPermissions &first, const FineGrainedAcce
bool operator!=(const FineGrainedAccessPermissions &first, const FineGrainedAccessPermissions &second);
class FineGrainedAccessHandler final {
public:
FineGrainedAccessHandler(const FineGrainedAccessPermissions &labelPermissions = {},
const FineGrainedAccessPermissions &edgeTypePermissions = {});
const FineGrainedAccessPermissions &label_permissions() const;
FineGrainedAccessPermissions &label_permissions();
const FineGrainedAccessPermissions &edge_type_permissions() const;
FineGrainedAccessPermissions &edge_type_permissions();
nlohmann::json Serialize() const;
/// @throw AuthException if unable to deserialize.
static FineGrainedAccessHandler Deserialize(const nlohmann::json &data);
friend bool operator==(const FineGrainedAccessHandler &first, const FineGrainedAccessHandler &second);
private:
FineGrainedAccessPermissions label_permissions_;
FineGrainedAccessPermissions edge_type_permissions_;
};
bool operator==(const FineGrainedAccessHandler &first, const FineGrainedAccessHandler &second);
class Role final {
public:
Role(const std::string &rolename);
Role(const std::string &rolename, const Permissions &permissions,
const FineGrainedAccessPermissions &fine_grained_access_permissions);
const FineGrainedAccessHandler &fine_grained_access_handler);
const std::string &rolename() const;
const Permissions &permissions() const;
Permissions &permissions();
const FineGrainedAccessPermissions &fine_grained_access_permissions() const;
FineGrainedAccessPermissions &fine_grained_access_permissions();
const AccessPermissions &edgeTypePermissions() const;
AccessPermissions &edgeTypePermissions();
const FineGrainedAccessHandler &fine_grained_access_handler() const;
FineGrainedAccessHandler &fine_grained_access_handler();
nlohmann::json Serialize() const;
@@ -146,7 +168,7 @@ class Role final {
private:
std::string rolename_;
Permissions permissions_;
FineGrainedAccessPermissions fine_grained_access_permissions_;
FineGrainedAccessHandler fine_grained_access_handler_;
};
bool operator==(const Role &first, const Role &second);
@@ -157,7 +179,7 @@ class User final {
User(const std::string &username);
User(const std::string &username, const std::string &password_hash, const Permissions &permissions,
const FineGrainedAccessPermissions &fine_grained_access_permissions);
const FineGrainedAccessHandler &fine_grained_access_handler);
/// @throw AuthException if unable to verify the password.
bool CheckPassword(const std::string &password);
@@ -170,17 +192,15 @@ class User final {
void ClearRole();
Permissions GetPermissions() const;
FineGrainedAccessPermissions GetFineGrainedAccessPermissions() const;
FineGrainedAccessPermissions GetFineGrainedAccessLabelPermissions() const;
FineGrainedAccessPermissions GetFineGrainedAccessEdgeTypePermissions() const;
const std::string &username() const;
const Permissions &permissions() const;
Permissions &permissions();
const FineGrainedAccessPermissions &fine_grained_access_permissions() const;
FineGrainedAccessPermissions &fine_grained_access_permissions();
const AccessPermissions &edgeTypePermissions() const;
AccessPermissions &edgeTypePermissions();
const FineGrainedAccessHandler &fine_grained_access_handler() const;
FineGrainedAccessHandler &fine_grained_access_handler();
const Role *role() const;
@@ -195,7 +215,7 @@ class User final {
std::string username_;
std::string password_hash_;
Permissions permissions_;
FineGrainedAccessPermissions fine_grained_access_permissions_;
FineGrainedAccessHandler fine_grained_access_handler_;
std::optional<Role> role_;
};

View File

@@ -506,7 +506,7 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
if (first_user) {
spdlog::info("{} is first created user. Granting all privileges.", username);
GrantPrivilege(username, memgraph::query::kPrivilegesAll, {"*"});
GrantPrivilege(username, memgraph::query::kPrivilegesAll, {"*"}, {"*"});
}
return user_added;
@@ -771,8 +771,8 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
void GrantPrivilege(const std::string &user_or_role,
const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::vector<std::string> &labels) override {
EditPermissions(user_or_role, privileges, labels, [](auto *permissions, const auto &permission) {
const std::vector<std::string> &labels, const std::vector<std::string> &edgeTypes) override {
EditPermissions(user_or_role, privileges, labels, edgeTypes, [](auto *permissions, const auto &permission) {
// TODO (mferencevic): should we first check that the
// privilege is granted/denied/revoked before
// unconditionally granting/denying/revoking it?
@@ -782,8 +782,8 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
void DenyPrivilege(const std::string &user_or_role,
const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::vector<std::string> &labels) override {
EditPermissions(user_or_role, privileges, labels, [](auto *permissions, const auto &permission) {
const std::vector<std::string> &labels, const std::vector<std::string> &edgeTypes) override {
EditPermissions(user_or_role, privileges, labels, edgeTypes, [](auto *permissions, const auto &permission) {
// TODO (mferencevic): should we first check that the
// privilege is granted/denied/revoked before
// unconditionally granting/denying/revoking it?
@@ -793,8 +793,8 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
void RevokePrivilege(const std::string &user_or_role,
const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::vector<std::string> &labels) override {
EditPermissions(user_or_role, privileges, labels, [](auto *permissions, const auto &permission) {
const std::vector<std::string> &labels, const std::vector<std::string> &edgeTypes) override {
EditPermissions(user_or_role, privileges, labels, edgeTypes, [](auto *permissions, const auto &permission) {
// TODO (mferencevic): should we first check that the
// privilege is granted/denied/revoked before
// unconditionally granting/denying/revoking it?
@@ -806,7 +806,8 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
template <class TEditFun>
void EditPermissions(const std::string &user_or_role,
const std::vector<memgraph::query::AuthQuery::Privilege> &privileges,
const std::vector<std::string> &labels, const TEditFun &edit_fun) {
const std::vector<std::string> &labels, const std::vector<std::string> &edgeTypes,
const TEditFun &edit_fun) {
if (!std::regex_match(user_or_role, name_regex_)) {
throw memgraph::query::QueryRuntimeException("Invalid user or role name.");
}
@@ -827,15 +828,22 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler {
edit_fun(&user->permissions(), permission);
}
for (const auto &label : labels) {
edit_fun(&user->fine_grained_access_permissions(), label);
edit_fun(&user->fine_grained_access_handler().label_permissions(), label);
}
for (const auto &edgeType : edgeTypes) {
edit_fun(&user->fine_grained_access_handler().edge_type_permissions(), edgeType);
}
locked_auth->SaveUser(*user);
} else {
for (const auto &permission : permissions) {
edit_fun(&role->permissions(), permission);
}
for (const auto &label : labels) {
edit_fun(&user->fine_grained_access_permissions(), label);
edit_fun(&user->fine_grained_access_handler().edge_type_permissions(), label);
}
for (const auto &edgeType : edgeTypes) {
edit_fun(&role->fine_grained_access_handler().edge_type_permissions(), edgeType);
}
locked_auth->SaveRole(*role);

View File

@@ -18,7 +18,8 @@
namespace memgraph::query {
class FineGrainedAccessChecker {
public:
virtual bool IsUserAuthorizedLabels(const std::vector<memgraph::storage::LabelId> &label,
memgraph::query::DbAccessor *dba) const = 0;
virtual bool IsUserAuthorizedLabels(const std::vector<memgraph::storage::LabelId> &labels) const = 0;
virtual bool IsUserAuthorizedEdgeType(const memgraph::storage::EdgeTypeId &edgeType) const = 0;
};
} // namespace memgraph::query

View File

@@ -45,6 +45,8 @@
#include "query/stream/common.hpp"
#include "query/trigger.hpp"
#include "query/typed_value.hpp"
#include "storage/v2/edge.hpp"
#include "storage/v2/id_types.hpp"
#include "storage/v2/property_value.hpp"
#include "utils/algorithm.hpp"
#include "utils/csv_parsing.hpp"
@@ -263,19 +265,23 @@ class ReplQueryHandler final : public query::ReplicationQueryHandler {
class FineGrainedAccessChecker final : public memgraph::query::FineGrainedAccessChecker {
public:
explicit FineGrainedAccessChecker(memgraph::auth::User *user) : user_{user} {}
explicit FineGrainedAccessChecker(memgraph::auth::User *user, DbAccessor *dba) : user_{user}, dba_{dba} {}
bool IsUserAuthorizedLabels(const std::vector<memgraph::storage::LabelId> &labels,
memgraph::query::DbAccessor *dba) const final {
auto labelPermissions = user_->GetFineGrainedAccessPermissions();
return std::any_of(labels.begin(), labels.end(), [&labelPermissions, &dba](const auto label) {
return labelPermissions.Has(dba->LabelToName(label)) == memgraph::auth::PermissionLevel::GRANT;
bool IsUserAuthorizedLabels(const std::vector<memgraph::storage::LabelId> &labels) const final {
return std::any_of(labels.begin(), labels.end(), [this](const auto label) {
return user_->GetFineGrainedAccessLabelPermissions().Has(dba_->LabelToName(label)) ==
memgraph::auth::PermissionLevel::GRANT;
});
}
bool IsUserAuthorizedEdgeType(const memgraph::storage::EdgeTypeId &edgeType) const final {
return user_->GetFineGrainedAccessEdgeTypePermissions().Has(dba_->EdgeTypeToName(edgeType)) ==
memgraph::auth::PermissionLevel::GRANT;
}
private:
memgraph::auth::User *user_;
DbAccessor *dba_;
};
/// returns false if the replication role can't be set
@@ -316,8 +322,7 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa
if (license_check_result.HasError() && enterprise_only_methods.contains(auth_query->action_)) {
throw utils::BasicException(
utils::license::LicenseCheckErrorToString(license_check_result.GetError(), "advanced authentication
features"));
utils::license::LicenseCheckErrorToString(license_check_result.GetError(), "advanced authentication features"));
}
switch (auth_query->action_) {
@@ -407,20 +412,20 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa
};
return callback;
case AuthQuery::Action::GRANT_PRIVILEGE:
callback.fn = [auth, user_or_role, privileges, labels] {
auth->GrantPrivilege(user_or_role, privileges, labels);
callback.fn = [auth, user_or_role, privileges, labels, edgeTypes] {
auth->GrantPrivilege(user_or_role, privileges, labels, edgeTypes);
return std::vector<std::vector<TypedValue>>();
};
return callback;
case AuthQuery::Action::DENY_PRIVILEGE:
callback.fn = [auth, user_or_role, privileges, labels] {
auth->DenyPrivilege(user_or_role, privileges, labels);
callback.fn = [auth, user_or_role, privileges, labels, edgeTypes] {
auth->DenyPrivilege(user_or_role, privileges, labels, edgeTypes);
return std::vector<std::vector<TypedValue>>();
};
return callback;
case AuthQuery::Action::REVOKE_PRIVILEGE: {
callback.fn = [auth, user_or_role, privileges, labels] {
auth->RevokePrivilege(user_or_role, privileges, labels);
callback.fn = [auth, user_or_role, privileges, labels, edgeTypes] {
auth->RevokePrivilege(user_or_role, privileges, labels, edgeTypes);
return std::vector<std::vector<TypedValue>>();
};
return callback;
@@ -964,11 +969,7 @@ PullPlan::PullPlan(const std::shared_ptr<CachedPlan> plan, const Parameters &par
#ifdef MG_ENTERPRISE
if (username.has_value()) {
memgraph::auth::User *user = interpreter_context->auth->GetUser(*username);
<<<<<<< HEAD
ctx_.access_checker = new AccessChecker{user};
=======
ctx_.fine_grained_access_checker = new FineGrainedAccessChecker{user};
>>>>>>> E129-MG-implement-label-based-authorization
}
#endif
if (interpreter_context->config.execution_timeout_sec > 0) {
@@ -1305,7 +1306,6 @@ PreparedQuery PrepareProfileQuery(ParsedQuery parsed_query, bool in_explicit_tra
auto optional_username = StringPointerToOptional(username);
rw_type_checker.InferRWType(const_cast<plan::LogicalOperator &>(cypher_query_plan->plan()));
auto optional_username = StringPointerToOptional(username);
return PreparedQuery{{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE TIME"},
std::move(parsed_query.required_privileges),

View File

@@ -104,15 +104,15 @@ class AuthQueryHandler {
/// @throw QueryRuntimeException if an error ocurred.
virtual void GrantPrivilege(const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges,
const std::vector<std::string> &labels) = 0;
const std::vector<std::string> &labels, const std::vector<std::string> &edgeTypes) = 0;
/// @throw QueryRuntimeException if an error ocurred.
virtual void DenyPrivilege(const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges,
const std::vector<std::string> &labels) = 0;
const std::vector<std::string> &labels, const std::vector<std::string> &edgeTypes) = 0;
/// @throw QueryRuntimeException if an error ocurred.
virtual void RevokePrivilege(const std::string &user_or_role, const std::vector<AuthQuery::Privilege> &privileges,
const std::vector<std::string> &labels) = 0;
const std::vector<std::string> &labels, const std::vector<std::string> &edgeTypes) = 0;
};
enum class QueryHandlerResult { COMMIT, ABORT, NOTHING };

View File

@@ -13,6 +13,8 @@
#include <memory>
#include "query/context.hpp"
#include "query/fine_grained_access_checker.hpp"
#include "storage/v2/edge_accessor.hpp"
#include "storage/v2/id_types.hpp"
#include "storage/v2/indices.hpp"
@@ -339,8 +341,9 @@ Result<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(View view
return std::move(properties);
}
Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, AccessChecker *access_checker,
const VertexAccessor *destination) const {
Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(
View view, const query::FineGrainedAccessChecker *fine_grained_access_checker,
const VertexAccessor *destination) const {
MG_ASSERT(!destination || destination->transaction_ == transaction_, "Invalid accessor!");
bool exists = true;
bool deleted = false;
@@ -349,65 +352,68 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, AccessCheck
{
std::lock_guard<utils::SpinLock> guard(vertex_->lock);
deleted = vertex_->deleted;
if (edge_types.empty() && !destination) {
if (!fine_grained_access_checker && !destination) {
in_edges = vertex_->in_edges;
} else {
for (const auto &item : vertex_->in_edges) {
const auto &[edge_type, from_vertex, edge] = item;
if (destination && from_vertex != destination->vertex_) continue;
if (!edge_types.empty() && std::find(edge_types.begin(), edge_types.end(), edge_type) == edge_types.end())
if (!fine_grained_access_checker && fine_grained_access_checker->IsUserAuthorizedEdgeType(edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(from_vertex->labels))
continue;
in_edges.push_back(item);
}
}
delta = vertex_->delta;
}
ApplyDeltasForRead(
transaction_, delta, view, [&exists, &deleted, &in_edges, &edge_types, &destination](const Delta &delta) {
switch (delta.action) {
case Delta::Action::ADD_IN_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!edge_types.empty() &&
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break;
// Add the edge because we don't see the removal.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
delta.vertex_edge.edge};
auto it = std::find(in_edges.begin(), in_edges.end(), link);
MG_ASSERT(it == in_edges.end(), "Invalid database state!");
in_edges.push_back(link);
break;
}
case Delta::Action::REMOVE_IN_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!edge_types.empty() &&
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break;
// Remove the label because we don't see the addition.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
delta.vertex_edge.edge};
auto it = std::find(in_edges.begin(), in_edges.end(), link);
MG_ASSERT(it != in_edges.end(), "Invalid database state!");
std::swap(*it, *in_edges.rbegin());
in_edges.pop_back();
break;
}
case Delta::Action::DELETE_OBJECT: {
exists = false;
break;
}
case Delta::Action::RECREATE_OBJECT: {
deleted = false;
break;
}
case Delta::Action::ADD_LABEL:
case Delta::Action::REMOVE_LABEL:
case Delta::Action::SET_PROPERTY:
case Delta::Action::ADD_OUT_EDGE:
case Delta::Action::REMOVE_OUT_EDGE:
break;
}
});
ApplyDeltasForRead(transaction_, delta, view,
[&exists, &deleted, &in_edges, &fine_grained_access_checker, &destination](const Delta &delta) {
switch (delta.action) {
case Delta::Action::ADD_IN_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!fine_grained_access_checker &&
fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels))
break;
// Add the edge because we don't see the removal.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
delta.vertex_edge.edge_type, delta.vertex_edge.vertex, delta.vertex_edge.edge};
auto it = std::find(in_edges.begin(), in_edges.end(), link);
MG_ASSERT(it == in_edges.end(), "Invalid database state!");
in_edges.push_back(link);
break;
}
case Delta::Action::REMOVE_IN_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!fine_grained_access_checker &&
fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels))
break;
// Remove the label because we don't see the addition.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
delta.vertex_edge.edge_type, delta.vertex_edge.vertex, delta.vertex_edge.edge};
auto it = std::find(in_edges.begin(), in_edges.end(), link);
MG_ASSERT(it != in_edges.end(), "Invalid database state!");
std::swap(*it, *in_edges.rbegin());
in_edges.pop_back();
break;
}
case Delta::Action::DELETE_OBJECT: {
exists = false;
break;
}
case Delta::Action::RECREATE_OBJECT: {
deleted = false;
break;
}
case Delta::Action::ADD_LABEL:
case Delta::Action::REMOVE_LABEL:
case Delta::Action::SET_PROPERTY:
case Delta::Action::ADD_OUT_EDGE:
case Delta::Action::REMOVE_OUT_EDGE:
break;
}
});
if (!exists) return Error::NONEXISTENT_OBJECT;
if (deleted) return Error::DELETED_OBJECT;
std::vector<EdgeAccessor> ret;
@@ -419,8 +425,9 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, AccessCheck
return std::move(ret);
}
Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const std::vector<EdgeTypeId> &edge_types,
const VertexAccessor *destination) const {
Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(
View view, const query::FineGrainedAccessChecker *fine_grained_access_checker,
const VertexAccessor *destination) const {
MG_ASSERT(!destination || destination->transaction_ == transaction_, "Invalid accessor!");
bool exists = true;
bool deleted = false;
@@ -429,65 +436,68 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const std:
{
std::lock_guard<utils::SpinLock> guard(vertex_->lock);
deleted = vertex_->deleted;
if (edge_types.empty() && !destination) {
if (!fine_grained_access_checker && !destination) {
out_edges = vertex_->out_edges;
} else {
for (const auto &item : vertex_->out_edges) {
const auto &[edge_type, to_vertex, edge] = item;
if (destination && to_vertex != destination->vertex_) continue;
if (!edge_types.empty() && std::find(edge_types.begin(), edge_types.end(), edge_type) == edge_types.end())
if (!fine_grained_access_checker && fine_grained_access_checker->IsUserAuthorizedEdgeType(edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(to_vertex->labels))
continue;
out_edges.push_back(item);
}
}
delta = vertex_->delta;
}
ApplyDeltasForRead(
transaction_, delta, view, [&exists, &deleted, &out_edges, &edge_types, &destination](const Delta &delta) {
switch (delta.action) {
case Delta::Action::ADD_OUT_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!edge_types.empty() &&
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break;
// Add the edge because we don't see the removal.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
delta.vertex_edge.edge};
auto it = std::find(out_edges.begin(), out_edges.end(), link);
MG_ASSERT(it == out_edges.end(), "Invalid database state!");
out_edges.push_back(link);
break;
}
case Delta::Action::REMOVE_OUT_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!edge_types.empty() &&
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break;
// Remove the label because we don't see the addition.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
delta.vertex_edge.edge};
auto it = std::find(out_edges.begin(), out_edges.end(), link);
MG_ASSERT(it != out_edges.end(), "Invalid database state!");
std::swap(*it, *out_edges.rbegin());
out_edges.pop_back();
break;
}
case Delta::Action::DELETE_OBJECT: {
exists = false;
break;
}
case Delta::Action::RECREATE_OBJECT: {
deleted = false;
break;
}
case Delta::Action::ADD_LABEL:
case Delta::Action::REMOVE_LABEL:
case Delta::Action::SET_PROPERTY:
case Delta::Action::ADD_IN_EDGE:
case Delta::Action::REMOVE_IN_EDGE:
break;
}
});
ApplyDeltasForRead(transaction_, delta, view,
[&exists, &deleted, &out_edges, &fine_grained_access_checker, &destination](const Delta &delta) {
switch (delta.action) {
case Delta::Action::ADD_OUT_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!fine_grained_access_checker &&
fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels))
break;
// Add the edge because we don't see the removal.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
delta.vertex_edge.edge_type, delta.vertex_edge.vertex, delta.vertex_edge.edge};
auto it = std::find(out_edges.begin(), out_edges.end(), link);
MG_ASSERT(it == out_edges.end(), "Invalid database state!");
out_edges.push_back(link);
break;
}
case Delta::Action::REMOVE_OUT_EDGE: {
if (destination && delta.vertex_edge.vertex != destination->vertex_) break;
if (!fine_grained_access_checker &&
fine_grained_access_checker->IsUserAuthorizedEdgeType(delta.vertex_edge.edge_type) &&
fine_grained_access_checker->IsUserAuthorizedLabels(delta.vertex_edge.vertex->labels))
break;
// Remove the label because we don't see the addition.
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
delta.vertex_edge.edge_type, delta.vertex_edge.vertex, delta.vertex_edge.edge};
auto it = std::find(out_edges.begin(), out_edges.end(), link);
MG_ASSERT(it != out_edges.end(), "Invalid database state!");
std::swap(*it, *out_edges.rbegin());
out_edges.pop_back();
break;
}
case Delta::Action::DELETE_OBJECT: {
exists = false;
break;
}
case Delta::Action::RECREATE_OBJECT: {
deleted = false;
break;
}
case Delta::Action::ADD_LABEL:
case Delta::Action::REMOVE_LABEL:
case Delta::Action::SET_PROPERTY:
case Delta::Action::ADD_IN_EDGE:
case Delta::Action::REMOVE_IN_EDGE:
break;
}
});
if (!exists) return Error::NONEXISTENT_OBJECT;
if (deleted) return Error::DELETED_OBJECT;
std::vector<EdgeAccessor> ret;

View File

@@ -13,6 +13,7 @@
#include <optional>
#include "query/fine_grained_access_checker.hpp"
#include "storage/v2/vertex.hpp"
#include "storage/v2/config.hpp"
@@ -81,14 +82,16 @@ class VertexAccessor final {
/// @throw std::bad_alloc
/// @throw std::length_error if the resulting vector exceeds
/// std::vector::max_size().
Result<std::vector<EdgeAccessor>> InEdges(View view, AccessChecker *access_checker = nullptr,
const VertexAccessor *destination = nullptr) const;
Result<std::vector<EdgeAccessor>> InEdges(
View view, const query::FineGrainedAccessChecker *fine_grained_access_checker = nullptr,
const VertexAccessor *destination = nullptr) const;
/// @throw std::bad_alloc
/// @throw std::length_error if the resulting vector exceeds
/// std::vector::max_size().
Result<std::vector<EdgeAccessor>> OutEdges(View view, const std::vector<EdgeTypeId> &edge_types = {},
const VertexAccessor *destination = nullptr) const;
Result<std::vector<EdgeAccessor>> OutEdges(
View view, const query::FineGrainedAccessChecker *fine_grained_access_checker = nullptr,
const VertexAccessor *destination = nullptr) const;
Result<size_t> InDegree(View view) const;