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> 20aecb47a4SBorawski.Lukasz #include <boost/optional.hpp> 21*1abe55efSEd Tanous #include <cstdint> 22*1abe55efSEd Tanous #include <vector> 23aecb47a4SBorawski.Lukasz 24*1abe55efSEd Tanous #include "crow.h" 2586e1b661SBorawski.Lukasz 26*1abe55efSEd Tanous namespace redfish 27*1abe55efSEd Tanous { 28*1abe55efSEd Tanous 29*1abe55efSEd Tanous enum class PrivilegeType 30*1abe55efSEd Tanous { 31*1abe55efSEd Tanous BASE, 32*1abe55efSEd Tanous OEM 33*1abe55efSEd Tanous }; 34aecb47a4SBorawski.Lukasz 35a692779fSEd Tanous /** @brief A fixed array of compile time privileges */ 36a692779fSEd Tanous constexpr std::array<const char*, 5> basePrivileges{ 373ebd75f7SEd Tanous "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf", 383ebd75f7SEd Tanous "ConfigureUsers"}; 3943a095abSBorawski.Lukasz 40a692779fSEd Tanous constexpr const int basePrivilegeCount = basePrivileges.size(); 41a692779fSEd Tanous 42a692779fSEd Tanous /** @brief Max number of privileges per type */ 4355c7b7a2SEd Tanous constexpr const int maxPrivilegeCount = 32; 44a692779fSEd Tanous 45a692779fSEd Tanous /** @brief A vector of all privilege names and their indexes */ 46a692779fSEd Tanous static const std::vector<std::string> privilegeNames{basePrivileges.begin(), 47a692779fSEd Tanous basePrivileges.end()}; 4843a095abSBorawski.Lukasz 4986e1b661SBorawski.Lukasz /** 50aecb47a4SBorawski.Lukasz * @brief Redfish privileges 51aecb47a4SBorawski.Lukasz * 52aecb47a4SBorawski.Lukasz * Entity privileges and user privileges are represented by this class. 53aecb47a4SBorawski.Lukasz * 5455c7b7a2SEd Tanous * Each incoming Connection requires a comparison between privileges held 55aecb47a4SBorawski.Lukasz * by the user issuing a request and the target entity's privileges. 56aecb47a4SBorawski.Lukasz * 57aecb47a4SBorawski.Lukasz * To ensure best runtime performance of this comparison, privileges 58aecb47a4SBorawski.Lukasz * are represented as bitsets. Each bit in the bitset corresponds to a 59aecb47a4SBorawski.Lukasz * unique privilege name. 60aecb47a4SBorawski.Lukasz * 61aecb47a4SBorawski.Lukasz * A bit is set if the privilege is required (entity domain) or granted 62aecb47a4SBorawski.Lukasz * (user domain) and false otherwise. 63aecb47a4SBorawski.Lukasz * 6486e1b661SBorawski.Lukasz */ 65*1abe55efSEd Tanous class Privileges 66*1abe55efSEd Tanous { 67aecb47a4SBorawski.Lukasz public: 68aecb47a4SBorawski.Lukasz /** 6943a095abSBorawski.Lukasz * @brief Constructs object without any privileges active 7043a095abSBorawski.Lukasz * 7143a095abSBorawski.Lukasz */ 7243a095abSBorawski.Lukasz Privileges() = default; 7343a095abSBorawski.Lukasz 7443a095abSBorawski.Lukasz /** 7543a095abSBorawski.Lukasz * @brief Constructs object with given privileges active 7643a095abSBorawski.Lukasz * 7743a095abSBorawski.Lukasz * @param[in] privilegeList List of privileges to be activated 7843a095abSBorawski.Lukasz * 7943a095abSBorawski.Lukasz */ 80*1abe55efSEd Tanous Privileges(std::initializer_list<const char*> privilegeList) 81*1abe55efSEd Tanous { 82*1abe55efSEd Tanous for (const char* privilege : privilegeList) 83*1abe55efSEd Tanous { 84*1abe55efSEd Tanous if (!setSinglePrivilege(privilege)) 85*1abe55efSEd Tanous { 8655c7b7a2SEd Tanous BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege 873ebd75f7SEd Tanous << "in constructor"; 8843a095abSBorawski.Lukasz } 8943a095abSBorawski.Lukasz } 903ebd75f7SEd Tanous } 91aecb47a4SBorawski.Lukasz 92aecb47a4SBorawski.Lukasz /** 93aecb47a4SBorawski.Lukasz * @brief Sets given privilege in the bitset 94aecb47a4SBorawski.Lukasz * 95aecb47a4SBorawski.Lukasz * @param[in] privilege Privilege to be set 96aecb47a4SBorawski.Lukasz * 97aecb47a4SBorawski.Lukasz * @return None 9843a095abSBorawski.Lukasz * 99aecb47a4SBorawski.Lukasz */ 100*1abe55efSEd Tanous bool setSinglePrivilege(const char* privilege) 101*1abe55efSEd Tanous { 10255c7b7a2SEd Tanous for (int searchIndex = 0; searchIndex < privilegeNames.size(); 103*1abe55efSEd Tanous searchIndex++) 104*1abe55efSEd Tanous { 105*1abe55efSEd Tanous if (privilege == privilegeNames[searchIndex]) 106*1abe55efSEd Tanous { 10755c7b7a2SEd Tanous privilegeBitset.set(searchIndex); 1083ebd75f7SEd Tanous return true; 109aecb47a4SBorawski.Lukasz } 110a692779fSEd Tanous } 111aecb47a4SBorawski.Lukasz 1123ebd75f7SEd Tanous return false; 1133ebd75f7SEd Tanous } 1143ebd75f7SEd Tanous 1153ebd75f7SEd Tanous /** 1163ebd75f7SEd Tanous * @brief Sets given privilege in the bitset 1173ebd75f7SEd Tanous * 1183ebd75f7SEd Tanous * @param[in] privilege Privilege to be set 1193ebd75f7SEd Tanous * 1203ebd75f7SEd Tanous * @return None 1213ebd75f7SEd Tanous * 1223ebd75f7SEd Tanous */ 123*1abe55efSEd Tanous bool setSinglePrivilege(const std::string& privilege) 124*1abe55efSEd Tanous { 1253ebd75f7SEd Tanous return setSinglePrivilege(privilege.c_str()); 126aecb47a4SBorawski.Lukasz } 127aecb47a4SBorawski.Lukasz 128aecb47a4SBorawski.Lukasz /** 129aecb47a4SBorawski.Lukasz * @brief Retrieves names of all active privileges for a given type 130aecb47a4SBorawski.Lukasz * 131aecb47a4SBorawski.Lukasz * @param[in] type Base or OEM 132aecb47a4SBorawski.Lukasz * 1333ebd75f7SEd Tanous * @return Vector of active privileges. Pointers are valid until 134a692779fSEd Tanous * the setSinglePrivilege is called, or the Privilege structure is destroyed 13543a095abSBorawski.Lukasz * 136aecb47a4SBorawski.Lukasz */ 137*1abe55efSEd Tanous std::vector<const std::string*> 138*1abe55efSEd Tanous getActivePrivilegeNames(const PrivilegeType type) const 139*1abe55efSEd Tanous { 1403ebd75f7SEd Tanous std::vector<const std::string*> activePrivileges; 141aecb47a4SBorawski.Lukasz 14255c7b7a2SEd Tanous int searchIndex = 0; 14355c7b7a2SEd Tanous int endIndex = basePrivilegeCount; 144*1abe55efSEd Tanous if (type == PrivilegeType::OEM) 145*1abe55efSEd Tanous { 14655c7b7a2SEd Tanous searchIndex = basePrivilegeCount - 1; 14755c7b7a2SEd Tanous endIndex = privilegeNames.size(); 148a692779fSEd Tanous } 149a692779fSEd Tanous 150*1abe55efSEd Tanous for (; searchIndex < endIndex; searchIndex++) 151*1abe55efSEd Tanous { 152*1abe55efSEd Tanous if (privilegeBitset.test(searchIndex)) 153*1abe55efSEd Tanous { 15455c7b7a2SEd Tanous activePrivileges.emplace_back(&privilegeNames[searchIndex]); 155aecb47a4SBorawski.Lukasz } 156aecb47a4SBorawski.Lukasz } 157a692779fSEd Tanous 158aecb47a4SBorawski.Lukasz return activePrivileges; 159aecb47a4SBorawski.Lukasz } 160aecb47a4SBorawski.Lukasz 1613ebd75f7SEd Tanous /** 1623ebd75f7SEd Tanous * @brief Determines if this Privilege set is a superset of the given 1633ebd75f7SEd Tanous * privilege set 1643ebd75f7SEd Tanous * 1653ebd75f7SEd Tanous * @param[in] privilege Privilege to be checked 1663ebd75f7SEd Tanous * 1673ebd75f7SEd Tanous * @return None 1683ebd75f7SEd Tanous * 1693ebd75f7SEd Tanous */ 170*1abe55efSEd Tanous bool isSupersetOf(const Privileges& p) const 171*1abe55efSEd Tanous { 172a692779fSEd Tanous return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset; 1733ebd75f7SEd Tanous } 1743ebd75f7SEd Tanous 17586e1b661SBorawski.Lukasz private: 17655c7b7a2SEd Tanous std::bitset<maxPrivilegeCount> privilegeBitset = 0; 17786e1b661SBorawski.Lukasz }; 17886e1b661SBorawski.Lukasz 179e0d918bcSEd Tanous using OperationMap = boost::container::flat_map<boost::beast::http::verb, 180e0d918bcSEd Tanous std::vector<Privileges>>; 18143a095abSBorawski.Lukasz 18243a095abSBorawski.Lukasz /** 183aecb47a4SBorawski.Lukasz * @brief Checks if given privileges allow to call an HTTP method 184aecb47a4SBorawski.Lukasz * 185aecb47a4SBorawski.Lukasz * @param[in] method HTTP method 186aecb47a4SBorawski.Lukasz * @param[in] user Privileges 187aecb47a4SBorawski.Lukasz * 188aecb47a4SBorawski.Lukasz * @return True if method allowed, false otherwise 18943a095abSBorawski.Lukasz * 190aecb47a4SBorawski.Lukasz */ 191e0d918bcSEd Tanous inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method, 1923ebd75f7SEd Tanous const OperationMap& operationMap, 193*1abe55efSEd Tanous const Privileges& userPrivileges) 194*1abe55efSEd Tanous { 1953ebd75f7SEd Tanous const auto& it = operationMap.find(method); 196*1abe55efSEd Tanous if (it == operationMap.end()) 197*1abe55efSEd Tanous { 19843a095abSBorawski.Lukasz return false; 19943a095abSBorawski.Lukasz } 200aecb47a4SBorawski.Lukasz 2013ebd75f7SEd Tanous // If there are no privileges assigned, assume no privileges required 202*1abe55efSEd Tanous if (it->second.empty()) 203*1abe55efSEd Tanous { 20443a095abSBorawski.Lukasz return true; 20543a095abSBorawski.Lukasz } 2063ebd75f7SEd Tanous 207*1abe55efSEd Tanous for (auto& requiredPrivileges : it->second) 208*1abe55efSEd Tanous { 209*1abe55efSEd Tanous if (userPrivileges.isSupersetOf(requiredPrivileges)) 210*1abe55efSEd Tanous { 2113ebd75f7SEd Tanous return true; 2123ebd75f7SEd Tanous } 2133ebd75f7SEd Tanous } 21443a095abSBorawski.Lukasz return false; 21586e1b661SBorawski.Lukasz } 216aecb47a4SBorawski.Lukasz 2173ebd75f7SEd Tanous /** 2183ebd75f7SEd Tanous * @brief Checks if a user is allowed to call an HTTP method 2193ebd75f7SEd Tanous * 2203ebd75f7SEd Tanous * @param[in] method HTTP method 2213ebd75f7SEd Tanous * @param[in] user Username 2223ebd75f7SEd Tanous * 2233ebd75f7SEd Tanous * @return True if method allowed, false otherwise 2243ebd75f7SEd Tanous * 2253ebd75f7SEd Tanous */ 226e0d918bcSEd Tanous inline bool isMethodAllowedForUser(const boost::beast::http::verb method, 2273ebd75f7SEd Tanous const OperationMap& operationMap, 228*1abe55efSEd Tanous const std::string& user) 229*1abe55efSEd Tanous { 2303ebd75f7SEd Tanous // TODO: load user privileges from configuration as soon as its available 2313ebd75f7SEd Tanous // now we are granting all privileges to everyone. 2323ebd75f7SEd Tanous Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf", 2333ebd75f7SEd Tanous "ConfigureUsers", "ConfigureComponents"}; 2343ebd75f7SEd Tanous 2353ebd75f7SEd Tanous return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges); 23686e1b661SBorawski.Lukasz } 23786e1b661SBorawski.Lukasz 23886e1b661SBorawski.Lukasz } // namespace redfish 239