blob: 4b5f61ee3b1aeec6e1b88e511e2cc1db032d37fa [file] [log] [blame]
#ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_AUTHZ_REDFISH_AUTHORIZER_H_
#define THIRD_PARTY_MILOTIC_EXTERNAL_CC_AUTHZ_REDFISH_AUTHORIZER_H_
#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <unordered_set>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/synchronization/mutex.h"
#include "authorizer_enums.h"
#include "nlohmann/json.hpp"
#include "config_parser.h"
#include "override.h"
#include "redfish_entity_trie.h"
#include "redfish_privileges.h"
#include "subscription_tracker.h"
namespace milotic::authz {
using ::ecclesia::Operation;
constexpr std::array<Operation, static_cast<int>(Operation::kUndefined)>
all_operations = {
Operation::kGet, Operation::kHead, Operation::kPatch,
Operation::kPut, Operation::kDelete, Operation::kPost,
};
struct AuthorizerOptions {
// The configuration of the authorizer; the schema is defined by
// |third_party/milotic/external/auth_config/schema|.
std::string configuration_path;
// The platform specific configuration of the authorizer; the schema is
// defined by
// |third_party/milotic/external/auth_config/platform_config_schema|.
std::string platform_configuration_path;
// The folder where base privileges are stored
std::string base_privileges_folder;
// The path to the non-standard pattern to resource configuration.
// The use case of this configuration is rare.
// Please contact the 3M team (nanzhou@, edwarddl@) for consultation.
std::string pattern_entity_overrides_path;
// The absolute path where Offline Node Entities file is. (Can be left empty)
// This should be the file installed on the node during RRI
// For more information see go/node-entities-api
std::string offline_node_entities_path;
// The path where the Google Machine Identity is. If left empty, machines are
// automatically assumed to not be in HWOPS. For more information see
// go/google-machine-identity-token
std::string google_machine_identity_path;
// Set to true to maximize debug logs.
bool verbose = true;
};
// An implementation of the Redfish authorization model. It supports runtime
// configuration reloading, OEM privileges, OEM roles, and privilege overrides.
// The class is thread-safe.
class RedfishAuthorizer {
public:
// EntityTypeIndex -> List of RedfishPrivileges for that entity type
using EntityPrivilegesMappings =
std::vector<std::vector<std::vector<RedfishPrivileges>>>;
// EntityTypeIndex -> List of Overrides for that entity type
using OverrideMappings = std::vector<std::vector<std::shared_ptr<Override>>>;
RedfishAuthorizer();
explicit RedfishAuthorizer(const AuthorizerOptions& options);
RedfishAuthorizer(const nlohmann::json& registry_json,
const nlohmann::json& configuration_json);
virtual ~RedfishAuthorizer() = default;
// Parse the Auth Config file into json
nlohmann::json ParseAuthConfig() const;
// Find the path to the Base Privilege Registry
std::string FindBasePrivilegeRegistryPath(
const nlohmann::json& configuration_json) const;
void ParseSubscriptionLimit(const nlohmann::json& configuration_json);
// Reloads the authorization configuration.
void ReloadConfiguration();
// Reloads the authorization configuration from the given path.
// Useful when you want to reload the configuration from a different path.
void ReloadConfiguration(const std::string& configuration_path);
void SetBasePrivilegesFolder(std::string_view base_privileges_folder);
// Returns the peer's redfish role. Returns an empty string if the peer is not
// authorized.
std::string GetPeerRedfishRole(const PeerSpiffeIdentity& peer) const;
// Returns the sample rate limit for the peer role.
uint64_t GetSampleRateLimit(const std::string& peer_role) const;
std::unordered_set<std::string> GetPeerRedfishPrivileges(
const PeerSpiffeIdentity& peer) const {
return authz_configuration_.GetPeerRedfishPrivileges(peer);
}
std::unordered_set<std::string> GetRedfishPrivileges(
const std::string& role) const {
return authz_configuration_.GetRedfishPrivileges(role);
}
void LoadRedfishEntityTrie();
ecclesia::ResourceEntity GetEntityTypeFromRedfishUri(
std::string_view uri) const;
// This method doesn't support any override.
virtual bool IsPeerAuthorized(ecclesia::ResourceEntity resource_entity,
ecclesia::Operation operation,
const RedfishPrivileges& peer_privileges) const;
// These methods support Resource and Subordinate Overrides but not Property
// Overrides
virtual bool IsPeerAuthorized(std::string_view uri,
ecclesia::Operation operation,
const RedfishPrivileges& peer_privileges) const;
// Get the Redfish Privilege Registry for current authorizer
// This output follows the DMTF Privilege Registry schema
// http://redfish.dmtf.org/schemas/v1/PrivilegeRegistry.v1_1_4.json#/definitions/PrivilegeRegistry
nlohmann::json::object_t GetRedfishPrivilegeRegistry() const;
// Records a new subscription and returns OK only if this subscription is
// within the limit.
absl::Status RecordNewSubscription(const PeerSpiffeIdentity& peer);
// Records a new unsubscription of the given client.
absl::Status RecordNewUnsubscription(const PeerSpiffeIdentity& peer);
int64_t GetSubscriptionLimit(const PeerSpiffeIdentity& peer) {
return subscription_tracker_.GetSubscriptionLimit(peer);
}
std::size_t GetNodeIndexInPatternArray(std::string_view uri) const {
return redfish_entity_trie_.GetNodeIndexInPatternArray(uri);
}
// TODO(nanzhou): add property override support.
protected:
absl::flat_hash_map<ecclesia::Operation, std::vector<RedfishPrivileges>>
GetOperationMapFromJson(const nlohmann::json& override_operation_map) const;
std::vector<RedfishPrivileges> GetPrivilegesArrFromJsonArr(
const nlohmann::json::array_t& operation_privilege_arr_json) const;
std::vector<std::string> GetTargetsArrFromJsonArr(
const nlohmann::json::array_t& targets_arr_json) const;
void ReconstructPrivilegeRegistry(const std::string& base_registry_path,
const nlohmann::json::array_t* oem_mappings,
const nlohmann::json* override_mappings,
const nlohmann::json& platform_config_json);
void ReconstructPrivilegeRegistry(
const nlohmann::json::array_t* registry_mappings,
const nlohmann::json::array_t* oem_mappings,
const nlohmann::json* override_mappings,
const nlohmann::json::array_t* additional_subtree_mappings,
const nlohmann::json::array_t* platform_subtree_mappings);
void ApplyOemMappings(const nlohmann::json::array_t& oem_mappings,
EntityPrivilegesMappings& entity_privileges_mappings);
void ApplySubordinateOverrides(
const nlohmann::json::array_t* subordinate_overrides,
OverrideMappings& new_override_mappings);
void ApplySubordinateOverridesToEntity(
const nlohmann::json::array_t* subordinate_overrides,
ecclesia::ResourceEntity entity, OverrideMappings& new_override_mappings);
void ApplyResourceOverrides(const nlohmann::json::array_t* resource_overrides,
OverrideMappings& new_override_mappings);
void ApplyResourceOverridesToEntity(
const nlohmann::json::array_t* resource_overrides,
ecclesia::ResourceEntity entity, OverrideMappings& new_override_mappings);
void ApplyOverrideMappings(const nlohmann::json& override_mappings_json,
OverrideMappings& new_override_mappings);
void ParseAdditionalSubtreeMappings(
std::vector<SubtreePrivilegeMapping>& additional_subtree_mappings,
const nlohmann::json& additional_subtree_mappings_json);
void ResetEntityPrivilegesMappings();
void SetPrivileges(EntityPrivilegesMappings&& new_entity_privileges_mappings,
OverrideMappings&& new_override_mappings);
void AppendPrivilege(const RedfishPrivileges& privileges,
ecclesia::ResourceEntity resource_entity,
ecclesia::Operation operation,
EntityPrivilegesMappings& entity_privileges_mappings);
virtual std::vector<RedfishPrivileges> GetRequiredPrivileges(
ecclesia::ResourceEntity resource_entity,
ecclesia::Operation operation) const;
virtual std::vector<std::shared_ptr<Override>> GetOverrides(
ecclesia::ResourceEntity resource_entity) const;
static EntityPrivilegesMappings DefaultEntityPrivilegesMappings();
static OverrideMappings DefaultOverrideMappings();
nlohmann::json::array_t RedfishPrivilegeRegistryMappings() const;
AuthorizerOptions options_;
mutable absl::Mutex mutex_;
// redfish_entity_trie_ is thread-safe for subtree mapping modification.
// InsertUri is NOT THREAD SAFE, but it is never called after initialization.
RedfishEntityTrie redfish_entity_trie_;
AuthzConfiguration authz_configuration_;
EntityPrivilegesMappings entity_privileges_mappings_ ABSL_GUARDED_BY(mutex_);
OverrideMappings override_mappings_ ABSL_GUARDED_BY(mutex_);
SubscriptionTracker subscription_tracker_;
};
} // namespace milotic::authz
#endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_AUTHZ_REDFISH_AUTHORIZER_H_