blob: 113f66ad2c91789584de28a5c76d39be7725f754 [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 *
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010065 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070066class Privileges
67{
68 public:
69 /**
70 * @brief Constructs object without any privileges active
71 *
72 */
73 Privileges() = default;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010074
Ed Tanous1abe55e2018-09-05 08:30:59 -070075 /**
76 * @brief Constructs object with given privileges active
77 *
78 * @param[in] privilegeList List of privileges to be activated
79 *
80 */
81 Privileges(std::initializer_list<const char*> privilegeList)
82 {
83 for (const char* privilege : privilegeList)
84 {
85 if (!setSinglePrivilege(privilege))
86 {
87 BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
88 << "in constructor";
89 }
90 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010091 }
92
Ed Tanous1abe55e2018-09-05 08:30:59 -070093 /**
94 * @brief Sets given privilege in the bitset
95 *
96 * @param[in] privilege Privilege to be set
97 *
98 * @return None
99 *
100 */
101 bool setSinglePrivilege(const char* privilege)
102 {
Ed Tanousb01bf292019-03-25 19:25:26 +0000103 for (int searchIndex = 0; searchIndex < privilegeNames.size();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700104 searchIndex++)
105 {
106 if (privilege == privilegeNames[searchIndex])
107 {
108 privilegeBitset.set(searchIndex);
109 return true;
110 }
111 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800112
Ed Tanous1abe55e2018-09-05 08:30:59 -0700113 return false;
Ed Tanousa6927792018-03-06 10:01:57 -0800114 }
115
Ed Tanous1abe55e2018-09-05 08:30:59 -0700116 /**
117 * @brief Sets given privilege in the bitset
118 *
119 * @param[in] privilege Privilege to be set
120 *
121 * @return None
122 *
123 */
124 bool setSinglePrivilege(const std::string& privilege)
125 {
126 return setSinglePrivilege(privilege.c_str());
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100127 }
Ed Tanousa6927792018-03-06 10:01:57 -0800128
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129 /**
130 * @brief Retrieves names of all active privileges for a given type
131 *
132 * @param[in] type Base or OEM
133 *
134 * @return Vector of active privileges. Pointers are valid until
135 * the setSinglePrivilege is called, or the Privilege structure is destroyed
136 *
137 */
138 std::vector<const std::string*>
139 getActivePrivilegeNames(const PrivilegeType type) const
140 {
141 std::vector<const std::string*> activePrivileges;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100142
Ed Tanousb01bf292019-03-25 19:25:26 +0000143 int searchIndex = 0;
144 int endIndex = basePrivilegeCount;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700145 if (type == PrivilegeType::OEM)
146 {
147 searchIndex = basePrivilegeCount - 1;
148 endIndex = privilegeNames.size();
149 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800150
Ed Tanous1abe55e2018-09-05 08:30:59 -0700151 for (; searchIndex < endIndex; searchIndex++)
152 {
153 if (privilegeBitset.test(searchIndex))
154 {
155 activePrivileges.emplace_back(&privilegeNames[searchIndex]);
156 }
157 }
158
159 return activePrivileges;
160 }
161
162 /**
163 * @brief Determines if this Privilege set is a superset of the given
164 * privilege set
165 *
166 * @param[in] privilege Privilege to be checked
167 *
168 * @return None
169 *
170 */
171 bool isSupersetOf(const Privileges& p) const
172 {
173 return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
174 }
175
176 private:
177 std::bitset<maxPrivilegeCount> privilegeBitset = 0;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100178};
179
Ratan Gupta6f359562019-04-03 10:39:08 +0530180inline const Privileges& getUserPrivileges(const std::string& userRole)
181{
182 // Redfish privilege : Administrator
183 if (userRole == "priv-admin")
184 {
185 static Privileges admin{"Login", "ConfigureManager", "ConfigureSelf",
186 "ConfigureUsers", "ConfigureComponents"};
187 return admin;
188 }
189 else if (userRole == "priv-operator")
190 {
191 // Redfish privilege : Operator
192 static Privileges op{"Login", "ConfigureSelf", "ConfigureComponents"};
193 return op;
194 }
anil kumar appana8e69d142019-08-26 12:49:15 +0000195 else if (userRole == "priv-user")
Ratan Gupta6f359562019-04-03 10:39:08 +0530196 {
197 // Redfish privilege : Readonly
198 static Privileges readOnly{"Login", "ConfigureSelf"};
199 return readOnly;
200 }
anil kumar appana8e69d142019-08-26 12:49:15 +0000201 else
202 {
203 // Redfish Privilege : No privileges for callback users
204 static Privileges noPriv{};
205 return noPriv;
206 }
Ratan Gupta6f359562019-04-03 10:39:08 +0530207}
208
Ed Tanouse0d918b2018-03-27 17:41:04 -0700209using OperationMap = boost::container::flat_map<boost::beast::http::verb,
210 std::vector<Privileges>>;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100211
212/**
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800213 * @brief Checks if given privileges allow to call an HTTP method
214 *
215 * @param[in] method HTTP method
216 * @param[in] user Privileges
217 *
218 * @return True if method allowed, false otherwise
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100219 *
220 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700221inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800222 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700223 const Privileges& userPrivileges)
224{
225 const auto& it = operationMap.find(method);
226 if (it == operationMap.end())
227 {
228 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800229 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700230
231 // If there are no privileges assigned, assume no privileges required
232 if (it->second.empty())
233 {
234 return true;
235 }
236
237 for (auto& requiredPrivileges : it->second)
238 {
239 if (userPrivileges.isSupersetOf(requiredPrivileges))
240 {
241 return true;
242 }
243 }
244 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800245}
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100246
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800247/**
248 * @brief Checks if a user is allowed to call an HTTP method
249 *
250 * @param[in] method HTTP method
251 * @param[in] user Username
252 *
253 * @return True if method allowed, false otherwise
254 *
255 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700256inline bool isMethodAllowedForUser(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800257 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700258 const std::string& user)
259{
260 // TODO: load user privileges from configuration as soon as its available
261 // now we are granting all privileges to everyone.
262 Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
263 "ConfigureUsers", "ConfigureComponents"};
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800264
Ed Tanous1abe55e2018-09-05 08:30:59 -0700265 return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800266}
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100267
Ed Tanous1abe55e2018-09-05 08:30:59 -0700268} // namespace redfish