blob: 3b20c9fda884e266a26a08a0b8cbe21af834d4b8 [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>
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010019#include <boost/container/flat_map.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070020#include <cstdint>
21#include <vector>
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010022
Ed Tanous1abe55e2018-09-05 08:30:59 -070023namespace redfish
24{
25
26enum class PrivilegeType
27{
28 BASE,
29 OEM
30};
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010031
Ed Tanousa6927792018-03-06 10:01:57 -080032/** @brief A fixed array of compile time privileges */
33constexpr std::array<const char*, 5> basePrivileges{
Ed Tanous3ebd75f2018-03-05 18:20:01 -080034 "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf",
35 "ConfigureUsers"};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010036
Ed Tanousa6927792018-03-06 10:01:57 -080037constexpr const int basePrivilegeCount = basePrivileges.size();
38
39/** @brief Max number of privileges per type */
Ed Tanous55c7b7a2018-05-22 15:27:24 -070040constexpr const int maxPrivilegeCount = 32;
Ed Tanousa6927792018-03-06 10:01:57 -080041
42/** @brief A vector of all privilege names and their indexes */
43static const std::vector<std::string> privilegeNames{basePrivileges.begin(),
44 basePrivileges.end()};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010045
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010046/**
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010047 * @brief Redfish privileges
48 *
49 * Entity privileges and user privileges are represented by this class.
50 *
Ed Tanous55c7b7a2018-05-22 15:27:24 -070051 * Each incoming Connection requires a comparison between privileges held
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010052 * by the user issuing a request and the target entity's privileges.
53 *
54 * To ensure best runtime performance of this comparison, privileges
55 * are represented as bitsets. Each bit in the bitset corresponds to a
56 * unique privilege name.
57 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010058 * A bit is set if the privilege is required (entity domain) or granted
59 * (user domain) and false otherwise.
60 *
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010061 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070062class Privileges
63{
64 public:
65 /**
66 * @brief Constructs object without any privileges active
67 *
68 */
69 Privileges() = default;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010070
Ed Tanous1abe55e2018-09-05 08:30:59 -070071 /**
72 * @brief Constructs object with given privileges active
73 *
74 * @param[in] privilegeList List of privileges to be activated
75 *
76 */
77 Privileges(std::initializer_list<const char*> privilegeList)
78 {
79 for (const char* privilege : privilegeList)
80 {
81 if (!setSinglePrivilege(privilege))
82 {
83 BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
84 << "in constructor";
85 }
86 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010087 }
88
Ed Tanous1abe55e2018-09-05 08:30:59 -070089 /**
90 * @brief Sets given privilege in the bitset
91 *
92 * @param[in] privilege Privilege to be set
93 *
94 * @return None
95 *
96 */
97 bool setSinglePrivilege(const char* privilege)
98 {
99 for (int searchIndex = 0; searchIndex < privilegeNames.size();
100 searchIndex++)
101 {
102 if (privilege == privilegeNames[searchIndex])
103 {
104 privilegeBitset.set(searchIndex);
105 return true;
106 }
107 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800108
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 return false;
Ed Tanousa6927792018-03-06 10:01:57 -0800110 }
111
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112 /**
113 * @brief Sets given privilege in the bitset
114 *
115 * @param[in] privilege Privilege to be set
116 *
117 * @return None
118 *
119 */
120 bool setSinglePrivilege(const std::string& privilege)
121 {
122 return setSinglePrivilege(privilege.c_str());
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100123 }
Ed Tanousa6927792018-03-06 10:01:57 -0800124
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125 /**
126 * @brief Retrieves names of all active privileges for a given type
127 *
128 * @param[in] type Base or OEM
129 *
130 * @return Vector of active privileges. Pointers are valid until
131 * the setSinglePrivilege is called, or the Privilege structure is destroyed
132 *
133 */
134 std::vector<const std::string*>
135 getActivePrivilegeNames(const PrivilegeType type) const
136 {
137 std::vector<const std::string*> activePrivileges;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100138
Ed Tanous1abe55e2018-09-05 08:30:59 -0700139 int searchIndex = 0;
140 int endIndex = basePrivilegeCount;
141 if (type == PrivilegeType::OEM)
142 {
143 searchIndex = basePrivilegeCount - 1;
144 endIndex = privilegeNames.size();
145 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800146
Ed Tanous1abe55e2018-09-05 08:30:59 -0700147 for (; searchIndex < endIndex; searchIndex++)
148 {
149 if (privilegeBitset.test(searchIndex))
150 {
151 activePrivileges.emplace_back(&privilegeNames[searchIndex]);
152 }
153 }
154
155 return activePrivileges;
156 }
157
158 /**
159 * @brief Determines if this Privilege set is a superset of the given
160 * privilege set
161 *
162 * @param[in] privilege Privilege to be checked
163 *
164 * @return None
165 *
166 */
167 bool isSupersetOf(const Privileges& p) const
168 {
169 return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
170 }
171
172 private:
173 std::bitset<maxPrivilegeCount> privilegeBitset = 0;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100174};
175
Ed Tanouse0d918b2018-03-27 17:41:04 -0700176using OperationMap = boost::container::flat_map<boost::beast::http::verb,
177 std::vector<Privileges>>;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100178
179/**
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800180 * @brief Checks if given privileges allow to call an HTTP method
181 *
182 * @param[in] method HTTP method
183 * @param[in] user Privileges
184 *
185 * @return True if method allowed, false otherwise
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100186 *
187 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700188inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800189 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700190 const Privileges& userPrivileges)
191{
192 const auto& it = operationMap.find(method);
193 if (it == operationMap.end())
194 {
195 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800196 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700197
198 // If there are no privileges assigned, assume no privileges required
199 if (it->second.empty())
200 {
201 return true;
202 }
203
204 for (auto& requiredPrivileges : it->second)
205 {
206 if (userPrivileges.isSupersetOf(requiredPrivileges))
207 {
208 return true;
209 }
210 }
211 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800212}
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100213
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800214/**
215 * @brief Checks if a user is allowed to call an HTTP method
216 *
217 * @param[in] method HTTP method
218 * @param[in] user Username
219 *
220 * @return True if method allowed, false otherwise
221 *
222 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700223inline bool isMethodAllowedForUser(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800224 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700225 const std::string& user)
226{
227 // TODO: load user privileges from configuration as soon as its available
228 // now we are granting all privileges to everyone.
229 Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
230 "ConfigureUsers", "ConfigureComponents"};
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800231
Ed Tanous1abe55e2018-09-05 08:30:59 -0700232 return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800233}
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100234
Ed Tanous1abe55e2018-09-05 08:30:59 -0700235} // namespace redfish