blob: 08e554a86c3a2311adcc674a84518381cfaa6c68 [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
Nan Zhoud5c80ad2022-07-11 01:16:31 +000018#include "logging.hpp"
19
Tanousf00032d2018-11-05 01:18:10 -030020#include <boost/beast/http/verb.hpp>
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010021#include <boost/container/flat_map.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000022#include <boost/container/vector.hpp>
23#include <boost/move/algo/move.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050024
25#include <array>
26#include <bitset>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000027#include <cstddef>
28#include <functional>
29#include <initializer_list>
30#include <string>
31#include <string_view>
32#include <utility>
Ed Tanous1abe55e2018-09-05 08:30:59 -070033#include <vector>
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010034
Nan Zhoud5c80ad2022-07-11 01:16:31 +000035// IWYU pragma: no_include <stddef.h>
36
Ed Tanous1abe55e2018-09-05 08:30:59 -070037namespace redfish
38{
39
40enum class PrivilegeType
41{
42 BASE,
43 OEM
44};
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010045
Ed Tanousa6927792018-03-06 10:01:57 -080046/** @brief A fixed array of compile time privileges */
47constexpr std::array<const char*, 5> basePrivileges{
Ed Tanous3ebd75f2018-03-05 18:20:01 -080048 "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf",
49 "ConfigureUsers"};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010050
Ed Tanous271584a2019-07-09 16:24:22 -070051constexpr const size_t basePrivilegeCount = basePrivileges.size();
Ed Tanousa6927792018-03-06 10:01:57 -080052
53/** @brief Max number of privileges per type */
Ed Tanous271584a2019-07-09 16:24:22 -070054constexpr const size_t maxPrivilegeCount = 32;
Ed Tanousa6927792018-03-06 10:01:57 -080055
56/** @brief A vector of all privilege names and their indexes */
Ed Tanous23a21a12020-07-25 04:45:05 +000057static const std::array<std::string, maxPrivilegeCount> privilegeNames{
58 "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf",
59 "ConfigureUsers"};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010060
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010061/**
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010062 * @brief Redfish privileges
63 *
Joseph Reynolds900f9492019-11-25 15:37:29 -060064 * This implements a set of Redfish privileges. These directly represent
65 * user privileges and help represent entity privileges.
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010066 *
Ed Tanous55c7b7a2018-05-22 15:27:24 -070067 * Each incoming Connection requires a comparison between privileges held
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010068 * by the user issuing a request and the target entity's privileges.
69 *
70 * To ensure best runtime performance of this comparison, privileges
71 * are represented as bitsets. Each bit in the bitset corresponds to a
72 * unique privilege name.
73 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010074 * A bit is set if the privilege is required (entity domain) or granted
75 * (user domain) and false otherwise.
76 *
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010077 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070078class Privileges
79{
80 public:
81 /**
82 * @brief Constructs object without any privileges active
83 *
84 */
85 Privileges() = default;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010086
Ed Tanous1abe55e2018-09-05 08:30:59 -070087 /**
88 * @brief Constructs object with given privileges active
89 *
90 * @param[in] privilegeList List of privileges to be activated
91 *
92 */
93 Privileges(std::initializer_list<const char*> privilegeList)
94 {
95 for (const char* privilege : privilegeList)
96 {
97 if (!setSinglePrivilege(privilege))
98 {
99 BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
100 << "in constructor";
101 }
102 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100103 }
104
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105 /**
106 * @brief Sets given privilege in the bitset
107 *
108 * @param[in] privilege Privilege to be set
109 *
110 * @return None
111 *
112 */
Ed Tanous26ccae32023-02-16 10:28:44 -0800113 bool setSinglePrivilege(std::string_view privilege)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700114 {
Ed Tanous271584a2019-07-09 16:24:22 -0700115 for (size_t searchIndex = 0; searchIndex < privilegeNames.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700116 searchIndex++)
117 {
118 if (privilege == privilegeNames[searchIndex])
119 {
120 privilegeBitset.set(searchIndex);
121 return true;
122 }
123 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800124
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125 return false;
Ed Tanousa6927792018-03-06 10:01:57 -0800126 }
127
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 /**
Joseph Reynolds900f9492019-11-25 15:37:29 -0600129 * @brief Resets the given privilege in the bitset
130 *
131 * @param[in] privilege Privilege to be reset
132 *
133 * @return None
134 *
135 */
136 bool resetSinglePrivilege(const char* privilege)
137 {
138 for (size_t searchIndex = 0; searchIndex < privilegeNames.size();
139 searchIndex++)
140 {
141 if (privilege == privilegeNames[searchIndex])
142 {
143 privilegeBitset.reset(searchIndex);
144 return true;
145 }
146 }
147 return false;
148 }
149
150 /**
Ed Tanous1abe55e2018-09-05 08:30:59 -0700151 * @brief Retrieves names of all active privileges for a given type
152 *
153 * @param[in] type Base or OEM
154 *
155 * @return Vector of active privileges. Pointers are valid until
156 * the setSinglePrivilege is called, or the Privilege structure is destroyed
157 *
158 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000159 std::vector<std::string>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700160 getActivePrivilegeNames(const PrivilegeType type) const
161 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000162 std::vector<std::string> activePrivileges;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100163
Ed Tanous271584a2019-07-09 16:24:22 -0700164 size_t searchIndex = 0;
165 size_t endIndex = basePrivilegeCount;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700166 if (type == PrivilegeType::OEM)
167 {
Joseph Reynolds87704462021-08-24 14:42:39 -0500168 searchIndex = basePrivilegeCount;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700169 endIndex = privilegeNames.size();
170 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800171
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172 for (; searchIndex < endIndex; searchIndex++)
173 {
174 if (privilegeBitset.test(searchIndex))
175 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000176 activePrivileges.emplace_back(privilegeNames[searchIndex]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700177 }
178 }
179
180 return activePrivileges;
181 }
182
183 /**
184 * @brief Determines if this Privilege set is a superset of the given
185 * privilege set
186 *
187 * @param[in] privilege Privilege to be checked
188 *
189 * @return None
190 *
191 */
192 bool isSupersetOf(const Privileges& p) const
193 {
194 return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
195 }
196
Joseph Reynolds3bf4e632020-02-06 14:44:32 -0600197 /**
198 * @brief Returns the intersection of two Privilege sets.
199 *
200 * @param[in] privilege Privilege set to intersect with.
201 *
202 * @return The new Privilege set.
203 *
204 */
205 Privileges intersection(const Privileges& p) const
206 {
207 return Privileges{privilegeBitset & p.privilegeBitset};
208 }
209
Ed Tanous1abe55e2018-09-05 08:30:59 -0700210 private:
Ed Tanous4e23a442022-06-06 09:57:26 -0700211 explicit Privileges(const std::bitset<maxPrivilegeCount>& p) :
212 privilegeBitset{p}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500213 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700214 std::bitset<maxPrivilegeCount> privilegeBitset = 0;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100215};
216
Ratan Gupta6f359562019-04-03 10:39:08 +0530217inline const Privileges& getUserPrivileges(const std::string& userRole)
218{
219 // Redfish privilege : Administrator
220 if (userRole == "priv-admin")
221 {
222 static Privileges admin{"Login", "ConfigureManager", "ConfigureSelf",
223 "ConfigureUsers", "ConfigureComponents"};
224 return admin;
225 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700226 if (userRole == "priv-operator")
Ratan Gupta6f359562019-04-03 10:39:08 +0530227 {
228 // Redfish privilege : Operator
229 static Privileges op{"Login", "ConfigureSelf", "ConfigureComponents"};
230 return op;
231 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700232 if (userRole == "priv-user")
Ratan Gupta6f359562019-04-03 10:39:08 +0530233 {
234 // Redfish privilege : Readonly
235 static Privileges readOnly{"Login", "ConfigureSelf"};
236 return readOnly;
237 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700238 // Redfish privilege : NoAccess
239 static Privileges noaccess;
240 return noaccess;
Ratan Gupta6f359562019-04-03 10:39:08 +0530241}
242
Joseph Reynolds900f9492019-11-25 15:37:29 -0600243/**
244 * @brief The OperationMap represents the privileges required for a
245 * single entity (URI). It maps from the allowable verbs to the
246 * privileges required to use that operation.
247 *
248 * This represents the Redfish "Privilege AND and OR syntax" as given
249 * in the spec and shown in the Privilege Registry. This does not
250 * implement any Redfish property overrides, subordinate overrides, or
251 * resource URI overrides. This does not implement the limitation of
252 * the ConfigureSelf privilege to operate only on your own account or
253 * session.
254 **/
Ed Tanouse0d918b2018-03-27 17:41:04 -0700255using OperationMap = boost::container::flat_map<boost::beast::http::verb,
256 std::vector<Privileges>>;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100257
Joseph Reynolds900f9492019-11-25 15:37:29 -0600258/* @brief Checks if user is allowed to call an operation
259 *
260 * @param[in] operationPrivilegesRequired Privileges required
261 * @param[in] userPrivileges Privileges the user has
262 *
263 * @return True if operation is allowed, false otherwise
264 */
265inline bool isOperationAllowedWithPrivileges(
266 const std::vector<Privileges>& operationPrivilegesRequired,
267 const Privileges& userPrivileges)
268{
269 // If there are no privileges assigned, there are no privileges required
270 if (operationPrivilegesRequired.empty())
271 {
272 return true;
273 }
Ed Tanous9eb808c2022-01-25 10:19:23 -0800274 for (const auto& requiredPrivileges : operationPrivilegesRequired)
Joseph Reynolds900f9492019-11-25 15:37:29 -0600275 {
Andrew Geissler54fbf172021-11-11 15:59:30 -0600276 BMCWEB_LOG_DEBUG << "Checking operation privileges...";
Joseph Reynolds900f9492019-11-25 15:37:29 -0600277 if (userPrivileges.isSupersetOf(requiredPrivileges))
278 {
Andrew Geissler54fbf172021-11-11 15:59:30 -0600279 BMCWEB_LOG_DEBUG << "...success";
Joseph Reynolds900f9492019-11-25 15:37:29 -0600280 return true;
281 }
282 }
283 return false;
284}
285
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100286/**
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800287 * @brief Checks if given privileges allow to call an HTTP method
288 *
289 * @param[in] method HTTP method
290 * @param[in] user Privileges
291 *
292 * @return True if method allowed, false otherwise
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100293 *
294 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700295inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800296 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700297 const Privileges& userPrivileges)
298{
299 const auto& it = operationMap.find(method);
300 if (it == operationMap.end())
301 {
302 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800303 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700304
Joseph Reynolds900f9492019-11-25 15:37:29 -0600305 return isOperationAllowedWithPrivileges(it->second, userPrivileges);
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800306}
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100307
Ed Tanous1abe55e2018-09-05 08:30:59 -0700308} // namespace redfish