blob: 4014d6161ca316a6f6110c55c5b2a3da0b6de206 [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
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010018#include <bitset>
19#include <cstdint>
20#include "crow.h"
21#include <boost/container/flat_map.hpp>
22#include <boost/optional.hpp>
23
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010024namespace redfish {
25
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010026enum class PrivilegeType { BASE, OEM };
27
28/** @brief Max number of privileges per type */
29constexpr const size_t MAX_PRIVILEGE_COUNT = 32;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010030
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010031using privilegeBitset = std::bitset<MAX_PRIVILEGE_COUNT>;
32
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010033/** @brief Number of mappings must be <= MAX_PRIVILEGE_COUNT */
Ed Tanous3ebd75f2018-03-05 18:20:01 -080034static const std::vector<std::string> privilegeNames{
35 "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf",
36 "ConfigureUsers"};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010037
38/** @brief Number of mappings must be <= MAX_PRIVILEGE_COUNT */
Ed Tanous3ebd75f2018-03-05 18:20:01 -080039static const std::vector<std::string> oemPrivilegeNames{};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010040
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010041/**
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010042 * @brief Redfish privileges
43 *
44 * Entity privileges and user privileges are represented by this class.
45 *
46 * Each incoming connection requires a comparison between privileges held
47 * by the user issuing a request and the target entity's privileges.
48 *
49 * To ensure best runtime performance of this comparison, privileges
50 * are represented as bitsets. Each bit in the bitset corresponds to a
51 * unique privilege name.
52 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010053 * A bit is set if the privilege is required (entity domain) or granted
54 * (user domain) and false otherwise.
55 *
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010056 */
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010057class Privileges {
58 public:
59 /**
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010060 * @brief Constructs object without any privileges active
61 *
62 */
63 Privileges() = default;
64
65 /**
66 * @brief Constructs object with given privileges active
67 *
68 * @param[in] privilegeList List of privileges to be activated
69 *
70 */
Ed Tanous3ebd75f2018-03-05 18:20:01 -080071 Privileges(std::initializer_list<const char*> privilegeList) {
72 for (const char* privilege : privilegeList) {
73 if (!setSinglePrivilege(privilege)) {
74 CROW_LOG_CRITICAL << "Unable to set privilege " << privilege
75 << "in constructor";
76 }
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010077 }
78 }
79
80 /**
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010081 * @brief Sets given privilege in the bitset
82 *
83 * @param[in] privilege Privilege to be set
84 *
85 * @return None
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010086 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010087 */
Ed Tanous3ebd75f2018-03-05 18:20:01 -080088 bool setSinglePrivilege(const char* privilege) {
89 int32_t index = getBitsetIndexForPrivilege(privilege, PrivilegeType::BASE);
90 if (index >= 0) {
91 basePrivilegeBitset.set(index);
92 return true;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010093 }
94
95 index = getBitsetIndexForPrivilege(privilege, PrivilegeType::OEM);
Ed Tanous3ebd75f2018-03-05 18:20:01 -080096 if (index >= 0) {
97 oemPrivilegeBitset.set(index);
98 return true;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010099 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800100 return false;
101 }
102
103 /**
104 * @brief Sets given privilege in the bitset
105 *
106 * @param[in] privilege Privilege to be set
107 *
108 * @return None
109 *
110 */
111 bool setSinglePrivilege(const std::string& privilege) {
112 return setSinglePrivilege(privilege.c_str());
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100113 }
114
115 /**
116 * @brief Retrieves names of all active privileges for a given type
117 *
118 * @param[in] type Base or OEM
119 *
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800120 * @return Vector of active privileges. Pointers are valid until
121 * the privilege structure is modified
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100122 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100123 */
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800124 std::vector<const std::string*> getActivePrivilegeNames(
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100125 const PrivilegeType type) const {
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800126 std::vector<const std::string*> activePrivileges;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100127
128 if (type == PrivilegeType::BASE) {
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800129 for (std::size_t index = 0; index < privilegeNames.size(); index++) {
130 if (basePrivilegeBitset.test(index)) {
131 activePrivileges.emplace_back(&privilegeNames[index]);
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100132 }
133 }
134 } else {
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800135 for (std::size_t index = 0; index < oemPrivilegeNames.size(); index++) {
136 {
137 if (oemPrivilegeBitset.test(index)) {
138 activePrivileges.emplace_back(&oemPrivilegeNames[index]);
139 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100140 }
141 }
142 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100143 return activePrivileges;
144 }
145
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800146 /**
147 * @brief Determines if this Privilege set is a superset of the given
148 * privilege set
149 *
150 * @param[in] privilege Privilege to be checked
151 *
152 * @return None
153 *
154 */
155 bool isSupersetOf(const Privileges& p) const {
156 bool has_base =
157 (basePrivilegeBitset & p.basePrivilegeBitset) == p.basePrivilegeBitset;
158
159 bool has_oem =
160 (oemPrivilegeBitset & p.oemPrivilegeBitset) == p.oemPrivilegeBitset;
161 return has_base & has_oem;
162 }
163
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100164 private:
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800165 int32_t getBitsetIndexForPrivilege(const char* privilege,
166 const PrivilegeType type) const {
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100167 if (type == PrivilegeType::BASE) {
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800168 for (std::size_t index = 0; index < privilegeNames.size(); index++) {
169 if (privilege == privilegeNames[index]) {
170 return index;
171 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100172 }
173 } else {
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800174 for (std::size_t index = 0; index < oemPrivilegeNames.size(); index++) {
175 if (privilege == oemPrivilegeNames[index]) {
176 return index;
177 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100178 }
179 }
180
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800181 return -1;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100182 }
183
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800184 privilegeBitset basePrivilegeBitset = 0;
185 privilegeBitset oemPrivilegeBitset = 0;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100186};
187
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100188using OperationMap =
189 boost::container::flat_map<crow::HTTPMethod, std::vector<Privileges>>;
190
191/**
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800192 * @brief Checks if given privileges allow to call an HTTP method
193 *
194 * @param[in] method HTTP method
195 * @param[in] user Privileges
196 *
197 * @return True if method allowed, false otherwise
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100198 *
199 */
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800200inline bool isMethodAllowedWithPrivileges(const crow::HTTPMethod method,
201 const OperationMap& operationMap,
202 const Privileges& userPrivileges) {
203 const auto& it = operationMap.find(method);
204 if (it == operationMap.end()) {
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100205 return false;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100206 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100207
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800208 // If there are no privileges assigned, assume no privileges required
209 if (it->second.empty()) {
210 return true;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100211 }
212
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800213 for (auto& requiredPrivileges : it->second) {
214 if (userPrivileges.isSupersetOf(requiredPrivileges)) {
215 return true;
216 }
217 }
218 return false;
219}
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100220
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800221/**
222 * @brief Checks if a user is allowed to call an HTTP method
223 *
224 * @param[in] method HTTP method
225 * @param[in] user Username
226 *
227 * @return True if method allowed, false otherwise
228 *
229 */
230inline bool isMethodAllowedForUser(const crow::HTTPMethod method,
231 const OperationMap& operationMap,
232 const std::string& user) {
233 // TODO: load user privileges from configuration as soon as its available
234 // now we are granting all privileges to everyone.
235 Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
236 "ConfigureUsers", "ConfigureComponents"};
237
238 return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
239}
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100240
241} // namespace redfish