blob: 437bb15e041d23c2db90a1bd36aa3aea48c51264 [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>
Ed Tanousa6927792018-03-06 10:01:57 -080020#include <vector>
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010021#include "crow.h"
22#include <boost/container/flat_map.hpp>
23#include <boost/optional.hpp>
24
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010025namespace redfish {
26
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010027enum class PrivilegeType { BASE, OEM };
28
Ed Tanousa6927792018-03-06 10:01:57 -080029/** @brief A fixed array of compile time privileges */
30constexpr std::array<const char*, 5> basePrivileges{
Ed Tanous3ebd75f2018-03-05 18:20:01 -080031 "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf",
32 "ConfigureUsers"};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010033
Ed Tanousa6927792018-03-06 10:01:57 -080034constexpr const int basePrivilegeCount = basePrivileges.size();
35
36/** @brief Max number of privileges per type */
Ed Tanous55c7b7a2018-05-22 15:27:24 -070037constexpr const int maxPrivilegeCount = 32;
Ed Tanousa6927792018-03-06 10:01:57 -080038
39/** @brief A vector of all privilege names and their indexes */
40static const std::vector<std::string> privilegeNames{basePrivileges.begin(),
41 basePrivileges.end()};
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010042
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010043/**
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010044 * @brief Redfish privileges
45 *
46 * Entity privileges and user privileges are represented by this class.
47 *
Ed Tanous55c7b7a2018-05-22 15:27:24 -070048 * Each incoming Connection requires a comparison between privileges held
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010049 * by the user issuing a request and the target entity's privileges.
50 *
51 * To ensure best runtime performance of this comparison, privileges
52 * are represented as bitsets. Each bit in the bitset corresponds to a
53 * unique privilege name.
54 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010055 * A bit is set if the privilege is required (entity domain) or granted
56 * (user domain) and false otherwise.
57 *
Borawski.Lukasz86e1b662018-01-19 14:22:14 +010058 */
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010059class Privileges {
60 public:
61 /**
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010062 * @brief Constructs object without any privileges active
63 *
64 */
65 Privileges() = default;
66
67 /**
68 * @brief Constructs object with given privileges active
69 *
70 * @param[in] privilegeList List of privileges to be activated
71 *
72 */
Ed Tanous3ebd75f2018-03-05 18:20:01 -080073 Privileges(std::initializer_list<const char*> privilegeList) {
74 for (const char* privilege : privilegeList) {
75 if (!setSinglePrivilege(privilege)) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070076 BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
77 << "in constructor";
Ed Tanous3ebd75f2018-03-05 18:20:01 -080078 }
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010079 }
80 }
81
82 /**
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010083 * @brief Sets given privilege in the bitset
84 *
85 * @param[in] privilege Privilege to be set
86 *
87 * @return None
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010088 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010089 */
Ed Tanous3ebd75f2018-03-05 18:20:01 -080090 bool setSinglePrivilege(const char* privilege) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070091 for (int searchIndex = 0; searchIndex < privilegeNames.size();
92 searchIndex++) {
93 if (privilege == privilegeNames[searchIndex]) {
94 privilegeBitset.set(searchIndex);
Ed Tanousa6927792018-03-06 10:01:57 -080095 return true;
96 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +010097 }
98
Ed Tanous3ebd75f2018-03-05 18:20:01 -080099 return false;
100 }
101
102 /**
103 * @brief Sets given privilege in the bitset
104 *
105 * @param[in] privilege Privilege to be set
106 *
107 * @return None
108 *
109 */
110 bool setSinglePrivilege(const std::string& privilege) {
111 return setSinglePrivilege(privilege.c_str());
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100112 }
113
114 /**
115 * @brief Retrieves names of all active privileges for a given type
116 *
117 * @param[in] type Base or OEM
118 *
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800119 * @return Vector of active privileges. Pointers are valid until
Ed Tanousa6927792018-03-06 10:01:57 -0800120 * the setSinglePrivilege is called, or the Privilege structure is destroyed
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100121 *
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100122 */
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800123 std::vector<const std::string*> getActivePrivilegeNames(
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100124 const PrivilegeType type) const {
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800125 std::vector<const std::string*> activePrivileges;
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100126
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700127 int searchIndex = 0;
128 int endIndex = basePrivilegeCount;
Ed Tanousa6927792018-03-06 10:01:57 -0800129 if (type == PrivilegeType::OEM) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700130 searchIndex = basePrivilegeCount - 1;
131 endIndex = privilegeNames.size();
Ed Tanousa6927792018-03-06 10:01:57 -0800132 }
133
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700134 for (; searchIndex < endIndex; searchIndex++) {
135 if (privilegeBitset.test(searchIndex)) {
136 activePrivileges.emplace_back(&privilegeNames[searchIndex]);
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100137 }
138 }
Ed Tanousa6927792018-03-06 10:01:57 -0800139
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100140 return activePrivileges;
141 }
142
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800143 /**
144 * @brief Determines if this Privilege set is a superset of the given
145 * privilege set
146 *
147 * @param[in] privilege Privilege to be checked
148 *
149 * @return None
150 *
151 */
152 bool isSupersetOf(const Privileges& p) const {
Ed Tanousa6927792018-03-06 10:01:57 -0800153 return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800154 }
155
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100156 private:
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700157 std::bitset<maxPrivilegeCount> privilegeBitset = 0;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100158};
159
Ed Tanouse0d918b2018-03-27 17:41:04 -0700160using OperationMap = boost::container::flat_map<boost::beast::http::verb,
161 std::vector<Privileges>>;
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100162
163/**
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800164 * @brief Checks if given privileges allow to call an HTTP method
165 *
166 * @param[in] method HTTP method
167 * @param[in] user Privileges
168 *
169 * @return True if method allowed, false otherwise
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100170 *
171 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700172inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800173 const OperationMap& operationMap,
174 const Privileges& userPrivileges) {
175 const auto& it = operationMap.find(method);
176 if (it == operationMap.end()) {
Borawski.Lukasz43a095a2018-02-19 15:39:01 +0100177 return false;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100178 }
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100179
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800180 // If there are no privileges assigned, assume no privileges required
181 if (it->second.empty()) {
182 return true;
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100183 }
184
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800185 for (auto& requiredPrivileges : it->second) {
186 if (userPrivileges.isSupersetOf(requiredPrivileges)) {
187 return true;
188 }
189 }
190 return false;
191}
Borawski.Lukaszaecb47a2018-01-25 12:14:14 +0100192
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800193/**
194 * @brief Checks if a user is allowed to call an HTTP method
195 *
196 * @param[in] method HTTP method
197 * @param[in] user Username
198 *
199 * @return True if method allowed, false otherwise
200 *
201 */
Ed Tanouse0d918b2018-03-27 17:41:04 -0700202inline bool isMethodAllowedForUser(const boost::beast::http::verb method,
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800203 const OperationMap& operationMap,
204 const std::string& user) {
205 // TODO: load user privileges from configuration as soon as its available
206 // now we are granting all privileges to everyone.
207 Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
208 "ConfigureUsers", "ConfigureComponents"};
209
210 return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
211}
Borawski.Lukasz86e1b662018-01-19 14:22:14 +0100212
213} // namespace redfish