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 18f00032dbSTanous #include <crow/logging.h> 19f00032dbSTanous 20f00032dbSTanous #include <array> 21aecb47a4SBorawski.Lukasz #include <bitset> 22f00032dbSTanous #include <boost/beast/http/verb.hpp> 23aecb47a4SBorawski.Lukasz #include <boost/container/flat_map.hpp> 241abe55efSEd Tanous #include <cstdint> 251abe55efSEd Tanous #include <vector> 26aecb47a4SBorawski.Lukasz 271abe55efSEd Tanous namespace redfish 281abe55efSEd Tanous { 291abe55efSEd Tanous 301abe55efSEd Tanous enum class PrivilegeType 311abe55efSEd Tanous { 321abe55efSEd Tanous BASE, 331abe55efSEd Tanous OEM 341abe55efSEd Tanous }; 35aecb47a4SBorawski.Lukasz 36a692779fSEd Tanous /** @brief A fixed array of compile time privileges */ 37a692779fSEd Tanous constexpr std::array<const char*, 5> basePrivileges{ 383ebd75f7SEd Tanous "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf", 393ebd75f7SEd Tanous "ConfigureUsers"}; 4043a095abSBorawski.Lukasz 41b01bf299SEd Tanous constexpr const int basePrivilegeCount = basePrivileges.size(); 42a692779fSEd Tanous 43a692779fSEd Tanous /** @brief Max number of privileges per type */ 44b01bf299SEd Tanous constexpr const int maxPrivilegeCount = 32; 45a692779fSEd Tanous 46a692779fSEd Tanous /** @brief A vector of all privilege names and their indexes */ 47a692779fSEd Tanous static const std::vector<std::string> privilegeNames{basePrivileges.begin(), 48a692779fSEd Tanous basePrivileges.end()}; 4943a095abSBorawski.Lukasz 5086e1b661SBorawski.Lukasz /** 51aecb47a4SBorawski.Lukasz * @brief Redfish privileges 52aecb47a4SBorawski.Lukasz * 53aecb47a4SBorawski.Lukasz * Entity privileges and user privileges are represented by this class. 54aecb47a4SBorawski.Lukasz * 5555c7b7a2SEd Tanous * Each incoming Connection requires a comparison between privileges held 56aecb47a4SBorawski.Lukasz * by the user issuing a request and the target entity's privileges. 57aecb47a4SBorawski.Lukasz * 58aecb47a4SBorawski.Lukasz * To ensure best runtime performance of this comparison, privileges 59aecb47a4SBorawski.Lukasz * are represented as bitsets. Each bit in the bitset corresponds to a 60aecb47a4SBorawski.Lukasz * unique privilege name. 61aecb47a4SBorawski.Lukasz * 62aecb47a4SBorawski.Lukasz * A bit is set if the privilege is required (entity domain) or granted 63aecb47a4SBorawski.Lukasz * (user domain) and false otherwise. 64aecb47a4SBorawski.Lukasz * 6586e1b661SBorawski.Lukasz */ 661abe55efSEd Tanous class Privileges 671abe55efSEd Tanous { 68aecb47a4SBorawski.Lukasz public: 69aecb47a4SBorawski.Lukasz /** 7043a095abSBorawski.Lukasz * @brief Constructs object without any privileges active 7143a095abSBorawski.Lukasz * 7243a095abSBorawski.Lukasz */ 7343a095abSBorawski.Lukasz Privileges() = default; 7443a095abSBorawski.Lukasz 7543a095abSBorawski.Lukasz /** 7643a095abSBorawski.Lukasz * @brief Constructs object with given privileges active 7743a095abSBorawski.Lukasz * 7843a095abSBorawski.Lukasz * @param[in] privilegeList List of privileges to be activated 7943a095abSBorawski.Lukasz * 8043a095abSBorawski.Lukasz */ 811abe55efSEd Tanous Privileges(std::initializer_list<const char*> privilegeList) 821abe55efSEd Tanous { 831abe55efSEd Tanous for (const char* privilege : privilegeList) 841abe55efSEd Tanous { 851abe55efSEd Tanous if (!setSinglePrivilege(privilege)) 861abe55efSEd Tanous { 8755c7b7a2SEd Tanous BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege 883ebd75f7SEd Tanous << "in constructor"; 8943a095abSBorawski.Lukasz } 9043a095abSBorawski.Lukasz } 913ebd75f7SEd Tanous } 92aecb47a4SBorawski.Lukasz 93aecb47a4SBorawski.Lukasz /** 94aecb47a4SBorawski.Lukasz * @brief Sets given privilege in the bitset 95aecb47a4SBorawski.Lukasz * 96aecb47a4SBorawski.Lukasz * @param[in] privilege Privilege to be set 97aecb47a4SBorawski.Lukasz * 98aecb47a4SBorawski.Lukasz * @return None 9943a095abSBorawski.Lukasz * 100aecb47a4SBorawski.Lukasz */ 1011abe55efSEd Tanous bool setSinglePrivilege(const char* privilege) 1021abe55efSEd Tanous { 103b01bf299SEd Tanous for (int searchIndex = 0; searchIndex < privilegeNames.size(); 1041abe55efSEd Tanous searchIndex++) 1051abe55efSEd Tanous { 1061abe55efSEd Tanous if (privilege == privilegeNames[searchIndex]) 1071abe55efSEd Tanous { 10855c7b7a2SEd Tanous privilegeBitset.set(searchIndex); 1093ebd75f7SEd Tanous return true; 110aecb47a4SBorawski.Lukasz } 111a692779fSEd Tanous } 112aecb47a4SBorawski.Lukasz 1133ebd75f7SEd Tanous return false; 1143ebd75f7SEd Tanous } 1153ebd75f7SEd Tanous 1163ebd75f7SEd Tanous /** 1173ebd75f7SEd Tanous * @brief Sets given privilege in the bitset 1183ebd75f7SEd Tanous * 1193ebd75f7SEd Tanous * @param[in] privilege Privilege to be set 1203ebd75f7SEd Tanous * 1213ebd75f7SEd Tanous * @return None 1223ebd75f7SEd Tanous * 1233ebd75f7SEd Tanous */ 1241abe55efSEd Tanous bool setSinglePrivilege(const std::string& privilege) 1251abe55efSEd Tanous { 1263ebd75f7SEd Tanous return setSinglePrivilege(privilege.c_str()); 127aecb47a4SBorawski.Lukasz } 128aecb47a4SBorawski.Lukasz 129aecb47a4SBorawski.Lukasz /** 130aecb47a4SBorawski.Lukasz * @brief Retrieves names of all active privileges for a given type 131aecb47a4SBorawski.Lukasz * 132aecb47a4SBorawski.Lukasz * @param[in] type Base or OEM 133aecb47a4SBorawski.Lukasz * 1343ebd75f7SEd Tanous * @return Vector of active privileges. Pointers are valid until 135a692779fSEd Tanous * the setSinglePrivilege is called, or the Privilege structure is destroyed 13643a095abSBorawski.Lukasz * 137aecb47a4SBorawski.Lukasz */ 1381abe55efSEd Tanous std::vector<const std::string*> 1391abe55efSEd Tanous getActivePrivilegeNames(const PrivilegeType type) const 1401abe55efSEd Tanous { 1413ebd75f7SEd Tanous std::vector<const std::string*> activePrivileges; 142aecb47a4SBorawski.Lukasz 143b01bf299SEd Tanous int searchIndex = 0; 144b01bf299SEd Tanous int endIndex = basePrivilegeCount; 1451abe55efSEd Tanous if (type == PrivilegeType::OEM) 1461abe55efSEd Tanous { 14755c7b7a2SEd Tanous searchIndex = basePrivilegeCount - 1; 14855c7b7a2SEd Tanous endIndex = privilegeNames.size(); 149a692779fSEd Tanous } 150a692779fSEd Tanous 1511abe55efSEd Tanous for (; searchIndex < endIndex; searchIndex++) 1521abe55efSEd Tanous { 1531abe55efSEd Tanous if (privilegeBitset.test(searchIndex)) 1541abe55efSEd Tanous { 15555c7b7a2SEd Tanous activePrivileges.emplace_back(&privilegeNames[searchIndex]); 156aecb47a4SBorawski.Lukasz } 157aecb47a4SBorawski.Lukasz } 158a692779fSEd Tanous 159aecb47a4SBorawski.Lukasz return activePrivileges; 160aecb47a4SBorawski.Lukasz } 161aecb47a4SBorawski.Lukasz 1623ebd75f7SEd Tanous /** 1633ebd75f7SEd Tanous * @brief Determines if this Privilege set is a superset of the given 1643ebd75f7SEd Tanous * privilege set 1653ebd75f7SEd Tanous * 1663ebd75f7SEd Tanous * @param[in] privilege Privilege to be checked 1673ebd75f7SEd Tanous * 1683ebd75f7SEd Tanous * @return None 1693ebd75f7SEd Tanous * 1703ebd75f7SEd Tanous */ 1711abe55efSEd Tanous bool isSupersetOf(const Privileges& p) const 1721abe55efSEd Tanous { 173a692779fSEd Tanous return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset; 1743ebd75f7SEd Tanous } 1753ebd75f7SEd Tanous 17686e1b661SBorawski.Lukasz private: 17755c7b7a2SEd Tanous std::bitset<maxPrivilegeCount> privilegeBitset = 0; 17886e1b661SBorawski.Lukasz }; 17986e1b661SBorawski.Lukasz 180*6f359568SRatan Gupta inline const Privileges& getUserPrivileges(const std::string& userRole) 181*6f359568SRatan Gupta { 182*6f359568SRatan Gupta // Redfish privilege : Administrator 183*6f359568SRatan Gupta if (userRole == "priv-admin") 184*6f359568SRatan Gupta { 185*6f359568SRatan Gupta static Privileges admin{"Login", "ConfigureManager", "ConfigureSelf", 186*6f359568SRatan Gupta "ConfigureUsers", "ConfigureComponents"}; 187*6f359568SRatan Gupta return admin; 188*6f359568SRatan Gupta } 189*6f359568SRatan Gupta else if (userRole == "priv-operator") 190*6f359568SRatan Gupta { 191*6f359568SRatan Gupta // Redfish privilege : Operator 192*6f359568SRatan Gupta static Privileges op{"Login", "ConfigureSelf", "ConfigureComponents"}; 193*6f359568SRatan Gupta return op; 194*6f359568SRatan Gupta } 195*6f359568SRatan Gupta else 196*6f359568SRatan Gupta { 197*6f359568SRatan Gupta // Redfish privilege : Readonly 198*6f359568SRatan Gupta static Privileges readOnly{"Login", "ConfigureSelf"}; 199*6f359568SRatan Gupta return readOnly; 200*6f359568SRatan Gupta } 201*6f359568SRatan Gupta } 202*6f359568SRatan Gupta 203e0d918bcSEd Tanous using OperationMap = boost::container::flat_map<boost::beast::http::verb, 204e0d918bcSEd Tanous std::vector<Privileges>>; 20543a095abSBorawski.Lukasz 20643a095abSBorawski.Lukasz /** 207aecb47a4SBorawski.Lukasz * @brief Checks if given privileges allow to call an HTTP method 208aecb47a4SBorawski.Lukasz * 209aecb47a4SBorawski.Lukasz * @param[in] method HTTP method 210aecb47a4SBorawski.Lukasz * @param[in] user Privileges 211aecb47a4SBorawski.Lukasz * 212aecb47a4SBorawski.Lukasz * @return True if method allowed, false otherwise 21343a095abSBorawski.Lukasz * 214aecb47a4SBorawski.Lukasz */ 215e0d918bcSEd Tanous inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method, 2163ebd75f7SEd Tanous const OperationMap& operationMap, 2171abe55efSEd Tanous const Privileges& userPrivileges) 2181abe55efSEd Tanous { 2193ebd75f7SEd Tanous const auto& it = operationMap.find(method); 2201abe55efSEd Tanous if (it == operationMap.end()) 2211abe55efSEd Tanous { 22243a095abSBorawski.Lukasz return false; 22343a095abSBorawski.Lukasz } 224aecb47a4SBorawski.Lukasz 2253ebd75f7SEd Tanous // If there are no privileges assigned, assume no privileges required 2261abe55efSEd Tanous if (it->second.empty()) 2271abe55efSEd Tanous { 22843a095abSBorawski.Lukasz return true; 22943a095abSBorawski.Lukasz } 2303ebd75f7SEd Tanous 2311abe55efSEd Tanous for (auto& requiredPrivileges : it->second) 2321abe55efSEd Tanous { 2331abe55efSEd Tanous if (userPrivileges.isSupersetOf(requiredPrivileges)) 2341abe55efSEd Tanous { 2353ebd75f7SEd Tanous return true; 2363ebd75f7SEd Tanous } 2373ebd75f7SEd Tanous } 23843a095abSBorawski.Lukasz return false; 23986e1b661SBorawski.Lukasz } 240aecb47a4SBorawski.Lukasz 2413ebd75f7SEd Tanous /** 2423ebd75f7SEd Tanous * @brief Checks if a user is allowed to call an HTTP method 2433ebd75f7SEd Tanous * 2443ebd75f7SEd Tanous * @param[in] method HTTP method 2453ebd75f7SEd Tanous * @param[in] user Username 2463ebd75f7SEd Tanous * 2473ebd75f7SEd Tanous * @return True if method allowed, false otherwise 2483ebd75f7SEd Tanous * 2493ebd75f7SEd Tanous */ 250e0d918bcSEd Tanous inline bool isMethodAllowedForUser(const boost::beast::http::verb method, 2513ebd75f7SEd Tanous const OperationMap& operationMap, 2521abe55efSEd Tanous const std::string& user) 2531abe55efSEd Tanous { 2543ebd75f7SEd Tanous // TODO: load user privileges from configuration as soon as its available 2553ebd75f7SEd Tanous // now we are granting all privileges to everyone. 2563ebd75f7SEd Tanous Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf", 2573ebd75f7SEd Tanous "ConfigureUsers", "ConfigureComponents"}; 2583ebd75f7SEd Tanous 2593ebd75f7SEd Tanous return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges); 26086e1b661SBorawski.Lukasz } 26186e1b661SBorawski.Lukasz 26286e1b661SBorawski.Lukasz } // namespace redfish 263