blob: d5201f091dc3c04f4cf370a535e1b7177e7701b1 [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 -070023#include "crow.h"
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010024
Ed Tanous1abe55e2018-09-05 08:30:59 -070025namespace redfish
26{
27
28enum class PrivilegeType
29{
30 BASE,
31 OEM
32};
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010033
Ed Tanousa6927792018-03-06 10:01:57 -080034/** @brief A fixed array of compile time privileges */
35constexpr std::array<const char*, 5> basePrivileges{
Ed Tanous3ebd75f2018-03-05 18:20:01 -080036 "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf",
37 "ConfigureUsers"};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010038
Ed Tanousa6927792018-03-06 10:01:57 -080039constexpr const int basePrivilegeCount = basePrivileges.size();
40
41/** @brief Max number of privileges per type */
Ed Tanous55c7b7a2018-05-22 15:27:24 -070042constexpr const int maxPrivilegeCount = 32;
Ed Tanousa6927792018-03-06 10:01:57 -080043
44/** @brief A vector of all privilege names and their indexes */
45static const std::vector<std::string> privilegeNames{basePrivileges.begin(),
46 basePrivileges.end()};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010047
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010048/**
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010049 * @brief Redfish privileges
50 *
51 * Entity privileges and user privileges are represented by this class.
52 *
Ed Tanous55c7b7a2018-05-22 15:27:24 -070053 * Each incoming Connection requires a comparison between privileges held
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010054 * by the user issuing a request and the target entity's privileges.
55 *
56 * To ensure best runtime performance of this comparison, privileges
57 * are represented as bitsets. Each bit in the bitset corresponds to a
58 * unique privilege name.
59 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010060 * A bit is set if the privilege is required (entity domain) or granted
61 * (user domain) and false otherwise.
62 *
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010063 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070064class Privileges
65{
66 public:
67 /**
68 * @brief Constructs object without any privileges active
69 *
70 */
71 Privileges() = default;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010072
Ed Tanous1abe55e2018-09-05 08:30:59 -070073 /**
74 * @brief Constructs object with given privileges active
75 *
76 * @param[in] privilegeList List of privileges to be activated
77 *
78 */
79 Privileges(std::initializer_list<const char*> privilegeList)
80 {
81 for (const char* privilege : privilegeList)
82 {
83 if (!setSinglePrivilege(privilege))
84 {
85 BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
86 << "in constructor";
87 }
88 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010089 }
90
Ed Tanous1abe55e2018-09-05 08:30:59 -070091 /**
92 * @brief Sets given privilege in the bitset
93 *
94 * @param[in] privilege Privilege to be set
95 *
96 * @return None
97 *
98 */
99 bool setSinglePrivilege(const char* privilege)
100 {
101 for (int searchIndex = 0; searchIndex < privilegeNames.size();
102 searchIndex++)
103 {
104 if (privilege == privilegeNames[searchIndex])
105 {
106 privilegeBitset.set(searchIndex);
107 return true;
108 }
109 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800110
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111 return false;
Ed Tanousa6927792018-03-06 10:01:57 -0800112 }
113
Ed Tanous1abe55e2018-09-05 08:30:59 -0700114 /**
115 * @brief Sets given privilege in the bitset
116 *
117 * @param[in] privilege Privilege to be set
118 *
119 * @return None
120 *
121 */
122 bool setSinglePrivilege(const std::string& privilege)
123 {
124 return setSinglePrivilege(privilege.c_str());
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100125 }
Ed Tanousa6927792018-03-06 10:01:57 -0800126
Ed Tanous1abe55e2018-09-05 08:30:59 -0700127 /**
128 * @brief Retrieves names of all active privileges for a given type
129 *
130 * @param[in] type Base or OEM
131 *
132 * @return Vector of active privileges. Pointers are valid until
133 * the setSinglePrivilege is called, or the Privilege structure is destroyed
134 *
135 */
136 std::vector<const std::string*>
137 getActivePrivilegeNames(const PrivilegeType type) const
138 {
139 std::vector<const std::string*> activePrivileges;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100140
Ed Tanous1abe55e2018-09-05 08:30:59 -0700141 int searchIndex = 0;
142 int endIndex = basePrivilegeCount;
143 if (type == PrivilegeType::OEM)
144 {
145 searchIndex = basePrivilegeCount - 1;
146 endIndex = privilegeNames.size();
147 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800148
Ed Tanous1abe55e2018-09-05 08:30:59 -0700149 for (; searchIndex < endIndex; searchIndex++)
150 {
151 if (privilegeBitset.test(searchIndex))
152 {
153 activePrivileges.emplace_back(&privilegeNames[searchIndex]);
154 }
155 }
156
157 return activePrivileges;
158 }
159
160 /**
161 * @brief Determines if this Privilege set is a superset of the given
162 * privilege set
163 *
164 * @param[in] privilege Privilege to be checked
165 *
166 * @return None
167 *
168 */
169 bool isSupersetOf(const Privileges& p) const
170 {
171 return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
172 }
173
174 private:
175 std::bitset<maxPrivilegeCount> privilegeBitset = 0;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100176};
177
Ed Tanouse0d918b2018-03-27 17:41:04 -0700178using OperationMap = boost::container::flat_map<boost::beast::http::verb,
179 std::vector<Privileges>>;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100180
181/**
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800182 * @brief Checks if given privileges allow to call an HTTP method
183 *
184 * @param[in] method HTTP method
185 * @param[in] user Privileges
186 *
187 * @return True if method allowed, false otherwise
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100188 *
189 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700190inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800191 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700192 const Privileges& userPrivileges)
193{
194 const auto& it = operationMap.find(method);
195 if (it == operationMap.end())
196 {
197 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800198 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700199
200 // If there are no privileges assigned, assume no privileges required
201 if (it->second.empty())
202 {
203 return true;
204 }
205
206 for (auto& requiredPrivileges : it->second)
207 {
208 if (userPrivileges.isSupersetOf(requiredPrivileges))
209 {
210 return true;
211 }
212 }
213 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800214}
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100215
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800216/**
217 * @brief Checks if a user is allowed to call an HTTP method
218 *
219 * @param[in] method HTTP method
220 * @param[in] user Username
221 *
222 * @return True if method allowed, false otherwise
223 *
224 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700225inline bool isMethodAllowedForUser(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800226 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700227 const std::string& user)
228{
229 // TODO: load user privileges from configuration as soon as its available
230 // now we are granting all privileges to everyone.
231 Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
232 "ConfigureUsers", "ConfigureComponents"};
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800233
Ed Tanous1abe55e2018-09-05 08:30:59 -0700234 return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800235}
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100236
Ed Tanous1abe55e2018-09-05 08:30:59 -0700237} // namespace redfish