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>
diff --git a/redfish-core/ut/privileges_test.cpp b/redfish-core/ut/privileges_test.cpp
new file mode 100644
index 0000000..9d0d156
--- /dev/null
+++ b/redfish-core/ut/privileges_test.cpp
@@ -0,0 +1,526 @@
+#include "privileges.hpp"
+#include <fstream>
+#include <string>
+#include "nlohmann/json.hpp"
+#include "gmock/gmock.h"
+
+using namespace redfish;
+
+class PrivilegeTest : public testing::Test {
+ protected:
+ nlohmann::json privilegeRegistryMockJson;
+
+ std::vector<std::string> expectedBasePrivileges{
+ "Login", "ConfigureManager", "ConfigureUsers", "ConfigureComponents",
+ "ConfigureSelf"};
+
+ std::vector<std::string> expectedOEMPrivileges{"OEMRoot", "OEMDummy"};
+
+ PrivilegeTest() {
+ crow::logger::setLogLevel(crow::LogLevel::CRITICAL);
+
+ std::ofstream privilegeRegistryMockOfstream("privilege_registry_mock.json");
+ privilegeRegistryMockJson = nlohmann::json::parse(
+ "{\
+ \"@Redfish.Copyright\": \"Dummy copyright\",\
+ \"@odata.type\": \"#PrivilegeRegistry.v1_0_0.PrivilegeRegistry\",\
+ \"Id\": \"Dummy id\",\
+ \"Name\": \"Dummy name\",\
+ \"PrivilegesUsed\": [\
+ \"Login\",\
+ \"ConfigureManager\",\
+ \"ConfigureUsers\",\
+ \"ConfigureComponents\",\
+ \"ConfigureSelf\"],\
+ \"OEMPrivilegesUsed\": [\
+ \"OEMRoot\",\
+ \"OEMDummy\"],\
+ \"Mappings\": [\
+ {\
+ \"Entity\": \"TestEntity\",\
+ \"OperationMap\": {\
+ \"GET\": [\
+ {\
+ \"Privilege\": [\
+ \"Login\"\
+ ]\
+ }\
+ ],\
+ \"PATCH\": [\
+ {\
+ \"Privilege\": [\
+ \"ConfigureManager\"\
+ ]\
+ },\
+ {\
+ \"Privilege\": [\
+ \"ConfigureUser\",\
+ \"ConfigureDummy\",\
+ \"OEMRoot\"\
+ ]\
+ }\
+ ],\
+ \"POST\": [\
+ {\
+ \"Privilege\": [\
+ \"ConfigureManager\",\
+ \"OEMDummy\"\
+ ]\
+ }\
+ ],\
+ \"DELETE\": [\
+ {\
+ \"Privilege\": [\
+ \"ConfigureManager\"\
+ ]\
+ }\
+ ]\
+ }\
+ },\
+ {\
+ \"Entity\": \"EntityWithNonStringPrivilege\",\
+ \"OperationMap\": {\
+ \"GET\": [\
+ {\
+ \"Privilege\": [\"Login\"]\
+ }\
+ ],\
+ \"POST\": [\
+ {\
+ \"Privilege\": [1]\
+ }\
+ ]\
+ }\
+ }\
+ ]\
+ }");
+ privilegeRegistryMockOfstream << std::setw(4) << privilegeRegistryMockJson
+ << std::endl;
+ privilegeRegistryMockOfstream.close();
+ }
+
+ virtual ~PrivilegeTest() { std::remove("privilege_registry_mock.json"); }
+
+ void removeFieldFromRegistry(const std::string& field) {
+ std::ifstream in("privilege_registry_mock.json");
+ nlohmann::json tempJson = nlohmann::json::parse(in);
+ in.close();
+
+ tempJson.erase(field);
+
+ std::ofstream out("privilege_registry_mock.json");
+ out << std::setw(4) << tempJson << std::endl;
+ out.close();
+ }
+
+ void removeFieldFromMappings(const std::string& field) {
+ std::ifstream in("privilege_registry_mock.json");
+ nlohmann::json tempJson = nlohmann::json::parse(in);
+ in.close();
+
+ tempJson.at("Mappings")[0].erase(field);
+
+ std::ofstream out("privilege_registry_mock.json");
+ out << std::setw(4) << tempJson << std::endl;
+ out.close();
+ }
+
+ void clearArryInJson(const std::string& key) {
+ std::ifstream in("privilege_registry_mock.json");
+ nlohmann::json tempJson = nlohmann::json::parse(in);
+ in.close();
+
+ tempJson[key].clear();
+
+ std::ofstream out("privilege_registry_mock.json");
+ out << std::setw(4) << tempJson << std::endl;
+ out.close();
+ }
+
+ template <typename T>
+ void fillPrivilegeArray(const std::string& key,
+ const std::vector<T>& values) {
+ std::ifstream in("privilege_registry_mock.json");
+ nlohmann::json tempJson = nlohmann::json::parse(in);
+ in.close();
+
+ tempJson[key].clear();
+ for (const auto& value : values) {
+ tempJson[key].push_back(value);
+ }
+
+ std::ofstream out("privilege_registry_mock.json");
+ out << std::setw(4) << tempJson << std::endl;
+ out.close();
+ }
+
+ template <typename T>
+ void addRequiredPrivilege(const T& value) {
+ std::ifstream in("privilege_registry_mock.json");
+ nlohmann::json tempJson = nlohmann::json::parse(in);
+ in.close();
+
+ tempJson["Mappings"][0]["OperationMap"]["GET"][0]["Privilege"].push_back(
+ value);
+
+ std::ofstream out("privilege_registry_mock.json");
+ out << std::setw(4) << tempJson << std::endl;
+ out.close();
+ }
+
+ bool isPrivilegeRegistryParsed(const EntityPrivileges& entityPrivileges) {
+ auto userPrivileges = Privileges();
+ userPrivileges.setSinglePrivilege("Login");
+ // given the privileges_registry_mock.json, GET should be allowed with Login
+ // if the file got parsed successfully
+ return entityPrivileges.isMethodAllowedWithPrivileges(crow::HTTPMethod::GET,
+ userPrivileges);
+ }
+};
+
+TEST_F(PrivilegeTest, PrivilegeRegistryJsonSuccessfullParse) {
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_TRUE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeRegistryJsonNotFound) {
+ std::remove("privilege_registry_mock.json");
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeRegistryMissingCopyright) {
+ removeFieldFromRegistry("@Redfish.Copyright");
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeRegistryMissingOdataType) {
+ removeFieldFromRegistry("@odata.type");
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeRegistryMissingId) {
+ removeFieldFromRegistry("Id");
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeRegistryMissingName) {
+ removeFieldFromRegistry("Name");
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeRegistryMissingMappings) {
+ removeFieldFromRegistry("Mappings");
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeRegistryMissingPrivilegesUsed) {
+ removeFieldFromRegistry("PrivilegesUsed");
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeRegistryMissingOEMPrivilegesUsed) {
+ removeFieldFromRegistry("OEMPrivilegesUsed");
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeRegistryMissingOperationMap) {
+ removeFieldFromMappings("OperationMap");
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeRegistryPrivilegesUsedMayNotBeEmpty) {
+ clearArryInJson("PrivilegesUsed");
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeRegistryOEMPrivilegesUsedMayByEmpty) {
+ clearArryInJson("OEMPrivilegesUsed");
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_TRUE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeValuesMayOnlyBeStrings) {
+ std::vector<int> privilegesUsed = {1, 3, 4};
+ fillPrivilegeArray("PrivilegesUsed", privilegesUsed);
+
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, OnlyMaxNoOfBasePrivilegesGetsLoaded) {
+ const std::string excessivePrivilege("ExcessivePrivilege");
+ std::vector<std::string> privilegesUsed;
+
+ for (int i = 0; i < MAX_PRIVILEGE_COUNT; i++) {
+ privilegesUsed.push_back(std::to_string(i));
+ }
+ privilegesUsed.push_back(excessivePrivilege);
+
+ fillPrivilegeArray("PrivilegesUsed", privilegesUsed);
+ addRequiredPrivilege(excessivePrivilege);
+
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ Privileges privileges;
+ privileges.setSinglePrivilege(excessivePrivilege);
+
+ EXPECT_EQ(privileges.getBasePrivilegeBitset(), 0);
+}
+
+TEST_F(PrivilegeTest, OnlyMaxNoOfOEMPrivilegesGetsLoaded) {
+ const std::string excessivePrivilege("ExcessivePrivilege");
+ std::vector<std::string> privilegesUsed;
+
+ for (int i = 0; i < MAX_PRIVILEGE_COUNT; i++) {
+ privilegesUsed.push_back(std::to_string(i));
+ }
+ privilegesUsed.push_back(excessivePrivilege);
+
+ fillPrivilegeArray("OEMPrivilegesUsed", privilegesUsed);
+ addRequiredPrivilege(excessivePrivilege);
+
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ Privileges privileges;
+ privileges.setSinglePrivilege(excessivePrivilege);
+
+ EXPECT_EQ(privileges.getOEMPrivilegeBitset(), 0);
+}
+
+TEST_F(PrivilegeTest, LoadEntityPrivilegesForExistingEntity) {
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.TestEntity");
+ EXPECT_TRUE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, LoadEntityPrivilegesForNonExistingEntity) {
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges =
+ privilegeProvider.getPrivilegesRequiredByEntity("", "foo.bar.NotExists");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, LoadEntityPrivilegesForEntityWithNonStringPrivilege) {
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+ auto entityPrivileges = privilegeProvider.getPrivilegesRequiredByEntity(
+ "", "foo.bar.EntityWithNonStringPrivilege");
+ EXPECT_FALSE(isPrivilegeRegistryParsed(entityPrivileges));
+}
+
+TEST_F(PrivilegeTest, DefaultEntityPrivilegesDenyAccess) {
+ auto entityPrivileges = EntityPrivileges();
+
+ auto res =
+ entityPrivileges.isMethodAllowedForUser(crow::HTTPMethod::GET, "user");
+ EXPECT_FALSE(res);
+}
+
+TEST_F(PrivilegeTest, PrivilegeCheckForSingleCaseSuccess) {
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ auto entityPrivileges = EntityPrivileges();
+ auto userPrivileges = Privileges();
+ auto requiredPrivileges = Privileges();
+
+ userPrivileges.setSinglePrivilege("Login");
+ requiredPrivileges.setSinglePrivilege("Login");
+ entityPrivileges.addPrivilegesRequiredByMethod(crow::HTTPMethod::GET,
+ requiredPrivileges);
+ EXPECT_TRUE(entityPrivileges.isMethodAllowedWithPrivileges(
+ crow::HTTPMethod::GET, userPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeCheckForSingleCaseFailure) {
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ auto entityPrivileges = EntityPrivileges();
+ auto userPrivileges = Privileges();
+ auto requiredPrivileges = Privileges();
+
+ userPrivileges.setSinglePrivilege("Login");
+ requiredPrivileges.setSinglePrivilege("ConfigureManager");
+ entityPrivileges.addPrivilegesRequiredByMethod(crow::HTTPMethod::GET,
+ requiredPrivileges);
+ EXPECT_FALSE(entityPrivileges.isMethodAllowedWithPrivileges(
+ crow::HTTPMethod::GET, userPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeCheckForANDCaseSuccess) {
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ auto entityPrivileges = EntityPrivileges();
+ auto userPrivileges = Privileges();
+ auto requiredPrivileges = Privileges();
+
+ userPrivileges.setSinglePrivilege("Login");
+ userPrivileges.setSinglePrivilege("ConfigureManager");
+ userPrivileges.setSinglePrivilege("OEMRoot");
+ requiredPrivileges.setSinglePrivilege("Login");
+ requiredPrivileges.setSinglePrivilege("ConfigureManager");
+ requiredPrivileges.setSinglePrivilege("OEMRoot");
+ entityPrivileges.addPrivilegesRequiredByMethod(crow::HTTPMethod::GET,
+ requiredPrivileges);
+ EXPECT_TRUE(entityPrivileges.isMethodAllowedWithPrivileges(
+ crow::HTTPMethod::GET, userPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeCheckForANDCaseFailure) {
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ auto entityPrivileges = EntityPrivileges();
+ auto userPrivileges = Privileges();
+ auto requiredPrivileges = Privileges();
+
+ userPrivileges.setSinglePrivilege("Login");
+ userPrivileges.setSinglePrivilege("ConfigureUsers");
+ requiredPrivileges.setSinglePrivilege("Login");
+ requiredPrivileges.setSinglePrivilege("OEMDummy");
+ requiredPrivileges.setSinglePrivilege("ConfigureUsers");
+ entityPrivileges.addPrivilegesRequiredByMethod(crow::HTTPMethod::GET,
+ requiredPrivileges);
+ EXPECT_FALSE(entityPrivileges.isMethodAllowedWithPrivileges(
+ crow::HTTPMethod::GET, userPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeCheckForORCaseSuccess) {
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ auto entityPrivileges = EntityPrivileges();
+ auto userPrivileges = Privileges();
+ auto requiredPrivileges = Privileges();
+
+ userPrivileges.setSinglePrivilege("OEMRoot");
+ requiredPrivileges.setSinglePrivilege("Login");
+ entityPrivileges.addPrivilegesRequiredByMethod(crow::HTTPMethod::GET,
+ requiredPrivileges);
+ requiredPrivileges = Privileges();
+ requiredPrivileges.setSinglePrivilege("OEMRoot");
+ entityPrivileges.addPrivilegesRequiredByMethod(crow::HTTPMethod::GET,
+ requiredPrivileges);
+ EXPECT_TRUE(entityPrivileges.isMethodAllowedWithPrivileges(
+ crow::HTTPMethod::GET, userPrivileges));
+}
+
+TEST_F(PrivilegeTest, PrivilegeCheckForORCaseFailure) {
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ auto entityPrivileges = EntityPrivileges();
+ auto userPrivileges = Privileges();
+ auto requiredPrivileges = Privileges();
+
+ userPrivileges.setSinglePrivilege("ConfigureComponents");
+ requiredPrivileges.setSinglePrivilege("Login");
+ entityPrivileges.addPrivilegesRequiredByMethod(crow::HTTPMethod::GET,
+ requiredPrivileges);
+ requiredPrivileges = Privileges();
+ requiredPrivileges.setSinglePrivilege("ConfigureManager");
+ entityPrivileges.addPrivilegesRequiredByMethod(crow::HTTPMethod::GET,
+ requiredPrivileges);
+ EXPECT_FALSE(entityPrivileges.isMethodAllowedWithPrivileges(
+ crow::HTTPMethod::GET, userPrivileges));
+}
+
+TEST_F(PrivilegeTest, DefaultPrivilegeBitsetsAreEmpty) {
+ Privileges privileges;
+ EXPECT_TRUE(privileges.getBasePrivilegeBitset() == 0);
+ EXPECT_TRUE(privileges.getOEMPrivilegeBitset() == 0);
+}
+
+TEST_F(PrivilegeTest, UniqueBitsAssignedForAllPrivilegeNames) {
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ Privileges privileges;
+
+ for (const auto& privilege : expectedBasePrivileges) {
+ privileges.setSinglePrivilege(privilege);
+ }
+
+ for (const auto& privilege : expectedOEMPrivileges) {
+ privileges.setSinglePrivilege(privilege);
+ }
+
+ EXPECT_EQ(privileges.getBasePrivilegeBitset().count(),
+ expectedBasePrivileges.size());
+ EXPECT_EQ(privileges.getOEMPrivilegeBitset().count(),
+ expectedOEMPrivileges.size());
+}
+
+TEST_F(PrivilegeTest, GetActiveBasePrivilegeNames) {
+ Privileges privileges;
+
+ EXPECT_EQ(privileges.getActivePrivilegeNames(PrivilegeType::BASE),
+ std::vector<std::string>());
+
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ for (const auto& privilege : expectedBasePrivileges) {
+ privileges.setSinglePrivilege(privilege);
+ }
+
+ std::vector<std::string> activePrivileges =
+ privileges.getActivePrivilegeNames(PrivilegeType::BASE);
+
+ std::sort(expectedBasePrivileges.begin(), expectedBasePrivileges.end());
+ std::sort(activePrivileges.begin(), activePrivileges.end());
+
+ EXPECT_EQ(activePrivileges, expectedBasePrivileges);
+}
+
+TEST_F(PrivilegeTest, GetActiveOEMPrivilegeNames) {
+ Privileges privileges;
+
+ EXPECT_EQ(privileges.getActivePrivilegeNames(PrivilegeType::OEM),
+ std::vector<std::string>());
+
+ PrivilegeProvider privilegeProvider("privilege_registry_mock.json");
+
+ for (const auto& privilege : expectedOEMPrivileges) {
+ privileges.setSinglePrivilege(privilege);
+ }
+
+ std::vector<std::string> activePrivileges =
+ privileges.getActivePrivilegeNames(PrivilegeType::OEM);
+
+ std::sort(expectedOEMPrivileges.begin(), expectedOEMPrivileges.end());
+ std::sort(activePrivileges.begin(), activePrivileges.end());
+
+ EXPECT_EQ(activePrivileges, expectedOEMPrivileges);
+}