diff --git a/src/auth/models.cpp b/src/auth/models.cpp index 54bf24da6..9720c3596 100644 --- a/src/auth/models.cpp +++ b/src/auth/models.cpp @@ -84,6 +84,8 @@ std::string PermissionToString(Permission permission) { return "MODULE_WRITE"; case Permission::WEBSOCKET: return "WEBSOCKET"; + case Permission::LABELS: + return "LABELS"; } } diff --git a/src/auth/models.hpp b/src/auth/models.hpp index 0f01c0a39..c6ed3e0ae 100644 --- a/src/auth/models.hpp +++ b/src/auth/models.hpp @@ -38,7 +38,8 @@ enum class Permission : uint64_t { STREAM = 1U << 17U, MODULE_READ = 1U << 18U, MODULE_WRITE = 1U << 19U, - WEBSOCKET = 1U << 20U + WEBSOCKET = 1U << 20U, + LABELS = 1U << 21U }; // clang-format on diff --git a/src/glue/auth.cpp b/src/glue/auth.cpp index 7f05d8045..650f215e8 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::LABELS: + return auth::Permission::LABELS; } } } // namespace memgraph::glue diff --git a/src/query/frontend/ast/ast.lcp b/src/query/frontend/ast/ast.lcp index 6b5b5a16f..e325a944c 100644 --- a/src/query/frontend/ast/ast.lcp +++ b/src/query/frontend/ast/ast.lcp @@ -2239,6 +2239,7 @@ 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")) @@ -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 labels) (:serialize)) #>cpp AuthQuery() = default; @@ -2264,13 +2265,14 @@ cpp<# #>cpp AuthQuery(Action action, std::string user, std::string role, std::string user_or_role, Expression *password, - std::vector privileges) + std::vector privileges, std::vector labels) : action_(action), user_(user), role_(role), user_or_role_(user_or_role), password_(password), - privileges_(privileges) {} + privileges_(privileges), + labels_(labels) {} cpp<#) (:private #>cpp @@ -2295,7 +2297,8 @@ 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<# (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..16112afb7 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->LABELS()) { + auth->labels_ = privilege->labelList()->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::visitLabelList(MemgraphCypher::LabelListContext *ctx) { + std::vector labels; + for (auto *label : ctx->label()) { + if (label->ASTERISK()) { + labels.push_back("*"); + } else { + labels.push_back(label->symbolicName()->accept(this).as()); + } + } + + return labels; +} + /** * @return AuthQuery::Privilege */ @@ -1344,6 +1364,10 @@ 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->LABELS()) { + // fill labels in authquery + return AuthQuery::Privilege::LABELS; + } 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..2fdd22b88 100644 --- a/src/query/frontend/ast/cypher_main_visitor.hpp +++ b/src/query/frontend/ast/cypher_main_visitor.hpp @@ -473,6 +473,11 @@ class CypherMainVisitor : public antlropencypher::MemgraphCypherBaseVisitor { */ antlrcpp::Any visitPrivilege(MemgraphCypher::PrivilegeContext *ctx) override; + /** + * @return AuthQuery::LabelList + */ + antlrcpp::Any visitLabelList(MemgraphCypher::LabelListContext *ctx) override; + /** * @return AuthQuery* */ diff --git a/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 b/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 index 8790b8731..d5c553f68 100644 --- a/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 +++ b/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 @@ -56,6 +56,7 @@ memgraphCypherKeyword : cypherKeyword | IDENTIFIED | ISOLATION | KAFKA + | LABELS | LEVEL | LOAD | LOCK @@ -254,10 +255,15 @@ privilege : CREATE | MODULE_READ | MODULE_WRITE | WEBSOCKET + | LABELS labels=labelList ; privilegeList : privilege ( ',' privilege )* ; +labelList : label ( ',' label )* ; + +label : ( '*' | symbolicName ) ; + showPrivileges : SHOW PRIVILEGES FOR userOrRole=userOrRoleName ; showRoleForUser : SHOW ROLE FOR user=userOrRoleName ; diff --git a/src/query/frontend/opencypher/grammar/MemgraphCypherLexer.g4 b/src/query/frontend/opencypher/grammar/MemgraphCypherLexer.g4 index 55e5d53a2..3f21cccf0 100644 --- a/src/query/frontend/opencypher/grammar/MemgraphCypherLexer.g4 +++ b/src/query/frontend/opencypher/grammar/MemgraphCypherLexer.g4 @@ -66,6 +66,7 @@ IDENTIFIED : I D E N T I F I E D ; IGNORE : I G N O R E ; ISOLATION : I S O L A T I O N ; KAFKA : K A F K A ; +LABELS : L A B E L S ; LEVEL : L E V E L ; LOAD : L O A D ; LOCK : L O C K ; diff --git a/src/query/frontend/stripped_lexer_constants.hpp b/src/query/frontend/stripped_lexer_constants.hpp index 42b7b4aeb..9e216e2c4 100644 --- a/src/query/frontend/stripped_lexer_constants.hpp +++ b/src/query/frontend/stripped_lexer_constants.hpp @@ -204,8 +204,9 @@ const trie::Trie kKeywords = {"union", "pulsar", "service_url", "version", - "websocket" - "foreach"}; + "websocket", + "foreach", + "labels"}; // Unicode codepoints that are allowed at the start of the unescaped name. const std::bitset kUnescapedNameAllowedStarts(