diff --git a/src/auth/models.cpp b/src/auth/models.cpp index 279bb9d5f..e03928bc0 100644 --- a/src/auth/models.cpp +++ b/src/auth/models.cpp @@ -396,6 +396,7 @@ nlohmann::json User::Serialize() const { data["username"] = username_; data["password_hash"] = password_hash_; data["permissions"] = permissions_.Serialize(); + data["labelPermissions"] = labelPermissions_.Serialize(); // The role shouldn't be serialized here, it is stored as a foreign key. return data; } @@ -417,4 +418,5 @@ bool operator==(const User &first, const User &second) { first.permissions_ == second.permissions_ && first.labelPermissions_ == second.labelPermissions_ && first.role_ == second.role_; } + } // namespace memgraph::auth diff --git a/src/auth/models.hpp b/src/auth/models.hpp index fd93c2806..5d38a2f1b 100644 --- a/src/auth/models.hpp +++ b/src/auth/models.hpp @@ -13,6 +13,7 @@ #include #include +#include namespace memgraph::auth { // These permissions must have values that are applicable for usage in a @@ -198,4 +199,5 @@ class User final { }; bool operator==(const User &first, const User &second); + } // namespace memgraph::auth diff --git a/src/memgraph.cpp b/src/memgraph.cpp index d1a972c7c..e935c03ec 100644 --- a/src/memgraph.cpp +++ b/src/memgraph.cpp @@ -501,7 +501,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; @@ -747,8 +747,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 &labels) override { + EditPermissions(user_or_role, privileges, labels, [](auto *permissions, const auto &permission) { // TODO (mferencevic): should we first check that the // privilege is granted/denied/revoked before // unconditionally granting/denying/revoking it? @@ -757,8 +758,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 &labels) override { + EditPermissions(user_or_role, privileges, labels, [](auto *permissions, const auto &permission) { // TODO (mferencevic): should we first check that the // privilege is granted/denied/revoked before // unconditionally granting/denying/revoking it? @@ -767,8 +769,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 &labels) override { + EditPermissions(user_or_role, privileges, labels, [](auto *permissions, const auto &permission) { // TODO (mferencevic): should we first check that the // privilege is granted/denied/revoked before // unconditionally granting/denying/revoking it? @@ -779,7 +782,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 &labels, const TEditFun &edit_fun) { if (!std::regex_match(user_or_role, name_regex_)) { throw memgraph::query::QueryRuntimeException("Invalid user or role name."); } @@ -799,11 +803,17 @@ class AuthQueryHandler final : public memgraph::query::AuthQueryHandler { for (const auto &permission : permissions) { edit_fun(&user->permissions(), permission); } + for (const auto &label : labels) { + edit_fun(&user->labelPermissions(), label); + } locked_auth->SaveUser(*user); } else { for (const auto &permission : permissions) { edit_fun(&role->permissions(), permission); } + for (const auto &label : labels) { + edit_fun(&role->labelPermissions(), label); + } locked_auth->SaveRole(*role); } } catch (const memgraph::auth::AuthException &e) { diff --git a/src/query/frontend/ast/ast.lcp b/src/query/frontend/ast/ast.lcp index e325a944c..a924b408b 100644 --- a/src/query/frontend/ast/ast.lcp +++ b/src/query/frontend/ast/ast.lcp @@ -2239,10 +2239,11 @@ cpp<# (user "std::string" :scope :public) (role "std::string" :scope :public) (user-or-role "std::string" :scope :public) - (labels "std::vector" :scope :public) + (password "Expression *" :initval "nullptr" :scope :public :slk-save #'slk-save-ast-pointer :slk-load (slk-load-ast-pointer "Expression")) + (labels "std::vector" :scope :public) (privileges "std::vector" :scope :public)) (:public (lcp:define-enum action @@ -2265,14 +2266,14 @@ cpp<# #>cpp AuthQuery(Action action, std::string user, std::string role, std::string user_or_role, Expression *password, - std::vector privileges, std::vector labels) + std::vector labels ,std::vector privileges) : action_(action), user_(user), role_(role), user_or_role_(user_or_role), password_(password), - privileges_(privileges), - labels_(labels) {} + labels_(labels), + privileges_(privileges){} cpp<#) (:private #>cpp @@ -2297,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, AuthQuery::Privilege::LABELS}; cpp<# diff --git a/src/query/frontend/ast/cypher_main_visitor.cpp b/src/query/frontend/ast/cypher_main_visitor.cpp index 16112afb7..741d4146e 100644 --- a/src/query/frontend/ast/cypher_main_visitor.cpp +++ b/src/query/frontend/ast/cypher_main_visitor.cpp @@ -1296,7 +1296,11 @@ antlrcpp::Any CypherMainVisitor::visitDenyPrivilege(MemgraphCypher::DenyPrivileg 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->LABELS()) { + auth->labels_ = privilege->labelList()->accept(this).as>(); + } else { + auth->privileges_.push_back(privilege->accept(this)); + } } } else { /* deny all privileges */ @@ -1314,7 +1318,11 @@ antlrcpp::Any CypherMainVisitor::visitRevokePrivilege(MemgraphCypher::RevokePriv 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->LABELS()) { + auth->labels_ = privilege->labelList()->accept(this).as>(); + } else { + auth->privileges_.push_back(privilege->accept(this)); + } } } else { /* revoke all privileges */ diff --git a/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 b/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 index d5c553f68..6988ac80b 100644 --- a/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 +++ b/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 @@ -260,7 +260,7 @@ privilege : CREATE privilegeList : privilege ( ',' privilege )* ; -labelList : label ( ',' label )* ; +labelList : COLON label ( ',' COLON label )* ; label : ( '*' | symbolicName ) ; diff --git a/src/query/interpreter.cpp b/src/query/interpreter.cpp index 17d62b240..209741f2b 100644 --- a/src/query/interpreter.cpp +++ b/src/query/interpreter.cpp @@ -278,6 +278,8 @@ 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 labels = auth_query->labels_; + // std::vector labels = NamesToLabels(labels, db_accessor); auto password = EvaluateOptionalExpression(auth_query->password_, &evaluator); Callback callback; @@ -307,7 +309,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>(); @@ -382,20 +384,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, labels] { + auth->GrantPrivilege(user_or_role, privileges, labels); 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, labels] { + auth->DenyPrivilege(user_or_role, privileges, labels); 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, labels] { + auth->RevokePrivilege(user_or_role, privileges, labels); return std::vector>(); }; return callback; diff --git a/src/query/interpreter.hpp b/src/query/interpreter.hpp index 5373588d9..77814da4a 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 &labels) = 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 &labels) = 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 &labels) = 0; }; enum class QueryHandlerResult { COMMIT, ABORT, NOTHING };