diff --git a/src/auth/models.cpp b/src/auth/models.cpp index 54bf24da6..08bb389c5 100644 --- a/src/auth/models.cpp +++ b/src/auth/models.cpp @@ -8,7 +8,10 @@ #include "auth/models.hpp" +#include +#include #include +#include #include @@ -84,6 +87,8 @@ std::string PermissionToString(Permission permission) { return "MODULE_WRITE"; case Permission::WEBSOCKET: return "WEBSOCKET"; + case Permission::EDGE_TYPES: + return "EDGE_TYPES"; } } @@ -98,12 +103,9 @@ std::string PermissionLevelToString(PermissionLevel level) { } } -Permissions::Permissions(uint64_t grants, uint64_t denies) { - // The deny bitmask has higher priority than the grant bitmask. - denies_ = denies; - // Mask out the grant bitmask to make sure that it is correct. - grants_ = grants & (~denies); -} +const std::string ASTERISK = "*"; + +Permissions::Permissions(uint64_t grants, uint64_t denies) : grants_(grants & (~denies)), denies_(denies) {} PermissionLevel Permissions::Has(Permission permission) const { // Check for the deny first because it has greater priority than a grant. @@ -183,19 +185,133 @@ bool operator==(const Permissions &first, const Permissions &second) { bool operator!=(const Permissions &first, const Permissions &second) { return !(first == second); } +AccessPermissions::AccessPermissions(const std::unordered_set &grants, + const std::unordered_set &denies) + : grants_(grants), denies_(denies) {} + +PermissionLevel AccessPermissions::Has(const std::string &permission) const { + if ((denies_.size() == 1 && denies_.find(ASTERISK) != denies_.end()) || denies_.find(permission) != denies_.end()) { + return PermissionLevel::DENY; + } + + if ((grants_.size() == 1 && grants_.find(ASTERISK) != grants_.end()) || grants_.find(permission) != denies_.end()) { + return PermissionLevel::GRANT; + } + + return PermissionLevel::NEUTRAL; +} + +void AccessPermissions::Grant(const std::string &permission) { + if (permission == ASTERISK) { + grants_.clear(); + grants_.insert(permission); + + return; + } + + auto deniedPermissionIter = denies_.find(permission); + + if (deniedPermissionIter != denies_.end()) { + denies_.erase(deniedPermissionIter); + } + + if (grants_.size() == 1 && grants_.find(ASTERISK) != grants_.end()) { + grants_.erase(ASTERISK); + } + + if (grants_.find(permission) == grants_.end()) { + grants_.insert(permission); + } +} + +void AccessPermissions::Revoke(const std::string &permission) { + if (permission == ASTERISK) { + grants_.clear(); + denies_.clear(); + + return; + } + + auto deniedPermissionIter = denies_.find(permission); + auto grantedPermissionIter = grants_.find(permission); + + if (deniedPermissionIter != denies_.end()) { + denies_.erase(deniedPermissionIter); + } + + if (grantedPermissionIter != grants_.end()) { + grants_.erase(grantedPermissionIter); + } +} + +void AccessPermissions::Deny(const std::string &permission) { + if (permission == ASTERISK) { + denies_.clear(); + denies_.insert(permission); + + return; + } + + auto grantedPermissionIter = grants_.find(permission); + + if (grantedPermissionIter != grants_.end()) { + grants_.erase(grantedPermissionIter); + } + + if (denies_.size() == 1 && denies_.find(ASTERISK) != denies_.end()) { + denies_.erase(ASTERISK); + } + + if (denies_.find(permission) == denies_.end()) { + denies_.insert(permission); + } +} + +std::unordered_set AccessPermissions::GetGrants() const { return grants_; } + +std::unordered_set AccessPermissions::GetDenies() const { return denies_; } + +nlohmann::json AccessPermissions::Serialize() const { + nlohmann::json data = nlohmann::json::object(); + data["grants"] = grants_; + data["denies"] = denies_; + return data; +} + +AccessPermissions AccessPermissions::Deserialize(const nlohmann::json &data) { + if (!data.is_object()) { + throw AuthException("Couldn't load permissions data!"); + } + + return {data["grants"], data["denies"]}; +} + +std::unordered_set AccessPermissions::grants() const { return grants_; } +std::unordered_set AccessPermissions::denies() const { return denies_; } + +bool operator==(const AccessPermissions &first, const AccessPermissions &second) { + return first.grants() == second.grants() && first.denies() == second.denies(); +} + +bool operator!=(const AccessPermissions &first, const AccessPermissions &second) { return !(first == second); } + Role::Role(const std::string &rolename) : rolename_(utils::ToLowerCase(rolename)) {} -Role::Role(const std::string &rolename, const Permissions &permissions) - : rolename_(utils::ToLowerCase(rolename)), permissions_(permissions) {} +Role::Role(const std::string &rolename, const Permissions &permissions, const AccessPermissions &edgeTypePermissions) + : rolename_(utils::ToLowerCase(rolename)), permissions_(permissions), edgeTypePermissions_(edgeTypePermissions) {} const std::string &Role::rolename() const { return rolename_; } const Permissions &Role::permissions() const { return permissions_; } Permissions &Role::permissions() { return permissions_; } +const AccessPermissions &Role::edgeTypePermissions() const { return edgeTypePermissions_; } +AccessPermissions &Role::edgeTypePermissions() { return edgeTypePermissions_; } + nlohmann::json Role::Serialize() const { nlohmann::json data = nlohmann::json::object(); data["rolename"] = rolename_; data["permissions"] = permissions_.Serialize(); + data["edgeTypePermissions"] = edgeTypePermissions_.Serialize(); return data; } @@ -207,17 +323,23 @@ Role Role::Deserialize(const nlohmann::json &data) { throw AuthException("Couldn't load role data!"); } auto permissions = Permissions::Deserialize(data["permissions"]); - return {data["rolename"], permissions}; + auto edgeTypePermissions = AccessPermissions::Deserialize(data["edgeTypePermissions"]); + return {data["rolename"], permissions, edgeTypePermissions}; } bool operator==(const Role &first, const Role &second) { - return first.rolename_ == second.rolename_ && first.permissions_ == second.permissions_; + return first.rolename_ == second.rolename_ && first.permissions_ == second.permissions_ && + first.edgeTypePermissions_ == second.edgeTypePermissions_; } User::User(const std::string &username) : username_(utils::ToLowerCase(username)) {} -User::User(const std::string &username, const std::string &password_hash, const Permissions &permissions) - : username_(utils::ToLowerCase(username)), password_hash_(password_hash), permissions_(permissions) {} +User::User(const std::string &username, const std::string &password_hash, const Permissions &permissions, + const AccessPermissions &edgeTypePermissions) + : username_(utils::ToLowerCase(username)), + password_hash_(password_hash), + permissions_(permissions), + edgeTypePermissions_(edgeTypePermissions) {} bool User::CheckPassword(const std::string &password) { if (password_hash_.empty()) return true; @@ -260,17 +382,39 @@ void User::ClearRole() { role_ = std::nullopt; } Permissions User::GetPermissions() const { if (role_) { - return Permissions(permissions_.grants() | role_->permissions().grants(), - permissions_.denies() | role_->permissions().denies()); + return {permissions_.grants() | role_->permissions().grants(), + permissions_.denies() | role_->permissions().denies()}; } return permissions_; } +AccessPermissions User::GetEdgeTypePermissions() const { + if (role_) { + std::unordered_set resultGrants; + + std::set_union(edgeTypePermissions_.grants().begin(), edgeTypePermissions_.grants().end(), + role_->edgeTypePermissions().grants().begin(), role_->edgeTypePermissions().grants().end(), + std::inserter(resultGrants, resultGrants.begin())); + + std::unordered_set resultDenies; + + std::set_union(edgeTypePermissions_.denies().begin(), edgeTypePermissions_.denies().end(), + role_->edgeTypePermissions().denies().begin(), role_->edgeTypePermissions().denies().end(), + std::inserter(resultDenies, resultDenies.begin())); + + return {resultGrants, resultDenies}; + } + return edgeTypePermissions_; +} + const std::string &User::username() const { return username_; } const Permissions &User::permissions() const { return permissions_; } Permissions &User::permissions() { return permissions_; } +const AccessPermissions &User::edgeTypePermissions() const { return edgeTypePermissions_; } +AccessPermissions &User::edgeTypePermissions() { return edgeTypePermissions_; } + const Role *User::role() const { if (role_.has_value()) { return &role_.value(); @@ -283,6 +427,7 @@ nlohmann::json User::Serialize() const { data["username"] = username_; data["password_hash"] = password_hash_; data["permissions"] = permissions_.Serialize(); + data["edgeTypePermissions"] = edgeTypePermissions_.Serialize(); // The role shouldn't be serialized here, it is stored as a foreign key. return data; } @@ -295,11 +440,14 @@ User User::Deserialize(const nlohmann::json &data) { throw AuthException("Couldn't load user data!"); } auto permissions = Permissions::Deserialize(data["permissions"]); - return {data["username"], data["password_hash"], permissions}; + auto edgeTypePermissions = AccessPermissions::Deserialize(data["edgeTypePermissions"]); + return {data["username"], data["password_hash"], permissions, edgeTypePermissions}; } bool operator==(const User &first, const User &second) { return first.username_ == second.username_ && first.password_hash_ == second.password_hash_ && - first.permissions_ == second.permissions_ && first.role_ == second.role_; + first.permissions_ == second.permissions_ && first.edgeTypePermissions_ == second.edgeTypePermissions_ && + first.role_ == second.role_; } + } // namespace memgraph::auth diff --git a/src/auth/models.hpp b/src/auth/models.hpp index 0f01c0a39..df621c91c 100644 --- a/src/auth/models.hpp +++ b/src/auth/models.hpp @@ -12,6 +12,7 @@ #include #include +#include namespace memgraph::auth { // These permissions must have values that are applicable for usage in a @@ -38,7 +39,8 @@ enum class Permission : uint64_t { STREAM = 1U << 17U, MODULE_READ = 1U << 18U, MODULE_WRITE = 1U << 19U, - WEBSOCKET = 1U << 20U + WEBSOCKET = 1U << 20U, + EDGE_TYPES = 1U << 22U }; // clang-format on @@ -88,16 +90,52 @@ bool operator==(const Permissions &first, const Permissions &second); bool operator!=(const Permissions &first, const Permissions &second); +class AccessPermissions final { + public: + AccessPermissions(const std::unordered_set &grants = {}, + const std::unordered_set &denies = {}); + + PermissionLevel Has(const std::string &permission) const; + + void Grant(const std::string &permission); + + void Revoke(const std::string &permission); + + void Deny(const std::string &permission); + + std::unordered_set GetGrants() const; + std::unordered_set GetDenies() const; + + nlohmann::json Serialize() const; + + /// @throw AuthException if unable to deserialize. + static AccessPermissions Deserialize(const nlohmann::json &data); + + std::unordered_set grants() const; + std::unordered_set denies() const; + + private: + std::unordered_set grants_{}; + std::unordered_set denies_{}; +}; + +bool operator==(const AccessPermissions &first, const AccessPermissions &second); + +bool operator!=(const AccessPermissions &first, const AccessPermissions &second); + class Role final { public: Role(const std::string &rolename); - Role(const std::string &rolename, const Permissions &permissions); + Role(const std::string &rolename, const Permissions &permissions, const AccessPermissions &edgeTypePermissions_); const std::string &rolename() const; const Permissions &permissions() const; Permissions &permissions(); + const AccessPermissions &edgeTypePermissions() const; + AccessPermissions &edgeTypePermissions(); + nlohmann::json Serialize() const; /// @throw AuthException if unable to deserialize. @@ -108,6 +146,7 @@ class Role final { private: std::string rolename_; Permissions permissions_; + AccessPermissions edgeTypePermissions_; }; bool operator==(const Role &first, const Role &second); @@ -117,7 +156,8 @@ class User final { public: User(const std::string &username); - User(const std::string &username, const std::string &password_hash, const Permissions &permissions); + User(const std::string &username, const std::string &password_hash, const Permissions &permissions, + const AccessPermissions &edgeTypePermissions_); /// @throw AuthException if unable to verify the password. bool CheckPassword(const std::string &password); @@ -130,12 +170,16 @@ class User final { void ClearRole(); Permissions GetPermissions() const; + AccessPermissions GetEdgeTypePermissions() const; const std::string &username() const; const Permissions &permissions() const; Permissions &permissions(); + const AccessPermissions &edgeTypePermissions() const; + AccessPermissions &edgeTypePermissions(); + const Role *role() const; nlohmann::json Serialize() const; @@ -149,6 +193,7 @@ class User final { std::string username_; std::string password_hash_; Permissions permissions_; + AccessPermissions edgeTypePermissions_; std::optional role_; }; diff --git a/src/glue/auth.cpp b/src/glue/auth.cpp index 7f05d8045..512b98880 100644 --- a/src/glue/auth.cpp +++ b/src/glue/auth.cpp @@ -57,6 +57,8 @@ auth::Permission PrivilegeToPermission(query::AuthQuery::Privilege privilege) { return auth::Permission::MODULE_WRITE; case query::AuthQuery::Privilege::WEBSOCKET: return auth::Permission::WEBSOCKET; + case query::AuthQuery::Privilege::EDGE_TYPES: + return auth::Permission::EDGE_TYPES; } } } // namespace memgraph::glue diff --git a/src/memgraph.cpp b/src/memgraph.cpp index 9bd3f3f92..e5395e0eb 100644 --- a/src/memgraph.cpp +++ b/src/memgraph.cpp @@ -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; @@ -752,8 +752,9 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler { } void GrantPrivilege(const std::string &user_or_role, - const std::vector &privileges) override { - EditPermissions(user_or_role, privileges, [](auto *permissions, const auto &permission) { + const std::vector &privileges, + const std::vector &edgeTypes) override { + EditPermissions(user_or_role, privileges, 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? @@ -762,8 +763,9 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler { } void DenyPrivilege(const std::string &user_or_role, - const std::vector &privileges) override { - EditPermissions(user_or_role, privileges, [](auto *permissions, const auto &permission) { + const std::vector &privileges, + const std::vector &edgeTypes) override { + EditPermissions(user_or_role, privileges, 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? @@ -772,8 +774,9 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler { } void RevokePrivilege(const std::string &user_or_role, - const std::vector &privileges) override { - EditPermissions(user_or_role, privileges, [](auto *permissions, const auto &permission) { + const std::vector &privileges, + const std::vector &edgeTypes) override { + EditPermissions(user_or_role, privileges, 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? @@ -784,7 +787,8 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler { private: template void EditPermissions(const std::string &user_or_role, - const std::vector &privileges, const TEditFun &edit_fun) { + const std::vector &privileges, + const std::vector &edgeTypes, const TEditFun &edit_fun) { if (!std::regex_match(user_or_role, name_regex_)) { throw memgraph::query::QueryRuntimeException("Invalid user or role name."); } @@ -804,11 +808,18 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler { for (const auto &permission : permissions) { edit_fun(&user->permissions(), permission); } + + for (const auto &edgeType : edgeTypes) { + edit_fun(&user->edgeTypePermissions(), edgeType); + } locked_auth->SaveUser(*user); } else { for (const auto &permission : permissions) { edit_fun(&role->permissions(), permission); } + for (const auto &edgeType : edgeTypes) { + edit_fun(&role->edgeTypePermissions(), edgeType); + } locked_auth->SaveRole(*role); } } catch (const memgraph::auth::AuthException &e) { diff --git a/src/query/access_checker.hpp b/src/query/access_checker.hpp new file mode 100644 index 000000000..493e1f01b --- /dev/null +++ b/src/query/access_checker.hpp @@ -0,0 +1,24 @@ +// 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 "auth/models.hpp" +#include "query/frontend/ast/ast.hpp" +#include "storage/v2/id_types.hpp" + +namespace memgraph::query { +class AccessChecker { + public: + virtual bool IsUserAuthorizedEdgeTypes(const std::vector &edgeTypes, + memgraph::query::DbAccessor *dba) const = 0; +}; +} // namespace memgraph::query diff --git a/src/query/frontend/ast/ast.lcp b/src/query/frontend/ast/ast.lcp index 6b5b5a16f..63cce8a89 100644 --- a/src/query/frontend/ast/ast.lcp +++ b/src/query/frontend/ast/ast.lcp @@ -2242,6 +2242,7 @@ cpp<# (password "Expression *" :initval "nullptr" :scope :public :slk-save #'slk-save-ast-pointer :slk-load (slk-load-ast-pointer "Expression")) + (edgeTypes "std::vector" :scope :public) (privileges "std::vector" :scope :public)) (:public (lcp:define-enum action @@ -2253,7 +2254,7 @@ cpp<# (lcp:define-enum privilege (create delete match merge set remove index stats auth constraint dump replication durability read_file free_memory trigger config stream module_read module_write - websocket) + websocket edge_types) (:serialize)) #>cpp AuthQuery() = default; @@ -2264,12 +2265,14 @@ cpp<# #>cpp AuthQuery(Action action, std::string user, std::string role, std::string user_or_role, Expression *password, + std::vector edgeTypes, std::vector privileges) : action_(action), user_(user), role_(role), user_or_role_(user_or_role), password_(password), + edgetypes_(edgeTypes), privileges_(privileges) {} cpp<#) (:private @@ -2295,7 +2298,7 @@ const std::vector kPrivilegesAll = { AuthQuery::Privilege::FREE_MEMORY, AuthQuery::Privilege::TRIGGER, AuthQuery::Privilege::CONFIG, AuthQuery::Privilege::STREAM, AuthQuery::Privilege::MODULE_READ, AuthQuery::Privilege::MODULE_WRITE, - AuthQuery::Privilege::WEBSOCKET}; + AuthQuery::Privilege::WEBSOCKET, }; cpp<# (lcp:define-class info-query (query) diff --git a/src/query/frontend/ast/cypher_main_visitor.cpp b/src/query/frontend/ast/cypher_main_visitor.cpp index a12643298..17781538c 100644 --- a/src/query/frontend/ast/cypher_main_visitor.cpp +++ b/src/query/frontend/ast/cypher_main_visitor.cpp @@ -1274,7 +1274,11 @@ antlrcpp::Any CypherMainVisitor::visitGrantPrivilege(MemgraphCypher::GrantPrivil auth->user_or_role_ = ctx->userOrRole->accept(this).as(); if (ctx->privilegeList()) { for (auto *privilege : ctx->privilegeList()->privilege()) { - auth->privileges_.push_back(privilege->accept(this)); + if (privilege->EDGE_TYPES()) { + auth->edgetypes_ = privilege->edgeTypeList()->accept(this).as>(); + } else { + auth->privileges_.push_back(privilege->accept(this)); + } } } else { /* grant all privileges */ @@ -1319,6 +1323,22 @@ antlrcpp::Any CypherMainVisitor::visitRevokePrivilege(MemgraphCypher::RevokePriv return auth; } +/** + * @return AuthQuery* + */ +antlrcpp::Any CypherMainVisitor::visitEdgeTypeList(MemgraphCypher::EdgeTypeListContext *ctx) { + std::vector edgeTypes; + if (ctx->listOfEdgeTypes()) { + for (auto *edgeType : ctx->listOfEdgeTypes()->edgeType()) { + edgeTypes.push_back(edgeType->symbolicName()->accept(this).as()); + } + } else { + edgeTypes.emplace_back("*"); + } + + return edgeTypes; +} + /** * @return AuthQuery::Privilege */ @@ -1344,6 +1364,7 @@ antlrcpp::Any CypherMainVisitor::visitPrivilege(MemgraphCypher::PrivilegeContext if (ctx->MODULE_READ()) return AuthQuery::Privilege::MODULE_READ; if (ctx->MODULE_WRITE()) return AuthQuery::Privilege::MODULE_WRITE; if (ctx->WEBSOCKET()) return AuthQuery::Privilege::WEBSOCKET; + if (ctx->EDGE_TYPES()) return AuthQuery::Privilege::EDGE_TYPES; LOG_FATAL("Should not get here - unknown privilege!"); } diff --git a/src/query/frontend/ast/cypher_main_visitor.hpp b/src/query/frontend/ast/cypher_main_visitor.hpp index 2a6b8ff5e..14b4600c3 100644 --- a/src/query/frontend/ast/cypher_main_visitor.hpp +++ b/src/query/frontend/ast/cypher_main_visitor.hpp @@ -468,6 +468,11 @@ class CypherMainVisitor : public antlropencypher::MemgraphCypherBaseVisitor { */ antlrcpp::Any visitRevokePrivilege(MemgraphCypher::RevokePrivilegeContext *ctx) override; + /** + * @return AuthQuery* + */ + antlrcpp::Any visitEdgeTypeList(MemgraphCypher::EdgeTypeListContext *ctx) override; + /** * @return AuthQuery::Privilege */ diff --git a/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 b/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 index 8790b8731..f60a0f079 100644 --- a/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 +++ b/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 @@ -254,10 +254,18 @@ privilege : CREATE | MODULE_READ | MODULE_WRITE | WEBSOCKET + | EDGE_TYPES edgeTypes = edgeTypeList ; privilegeList : privilege ( ',' privilege )* ; + +edgeTypeList : '*' | listOfEdgeTypes ; + +listOfEdgeTypes : edgeType ( ',' edgeType )* ; + +edgeType : COLON symbolicName ; + showPrivileges : SHOW PRIVILEGES FOR userOrRole=userOrRoleName ; showRoleForUser : SHOW ROLE FOR user=userOrRoleName ; diff --git a/src/query/interpreter.cpp b/src/query/interpreter.cpp index bc1a6a725..aa55d0fba 100644 --- a/src/query/interpreter.cpp +++ b/src/query/interpreter.cpp @@ -23,6 +23,7 @@ #include "glue/communication.hpp" #include "memory/memory_control.hpp" +#include "query/access_checker.hpp" #include "query/constants.hpp" #include "query/context.hpp" #include "query/cypher_query_interpreter.hpp" @@ -43,6 +44,7 @@ #include "query/stream/common.hpp" #include "query/trigger.hpp" #include "query/typed_value.hpp" +#include "storage/v2/id_types.hpp" #include "storage/v2/property_value.hpp" #include "storage/v2/replication/enums.hpp" #include "utils/algorithm.hpp" @@ -259,6 +261,24 @@ class ReplQueryHandler final : public query::ReplicationQueryHandler { private: storage::Storage *db_; }; + +class AccessChecker final : public memgraph::query::AccessChecker { + public: + explicit AccessChecker(memgraph::auth::User *user) : user_{user} {} + + bool IsUserAuthorizedEdgeTypes(const std::vector &edgeTypes, + memgraph::query::DbAccessor *dba) const final { + auto edgeTypePermissions = user_->GetEdgeTypePermissions(); + + return std::any_of(edgeTypes.begin(), edgeTypes.end(), [edgeTypePermissions, dba](const auto edgeType) { + return edgeTypePermissions.Has(dba->EdgeTypeToName(edgeType)) == memgraph::auth::PermissionLevel::GRANT; + }); + } + + private: + memgraph::auth::User *user_; +}; + /// returns false if the replication role can't be set /// @throw QueryRuntimeException if an error ocurred. @@ -280,6 +300,7 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa std::string rolename = auth_query->role_; std::string user_or_role = auth_query->user_or_role_; std::vector privileges = auth_query->privileges_; + std::vector edgeTypes = auth_query->edgetypes_; auto password = EvaluateOptionalExpression(auth_query->password_, &evaluator); Callback callback; @@ -309,7 +330,7 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa // If the license is not valid we create users with admin access if (!valid_enterprise_license) { spdlog::warn("Granting all the privileges to {}.", username); - auth->GrantPrivilege(username, kPrivilegesAll); + auth->GrantPrivilege(username, kPrivilegesAll, {"*"}); } return std::vector>(); @@ -384,20 +405,20 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa }; return callback; case AuthQuery::Action::GRANT_PRIVILEGE: - callback.fn = [auth, user_or_role, privileges] { - auth->GrantPrivilege(user_or_role, privileges); + callback.fn = [auth, user_or_role, privileges, edgeTypes] { + auth->GrantPrivilege(user_or_role, privileges, edgeTypes); return std::vector>(); }; return callback; case AuthQuery::Action::DENY_PRIVILEGE: - callback.fn = [auth, user_or_role, privileges] { - auth->DenyPrivilege(user_or_role, privileges); + callback.fn = [auth, user_or_role, privileges, edgeTypes] { + auth->DenyPrivilege(user_or_role, privileges, edgeTypes); return std::vector>(); }; return callback; case AuthQuery::Action::REVOKE_PRIVILEGE: { - callback.fn = [auth, user_or_role, privileges] { - auth->RevokePrivilege(user_or_role, privileges); + callback.fn = [auth, user_or_role, privileges, edgeTypes] { + auth->RevokePrivilege(user_or_role, privileges, edgeTypes); return std::vector>(); }; return callback; diff --git a/src/query/interpreter.hpp b/src/query/interpreter.hpp index 5373588d9..f04b0075c 100644 --- a/src/query/interpreter.hpp +++ b/src/query/interpreter.hpp @@ -99,14 +99,16 @@ class AuthQueryHandler { virtual std::vector> GetPrivileges(const std::string &user_or_role) = 0; /// @throw QueryRuntimeException if an error ocurred. - virtual void GrantPrivilege(const std::string &user_or_role, const std::vector &privileges) = 0; + virtual void GrantPrivilege(const std::string &user_or_role, const std::vector &privileges, + const std::vector &edgeTypes) = 0; /// @throw QueryRuntimeException if an error ocurred. - virtual void DenyPrivilege(const std::string &user_or_role, const std::vector &privileges) = 0; + virtual void DenyPrivilege(const std::string &user_or_role, const std::vector &privileges, + const std::vector &edgeTypes) = 0; /// @throw QueryRuntimeException if an error ocurred. - virtual void RevokePrivilege(const std::string &user_or_role, - const std::vector &privileges) = 0; + virtual void RevokePrivilege(const std::string &user_or_role, const std::vector &privileges, + const std::vector &edgeTypes) = 0; }; enum class QueryHandlerResult { COMMIT, ABORT, NOTHING };