blob: 35f619b77a7fae62db43c5761ab641d2ca4d8555 [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
Ed Tanousc94ad492019-10-10 15:39:33 -070018#include <logging.h>
Tanousf00032d2018-11-05 01:18:10 -030019
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 Tanous271584a2019-07-09 16:24:22 -070041constexpr const size_t basePrivilegeCount = basePrivileges.size();
Ed Tanousa6927792018-03-06 10:01:57 -080042
43/** @brief Max number of privileges per type */
Ed Tanous271584a2019-07-09 16:24:22 -070044constexpr const size_t 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 *
Joseph Reynolds900f9492019-11-25 15:37:29 -060053 * This implements a set of Redfish privileges. These directly represent
54 * user privileges and help represent entity privileges.
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010055 *
Ed Tanous55c7b7a2018-05-22 15:27:24 -070056 * Each incoming Connection requires a comparison between privileges held
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010057 * by the user issuing a request and the target entity's privileges.
58 *
59 * To ensure best runtime performance of this comparison, privileges
60 * are represented as bitsets. Each bit in the bitset corresponds to a
61 * unique privilege name.
62 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010063 * A bit is set if the privilege is required (entity domain) or granted
64 * (user domain) and false otherwise.
65 *
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010066 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070067class Privileges
68{
69 public:
70 /**
71 * @brief Constructs object without any privileges active
72 *
73 */
74 Privileges() = default;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010075
Ed Tanous1abe55e2018-09-05 08:30:59 -070076 /**
77 * @brief Constructs object with given privileges active
78 *
79 * @param[in] privilegeList List of privileges to be activated
80 *
81 */
82 Privileges(std::initializer_list<const char*> privilegeList)
83 {
84 for (const char* privilege : privilegeList)
85 {
86 if (!setSinglePrivilege(privilege))
87 {
88 BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
89 << "in constructor";
90 }
91 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010092 }
93
Ed Tanous1abe55e2018-09-05 08:30:59 -070094 /**
95 * @brief Sets given privilege in the bitset
96 *
97 * @param[in] privilege Privilege to be set
98 *
99 * @return None
100 *
101 */
102 bool setSinglePrivilege(const char* privilege)
103 {
Ed Tanous271584a2019-07-09 16:24:22 -0700104 for (size_t searchIndex = 0; searchIndex < privilegeNames.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105 searchIndex++)
106 {
107 if (privilege == privilegeNames[searchIndex])
108 {
109 privilegeBitset.set(searchIndex);
110 return true;
111 }
112 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800113
Ed Tanous1abe55e2018-09-05 08:30:59 -0700114 return false;
Ed Tanousa6927792018-03-06 10:01:57 -0800115 }
116
Ed Tanous1abe55e2018-09-05 08:30:59 -0700117 /**
118 * @brief Sets given privilege in the bitset
119 *
120 * @param[in] privilege Privilege to be set
121 *
122 * @return None
123 *
124 */
125 bool setSinglePrivilege(const std::string& privilege)
126 {
127 return setSinglePrivilege(privilege.c_str());
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100128 }
Ed Tanousa6927792018-03-06 10:01:57 -0800129
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 /**
Joseph Reynolds900f9492019-11-25 15:37:29 -0600131 * @brief Resets the given privilege in the bitset
132 *
133 * @param[in] privilege Privilege to be reset
134 *
135 * @return None
136 *
137 */
138 bool resetSinglePrivilege(const char* privilege)
139 {
140 for (size_t searchIndex = 0; searchIndex < privilegeNames.size();
141 searchIndex++)
142 {
143 if (privilege == privilegeNames[searchIndex])
144 {
145 privilegeBitset.reset(searchIndex);
146 return true;
147 }
148 }
149 return false;
150 }
151
152 /**
Ed Tanous1abe55e2018-09-05 08:30:59 -0700153 * @brief Retrieves names of all active privileges for a given type
154 *
155 * @param[in] type Base or OEM
156 *
157 * @return Vector of active privileges. Pointers are valid until
158 * the setSinglePrivilege is called, or the Privilege structure is destroyed
159 *
160 */
161 std::vector<const std::string*>
162 getActivePrivilegeNames(const PrivilegeType type) const
163 {
164 std::vector<const std::string*> activePrivileges;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100165
Ed Tanous271584a2019-07-09 16:24:22 -0700166 size_t searchIndex = 0;
167 size_t endIndex = basePrivilegeCount;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700168 if (type == PrivilegeType::OEM)
169 {
170 searchIndex = basePrivilegeCount - 1;
171 endIndex = privilegeNames.size();
172 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800173
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 for (; searchIndex < endIndex; searchIndex++)
175 {
176 if (privilegeBitset.test(searchIndex))
177 {
178 activePrivileges.emplace_back(&privilegeNames[searchIndex]);
179 }
180 }
181
182 return activePrivileges;
183 }
184
185 /**
186 * @brief Determines if this Privilege set is a superset of the given
187 * privilege set
188 *
189 * @param[in] privilege Privilege to be checked
190 *
191 * @return None
192 *
193 */
194 bool isSupersetOf(const Privileges& p) const
195 {
196 return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
197 }
198
Joseph Reynolds3bf4e632020-02-06 14:44:32 -0600199 /**
200 * @brief Returns the intersection of two Privilege sets.
201 *
202 * @param[in] privilege Privilege set to intersect with.
203 *
204 * @return The new Privilege set.
205 *
206 */
207 Privileges intersection(const Privileges& p) const
208 {
209 return Privileges{privilegeBitset & p.privilegeBitset};
210 }
211
Ed Tanous1abe55e2018-09-05 08:30:59 -0700212 private:
Joseph Reynolds3bf4e632020-02-06 14:44:32 -0600213 Privileges(const std::bitset<maxPrivilegeCount>& p) : privilegeBitset{p}
214 {
215 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700216 std::bitset<maxPrivilegeCount> privilegeBitset = 0;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100217};
218
Ratan Gupta6f359562019-04-03 10:39:08 +0530219inline const Privileges& getUserPrivileges(const std::string& userRole)
220{
221 // Redfish privilege : Administrator
222 if (userRole == "priv-admin")
223 {
224 static Privileges admin{"Login", "ConfigureManager", "ConfigureSelf",
225 "ConfigureUsers", "ConfigureComponents"};
226 return admin;
227 }
228 else if (userRole == "priv-operator")
229 {
230 // Redfish privilege : Operator
231 static Privileges op{"Login", "ConfigureSelf", "ConfigureComponents"};
232 return op;
233 }
jayaprakash Mutyalad7e08022019-12-05 23:29:13 +0000234 else if (userRole == "priv-user")
Ratan Gupta6f359562019-04-03 10:39:08 +0530235 {
236 // Redfish privilege : Readonly
237 static Privileges readOnly{"Login", "ConfigureSelf"};
238 return readOnly;
239 }
jayaprakash Mutyalad7e08022019-12-05 23:29:13 +0000240 else
241 {
242 // Redfish privilege : NoAccess
243 static Privileges noaccess;
244 return noaccess;
245 }
Ratan Gupta6f359562019-04-03 10:39:08 +0530246}
247
Joseph Reynolds900f9492019-11-25 15:37:29 -0600248/**
249 * @brief The OperationMap represents the privileges required for a
250 * single entity (URI). It maps from the allowable verbs to the
251 * privileges required to use that operation.
252 *
253 * This represents the Redfish "Privilege AND and OR syntax" as given
254 * in the spec and shown in the Privilege Registry. This does not
255 * implement any Redfish property overrides, subordinate overrides, or
256 * resource URI overrides. This does not implement the limitation of
257 * the ConfigureSelf privilege to operate only on your own account or
258 * session.
259 **/
Ed Tanouse0d918b2018-03-27 17:41:04 -0700260using OperationMap = boost::container::flat_map<boost::beast::http::verb,
261 std::vector<Privileges>>;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100262
Joseph Reynolds900f9492019-11-25 15:37:29 -0600263/* @brief Checks if user is allowed to call an operation
264 *
265 * @param[in] operationPrivilegesRequired Privileges required
266 * @param[in] userPrivileges Privileges the user has
267 *
268 * @return True if operation is allowed, false otherwise
269 */
270inline bool isOperationAllowedWithPrivileges(
271 const std::vector<Privileges>& operationPrivilegesRequired,
272 const Privileges& userPrivileges)
273{
274 // If there are no privileges assigned, there are no privileges required
275 if (operationPrivilegesRequired.empty())
276 {
277 return true;
278 }
279 for (auto& requiredPrivileges : operationPrivilegesRequired)
280 {
281 BMCWEB_LOG_ERROR << "Checking operation privileges...";
282 if (userPrivileges.isSupersetOf(requiredPrivileges))
283 {
284 BMCWEB_LOG_ERROR << "...success";
285 return true;
286 }
287 }
288 return false;
289}
290
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100291/**
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800292 * @brief Checks if given privileges allow to call an HTTP method
293 *
294 * @param[in] method HTTP method
295 * @param[in] user Privileges
296 *
297 * @return True if method allowed, false otherwise
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100298 *
299 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700300inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800301 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700302 const Privileges& userPrivileges)
303{
304 const auto& it = operationMap.find(method);
305 if (it == operationMap.end())
306 {
307 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800308 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700309
Joseph Reynolds900f9492019-11-25 15:37:29 -0600310 return isOperationAllowedWithPrivileges(it->second, userPrivileges);
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800311}
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100312
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800313/**
314 * @brief Checks if a user is allowed to call an HTTP method
315 *
316 * @param[in] method HTTP method
317 * @param[in] user Username
318 *
319 * @return True if method allowed, false otherwise
320 *
321 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700322inline bool isMethodAllowedForUser(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800323 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700324 const std::string& user)
325{
326 // TODO: load user privileges from configuration as soon as its available
327 // now we are granting all privileges to everyone.
328 Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
329 "ConfigureUsers", "ConfigureComponents"};
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800330
Ed Tanous1abe55e2018-09-05 08:30:59 -0700331 return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800332}
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100333
Ed Tanous1abe55e2018-09-05 08:30:59 -0700334} // namespace redfish