xref: /openbmc/bmcweb/features/redfish/include/privileges.hpp (revision 1abe55ef9844afcddcab9d862ae06118f3a2390c)
186e1b661SBorawski.Lukasz /*
286e1b661SBorawski.Lukasz // Copyright (c) 2018 Intel Corporation
386e1b661SBorawski.Lukasz //
486e1b661SBorawski.Lukasz // Licensed under the Apache License, Version 2.0 (the "License");
586e1b661SBorawski.Lukasz // you may not use this file except in compliance with the License.
686e1b661SBorawski.Lukasz // You may obtain a copy of the License at
786e1b661SBorawski.Lukasz //
886e1b661SBorawski.Lukasz //      http://www.apache.org/licenses/LICENSE-2.0
986e1b661SBorawski.Lukasz //
1086e1b661SBorawski.Lukasz // Unless required by applicable law or agreed to in writing, software
1186e1b661SBorawski.Lukasz // distributed under the License is distributed on an "AS IS" BASIS,
1286e1b661SBorawski.Lukasz // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1386e1b661SBorawski.Lukasz // See the License for the specific language governing permissions and
1486e1b661SBorawski.Lukasz // limitations under the License.
1586e1b661SBorawski.Lukasz */
1686e1b661SBorawski.Lukasz #pragma once
1786e1b661SBorawski.Lukasz 
18aecb47a4SBorawski.Lukasz #include <bitset>
19aecb47a4SBorawski.Lukasz #include <boost/container/flat_map.hpp>
20aecb47a4SBorawski.Lukasz #include <boost/optional.hpp>
21*1abe55efSEd Tanous #include <cstdint>
22*1abe55efSEd Tanous #include <vector>
23aecb47a4SBorawski.Lukasz 
24*1abe55efSEd Tanous #include "crow.h"
2586e1b661SBorawski.Lukasz 
26*1abe55efSEd Tanous namespace redfish
27*1abe55efSEd Tanous {
28*1abe55efSEd Tanous 
29*1abe55efSEd Tanous enum class PrivilegeType
30*1abe55efSEd Tanous {
31*1abe55efSEd Tanous     BASE,
32*1abe55efSEd Tanous     OEM
33*1abe55efSEd Tanous };
34aecb47a4SBorawski.Lukasz 
35a692779fSEd Tanous /** @brief A fixed array of compile time privileges  */
36a692779fSEd Tanous constexpr std::array<const char*, 5> basePrivileges{
373ebd75f7SEd Tanous     "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf",
383ebd75f7SEd Tanous     "ConfigureUsers"};
3943a095abSBorawski.Lukasz 
40a692779fSEd Tanous constexpr const int basePrivilegeCount = basePrivileges.size();
41a692779fSEd Tanous 
42a692779fSEd Tanous /** @brief Max number of privileges per type  */
4355c7b7a2SEd Tanous constexpr const int maxPrivilegeCount = 32;
44a692779fSEd Tanous 
45a692779fSEd Tanous /** @brief A vector of all privilege names and their indexes */
46a692779fSEd Tanous static const std::vector<std::string> privilegeNames{basePrivileges.begin(),
47a692779fSEd Tanous                                                      basePrivileges.end()};
4843a095abSBorawski.Lukasz 
4986e1b661SBorawski.Lukasz /**
50aecb47a4SBorawski.Lukasz  * @brief Redfish privileges
51aecb47a4SBorawski.Lukasz  *
52aecb47a4SBorawski.Lukasz  *        Entity privileges and user privileges are represented by this class.
53aecb47a4SBorawski.Lukasz  *
5455c7b7a2SEd Tanous  *        Each incoming Connection requires a comparison between privileges held
55aecb47a4SBorawski.Lukasz  *        by the user issuing a request and the target entity's privileges.
56aecb47a4SBorawski.Lukasz  *
57aecb47a4SBorawski.Lukasz  *        To ensure best runtime performance of this comparison, privileges
58aecb47a4SBorawski.Lukasz  *        are represented as bitsets. Each bit in the bitset corresponds to a
59aecb47a4SBorawski.Lukasz  *        unique privilege name.
60aecb47a4SBorawski.Lukasz  *
61aecb47a4SBorawski.Lukasz  *        A bit is set if the privilege is required (entity domain) or granted
62aecb47a4SBorawski.Lukasz  *        (user domain) and false otherwise.
63aecb47a4SBorawski.Lukasz  *
6486e1b661SBorawski.Lukasz  */
65*1abe55efSEd Tanous class Privileges
66*1abe55efSEd Tanous {
67aecb47a4SBorawski.Lukasz   public:
68aecb47a4SBorawski.Lukasz     /**
6943a095abSBorawski.Lukasz      * @brief Constructs object without any privileges active
7043a095abSBorawski.Lukasz      *
7143a095abSBorawski.Lukasz      */
7243a095abSBorawski.Lukasz     Privileges() = default;
7343a095abSBorawski.Lukasz 
7443a095abSBorawski.Lukasz     /**
7543a095abSBorawski.Lukasz      * @brief Constructs object with given privileges active
7643a095abSBorawski.Lukasz      *
7743a095abSBorawski.Lukasz      * @param[in] privilegeList  List of privileges to be activated
7843a095abSBorawski.Lukasz      *
7943a095abSBorawski.Lukasz      */
80*1abe55efSEd Tanous     Privileges(std::initializer_list<const char*> privilegeList)
81*1abe55efSEd Tanous     {
82*1abe55efSEd Tanous         for (const char* privilege : privilegeList)
83*1abe55efSEd Tanous         {
84*1abe55efSEd Tanous             if (!setSinglePrivilege(privilege))
85*1abe55efSEd Tanous             {
8655c7b7a2SEd Tanous                 BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
873ebd75f7SEd Tanous                                     << "in constructor";
8843a095abSBorawski.Lukasz             }
8943a095abSBorawski.Lukasz         }
903ebd75f7SEd Tanous     }
91aecb47a4SBorawski.Lukasz 
92aecb47a4SBorawski.Lukasz     /**
93aecb47a4SBorawski.Lukasz      * @brief Sets given privilege in the bitset
94aecb47a4SBorawski.Lukasz      *
95aecb47a4SBorawski.Lukasz      * @param[in] privilege  Privilege to be set
96aecb47a4SBorawski.Lukasz      *
97aecb47a4SBorawski.Lukasz      * @return               None
9843a095abSBorawski.Lukasz      *
99aecb47a4SBorawski.Lukasz      */
100*1abe55efSEd Tanous     bool setSinglePrivilege(const char* privilege)
101*1abe55efSEd Tanous     {
10255c7b7a2SEd Tanous         for (int searchIndex = 0; searchIndex < privilegeNames.size();
103*1abe55efSEd Tanous              searchIndex++)
104*1abe55efSEd Tanous         {
105*1abe55efSEd Tanous             if (privilege == privilegeNames[searchIndex])
106*1abe55efSEd Tanous             {
10755c7b7a2SEd Tanous                 privilegeBitset.set(searchIndex);
1083ebd75f7SEd Tanous                 return true;
109aecb47a4SBorawski.Lukasz             }
110a692779fSEd Tanous         }
111aecb47a4SBorawski.Lukasz 
1123ebd75f7SEd Tanous         return false;
1133ebd75f7SEd Tanous     }
1143ebd75f7SEd Tanous 
1153ebd75f7SEd Tanous     /**
1163ebd75f7SEd Tanous      * @brief Sets given privilege in the bitset
1173ebd75f7SEd Tanous      *
1183ebd75f7SEd Tanous      * @param[in] privilege  Privilege to be set
1193ebd75f7SEd Tanous      *
1203ebd75f7SEd Tanous      * @return               None
1213ebd75f7SEd Tanous      *
1223ebd75f7SEd Tanous      */
123*1abe55efSEd Tanous     bool setSinglePrivilege(const std::string& privilege)
124*1abe55efSEd Tanous     {
1253ebd75f7SEd Tanous         return setSinglePrivilege(privilege.c_str());
126aecb47a4SBorawski.Lukasz     }
127aecb47a4SBorawski.Lukasz 
128aecb47a4SBorawski.Lukasz     /**
129aecb47a4SBorawski.Lukasz      * @brief Retrieves names of all active privileges for a given type
130aecb47a4SBorawski.Lukasz      *
131aecb47a4SBorawski.Lukasz      * @param[in] type    Base or OEM
132aecb47a4SBorawski.Lukasz      *
1333ebd75f7SEd Tanous      * @return            Vector of active privileges.  Pointers are valid until
134a692779fSEd Tanous      * the setSinglePrivilege is called, or the Privilege structure is destroyed
13543a095abSBorawski.Lukasz      *
136aecb47a4SBorawski.Lukasz      */
137*1abe55efSEd Tanous     std::vector<const std::string*>
138*1abe55efSEd Tanous         getActivePrivilegeNames(const PrivilegeType type) const
139*1abe55efSEd Tanous     {
1403ebd75f7SEd Tanous         std::vector<const std::string*> activePrivileges;
141aecb47a4SBorawski.Lukasz 
14255c7b7a2SEd Tanous         int searchIndex = 0;
14355c7b7a2SEd Tanous         int endIndex = basePrivilegeCount;
144*1abe55efSEd Tanous         if (type == PrivilegeType::OEM)
145*1abe55efSEd Tanous         {
14655c7b7a2SEd Tanous             searchIndex = basePrivilegeCount - 1;
14755c7b7a2SEd Tanous             endIndex = privilegeNames.size();
148a692779fSEd Tanous         }
149a692779fSEd Tanous 
150*1abe55efSEd Tanous         for (; searchIndex < endIndex; searchIndex++)
151*1abe55efSEd Tanous         {
152*1abe55efSEd Tanous             if (privilegeBitset.test(searchIndex))
153*1abe55efSEd Tanous             {
15455c7b7a2SEd Tanous                 activePrivileges.emplace_back(&privilegeNames[searchIndex]);
155aecb47a4SBorawski.Lukasz             }
156aecb47a4SBorawski.Lukasz         }
157a692779fSEd Tanous 
158aecb47a4SBorawski.Lukasz         return activePrivileges;
159aecb47a4SBorawski.Lukasz     }
160aecb47a4SBorawski.Lukasz 
1613ebd75f7SEd Tanous     /**
1623ebd75f7SEd Tanous      * @brief Determines if this Privilege set is a superset of the given
1633ebd75f7SEd Tanous      * privilege set
1643ebd75f7SEd Tanous      *
1653ebd75f7SEd Tanous      * @param[in] privilege  Privilege to be checked
1663ebd75f7SEd Tanous      *
1673ebd75f7SEd Tanous      * @return               None
1683ebd75f7SEd Tanous      *
1693ebd75f7SEd Tanous      */
170*1abe55efSEd Tanous     bool isSupersetOf(const Privileges& p) const
171*1abe55efSEd Tanous     {
172a692779fSEd Tanous         return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
1733ebd75f7SEd Tanous     }
1743ebd75f7SEd Tanous 
17586e1b661SBorawski.Lukasz   private:
17655c7b7a2SEd Tanous     std::bitset<maxPrivilegeCount> privilegeBitset = 0;
17786e1b661SBorawski.Lukasz };
17886e1b661SBorawski.Lukasz 
179e0d918bcSEd Tanous using OperationMap = boost::container::flat_map<boost::beast::http::verb,
180e0d918bcSEd Tanous                                                 std::vector<Privileges>>;
18143a095abSBorawski.Lukasz 
18243a095abSBorawski.Lukasz /**
183aecb47a4SBorawski.Lukasz  * @brief Checks if given privileges allow to call an HTTP method
184aecb47a4SBorawski.Lukasz  *
185aecb47a4SBorawski.Lukasz  * @param[in] method       HTTP method
186aecb47a4SBorawski.Lukasz  * @param[in] user         Privileges
187aecb47a4SBorawski.Lukasz  *
188aecb47a4SBorawski.Lukasz  * @return                 True if method allowed, false otherwise
18943a095abSBorawski.Lukasz  *
190aecb47a4SBorawski.Lukasz  */
191e0d918bcSEd Tanous inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
1923ebd75f7SEd Tanous                                           const OperationMap& operationMap,
193*1abe55efSEd Tanous                                           const Privileges& userPrivileges)
194*1abe55efSEd Tanous {
1953ebd75f7SEd Tanous     const auto& it = operationMap.find(method);
196*1abe55efSEd Tanous     if (it == operationMap.end())
197*1abe55efSEd Tanous     {
19843a095abSBorawski.Lukasz         return false;
19943a095abSBorawski.Lukasz     }
200aecb47a4SBorawski.Lukasz 
2013ebd75f7SEd Tanous     // If there are no privileges assigned, assume no privileges required
202*1abe55efSEd Tanous     if (it->second.empty())
203*1abe55efSEd Tanous     {
20443a095abSBorawski.Lukasz         return true;
20543a095abSBorawski.Lukasz     }
2063ebd75f7SEd Tanous 
207*1abe55efSEd Tanous     for (auto& requiredPrivileges : it->second)
208*1abe55efSEd Tanous     {
209*1abe55efSEd Tanous         if (userPrivileges.isSupersetOf(requiredPrivileges))
210*1abe55efSEd Tanous         {
2113ebd75f7SEd Tanous             return true;
2123ebd75f7SEd Tanous         }
2133ebd75f7SEd Tanous     }
21443a095abSBorawski.Lukasz     return false;
21586e1b661SBorawski.Lukasz }
216aecb47a4SBorawski.Lukasz 
2173ebd75f7SEd Tanous /**
2183ebd75f7SEd Tanous  * @brief Checks if a user is allowed to call an HTTP method
2193ebd75f7SEd Tanous  *
2203ebd75f7SEd Tanous  * @param[in] method       HTTP method
2213ebd75f7SEd Tanous  * @param[in] user         Username
2223ebd75f7SEd Tanous  *
2233ebd75f7SEd Tanous  * @return                 True if method allowed, false otherwise
2243ebd75f7SEd Tanous  *
2253ebd75f7SEd Tanous  */
226e0d918bcSEd Tanous inline bool isMethodAllowedForUser(const boost::beast::http::verb method,
2273ebd75f7SEd Tanous                                    const OperationMap& operationMap,
228*1abe55efSEd Tanous                                    const std::string& user)
229*1abe55efSEd Tanous {
2303ebd75f7SEd Tanous     // TODO: load user privileges from configuration as soon as its available
2313ebd75f7SEd Tanous     // now we are granting all privileges to everyone.
2323ebd75f7SEd Tanous     Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
2333ebd75f7SEd Tanous                               "ConfigureUsers", "ConfigureComponents"};
2343ebd75f7SEd Tanous 
2353ebd75f7SEd Tanous     return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
23686e1b661SBorawski.Lukasz }
23786e1b661SBorawski.Lukasz 
23886e1b661SBorawski.Lukasz } // namespace redfish
239