1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #pragma once 17 18 #include <bitset> 19 #include <boost/container/flat_map.hpp> 20 #include <cstdint> 21 #include <vector> 22 23 namespace redfish 24 { 25 26 enum class PrivilegeType 27 { 28 BASE, 29 OEM 30 }; 31 32 /** @brief A fixed array of compile time privileges */ 33 constexpr std::array<const char*, 5> basePrivileges{ 34 "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf", 35 "ConfigureUsers"}; 36 37 constexpr const int basePrivilegeCount = basePrivileges.size(); 38 39 /** @brief Max number of privileges per type */ 40 constexpr const int maxPrivilegeCount = 32; 41 42 /** @brief A vector of all privilege names and their indexes */ 43 static const std::vector<std::string> privilegeNames{basePrivileges.begin(), 44 basePrivileges.end()}; 45 46 /** 47 * @brief Redfish privileges 48 * 49 * Entity privileges and user privileges are represented by this class. 50 * 51 * Each incoming Connection requires a comparison between privileges held 52 * by the user issuing a request and the target entity's privileges. 53 * 54 * To ensure best runtime performance of this comparison, privileges 55 * are represented as bitsets. Each bit in the bitset corresponds to a 56 * unique privilege name. 57 * 58 * A bit is set if the privilege is required (entity domain) or granted 59 * (user domain) and false otherwise. 60 * 61 */ 62 class Privileges 63 { 64 public: 65 /** 66 * @brief Constructs object without any privileges active 67 * 68 */ 69 Privileges() = default; 70 71 /** 72 * @brief Constructs object with given privileges active 73 * 74 * @param[in] privilegeList List of privileges to be activated 75 * 76 */ 77 Privileges(std::initializer_list<const char*> privilegeList) 78 { 79 for (const char* privilege : privilegeList) 80 { 81 if (!setSinglePrivilege(privilege)) 82 { 83 BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege 84 << "in constructor"; 85 } 86 } 87 } 88 89 /** 90 * @brief Sets given privilege in the bitset 91 * 92 * @param[in] privilege Privilege to be set 93 * 94 * @return None 95 * 96 */ 97 bool setSinglePrivilege(const char* privilege) 98 { 99 for (int searchIndex = 0; searchIndex < privilegeNames.size(); 100 searchIndex++) 101 { 102 if (privilege == privilegeNames[searchIndex]) 103 { 104 privilegeBitset.set(searchIndex); 105 return true; 106 } 107 } 108 109 return false; 110 } 111 112 /** 113 * @brief Sets given privilege in the bitset 114 * 115 * @param[in] privilege Privilege to be set 116 * 117 * @return None 118 * 119 */ 120 bool setSinglePrivilege(const std::string& privilege) 121 { 122 return setSinglePrivilege(privilege.c_str()); 123 } 124 125 /** 126 * @brief Retrieves names of all active privileges for a given type 127 * 128 * @param[in] type Base or OEM 129 * 130 * @return Vector of active privileges. Pointers are valid until 131 * the setSinglePrivilege is called, or the Privilege structure is destroyed 132 * 133 */ 134 std::vector<const std::string*> 135 getActivePrivilegeNames(const PrivilegeType type) const 136 { 137 std::vector<const std::string*> activePrivileges; 138 139 int searchIndex = 0; 140 int endIndex = basePrivilegeCount; 141 if (type == PrivilegeType::OEM) 142 { 143 searchIndex = basePrivilegeCount - 1; 144 endIndex = privilegeNames.size(); 145 } 146 147 for (; searchIndex < endIndex; searchIndex++) 148 { 149 if (privilegeBitset.test(searchIndex)) 150 { 151 activePrivileges.emplace_back(&privilegeNames[searchIndex]); 152 } 153 } 154 155 return activePrivileges; 156 } 157 158 /** 159 * @brief Determines if this Privilege set is a superset of the given 160 * privilege set 161 * 162 * @param[in] privilege Privilege to be checked 163 * 164 * @return None 165 * 166 */ 167 bool isSupersetOf(const Privileges& p) const 168 { 169 return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset; 170 } 171 172 private: 173 std::bitset<maxPrivilegeCount> privilegeBitset = 0; 174 }; 175 176 using OperationMap = boost::container::flat_map<boost::beast::http::verb, 177 std::vector<Privileges>>; 178 179 /** 180 * @brief Checks if given privileges allow to call an HTTP method 181 * 182 * @param[in] method HTTP method 183 * @param[in] user Privileges 184 * 185 * @return True if method allowed, false otherwise 186 * 187 */ 188 inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method, 189 const OperationMap& operationMap, 190 const Privileges& userPrivileges) 191 { 192 const auto& it = operationMap.find(method); 193 if (it == operationMap.end()) 194 { 195 return false; 196 } 197 198 // If there are no privileges assigned, assume no privileges required 199 if (it->second.empty()) 200 { 201 return true; 202 } 203 204 for (auto& requiredPrivileges : it->second) 205 { 206 if (userPrivileges.isSupersetOf(requiredPrivileges)) 207 { 208 return true; 209 } 210 } 211 return false; 212 } 213 214 /** 215 * @brief Checks if a user is allowed to call an HTTP method 216 * 217 * @param[in] method HTTP method 218 * @param[in] user Username 219 * 220 * @return True if method allowed, false otherwise 221 * 222 */ 223 inline bool isMethodAllowedForUser(const boost::beast::http::verb method, 224 const OperationMap& operationMap, 225 const std::string& user) 226 { 227 // TODO: load user privileges from configuration as soon as its available 228 // now we are granting all privileges to everyone. 229 Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf", 230 "ConfigureUsers", "ConfigureComponents"}; 231 232 return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges); 233 } 234 235 } // namespace redfish 236