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 <boost/container/flat_map.hpp> 201abe55efSEd Tanous #include <cstdint> 211abe55efSEd Tanous #include <vector> 22aecb47a4SBorawski.Lukasz 231abe55efSEd Tanous namespace redfish 241abe55efSEd Tanous { 251abe55efSEd Tanous 261abe55efSEd Tanous enum class PrivilegeType 271abe55efSEd Tanous { 281abe55efSEd Tanous BASE, 291abe55efSEd Tanous OEM 301abe55efSEd Tanous }; 31aecb47a4SBorawski.Lukasz 32a692779fSEd Tanous /** @brief A fixed array of compile time privileges */ 33a692779fSEd Tanous constexpr std::array<const char*, 5> basePrivileges{ 343ebd75f7SEd Tanous "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf", 353ebd75f7SEd Tanous "ConfigureUsers"}; 3643a095abSBorawski.Lukasz 37*b01bf299SEd Tanous constexpr const int basePrivilegeCount = basePrivileges.size(); 38a692779fSEd Tanous 39a692779fSEd Tanous /** @brief Max number of privileges per type */ 40*b01bf299SEd Tanous constexpr const int maxPrivilegeCount = 32; 41a692779fSEd Tanous 42a692779fSEd Tanous /** @brief A vector of all privilege names and their indexes */ 43a692779fSEd Tanous static const std::vector<std::string> privilegeNames{basePrivileges.begin(), 44a692779fSEd Tanous basePrivileges.end()}; 4543a095abSBorawski.Lukasz 4686e1b661SBorawski.Lukasz /** 47aecb47a4SBorawski.Lukasz * @brief Redfish privileges 48aecb47a4SBorawski.Lukasz * 49aecb47a4SBorawski.Lukasz * Entity privileges and user privileges are represented by this class. 50aecb47a4SBorawski.Lukasz * 5155c7b7a2SEd Tanous * Each incoming Connection requires a comparison between privileges held 52aecb47a4SBorawski.Lukasz * by the user issuing a request and the target entity's privileges. 53aecb47a4SBorawski.Lukasz * 54aecb47a4SBorawski.Lukasz * To ensure best runtime performance of this comparison, privileges 55aecb47a4SBorawski.Lukasz * are represented as bitsets. Each bit in the bitset corresponds to a 56aecb47a4SBorawski.Lukasz * unique privilege name. 57aecb47a4SBorawski.Lukasz * 58aecb47a4SBorawski.Lukasz * A bit is set if the privilege is required (entity domain) or granted 59aecb47a4SBorawski.Lukasz * (user domain) and false otherwise. 60aecb47a4SBorawski.Lukasz * 6186e1b661SBorawski.Lukasz */ 621abe55efSEd Tanous class Privileges 631abe55efSEd Tanous { 64aecb47a4SBorawski.Lukasz public: 65aecb47a4SBorawski.Lukasz /** 6643a095abSBorawski.Lukasz * @brief Constructs object without any privileges active 6743a095abSBorawski.Lukasz * 6843a095abSBorawski.Lukasz */ 6943a095abSBorawski.Lukasz Privileges() = default; 7043a095abSBorawski.Lukasz 7143a095abSBorawski.Lukasz /** 7243a095abSBorawski.Lukasz * @brief Constructs object with given privileges active 7343a095abSBorawski.Lukasz * 7443a095abSBorawski.Lukasz * @param[in] privilegeList List of privileges to be activated 7543a095abSBorawski.Lukasz * 7643a095abSBorawski.Lukasz */ 771abe55efSEd Tanous Privileges(std::initializer_list<const char*> privilegeList) 781abe55efSEd Tanous { 791abe55efSEd Tanous for (const char* privilege : privilegeList) 801abe55efSEd Tanous { 811abe55efSEd Tanous if (!setSinglePrivilege(privilege)) 821abe55efSEd Tanous { 8355c7b7a2SEd Tanous BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege 843ebd75f7SEd Tanous << "in constructor"; 8543a095abSBorawski.Lukasz } 8643a095abSBorawski.Lukasz } 873ebd75f7SEd Tanous } 88aecb47a4SBorawski.Lukasz 89aecb47a4SBorawski.Lukasz /** 90aecb47a4SBorawski.Lukasz * @brief Sets given privilege in the bitset 91aecb47a4SBorawski.Lukasz * 92aecb47a4SBorawski.Lukasz * @param[in] privilege Privilege to be set 93aecb47a4SBorawski.Lukasz * 94aecb47a4SBorawski.Lukasz * @return None 9543a095abSBorawski.Lukasz * 96aecb47a4SBorawski.Lukasz */ 971abe55efSEd Tanous bool setSinglePrivilege(const char* privilege) 981abe55efSEd Tanous { 99*b01bf299SEd Tanous for (int searchIndex = 0; searchIndex < privilegeNames.size(); 1001abe55efSEd Tanous searchIndex++) 1011abe55efSEd Tanous { 1021abe55efSEd Tanous if (privilege == privilegeNames[searchIndex]) 1031abe55efSEd Tanous { 10455c7b7a2SEd Tanous privilegeBitset.set(searchIndex); 1053ebd75f7SEd Tanous return true; 106aecb47a4SBorawski.Lukasz } 107a692779fSEd Tanous } 108aecb47a4SBorawski.Lukasz 1093ebd75f7SEd Tanous return false; 1103ebd75f7SEd Tanous } 1113ebd75f7SEd Tanous 1123ebd75f7SEd Tanous /** 1133ebd75f7SEd Tanous * @brief Sets given privilege in the bitset 1143ebd75f7SEd Tanous * 1153ebd75f7SEd Tanous * @param[in] privilege Privilege to be set 1163ebd75f7SEd Tanous * 1173ebd75f7SEd Tanous * @return None 1183ebd75f7SEd Tanous * 1193ebd75f7SEd Tanous */ 1201abe55efSEd Tanous bool setSinglePrivilege(const std::string& privilege) 1211abe55efSEd Tanous { 1223ebd75f7SEd Tanous return setSinglePrivilege(privilege.c_str()); 123aecb47a4SBorawski.Lukasz } 124aecb47a4SBorawski.Lukasz 125aecb47a4SBorawski.Lukasz /** 126aecb47a4SBorawski.Lukasz * @brief Retrieves names of all active privileges for a given type 127aecb47a4SBorawski.Lukasz * 128aecb47a4SBorawski.Lukasz * @param[in] type Base or OEM 129aecb47a4SBorawski.Lukasz * 1303ebd75f7SEd Tanous * @return Vector of active privileges. Pointers are valid until 131a692779fSEd Tanous * the setSinglePrivilege is called, or the Privilege structure is destroyed 13243a095abSBorawski.Lukasz * 133aecb47a4SBorawski.Lukasz */ 1341abe55efSEd Tanous std::vector<const std::string*> 1351abe55efSEd Tanous getActivePrivilegeNames(const PrivilegeType type) const 1361abe55efSEd Tanous { 1373ebd75f7SEd Tanous std::vector<const std::string*> activePrivileges; 138aecb47a4SBorawski.Lukasz 139*b01bf299SEd Tanous int searchIndex = 0; 140*b01bf299SEd Tanous int endIndex = basePrivilegeCount; 1411abe55efSEd Tanous if (type == PrivilegeType::OEM) 1421abe55efSEd Tanous { 14355c7b7a2SEd Tanous searchIndex = basePrivilegeCount - 1; 14455c7b7a2SEd Tanous endIndex = privilegeNames.size(); 145a692779fSEd Tanous } 146a692779fSEd Tanous 1471abe55efSEd Tanous for (; searchIndex < endIndex; searchIndex++) 1481abe55efSEd Tanous { 1491abe55efSEd Tanous if (privilegeBitset.test(searchIndex)) 1501abe55efSEd Tanous { 15155c7b7a2SEd Tanous activePrivileges.emplace_back(&privilegeNames[searchIndex]); 152aecb47a4SBorawski.Lukasz } 153aecb47a4SBorawski.Lukasz } 154a692779fSEd Tanous 155aecb47a4SBorawski.Lukasz return activePrivileges; 156aecb47a4SBorawski.Lukasz } 157aecb47a4SBorawski.Lukasz 1583ebd75f7SEd Tanous /** 1593ebd75f7SEd Tanous * @brief Determines if this Privilege set is a superset of the given 1603ebd75f7SEd Tanous * privilege set 1613ebd75f7SEd Tanous * 1623ebd75f7SEd Tanous * @param[in] privilege Privilege to be checked 1633ebd75f7SEd Tanous * 1643ebd75f7SEd Tanous * @return None 1653ebd75f7SEd Tanous * 1663ebd75f7SEd Tanous */ 1671abe55efSEd Tanous bool isSupersetOf(const Privileges& p) const 1681abe55efSEd Tanous { 169a692779fSEd Tanous return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset; 1703ebd75f7SEd Tanous } 1713ebd75f7SEd Tanous 17286e1b661SBorawski.Lukasz private: 17355c7b7a2SEd Tanous std::bitset<maxPrivilegeCount> privilegeBitset = 0; 17486e1b661SBorawski.Lukasz }; 17586e1b661SBorawski.Lukasz 176e0d918bcSEd Tanous using OperationMap = boost::container::flat_map<boost::beast::http::verb, 177e0d918bcSEd Tanous std::vector<Privileges>>; 17843a095abSBorawski.Lukasz 17943a095abSBorawski.Lukasz /** 180aecb47a4SBorawski.Lukasz * @brief Checks if given privileges allow to call an HTTP method 181aecb47a4SBorawski.Lukasz * 182aecb47a4SBorawski.Lukasz * @param[in] method HTTP method 183aecb47a4SBorawski.Lukasz * @param[in] user Privileges 184aecb47a4SBorawski.Lukasz * 185aecb47a4SBorawski.Lukasz * @return True if method allowed, false otherwise 18643a095abSBorawski.Lukasz * 187aecb47a4SBorawski.Lukasz */ 188e0d918bcSEd Tanous inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method, 1893ebd75f7SEd Tanous const OperationMap& operationMap, 1901abe55efSEd Tanous const Privileges& userPrivileges) 1911abe55efSEd Tanous { 1923ebd75f7SEd Tanous const auto& it = operationMap.find(method); 1931abe55efSEd Tanous if (it == operationMap.end()) 1941abe55efSEd Tanous { 19543a095abSBorawski.Lukasz return false; 19643a095abSBorawski.Lukasz } 197aecb47a4SBorawski.Lukasz 1983ebd75f7SEd Tanous // If there are no privileges assigned, assume no privileges required 1991abe55efSEd Tanous if (it->second.empty()) 2001abe55efSEd Tanous { 20143a095abSBorawski.Lukasz return true; 20243a095abSBorawski.Lukasz } 2033ebd75f7SEd Tanous 2041abe55efSEd Tanous for (auto& requiredPrivileges : it->second) 2051abe55efSEd Tanous { 2061abe55efSEd Tanous if (userPrivileges.isSupersetOf(requiredPrivileges)) 2071abe55efSEd Tanous { 2083ebd75f7SEd Tanous return true; 2093ebd75f7SEd Tanous } 2103ebd75f7SEd Tanous } 21143a095abSBorawski.Lukasz return false; 21286e1b661SBorawski.Lukasz } 213aecb47a4SBorawski.Lukasz 2143ebd75f7SEd Tanous /** 2153ebd75f7SEd Tanous * @brief Checks if a user is allowed to call an HTTP method 2163ebd75f7SEd Tanous * 2173ebd75f7SEd Tanous * @param[in] method HTTP method 2183ebd75f7SEd Tanous * @param[in] user Username 2193ebd75f7SEd Tanous * 2203ebd75f7SEd Tanous * @return True if method allowed, false otherwise 2213ebd75f7SEd Tanous * 2223ebd75f7SEd Tanous */ 223e0d918bcSEd Tanous inline bool isMethodAllowedForUser(const boost::beast::http::verb method, 2243ebd75f7SEd Tanous const OperationMap& operationMap, 2251abe55efSEd Tanous const std::string& user) 2261abe55efSEd Tanous { 2273ebd75f7SEd Tanous // TODO: load user privileges from configuration as soon as its available 2283ebd75f7SEd Tanous // now we are granting all privileges to everyone. 2293ebd75f7SEd Tanous Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf", 2303ebd75f7SEd Tanous "ConfigureUsers", "ConfigureComponents"}; 2313ebd75f7SEd Tanous 2323ebd75f7SEd Tanous return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges); 23386e1b661SBorawski.Lukasz } 23486e1b661SBorawski.Lukasz 23586e1b661SBorawski.Lukasz } // namespace redfish 236