blob: 5fbce232af8ee8c155bb49e0f78086279389c9b5 [file] [log] [blame]
Borawski.Lukaszaecb47a2018-01-25 12:14: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#include "privileges.hpp"
17
18namespace redfish {
19
20boost::container::flat_map<std::string, size_t>
21 Privileges::basePrivNameToIndexMap;
22boost::container::flat_map<std::string, size_t>
23 Privileges::oemPrivNameToIndexMap;
24
25bool EntityPrivileges::isMethodAllowedForUser(const crow::HTTPMethod method,
26 const std::string& user) const {
27 // TODO: load user privileges from configuration as soon as its available
28 // now we are granting only Login.
29 auto userPrivileges = Privileges();
30 userPrivileges.setSinglePrivilege("Login");
31
32 return isMethodAllowedWithPrivileges(method, userPrivileges);
33}
34
35bool EntityPrivileges::isMethodAllowedWithPrivileges(
36 const crow::HTTPMethod method, const Privileges& userPrivileges) const {
37 if (methodToPrivilegeMap.find(method) == methodToPrivilegeMap.end()) {
38 return false;
39 }
40
41 for (auto& requiredPrivileges : methodToPrivilegeMap.at(method)) {
42 // Check if user has required base privileges
43 if (!verifyPrivileges(userPrivileges.getBasePrivilegeBitset(),
44 requiredPrivileges.getBasePrivilegeBitset())) {
45 continue;
46 }
47
48 // Check if user has required OEM privileges
49 if (!verifyPrivileges(userPrivileges.getOEMPrivilegeBitset(),
50 requiredPrivileges.getOEMPrivilegeBitset())) {
51 continue;
52 }
53
54 return true;
55 }
56 return false;
57}
58
59bool EntityPrivileges::verifyPrivileges(
60 const privilegeBitset userPrivilegeBitset,
61 const privilegeBitset requiredPrivilegeBitset) const {
62 return (userPrivilegeBitset & requiredPrivilegeBitset) ==
63 requiredPrivilegeBitset;
64}
65
66EntityPrivileges PrivilegeProvider::getPrivilegesRequiredByEntity(
67 const std::string& entityUrl, const std::string& entityType) const {
68 if (privilegeRegistryJson.empty()) {
69 return EntityPrivileges();
70 }
71
72 // type from @odata.type e.g: ServiceRoot from #ServiceRoot.v1_1_1.ServiceRoot
73 auto entity = entityType.substr(entityType.find_last_of(".") + strlen("."));
74
75 for (auto mapping : privilegeRegistryJson.at("Mappings")) {
76 const auto& entityJson = mapping.find("Entity");
77 const auto& operationMapJson = mapping.find("OperationMap");
78 const auto& propertyOverridesJson = mapping.find("PropertyOverrides");
79 const auto& subordinateOverridesJson = mapping.find("SubordinateOverrides");
80 const auto& resourceURIOverridesJson = mapping.find("ResourceURIOverrides");
81
82 if (entityJson == mapping.end() || operationMapJson == mapping.end()) {
83 return EntityPrivileges();
84 }
85
86 if (entityJson->is_string() && entity == entityJson.value()) {
87 auto entityPrivileges = EntityPrivileges();
88
89 if (!parseOperationMap(operationMapJson.value(), entityPrivileges)) {
90 return EntityPrivileges();
91 }
92
93 if (propertyOverridesJson != mapping.end()) {
94 // TODO: implementation comes in next patch-sets
95 }
96 if (subordinateOverridesJson != mapping.end()) {
97 // TODO: implementation comes in next patch-sets
98 }
99 if (resourceURIOverridesJson != mapping.end()) {
100 // TODO: implementation comes in next patch-sets
101 }
102
103 return entityPrivileges;
104 }
105 }
106 return EntityPrivileges();
107}
108
109bool PrivilegeProvider::parseOperationMap(
110 const nlohmann::json& operationMap,
111 EntityPrivileges& entityPrivileges) const {
112 for (auto it = operationMap.begin(); it != operationMap.end(); ++it) {
113 const std::string& method = it.key();
114 const nlohmann::json& privilegesForMethod = it.value();
115
116 for (const auto& privilegeOr : privilegesForMethod) {
117 const auto& privilegeJson = privilegeOr.find("Privilege");
118
119 if (privilegeJson == privilegeOr.end()) {
120 return false;
121 }
122 auto privileges = Privileges();
123
124 for (auto& privilegeAnd : privilegeJson.value()) {
125 if (!privilegeAnd.is_string()) {
126 return false;
127 }
128 privileges.setSinglePrivilege(privilegeAnd);
129 }
130 entityPrivileges.addPrivilegesRequiredByMethod(operator"" _method(
131 method.c_str(),
132 method.size()),
133 privileges);
134 }
135 }
136 return true;
137}
138
139bool PrivilegeProvider::loadPrivilegesFromFile(
140 std::ifstream& privilegeRegistryFile) {
141 privilegeRegistryJson =
142 nlohmann::json::parse(privilegeRegistryFile, nullptr, false);
143
144 if (!privilegeRegistryHasRequiredFields()) {
145 return false;
146 }
147
148 const nlohmann::json& basePrivilegesUsed =
149 privilegeRegistryJson.at("PrivilegesUsed");
150 if (basePrivilegesUsed.size() == 0) {
151 return false;
152 }
153 if (!fillPrivilegeMap(basePrivilegesUsed,
154 Privileges::basePrivNameToIndexMap)) {
155 return false;
156 }
157
158 const nlohmann::json& oemPrivilegesUsed =
159 privilegeRegistryJson.at("OEMPrivilegesUsed");
160 if (!fillPrivilegeMap(oemPrivilegesUsed, Privileges::oemPrivNameToIndexMap)) {
161 return false;
162 }
163
164 return true;
165}
166
167bool PrivilegeProvider::privilegeRegistryHasRequiredFields() const {
168 if (privilegeRegistryJson.is_discarded() ||
169 privilegeRegistryJson.find("@Redfish.Copyright") ==
170 privilegeRegistryJson.end() ||
171 privilegeRegistryJson.find("@odata.type") ==
172 privilegeRegistryJson.end() ||
173 privilegeRegistryJson.find("Id") == privilegeRegistryJson.end() ||
174 privilegeRegistryJson.find("Name") == privilegeRegistryJson.end() ||
175 privilegeRegistryJson.find("Mappings") == privilegeRegistryJson.end() ||
176 privilegeRegistryJson.find("PrivilegesUsed") ==
177 privilegeRegistryJson.end() ||
178 privilegeRegistryJson.find("OEMPrivilegesUsed") ==
179 privilegeRegistryJson.end()) {
180 return false;
181 }
182 return true;
183}
184
185bool PrivilegeProvider::fillPrivilegeMap(
186 const nlohmann::json& privilegesUsed,
187 boost::container::flat_map<std::string, size_t>& privilegeToIndexMap)
188 const {
189 privilegeToIndexMap.clear();
190 for (auto& privilege : privilegesUsed) {
191 if (privilegeToIndexMap.size() < MAX_PRIVILEGE_COUNT) {
192 if (!privilege.is_string()) {
193 return false;
194 }
195 privilegeToIndexMap.insert(std::pair<std::string, size_t>(
196 privilege.get<std::string>(), privilegeToIndexMap.size()));
197 }
198 }
199 return true;
200}
201
202} // namespace redfish