blob: a62235abeae01ec746b70d2546c4bfb514c1439f [file] [log] [blame]
Borawski.Lukasz86e1b662018-01-19 14:22:14 +01001/*
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
Tanousf00032d2018-11-05 01:18:10 -030018#include <crow/logging.h>
19
20#include <array>
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010021#include <bitset>
Tanousf00032d2018-11-05 01:18:10 -030022#include <boost/beast/http/verb.hpp>
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010023#include <boost/container/flat_map.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070024#include <cstdint>
25#include <vector>
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace redfish
28{
29
30enum class PrivilegeType
31{
32 BASE,
33 OEM
34};
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010035
Ed Tanousa6927792018-03-06 10:01:57 -080036/** @brief A fixed array of compile time privileges */
37constexpr std::array<const char*, 5> basePrivileges{
Ed Tanous3ebd75f2018-03-05 18:20:01 -080038 "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf",
39 "ConfigureUsers"};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010040
Ed Tanousb01bf292019-03-25 19:25:26 +000041constexpr const int basePrivilegeCount = basePrivileges.size();
Ed Tanousa6927792018-03-06 10:01:57 -080042
43/** @brief Max number of privileges per type */
Ed Tanousb01bf292019-03-25 19:25:26 +000044constexpr const int maxPrivilegeCount = 32;
Ed Tanousa6927792018-03-06 10:01:57 -080045
46/** @brief A vector of all privilege names and their indexes */
47static const std::vector<std::string> privilegeNames{basePrivileges.begin(),
48 basePrivileges.end()};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010049
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010050/**
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010051 * @brief Redfish privileges
52 *
53 * Entity privileges and user privileges are represented by this class.
54 *
Ed Tanous55c7b7a2018-05-22 15:27:24 -070055 * Each incoming Connection requires a comparison between privileges held
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010056 * by the user issuing a request and the target entity's privileges.
57 *
58 * To ensure best runtime performance of this comparison, privileges
59 * are represented as bitsets. Each bit in the bitset corresponds to a
60 * unique privilege name.
61 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010062 * A bit is set if the privilege is required (entity domain) or granted
63 * (user domain) and false otherwise.
64 *
Joseph Reynolds8fd315a2019-09-12 12:02:33 -050065 * This does not implement any Redfish property overrides,
66 * subordinate overrides, or resource URI overrides. This does
67 * not implement the limitation of the ConfigureSelf privilege
68 * to operate only on your own account or session.
69 *
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010070 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070071class Privileges
72{
73 public:
74 /**
75 * @brief Constructs object without any privileges active
76 *
77 */
78 Privileges() = default;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010079
Ed Tanous1abe55e2018-09-05 08:30:59 -070080 /**
81 * @brief Constructs object with given privileges active
82 *
83 * @param[in] privilegeList List of privileges to be activated
84 *
85 */
86 Privileges(std::initializer_list<const char*> privilegeList)
87 {
88 for (const char* privilege : privilegeList)
89 {
90 if (!setSinglePrivilege(privilege))
91 {
92 BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
93 << "in constructor";
94 }
95 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010096 }
97
Ed Tanous1abe55e2018-09-05 08:30:59 -070098 /**
Joseph Reynolds8fd315a2019-09-12 12:02:33 -050099 * @brief Resets the given privilege in the bitset
100 *
101 * @param[in] privilege Privilege to be reset
102 *
103 * @return None
104 *
105 */
106 bool resetSinglePrivilege(const char* privilege)
107 {
108 for (int searchIndex = 0; searchIndex < privilegeNames.size();
109 searchIndex++)
110 {
111 if (privilege == privilegeNames[searchIndex])
112 {
113 privilegeBitset.reset(searchIndex);
114 return true;
115 }
116 }
117
118 return false;
119 }
120
121 /**
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122 * @brief Sets given privilege in the bitset
123 *
124 * @param[in] privilege Privilege to be set
125 *
126 * @return None
127 *
128 */
129 bool setSinglePrivilege(const char* privilege)
130 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000131 for (int searchIndex = 0; searchIndex < privilegeNames.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132 searchIndex++)
133 {
134 if (privilege == privilegeNames[searchIndex])
135 {
136 privilegeBitset.set(searchIndex);
137 return true;
138 }
139 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800140
Ed Tanous1abe55e2018-09-05 08:30:59 -0700141 return false;
Ed Tanousa6927792018-03-06 10:01:57 -0800142 }
143
Ed Tanous1abe55e2018-09-05 08:30:59 -0700144 /**
145 * @brief Sets given privilege in the bitset
146 *
147 * @param[in] privilege Privilege to be set
148 *
149 * @return None
150 *
151 */
152 bool setSinglePrivilege(const std::string& privilege)
153 {
154 return setSinglePrivilege(privilege.c_str());
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100155 }
Ed Tanousa6927792018-03-06 10:01:57 -0800156
Ed Tanous1abe55e2018-09-05 08:30:59 -0700157 /**
158 * @brief Retrieves names of all active privileges for a given type
159 *
160 * @param[in] type Base or OEM
161 *
162 * @return Vector of active privileges. Pointers are valid until
163 * the setSinglePrivilege is called, or the Privilege structure is destroyed
164 *
165 */
166 std::vector<const std::string*>
167 getActivePrivilegeNames(const PrivilegeType type) const
168 {
169 std::vector<const std::string*> activePrivileges;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100170
Ed Tanousb01bf292019-03-25 19:25:26 +0000171 int searchIndex = 0;
172 int endIndex = basePrivilegeCount;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700173 if (type == PrivilegeType::OEM)
174 {
175 searchIndex = basePrivilegeCount - 1;
176 endIndex = privilegeNames.size();
177 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800178
Ed Tanous1abe55e2018-09-05 08:30:59 -0700179 for (; searchIndex < endIndex; searchIndex++)
180 {
181 if (privilegeBitset.test(searchIndex))
182 {
183 activePrivileges.emplace_back(&privilegeNames[searchIndex]);
184 }
185 }
186
187 return activePrivileges;
188 }
189
190 /**
191 * @brief Determines if this Privilege set is a superset of the given
192 * privilege set
193 *
194 * @param[in] privilege Privilege to be checked
195 *
196 * @return None
197 *
198 */
199 bool isSupersetOf(const Privileges& p) const
200 {
201 return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
202 }
203
Joseph Reynolds8fd315a2019-09-12 12:02:33 -0500204 std::string to_string() const
205 {
206 return privilegeBitset.to_string();
207 }
208
Ed Tanous1abe55e2018-09-05 08:30:59 -0700209 private:
210 std::bitset<maxPrivilegeCount> privilegeBitset = 0;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100211};
212
Ratan Gupta6f359562019-04-03 10:39:08 +0530213inline const Privileges& getUserPrivileges(const std::string& userRole)
214{
215 // Redfish privilege : Administrator
216 if (userRole == "priv-admin")
217 {
218 static Privileges admin{"Login", "ConfigureManager", "ConfigureSelf",
219 "ConfigureUsers", "ConfigureComponents"};
220 return admin;
221 }
222 else if (userRole == "priv-operator")
223 {
224 // Redfish privilege : Operator
225 static Privileges op{"Login", "ConfigureSelf", "ConfigureComponents"};
226 return op;
227 }
Joseph Reynolds8fd315a2019-09-12 12:02:33 -0500228 else if (userRole == "special-priv-configure-self")
229 {
230 // Redfish privilege : N/A - internal within BMCWeb
231 static Privileges configSelf{"ConfigureSelf"};
232 return configSelf;
233 }
Ed Tanous88e097c2019-09-18 16:03:55 +0000234 else
Ratan Gupta6f359562019-04-03 10:39:08 +0530235 {
236 // Redfish privilege : Readonly
237 static Privileges readOnly{"Login", "ConfigureSelf"};
238 return readOnly;
239 }
240}
241
Ed Tanouse0d918b2018-03-27 17:41:04 -0700242using OperationMap = boost::container::flat_map<boost::beast::http::verb,
243 std::vector<Privileges>>;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100244
Joseph Reynolds8fd315a2019-09-12 12:02:33 -0500245/* @brief Checks if user is allowed to call an operation
246 *
247 * @param[in] operationPrivilegesRequired Privileges required
248 * @param[in] userPrivileges Privileges the user has
249 *
250 * @return True if operation is allowed, false otherwise
251 */
252inline bool isOperationAllowedWithPrivileges(
253 const std::vector<Privileges>& operationPrivilegesRequired,
254 const Privileges& userPrivileges)
255{
256 // If there are no privileges assigned, there are no privileges required
257 if (operationPrivilegesRequired.empty())
258 {
259 return true;
260 }
261 for (auto& requiredPrivileges : operationPrivilegesRequired)
262 {
263 BMCWEB_LOG_ERROR << "Checking operation privileges...";
264 if (userPrivileges.isSupersetOf(requiredPrivileges))
265 {
266 BMCWEB_LOG_ERROR << "...success";
267 return true;
268 }
269 }
270 return false;
271}
272
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100273/**
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800274 * @brief Checks if given privileges allow to call an HTTP method
275 *
276 * @param[in] method HTTP method
277 * @param[in] user Privileges
278 *
279 * @return True if method allowed, false otherwise
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100280 *
281 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700282inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800283 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700284 const Privileges& userPrivileges)
285{
286 const auto& it = operationMap.find(method);
287 if (it == operationMap.end())
288 {
289 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800290 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291
Joseph Reynolds8fd315a2019-09-12 12:02:33 -0500292 return isOperationAllowedWithPrivileges(it->second, userPrivileges);
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800293}
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100294
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800295/**
296 * @brief Checks if a user is allowed to call an HTTP method
297 *
298 * @param[in] method HTTP method
299 * @param[in] user Username
300 *
301 * @return True if method allowed, false otherwise
302 *
303 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700304inline bool isMethodAllowedForUser(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800305 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700306 const std::string& user)
307{
308 // TODO: load user privileges from configuration as soon as its available
309 // now we are granting all privileges to everyone.
310 Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
311 "ConfigureUsers", "ConfigureComponents"};
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800312
Ed Tanous1abe55e2018-09-05 08:30:59 -0700313 return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800314}
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100315
Ed Tanous1abe55e2018-09-05 08:30:59 -0700316} // namespace redfish