| #ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_AUTHZ_REDFISH_ENTITY_TRIE_H_ |
| #define THIRD_PARTY_MILOTIC_EXTERNAL_CC_AUTHZ_REDFISH_ENTITY_TRIE_H_ |
| |
| #include <cstddef> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <vector> |
| |
| #include "absl/base/thread_annotations.h" |
| #include "absl/container/flat_hash_set.h" |
| #include "absl/status/status.h" |
| #include "absl/strings/substitute.h" |
| #include "absl/synchronization/mutex.h" |
| #include "authorizer_enums.h" |
| #include "redfish_entity_trie_node.h" |
| #include "redfish_privileges.h" |
| #include "redfish_subtree_privileges_trie_node.h" |
| |
| namespace milotic::authz { |
| |
| /* |
| Redfish Entity Trie intended to be used as a method to obtain an entity type |
| when given a redfish path regardless of if wildcards are inputted. |
| |
| Sample usage: |
| |
| "I know that /redfish/v1/Chassis/{ChassisId} has an entity type Chassis from the |
| schema". This can be entered using |
| trie.InsertUri("/redfish/v1/Chassis/{ChassisId}", "Chassis"); |
| |
| "I want to figure out the entity type for /redfish/v1/Chassis/test" |
| This can be found by |
| trie.GetEntityType("/redfish/v1/Chassis/test") -> "Chassis" |
| |
| Another usage of this trie is to obtain all the privileges that is able to |
| access this URI via subtree mapping. |
| |
| "I want privilege 'ChassisXOwner' to be able to access every URI with prefix |
| '/redfish/v1/Chassis/ChassisX'" |
| |
| This can be entered using |
| trie.SetSubtreePrivilegeMappings({{"/redfish/v1/Chassis/ChassisX", |
| "ChassisXOwner"}}); |
| |
| "I want to see what additional OEM privileges can access |
| '/redfish/v1/Chassis/ChassisX/Sensors/sensorY" |
| |
| This can be found by |
| trie.GetAdditionalSubtreePrivileges("/redfish/v1/Chassis/ChassisX/Sensors/sensorY"); |
| |
| |
| ReplaceSubtreeMappings is done instead of exposing AddSubtreeMapping to public |
| and allowing modification after initialization to subtree privileges due to |
| duplication issues that can occur. If we had exposed AddSubtreeMapping to |
| public, then there are orders in which duplications can occur in subtrees that |
| make it hard for deduplication to occur. |
| |
| AddPrivilegeForSubtree("/redfish/v1", "SubtreePrivileges1"); |
| AddPrivilegeForSubtree("/redfish/v1/Chassis", "SubtreePrivileges1"); |
| |
| When performing the queries above, the second AddPrivilege doesn't mean |
| anything, so we ignore the second command as we see a duplicate when traversing |
| down the trie. |
| |
| However if we perform |
| |
| AddPrivilegeForSubtree("/redfish/v1/Chassis", "SubtreePrivileges1"); |
| AddPrivilegeForSubtree("/redfish/v1", "SubtreePrivileges1"); |
| |
| Then, it is impossible to tell without iterating through the rest of the trie |
| that a duplication exists. The current workaround is to sort it first so we can |
| always find the duplicates, but an alternative that was deemed to complex for |
| the first iteration is lazy propagation. |
| |
| |
| NOTE: This class is only partially thread safe. Please check the method's |
| documentation to see if that method is thread safe or not |
| */ |
| |
| // Struct to hold information regarding individual subtree privilege mapping |
| struct SubtreePrivilegeMapping { |
| std::string url; |
| ecclesia::Operation operation; |
| RedfishPrivileges privileges; |
| |
| bool operator<(const SubtreePrivilegeMapping& other) const { |
| return url < other.url; |
| } |
| |
| std::string ToString() const { |
| return absl::Substitute("URL: $0, Operation: $1 has privileges: $2", url, |
| ::ecclesia::OperationToString(operation), |
| privileges.GetDebugString()); |
| } |
| }; |
| |
| class RedfishEntityTrie { |
| public: |
| RedfishEntityTrie(); |
| |
| // Inserts a URI into the entity trie. NOT THREAD SAFE. |
| void InsertUri(std::string_view uri, ecclesia::ResourceEntity entity_tag, |
| std::size_t node_index_in_pattern_array); |
| |
| // Supports normal and fragmented URIs. |
| // THREAD SAFE IF InsertUri IS NOT CALLED IN PARALLEL |
| // TODO (edwarddl): Support ignoring query parameters |
| ecclesia::ResourceEntity GetEntityType(std::string_view uri) const; |
| |
| // THREAD SAFE after all InsertUri is done. |
| // Returns the index of the node in the pattern array. If the URI is not |
| // found, returns std::numeric_limits<std::size_t>::max() |
| std::size_t GetNodeIndexInPatternArray(std::string_view uri) const; |
| |
| // Replace subtree mappings for trie. This will clear the current mappings and |
| // replace them with what is passed into the method. THREAD SAFE |
| // TODO: Consider removing this if we ever decide to implement lazy |
| // propagation |
| void ReplaceSubtreePrivilegeMappings( |
| std::vector<SubtreePrivilegeMapping>&& subtree_privilege_mappings); |
| |
| // Get privileges that can access to uri via additional subtree mappings |
| // THREAD SAFE |
| absl::flat_hash_set<RedfishPrivileges> GetAdditionalSubtreePrivileges( |
| std::string_view uri, const ecclesia::Operation& operation) const; |
| |
| private: |
| const internal::RedfishEntityTrieNode* GetTrieNode( |
| std::string_view uri) const; |
| // We only support setting and removing subtree mappings. We don't support |
| // individual additions. |
| absl::Status AddSubtreeMapping( |
| SubtreePrivilegeMapping&& subtree_privilege_mapping) |
| ABSL_SHARED_LOCKS_REQUIRED(subtree_privileges_mutex_); |
| |
| mutable absl::Mutex subtree_privileges_mutex_; |
| std::unique_ptr<internal::RedfishEntityTrieNode> entity_trie_root_; |
| |
| std::unique_ptr<internal::RedfishSubtreePrivilegesTrieNode> |
| subtree_privileges_trie_root_ ABSL_GUARDED_BY(subtree_privileges_mutex_); |
| }; |
| } // namespace milotic::authz |
| |
| #endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_AUTHZ_REDFISH_ENTITY_TRIE_H_ |