summaryrefslogtreecommitdiffstats
path: root/redfish-core/src
diff options
context:
space:
mode:
authorBorawski.Lukasz <lukasz.borawski@intel.com>2018-01-25 12:14:14 +0100
committerEd Tanous <ed.tanous@intel.com>2018-03-27 21:02:27 +0000
commitaecb47a427e201f685369cb2eb94dc524358ea19 (patch)
treeeacd3ec6416844e8447ff4e11454a1ef6c6dad44 /redfish-core/src
parentb8f09e1140cfa9d34fc086ea1aa9197f3bcb0801 (diff)
downloadbmcweb-aecb47a427e201f685369cb2eb94dc524358ea19.tar.gz
bmcweb-aecb47a427e201f685369cb2eb94dc524358ea19.zip
Redfish privileges
Redfish privilege authorization subsystem controlled by the privilege_registy.json configuration file. PropertyOverrides, SubordinateOverrides and ResourceURIOverrides are not yet implemented. Change-Id: I4d5670d557f4da172460ada3512e015830dab667 Signed-off-by: Borawski.Lukasz <lukasz.borawski@intel.com> Signed-off-by: Ed Tanous <ed.tanous@intel.com>
Diffstat (limited to 'redfish-core/src')
-rw-r--r--redfish-core/src/privileges.cpp202
1 files changed, 202 insertions, 0 deletions
diff --git a/redfish-core/src/privileges.cpp b/redfish-core/src/privileges.cpp
new file mode 100644
index 0000000..5fbce23
--- /dev/null
+++ b/redfish-core/src/privileges.cpp
@@ -0,0 +1,202 @@
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include "privileges.hpp"
+
+namespace redfish {
+
+boost::container::flat_map<std::string, size_t>
+ Privileges::basePrivNameToIndexMap;
+boost::container::flat_map<std::string, size_t>
+ Privileges::oemPrivNameToIndexMap;
+
+bool EntityPrivileges::isMethodAllowedForUser(const crow::HTTPMethod method,
+ const std::string& user) const {
+ // TODO: load user privileges from configuration as soon as its available
+ // now we are granting only Login.
+ auto userPrivileges = Privileges();
+ userPrivileges.setSinglePrivilege("Login");
+
+ return isMethodAllowedWithPrivileges(method, userPrivileges);
+}
+
+bool EntityPrivileges::isMethodAllowedWithPrivileges(
+ const crow::HTTPMethod method, const Privileges& userPrivileges) const {
+ if (methodToPrivilegeMap.find(method) == methodToPrivilegeMap.end()) {
+ return false;
+ }
+
+ for (auto& requiredPrivileges : methodToPrivilegeMap.at(method)) {
+ // Check if user has required base privileges
+ if (!verifyPrivileges(userPrivileges.getBasePrivilegeBitset(),
+ requiredPrivileges.getBasePrivilegeBitset())) {
+ continue;
+ }
+
+ // Check if user has required OEM privileges
+ if (!verifyPrivileges(userPrivileges.getOEMPrivilegeBitset(),
+ requiredPrivileges.getOEMPrivilegeBitset())) {
+ continue;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool EntityPrivileges::verifyPrivileges(
+ const privilegeBitset userPrivilegeBitset,
+ const privilegeBitset requiredPrivilegeBitset) const {
+ return (userPrivilegeBitset & requiredPrivilegeBitset) ==
+ requiredPrivilegeBitset;
+}
+
+EntityPrivileges PrivilegeProvider::getPrivilegesRequiredByEntity(
+ const std::string& entityUrl, const std::string& entityType) const {
+ if (privilegeRegistryJson.empty()) {
+ return EntityPrivileges();
+ }
+
+ // type from @odata.type e.g: ServiceRoot from #ServiceRoot.v1_1_1.ServiceRoot
+ auto entity = entityType.substr(entityType.find_last_of(".") + strlen("."));
+
+ for (auto mapping : privilegeRegistryJson.at("Mappings")) {
+ const auto& entityJson = mapping.find("Entity");
+ const auto& operationMapJson = mapping.find("OperationMap");
+ const auto& propertyOverridesJson = mapping.find("PropertyOverrides");
+ const auto& subordinateOverridesJson = mapping.find("SubordinateOverrides");
+ const auto& resourceURIOverridesJson = mapping.find("ResourceURIOverrides");
+
+ if (entityJson == mapping.end() || operationMapJson == mapping.end()) {
+ return EntityPrivileges();
+ }
+
+ if (entityJson->is_string() && entity == entityJson.value()) {
+ auto entityPrivileges = EntityPrivileges();
+
+ if (!parseOperationMap(operationMapJson.value(), entityPrivileges)) {
+ return EntityPrivileges();
+ }
+
+ if (propertyOverridesJson != mapping.end()) {
+ // TODO: implementation comes in next patch-sets
+ }
+ if (subordinateOverridesJson != mapping.end()) {
+ // TODO: implementation comes in next patch-sets
+ }
+ if (resourceURIOverridesJson != mapping.end()) {
+ // TODO: implementation comes in next patch-sets
+ }
+
+ return entityPrivileges;
+ }
+ }
+ return EntityPrivileges();
+}
+
+bool PrivilegeProvider::parseOperationMap(
+ const nlohmann::json& operationMap,
+ EntityPrivileges& entityPrivileges) const {
+ for (auto it = operationMap.begin(); it != operationMap.end(); ++it) {
+ const std::string& method = it.key();
+ const nlohmann::json& privilegesForMethod = it.value();
+
+ for (const auto& privilegeOr : privilegesForMethod) {
+ const auto& privilegeJson = privilegeOr.find("Privilege");
+
+ if (privilegeJson == privilegeOr.end()) {
+ return false;
+ }
+ auto privileges = Privileges();
+
+ for (auto& privilegeAnd : privilegeJson.value()) {
+ if (!privilegeAnd.is_string()) {
+ return false;
+ }
+ privileges.setSinglePrivilege(privilegeAnd);
+ }
+ entityPrivileges.addPrivilegesRequiredByMethod(operator"" _method(
+ method.c_str(),
+ method.size()),
+ privileges);
+ }
+ }
+ return true;
+}
+
+bool PrivilegeProvider::loadPrivilegesFromFile(
+ std::ifstream& privilegeRegistryFile) {
+ privilegeRegistryJson =
+ nlohmann::json::parse(privilegeRegistryFile, nullptr, false);
+
+ if (!privilegeRegistryHasRequiredFields()) {
+ return false;
+ }
+
+ const nlohmann::json& basePrivilegesUsed =
+ privilegeRegistryJson.at("PrivilegesUsed");
+ if (basePrivilegesUsed.size() == 0) {
+ return false;
+ }
+ if (!fillPrivilegeMap(basePrivilegesUsed,
+ Privileges::basePrivNameToIndexMap)) {
+ return false;
+ }
+
+ const nlohmann::json& oemPrivilegesUsed =
+ privilegeRegistryJson.at("OEMPrivilegesUsed");
+ if (!fillPrivilegeMap(oemPrivilegesUsed, Privileges::oemPrivNameToIndexMap)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool PrivilegeProvider::privilegeRegistryHasRequiredFields() const {
+ if (privilegeRegistryJson.is_discarded() ||
+ privilegeRegistryJson.find("@Redfish.Copyright") ==
+ privilegeRegistryJson.end() ||
+ privilegeRegistryJson.find("@odata.type") ==
+ privilegeRegistryJson.end() ||
+ privilegeRegistryJson.find("Id") == privilegeRegistryJson.end() ||
+ privilegeRegistryJson.find("Name") == privilegeRegistryJson.end() ||
+ privilegeRegistryJson.find("Mappings") == privilegeRegistryJson.end() ||
+ privilegeRegistryJson.find("PrivilegesUsed") ==
+ privilegeRegistryJson.end() ||
+ privilegeRegistryJson.find("OEMPrivilegesUsed") ==
+ privilegeRegistryJson.end()) {
+ return false;
+ }
+ return true;
+}
+
+bool PrivilegeProvider::fillPrivilegeMap(
+ const nlohmann::json& privilegesUsed,
+ boost::container::flat_map<std::string, size_t>& privilegeToIndexMap)
+ const {
+ privilegeToIndexMap.clear();
+ for (auto& privilege : privilegesUsed) {
+ if (privilegeToIndexMap.size() < MAX_PRIVILEGE_COUNT) {
+ if (!privilege.is_string()) {
+ return false;
+ }
+ privilegeToIndexMap.insert(std::pair<std::string, size_t>(
+ privilege.get<std::string>(), privilegeToIndexMap.size()));
+ }
+ }
+ return true;
+}
+
+} // namespace redfish
OpenPOWER on IntegriCloud