From ca95ac253bc0339f10dbea895189d3e713fd9924 Mon Sep 17 00:00:00 2001 From: Boris Tasevski Date: Tue, 5 Jul 2022 16:36:04 +0200 Subject: [PATCH 1/5] added LabelPermission class to model.hpp; added dummy implementation to model.cpp --- src/auth/models.cpp | 80 +++++++++++++++++++++++++++++++++++++-------- src/auth/models.hpp | 46 ++++++++++++++++++++++++-- 2 files changed, 111 insertions(+), 15 deletions(-) diff --git a/src/auth/models.cpp b/src/auth/models.cpp index 54bf24da6..2a45735c8 100644 --- a/src/auth/models.cpp +++ b/src/auth/models.cpp @@ -98,11 +98,11 @@ 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); +Permissions::Permissions(uint64_t grants, uint64_t denies) : grants_(grants & (~denies)), denies_(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); } PermissionLevel Permissions::Has(Permission permission) const { @@ -183,10 +183,57 @@ bool operator==(const Permissions &first, const Permissions &second) { bool operator!=(const Permissions &first, const Permissions &second) { return !(first == second); } +//////////////////////////////// +LabelPermissions::LabelPermissions(const std::vector &grants, const std::vector &denies) + : grants_(grants), denies_(denies) {} + +PermissionLevel LabelPermissions::Has(LabelPermissions permission) const { + // Check for the deny first because it has greater priority than a grant. + return PermissionLevel::NEUTRAL; +} + +void LabelPermissions::Grant(LabelPermissions permission) {} + +void LabelPermissions::Revoke(LabelPermissions permission) {} + +void LabelPermissions::Deny(LabelPermissions permission) {} + +std::vector LabelPermissions::GetGrants() const { return grants_; } + +std::vector LabelPermissions::GetDenies() const { return denies_; } + +nlohmann::json LabelPermissions::Serialize() const { + nlohmann::json data = nlohmann::json::object(); + data["grants"] = grants_; + data["denies"] = denies_; + return data; +} + +LabelPermissions LabelPermissions::Deserialize(const nlohmann::json &data) { + if (!data.is_object()) { + throw AuthException("Couldn't load permissions data!"); + } + if (!data["grants"].is_number_unsigned() || !data["denies"].is_number_unsigned()) { + throw AuthException("Couldn't load permissions data!"); + } + + return LabelPermissions(data["grants"], data["denies"]); +} + +std::vector LabelPermissions::grants() const { return grants_; } +std::vector LabelPermissions::denies() const { return denies_; } + +bool operator==(const LabelPermissions &first, const LabelPermissions &second) { + return first.grants() == second.grants() && first.denies() == second.denies(); +} + +bool operator!=(const LabelPermissions &first, const LabelPermissions &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 LabelPermissions &labelPermissions) + : rolename_(utils::ToLowerCase(rolename)), permissions_(permissions), labelPermissions_(labelPermissions) {} const std::string &Role::rolename() const { return rolename_; } const Permissions &Role::permissions() const { return permissions_; } @@ -196,6 +243,7 @@ nlohmann::json Role::Serialize() const { nlohmann::json data = nlohmann::json::object(); data["rolename"] = rolename_; data["permissions"] = permissions_.Serialize(); + data["labelPermissions"] = labelPermissions_.Serialize(); return data; } @@ -207,7 +255,8 @@ 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 labelPermissions = LabelPermissions::Deserialize(data["labelPermissions"]); + return {data["rolename"], permissions, labelPermissions}; } bool operator==(const Role &first, const Role &second) { @@ -216,8 +265,12 @@ bool operator==(const Role &first, const Role &second) { 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 LabelPermissions &labelPermissions) + : username_(utils::ToLowerCase(username)), + password_hash_(password_hash), + permissions_(permissions), + labelPermissions_(labelPermissions) {} bool User::CheckPassword(const std::string &password) { if (password_hash_.empty()) return true; @@ -260,8 +313,8 @@ 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_; } @@ -295,7 +348,8 @@ 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 labelPermissions = LabelPermissions::Deserialize(data["labelPermissions"]); + return {data["username"], data["password_hash"], permissions, labelPermissions}; } bool operator==(const User &first, const User &second) { diff --git a/src/auth/models.hpp b/src/auth/models.hpp index 0f01c0a39..464d4f829 100644 --- a/src/auth/models.hpp +++ b/src/auth/models.hpp @@ -88,16 +88,52 @@ bool operator==(const Permissions &first, const Permissions &second); bool operator!=(const Permissions &first, const Permissions &second); +class LabelPermissions final { + public: + explicit LabelPermissions(const std::vector &grants = {}, const std::vector &denies = {}); + + PermissionLevel Has(LabelPermissions permission) const; + + void Grant(LabelPermissions permission); + + void Revoke(LabelPermissions permission); + + void Deny(LabelPermissions permission); + + std::vector GetGrants() const; + + std::vector GetDenies() const; + + nlohmann::json Serialize() const; + + /// @throw AuthException if unable to deserialize. + static LabelPermissions Deserialize(const nlohmann::json &data); + + std::vector grants() const; + std::vector denies() const; + + private: + std::vector grants_{}; + std::vector denies_{}; +}; + +bool operator==(const LabelPermissions &first, const LabelPermissions &second); + +bool operator!=(const LabelPermissions &first, const LabelPermissions &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 LabelPermissions &labelPermissions); const std::string &rolename() const; const Permissions &permissions() const; Permissions &permissions(); + const LabelPermissions &labelPermissions() const; + LabelPermissions &labelPermissions(); + nlohmann::json Serialize() const; /// @throw AuthException if unable to deserialize. @@ -108,6 +144,7 @@ class Role final { private: std::string rolename_; Permissions permissions_; + LabelPermissions labelPermissions_; }; bool operator==(const Role &first, const Role &second); @@ -117,7 +154,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 LabelPermissions &labelPermissions); /// @throw AuthException if unable to verify the password. bool CheckPassword(const std::string &password); @@ -136,6 +174,9 @@ class User final { const Permissions &permissions() const; Permissions &permissions(); + const LabelPermissions &labelPermissions() const; + Permissions &labelPermissions(); + const Role *role() const; nlohmann::json Serialize() const; @@ -149,6 +190,7 @@ class User final { std::string username_; std::string password_hash_; Permissions permissions_; + LabelPermissions labelPermissions_; std::optional role_; }; From 20da67358337e39b98f521f5cbe3e8119e4be053 Mon Sep 17 00:00:00 2001 From: Boris Tasevski Date: Wed, 6 Jul 2022 09:45:21 +0200 Subject: [PATCH 2/5] implement LabelPermissions specific methods --- src/auth/models.cpp | 68 +++++++++++++++++++++++++++++++++------------ src/auth/models.hpp | 25 +++++++++-------- 2 files changed, 63 insertions(+), 30 deletions(-) diff --git a/src/auth/models.cpp b/src/auth/models.cpp index 2a45735c8..153303e0c 100644 --- a/src/auth/models.cpp +++ b/src/auth/models.cpp @@ -98,12 +98,7 @@ std::string PermissionLevelToString(PermissionLevel level) { } } -Permissions::Permissions(uint64_t grants, uint64_t denies) : grants_(grants & (~denies)), denies_(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); -} +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,24 +178,62 @@ bool operator==(const Permissions &first, const Permissions &second) { bool operator!=(const Permissions &first, const Permissions &second) { return !(first == second); } -//////////////////////////////// -LabelPermissions::LabelPermissions(const std::vector &grants, const std::vector &denies) +LabelPermissions::LabelPermissions(const std::unordered_set &grants, + const std::unordered_set &denies) : grants_(grants), denies_(denies) {} -PermissionLevel LabelPermissions::Has(LabelPermissions permission) const { - // Check for the deny first because it has greater priority than a grant. +PermissionLevel LabelPermissions::Has(const std::string &permission) const { + if (denies_.find(permission) != denies_.end()) { + return PermissionLevel::DENY; + } + + if (grants_.find(permission) != denies_.end()) { + return PermissionLevel::GRANT; + } + return PermissionLevel::NEUTRAL; } -void LabelPermissions::Grant(LabelPermissions permission) {} +void LabelPermissions::Grant(const std::string &permission) { + auto deniedPermissionIter = denies_.find(permission); -void LabelPermissions::Revoke(LabelPermissions permission) {} + if (deniedPermissionIter != denies_.end()) { + denies_.erase(deniedPermissionIter); + } -void LabelPermissions::Deny(LabelPermissions permission) {} + if (grants_.find(permission) == grants_.end()) { + grants_.insert(permission); + } +} -std::vector LabelPermissions::GetGrants() const { return grants_; } +void LabelPermissions::Revoke(const std::string &permission) { + auto deniedPermissionIter = denies_.find(permission); + auto grantedPermissionIter = grants_.find(permission); -std::vector LabelPermissions::GetDenies() const { return denies_; } + if (deniedPermissionIter != denies_.end()) { + denies_.erase(deniedPermissionIter); + } + + if (grantedPermissionIter != grants_.end()) { + grants_.erase(grantedPermissionIter); + } +} + +void LabelPermissions::Deny(const std::string &permission) { + auto grantedPermissionIter = grants_.find(permission); + + if (grantedPermissionIter != grants_.end()) { + grants_.erase(grantedPermissionIter); + } + + if (denies_.find(permission) == denies_.end()) { + denies_.insert(permission); + } +} + +std::unordered_set LabelPermissions::GetGrants() const { return grants_; } + +std::unordered_set LabelPermissions::GetDenies() const { return denies_; } nlohmann::json LabelPermissions::Serialize() const { nlohmann::json data = nlohmann::json::object(); @@ -220,15 +253,14 @@ LabelPermissions LabelPermissions::Deserialize(const nlohmann::json &data) { return LabelPermissions(data["grants"], data["denies"]); } -std::vector LabelPermissions::grants() const { return grants_; } -std::vector LabelPermissions::denies() const { return denies_; } +std::unordered_set LabelPermissions::grants() const { return grants_; } +std::unordered_set LabelPermissions::denies() const { return denies_; } bool operator==(const LabelPermissions &first, const LabelPermissions &second) { return first.grants() == second.grants() && first.denies() == second.denies(); } bool operator!=(const LabelPermissions &first, const LabelPermissions &second) { return !(first == second); } -//////////////////////////////// Role::Role(const std::string &rolename) : rolename_(utils::ToLowerCase(rolename)) {} diff --git a/src/auth/models.hpp b/src/auth/models.hpp index 464d4f829..b3faee63e 100644 --- a/src/auth/models.hpp +++ b/src/auth/models.hpp @@ -10,6 +10,7 @@ #include #include +#include #include @@ -90,31 +91,31 @@ bool operator!=(const Permissions &first, const Permissions &second); class LabelPermissions final { public: - explicit LabelPermissions(const std::vector &grants = {}, const std::vector &denies = {}); + explicit LabelPermissions(const std::unordered_set &grants = {}, + const std::unordered_set &denies = {}); - PermissionLevel Has(LabelPermissions permission) const; + PermissionLevel Has(const std::string &permission) const; - void Grant(LabelPermissions permission); + void Grant(const std::string &permission); - void Revoke(LabelPermissions permission); + void Revoke(const std::string &permission); - void Deny(LabelPermissions permission); + void Deny(const std::string &permission); - std::vector GetGrants() const; - - std::vector GetDenies() const; + std::unordered_set GetGrants() const; + std::unordered_set GetDenies() const; nlohmann::json Serialize() const; /// @throw AuthException if unable to deserialize. static LabelPermissions Deserialize(const nlohmann::json &data); - std::vector grants() const; - std::vector denies() const; + std::unordered_set grants() const; + std::unordered_set denies() const; private: - std::vector grants_{}; - std::vector denies_{}; + std::unordered_set grants_{}; + std::unordered_set denies_{}; }; bool operator==(const LabelPermissions &first, const LabelPermissions &second); From d657a77a57e4d1b31816c31b31854da8566dfc32 Mon Sep 17 00:00:00 2001 From: Boris Tasevski Date: Wed, 6 Jul 2022 11:49:00 +0200 Subject: [PATCH 3/5] initial functionalities for users and roles implemented --- src/auth/models.cpp | 29 +++++++++++++++++++++++++++-- src/auth/models.hpp | 3 ++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/auth/models.cpp b/src/auth/models.cpp index 153303e0c..7bc998215 100644 --- a/src/auth/models.cpp +++ b/src/auth/models.cpp @@ -8,7 +8,10 @@ #include "auth/models.hpp" +#include +#include #include +#include #include @@ -292,7 +295,8 @@ Role Role::Deserialize(const nlohmann::json &data) { } 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.labelPermissions_ == second.labelPermissions_; } User::User(const std::string &username) : username_(utils::ToLowerCase(username)) {} @@ -351,11 +355,31 @@ Permissions User::GetPermissions() const { return permissions_; } +LabelPermissions User::GetLabelPermissions() const { + if (role_) { + std::unordered_set resultGrants; + + std::set_union(labelPermissions_.grants().begin(), labelPermissions_.grants().end(), + role_->labelPermissions().grants().begin(), role_->labelPermissions().grants().end(), + std::inserter(resultGrants, resultGrants.begin())); + + std::unordered_set resultDenies; + + std::set_union(labelPermissions_.denies().begin(), labelPermissions_.denies().end(), + role_->labelPermissions().denies().begin(), role_->labelPermissions().denies().end(), + std::inserter(resultDenies, resultDenies.begin())); + } + return labelPermissions_; +} + const std::string &User::username() const { return username_; } const Permissions &User::permissions() const { return permissions_; } Permissions &User::permissions() { return permissions_; } +const LabelPermissions &User::labelPermissions() const { return labelPermissions_; } +LabelPermissions &User::labelPermissions() { return labelPermissions_; } + const Role *User::role() const { if (role_.has_value()) { return &role_.value(); @@ -386,6 +410,7 @@ User User::Deserialize(const nlohmann::json &data) { 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.labelPermissions_ == second.labelPermissions_ && + first.role_ == second.role_; } } // namespace memgraph::auth diff --git a/src/auth/models.hpp b/src/auth/models.hpp index b3faee63e..ec71e8666 100644 --- a/src/auth/models.hpp +++ b/src/auth/models.hpp @@ -169,6 +169,7 @@ class User final { void ClearRole(); Permissions GetPermissions() const; + LabelPermissions GetLabelPermissions() const; const std::string &username() const; @@ -176,7 +177,7 @@ class User final { Permissions &permissions(); const LabelPermissions &labelPermissions() const; - Permissions &labelPermissions(); + LabelPermissions &labelPermissions(); const Role *role() const; From d626b49cc40339d3c7621da2542455118f7caec8 Mon Sep 17 00:00:00 2001 From: Boris Tasevski Date: Wed, 6 Jul 2022 15:44:28 +0200 Subject: [PATCH 4/5] no return fixed; removed explicit keyword from LabelPermissions --- src/auth/models.cpp | 2 ++ src/auth/models.hpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/auth/models.cpp b/src/auth/models.cpp index 7bc998215..3825cf629 100644 --- a/src/auth/models.cpp +++ b/src/auth/models.cpp @@ -368,6 +368,8 @@ LabelPermissions User::GetLabelPermissions() const { std::set_union(labelPermissions_.denies().begin(), labelPermissions_.denies().end(), role_->labelPermissions().denies().begin(), role_->labelPermissions().denies().end(), std::inserter(resultDenies, resultDenies.begin())); + + return {resultGrants, resultDenies}; } return labelPermissions_; } diff --git a/src/auth/models.hpp b/src/auth/models.hpp index ec71e8666..56e6fb9ea 100644 --- a/src/auth/models.hpp +++ b/src/auth/models.hpp @@ -91,8 +91,8 @@ bool operator!=(const Permissions &first, const Permissions &second); class LabelPermissions final { public: - explicit LabelPermissions(const std::unordered_set &grants = {}, - const std::unordered_set &denies = {}); + LabelPermissions(const std::unordered_set &grants = {}, + const std::unordered_set &denies = {}); PermissionLevel Has(const std::string &permission) const; From ace8608dd7d0d3eea79e77aa6915c41099c4ee46 Mon Sep 17 00:00:00 2001 From: Boris Tasevski Date: Fri, 8 Jul 2022 10:22:49 +0200 Subject: [PATCH 5/5] add missing methods to Role; Removed wrong check --- src/auth/models.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/auth/models.cpp b/src/auth/models.cpp index 3825cf629..5e4fb9ed7 100644 --- a/src/auth/models.cpp +++ b/src/auth/models.cpp @@ -249,11 +249,8 @@ LabelPermissions LabelPermissions::Deserialize(const nlohmann::json &data) { if (!data.is_object()) { throw AuthException("Couldn't load permissions data!"); } - if (!data["grants"].is_number_unsigned() || !data["denies"].is_number_unsigned()) { - throw AuthException("Couldn't load permissions data!"); - } - return LabelPermissions(data["grants"], data["denies"]); + return {data["grants"], data["denies"]}; } std::unordered_set LabelPermissions::grants() const { return grants_; } @@ -274,6 +271,9 @@ const std::string &Role::rolename() const { return rolename_; } const Permissions &Role::permissions() const { return permissions_; } Permissions &Role::permissions() { return permissions_; } +const LabelPermissions &Role::labelPermissions() const { return labelPermissions_; } +LabelPermissions &Role::labelPermissions() { return labelPermissions_; } + nlohmann::json Role::Serialize() const { nlohmann::json data = nlohmann::json::object(); data["rolename"] = rolename_;