blob: ca445518355cf201cc739e25b050b0e01c7e3c53 [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
Ed Tanouse0d918b2018-03-27 17:41:04 -0700180using OperationMap = boost::container::flat_map<boost::beast::http::verb,
181 std::vector<Privileges>>;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100182
183/**
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800184 * @brief Checks if given privileges allow to call an HTTP method
185 *
186 * @param[in] method HTTP method
187 * @param[in] user Privileges
188 *
189 * @return True if method allowed, false otherwise
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100190 *
191 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700192inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800193 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 const Privileges& userPrivileges)
195{
196 const auto& it = operationMap.find(method);
197 if (it == operationMap.end())
198 {
199 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800200 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700201
202 // If there are no privileges assigned, assume no privileges required
203 if (it->second.empty())
204 {
205 return true;
206 }
207
208 for (auto& requiredPrivileges : it->second)
209 {
210 if (userPrivileges.isSupersetOf(requiredPrivileges))
211 {
212 return true;
213 }
214 }
215 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800216}
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100217
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800218/**
219 * @brief Checks if a user is allowed to call an HTTP method
220 *
221 * @param[in] method HTTP method
222 * @param[in] user Username
223 *
224 * @return True if method allowed, false otherwise
225 *
226 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700227inline bool isMethodAllowedForUser(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800228 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700229 const std::string& user)
230{
231 // TODO: load user privileges from configuration as soon as its available
232 // now we are granting all privileges to everyone.
233 Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
234 "ConfigureUsers", "ConfigureComponents"};
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800235
Ed Tanous1abe55e2018-09-05 08:30:59 -0700236 return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800237}
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100238
Ed Tanous1abe55e2018-09-05 08:30:59 -0700239} // namespace redfish