blob: 0f6b903793cf33dd5b1517b7a3c3713d8f9063f3 [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>
20#include <boost/optional.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070021#include <cstdint>
22#include <vector>
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010023
Ed Tanous1abe55e2018-09-05 08:30:59 -070024#include "crow.h"
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010025
Ed Tanous1abe55e2018-09-05 08:30:59 -070026namespace redfish
27{
28
29enum class PrivilegeType
30{
31 BASE,
32 OEM
33};
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010034
Ed Tanousa6927792018-03-06 10:01:57 -080035/** @brief A fixed array of compile time privileges */
36constexpr std::array<const char*, 5> basePrivileges{
Ed Tanous3ebd75f2018-03-05 18:20:01 -080037 "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf",
38 "ConfigureUsers"};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010039
Ed Tanousa6927792018-03-06 10:01:57 -080040constexpr const int basePrivilegeCount = basePrivileges.size();
41
42/** @brief Max number of privileges per type */
Ed Tanous55c7b7a2018-05-22 15:27:24 -070043constexpr const int maxPrivilegeCount = 32;
Ed Tanousa6927792018-03-06 10:01:57 -080044
45/** @brief A vector of all privilege names and their indexes */
46static const std::vector<std::string> privilegeNames{basePrivileges.begin(),
47 basePrivileges.end()};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010048
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010049/**
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010050 * @brief Redfish privileges
51 *
52 * Entity privileges and user privileges are represented by this class.
53 *
Ed Tanous55c7b7a2018-05-22 15:27:24 -070054 * Each incoming Connection requires a comparison between privileges held
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010055 * by the user issuing a request and the target entity's privileges.
56 *
57 * To ensure best runtime performance of this comparison, privileges
58 * are represented as bitsets. Each bit in the bitset corresponds to a
59 * unique privilege name.
60 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010061 * A bit is set if the privilege is required (entity domain) or granted
62 * (user domain) and false otherwise.
63 *
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010064 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070065class Privileges
66{
67 public:
68 /**
69 * @brief Constructs object without any privileges active
70 *
71 */
72 Privileges() = default;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010073
Ed Tanous1abe55e2018-09-05 08:30:59 -070074 /**
75 * @brief Constructs object with given privileges active
76 *
77 * @param[in] privilegeList List of privileges to be activated
78 *
79 */
80 Privileges(std::initializer_list<const char*> privilegeList)
81 {
82 for (const char* privilege : privilegeList)
83 {
84 if (!setSinglePrivilege(privilege))
85 {
86 BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
87 << "in constructor";
88 }
89 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010090 }
91
Ed Tanous1abe55e2018-09-05 08:30:59 -070092 /**
93 * @brief Sets given privilege in the bitset
94 *
95 * @param[in] privilege Privilege to be set
96 *
97 * @return None
98 *
99 */
100 bool setSinglePrivilege(const char* privilege)
101 {
102 for (int searchIndex = 0; searchIndex < privilegeNames.size();
103 searchIndex++)
104 {
105 if (privilege == privilegeNames[searchIndex])
106 {
107 privilegeBitset.set(searchIndex);
108 return true;
109 }
110 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800111
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112 return false;
Ed Tanousa6927792018-03-06 10:01:57 -0800113 }
114
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 /**
116 * @brief Sets given privilege in the bitset
117 *
118 * @param[in] privilege Privilege to be set
119 *
120 * @return None
121 *
122 */
123 bool setSinglePrivilege(const std::string& privilege)
124 {
125 return setSinglePrivilege(privilege.c_str());
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100126 }
Ed Tanousa6927792018-03-06 10:01:57 -0800127
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 /**
129 * @brief Retrieves names of all active privileges for a given type
130 *
131 * @param[in] type Base or OEM
132 *
133 * @return Vector of active privileges. Pointers are valid until
134 * the setSinglePrivilege is called, or the Privilege structure is destroyed
135 *
136 */
137 std::vector<const std::string*>
138 getActivePrivilegeNames(const PrivilegeType type) const
139 {
140 std::vector<const std::string*> activePrivileges;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100141
Ed Tanous1abe55e2018-09-05 08:30:59 -0700142 int searchIndex = 0;
143 int endIndex = basePrivilegeCount;
144 if (type == PrivilegeType::OEM)
145 {
146 searchIndex = basePrivilegeCount - 1;
147 endIndex = privilegeNames.size();
148 }
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800149
Ed Tanous1abe55e2018-09-05 08:30:59 -0700150 for (; searchIndex < endIndex; searchIndex++)
151 {
152 if (privilegeBitset.test(searchIndex))
153 {
154 activePrivileges.emplace_back(&privilegeNames[searchIndex]);
155 }
156 }
157
158 return activePrivileges;
159 }
160
161 /**
162 * @brief Determines if this Privilege set is a superset of the given
163 * privilege set
164 *
165 * @param[in] privilege Privilege to be checked
166 *
167 * @return None
168 *
169 */
170 bool isSupersetOf(const Privileges& p) const
171 {
172 return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
173 }
174
175 private:
176 std::bitset<maxPrivilegeCount> privilegeBitset = 0;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100177};
178
Ed Tanouse0d918b2018-03-27 17:41:04 -0700179using OperationMap = boost::container::flat_map<boost::beast::http::verb,
180 std::vector<Privileges>>;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100181
182/**
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800183 * @brief Checks if given privileges allow to call an HTTP method
184 *
185 * @param[in] method HTTP method
186 * @param[in] user Privileges
187 *
188 * @return True if method allowed, false otherwise
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100189 *
190 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700191inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800192 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193 const Privileges& userPrivileges)
194{
195 const auto& it = operationMap.find(method);
196 if (it == operationMap.end())
197 {
198 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800199 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200
201 // If there are no privileges assigned, assume no privileges required
202 if (it->second.empty())
203 {
204 return true;
205 }
206
207 for (auto& requiredPrivileges : it->second)
208 {
209 if (userPrivileges.isSupersetOf(requiredPrivileges))
210 {
211 return true;
212 }
213 }
214 return false;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800215}
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100216
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800217/**
218 * @brief Checks if a user is allowed to call an HTTP method
219 *
220 * @param[in] method HTTP method
221 * @param[in] user Username
222 *
223 * @return True if method allowed, false otherwise
224 *
225 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700226inline bool isMethodAllowedForUser(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800227 const OperationMap& operationMap,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700228 const std::string& user)
229{
230 // TODO: load user privileges from configuration as soon as its available
231 // now we are granting all privileges to everyone.
232 Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
233 "ConfigureUsers", "ConfigureComponents"};
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800234
Ed Tanous1abe55e2018-09-05 08:30:59 -0700235 return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800236}
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100237
Ed Tanous1abe55e2018-09-05 08:30:59 -0700238} // namespace redfish