186e1b661SBorawski.Lukasz /* 286e1b661SBorawski.Lukasz // Copyright (c) 2018 Intel Corporation 386e1b661SBorawski.Lukasz // 486e1b661SBorawski.Lukasz // Licensed under the Apache License, Version 2.0 (the "License"); 586e1b661SBorawski.Lukasz // you may not use this file except in compliance with the License. 686e1b661SBorawski.Lukasz // You may obtain a copy of the License at 786e1b661SBorawski.Lukasz // 886e1b661SBorawski.Lukasz // http://www.apache.org/licenses/LICENSE-2.0 986e1b661SBorawski.Lukasz // 1086e1b661SBorawski.Lukasz // Unless required by applicable law or agreed to in writing, software 1186e1b661SBorawski.Lukasz // distributed under the License is distributed on an "AS IS" BASIS, 1286e1b661SBorawski.Lukasz // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1386e1b661SBorawski.Lukasz // See the License for the specific language governing permissions and 1486e1b661SBorawski.Lukasz // limitations under the License. 1586e1b661SBorawski.Lukasz */ 1686e1b661SBorawski.Lukasz #pragma once 1786e1b661SBorawski.Lukasz 18aecb47a4SBorawski.Lukasz #include <bitset> 19aecb47a4SBorawski.Lukasz #include <cstdint> 20*a692779fSEd Tanous #include <vector> 21aecb47a4SBorawski.Lukasz #include "crow.h" 22aecb47a4SBorawski.Lukasz #include <boost/container/flat_map.hpp> 23aecb47a4SBorawski.Lukasz #include <boost/optional.hpp> 24aecb47a4SBorawski.Lukasz 2586e1b661SBorawski.Lukasz namespace redfish { 2686e1b661SBorawski.Lukasz 27aecb47a4SBorawski.Lukasz enum class PrivilegeType { BASE, OEM }; 28aecb47a4SBorawski.Lukasz 29*a692779fSEd Tanous /** @brief A fixed array of compile time privileges */ 30*a692779fSEd Tanous constexpr std::array<const char*, 5> basePrivileges{ 313ebd75f7SEd Tanous "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf", 323ebd75f7SEd Tanous "ConfigureUsers"}; 3343a095abSBorawski.Lukasz 34*a692779fSEd Tanous constexpr const int basePrivilegeCount = basePrivileges.size(); 35*a692779fSEd Tanous 36*a692779fSEd Tanous /** @brief Max number of privileges per type */ 37*a692779fSEd Tanous constexpr const int MAX_PRIVILEGE_COUNT = 32; 38*a692779fSEd Tanous 39*a692779fSEd Tanous /** @brief A vector of all privilege names and their indexes */ 40*a692779fSEd Tanous static const std::vector<std::string> privilegeNames{basePrivileges.begin(), 41*a692779fSEd Tanous basePrivileges.end()}; 4243a095abSBorawski.Lukasz 4386e1b661SBorawski.Lukasz /** 44aecb47a4SBorawski.Lukasz * @brief Redfish privileges 45aecb47a4SBorawski.Lukasz * 46aecb47a4SBorawski.Lukasz * Entity privileges and user privileges are represented by this class. 47aecb47a4SBorawski.Lukasz * 48aecb47a4SBorawski.Lukasz * Each incoming connection requires a comparison between privileges held 49aecb47a4SBorawski.Lukasz * by the user issuing a request and the target entity's privileges. 50aecb47a4SBorawski.Lukasz * 51aecb47a4SBorawski.Lukasz * To ensure best runtime performance of this comparison, privileges 52aecb47a4SBorawski.Lukasz * are represented as bitsets. Each bit in the bitset corresponds to a 53aecb47a4SBorawski.Lukasz * unique privilege name. 54aecb47a4SBorawski.Lukasz * 55aecb47a4SBorawski.Lukasz * A bit is set if the privilege is required (entity domain) or granted 56aecb47a4SBorawski.Lukasz * (user domain) and false otherwise. 57aecb47a4SBorawski.Lukasz * 5886e1b661SBorawski.Lukasz */ 59aecb47a4SBorawski.Lukasz class Privileges { 60aecb47a4SBorawski.Lukasz public: 61aecb47a4SBorawski.Lukasz /** 6243a095abSBorawski.Lukasz * @brief Constructs object without any privileges active 6343a095abSBorawski.Lukasz * 6443a095abSBorawski.Lukasz */ 6543a095abSBorawski.Lukasz Privileges() = default; 6643a095abSBorawski.Lukasz 6743a095abSBorawski.Lukasz /** 6843a095abSBorawski.Lukasz * @brief Constructs object with given privileges active 6943a095abSBorawski.Lukasz * 7043a095abSBorawski.Lukasz * @param[in] privilegeList List of privileges to be activated 7143a095abSBorawski.Lukasz * 7243a095abSBorawski.Lukasz */ 733ebd75f7SEd Tanous Privileges(std::initializer_list<const char*> privilegeList) { 743ebd75f7SEd Tanous for (const char* privilege : privilegeList) { 753ebd75f7SEd Tanous if (!setSinglePrivilege(privilege)) { 763ebd75f7SEd Tanous CROW_LOG_CRITICAL << "Unable to set privilege " << privilege 773ebd75f7SEd Tanous << "in constructor"; 7843a095abSBorawski.Lukasz } 7943a095abSBorawski.Lukasz } 803ebd75f7SEd Tanous } 81aecb47a4SBorawski.Lukasz 82aecb47a4SBorawski.Lukasz /** 83aecb47a4SBorawski.Lukasz * @brief Sets given privilege in the bitset 84aecb47a4SBorawski.Lukasz * 85aecb47a4SBorawski.Lukasz * @param[in] privilege Privilege to be set 86aecb47a4SBorawski.Lukasz * 87aecb47a4SBorawski.Lukasz * @return None 8843a095abSBorawski.Lukasz * 89aecb47a4SBorawski.Lukasz */ 903ebd75f7SEd Tanous bool setSinglePrivilege(const char* privilege) { 91*a692779fSEd Tanous for (int search_index = 0; search_index < privilegeNames.size(); 92*a692779fSEd Tanous search_index++) { 93*a692779fSEd Tanous if (privilege == privilegeNames[search_index]) { 94*a692779fSEd Tanous privilegeBitset.set(search_index); 953ebd75f7SEd Tanous return true; 96aecb47a4SBorawski.Lukasz } 97*a692779fSEd Tanous } 98aecb47a4SBorawski.Lukasz 993ebd75f7SEd Tanous return false; 1003ebd75f7SEd Tanous } 1013ebd75f7SEd Tanous 1023ebd75f7SEd Tanous /** 1033ebd75f7SEd Tanous * @brief Sets given privilege in the bitset 1043ebd75f7SEd Tanous * 1053ebd75f7SEd Tanous * @param[in] privilege Privilege to be set 1063ebd75f7SEd Tanous * 1073ebd75f7SEd Tanous * @return None 1083ebd75f7SEd Tanous * 1093ebd75f7SEd Tanous */ 1103ebd75f7SEd Tanous bool setSinglePrivilege(const std::string& privilege) { 1113ebd75f7SEd Tanous return setSinglePrivilege(privilege.c_str()); 112aecb47a4SBorawski.Lukasz } 113aecb47a4SBorawski.Lukasz 114aecb47a4SBorawski.Lukasz /** 115aecb47a4SBorawski.Lukasz * @brief Retrieves names of all active privileges for a given type 116aecb47a4SBorawski.Lukasz * 117aecb47a4SBorawski.Lukasz * @param[in] type Base or OEM 118aecb47a4SBorawski.Lukasz * 1193ebd75f7SEd Tanous * @return Vector of active privileges. Pointers are valid until 120*a692779fSEd Tanous * the setSinglePrivilege is called, or the Privilege structure is destroyed 12143a095abSBorawski.Lukasz * 122aecb47a4SBorawski.Lukasz */ 1233ebd75f7SEd Tanous std::vector<const std::string*> getActivePrivilegeNames( 124aecb47a4SBorawski.Lukasz const PrivilegeType type) const { 1253ebd75f7SEd Tanous std::vector<const std::string*> activePrivileges; 126aecb47a4SBorawski.Lukasz 127*a692779fSEd Tanous int search_index = 0; 128*a692779fSEd Tanous int end_index = basePrivilegeCount; 129*a692779fSEd Tanous if (type == PrivilegeType::OEM) { 130*a692779fSEd Tanous search_index = basePrivilegeCount - 1; 131*a692779fSEd Tanous end_index = privilegeNames.size(); 132*a692779fSEd Tanous } 133*a692779fSEd Tanous 134*a692779fSEd Tanous for (; search_index < end_index; search_index++) { 135*a692779fSEd Tanous if (privilegeBitset.test(search_index)) { 136*a692779fSEd Tanous activePrivileges.emplace_back(&privilegeNames[search_index]); 137aecb47a4SBorawski.Lukasz } 138aecb47a4SBorawski.Lukasz } 139*a692779fSEd Tanous 140aecb47a4SBorawski.Lukasz return activePrivileges; 141aecb47a4SBorawski.Lukasz } 142aecb47a4SBorawski.Lukasz 1433ebd75f7SEd Tanous /** 1443ebd75f7SEd Tanous * @brief Determines if this Privilege set is a superset of the given 1453ebd75f7SEd Tanous * privilege set 1463ebd75f7SEd Tanous * 1473ebd75f7SEd Tanous * @param[in] privilege Privilege to be checked 1483ebd75f7SEd Tanous * 1493ebd75f7SEd Tanous * @return None 1503ebd75f7SEd Tanous * 1513ebd75f7SEd Tanous */ 1523ebd75f7SEd Tanous bool isSupersetOf(const Privileges& p) const { 153*a692779fSEd Tanous return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset; 1543ebd75f7SEd Tanous } 1553ebd75f7SEd Tanous 15686e1b661SBorawski.Lukasz private: 157*a692779fSEd Tanous std::bitset<MAX_PRIVILEGE_COUNT> privilegeBitset = 0; 15886e1b661SBorawski.Lukasz }; 15986e1b661SBorawski.Lukasz 16043a095abSBorawski.Lukasz using OperationMap = 16143a095abSBorawski.Lukasz boost::container::flat_map<crow::HTTPMethod, std::vector<Privileges>>; 16243a095abSBorawski.Lukasz 16343a095abSBorawski.Lukasz /** 164aecb47a4SBorawski.Lukasz * @brief Checks if given privileges allow to call an HTTP method 165aecb47a4SBorawski.Lukasz * 166aecb47a4SBorawski.Lukasz * @param[in] method HTTP method 167aecb47a4SBorawski.Lukasz * @param[in] user Privileges 168aecb47a4SBorawski.Lukasz * 169aecb47a4SBorawski.Lukasz * @return True if method allowed, false otherwise 17043a095abSBorawski.Lukasz * 171aecb47a4SBorawski.Lukasz */ 1723ebd75f7SEd Tanous inline bool isMethodAllowedWithPrivileges(const crow::HTTPMethod method, 1733ebd75f7SEd Tanous const OperationMap& operationMap, 1743ebd75f7SEd Tanous const Privileges& userPrivileges) { 1753ebd75f7SEd Tanous const auto& it = operationMap.find(method); 1763ebd75f7SEd Tanous if (it == operationMap.end()) { 17743a095abSBorawski.Lukasz return false; 17843a095abSBorawski.Lukasz } 179aecb47a4SBorawski.Lukasz 1803ebd75f7SEd Tanous // If there are no privileges assigned, assume no privileges required 1813ebd75f7SEd Tanous if (it->second.empty()) { 18243a095abSBorawski.Lukasz return true; 18343a095abSBorawski.Lukasz } 1843ebd75f7SEd Tanous 1853ebd75f7SEd Tanous for (auto& requiredPrivileges : it->second) { 1863ebd75f7SEd Tanous if (userPrivileges.isSupersetOf(requiredPrivileges)) { 1873ebd75f7SEd Tanous return true; 1883ebd75f7SEd Tanous } 1893ebd75f7SEd Tanous } 19043a095abSBorawski.Lukasz return false; 19186e1b661SBorawski.Lukasz } 192aecb47a4SBorawski.Lukasz 1933ebd75f7SEd Tanous /** 1943ebd75f7SEd Tanous * @brief Checks if a user is allowed to call an HTTP method 1953ebd75f7SEd Tanous * 1963ebd75f7SEd Tanous * @param[in] method HTTP method 1973ebd75f7SEd Tanous * @param[in] user Username 1983ebd75f7SEd Tanous * 1993ebd75f7SEd Tanous * @return True if method allowed, false otherwise 2003ebd75f7SEd Tanous * 2013ebd75f7SEd Tanous */ 2023ebd75f7SEd Tanous inline bool isMethodAllowedForUser(const crow::HTTPMethod method, 2033ebd75f7SEd Tanous const OperationMap& operationMap, 2043ebd75f7SEd Tanous const std::string& user) { 2053ebd75f7SEd Tanous // TODO: load user privileges from configuration as soon as its available 2063ebd75f7SEd Tanous // now we are granting all privileges to everyone. 2073ebd75f7SEd Tanous Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf", 2083ebd75f7SEd Tanous "ConfigureUsers", "ConfigureComponents"}; 2093ebd75f7SEd Tanous 2103ebd75f7SEd Tanous return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges); 21186e1b661SBorawski.Lukasz } 21286e1b661SBorawski.Lukasz 21386e1b661SBorawski.Lukasz } // namespace redfish 214