xref: /openbmc/bmcweb/features/redfish/include/privileges.hpp (revision b01bf2991955ef267ce2be8e7a18eac984990de8)
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>
201abe55efSEd Tanous #include <cstdint>
211abe55efSEd Tanous #include <vector>
22aecb47a4SBorawski.Lukasz 
231abe55efSEd Tanous namespace redfish
241abe55efSEd Tanous {
251abe55efSEd Tanous 
261abe55efSEd Tanous enum class PrivilegeType
271abe55efSEd Tanous {
281abe55efSEd Tanous     BASE,
291abe55efSEd Tanous     OEM
301abe55efSEd Tanous };
31aecb47a4SBorawski.Lukasz 
32a692779fSEd Tanous /** @brief A fixed array of compile time privileges  */
33a692779fSEd Tanous constexpr std::array<const char*, 5> basePrivileges{
343ebd75f7SEd Tanous     "Login", "ConfigureManager", "ConfigureComponents", "ConfigureSelf",
353ebd75f7SEd Tanous     "ConfigureUsers"};
3643a095abSBorawski.Lukasz 
37*b01bf299SEd Tanous constexpr const int basePrivilegeCount = basePrivileges.size();
38a692779fSEd Tanous 
39a692779fSEd Tanous /** @brief Max number of privileges per type  */
40*b01bf299SEd Tanous constexpr const int maxPrivilegeCount = 32;
41a692779fSEd Tanous 
42a692779fSEd Tanous /** @brief A vector of all privilege names and their indexes */
43a692779fSEd Tanous static const std::vector<std::string> privilegeNames{basePrivileges.begin(),
44a692779fSEd Tanous                                                      basePrivileges.end()};
4543a095abSBorawski.Lukasz 
4686e1b661SBorawski.Lukasz /**
47aecb47a4SBorawski.Lukasz  * @brief Redfish privileges
48aecb47a4SBorawski.Lukasz  *
49aecb47a4SBorawski.Lukasz  *        Entity privileges and user privileges are represented by this class.
50aecb47a4SBorawski.Lukasz  *
5155c7b7a2SEd Tanous  *        Each incoming Connection requires a comparison between privileges held
52aecb47a4SBorawski.Lukasz  *        by the user issuing a request and the target entity's privileges.
53aecb47a4SBorawski.Lukasz  *
54aecb47a4SBorawski.Lukasz  *        To ensure best runtime performance of this comparison, privileges
55aecb47a4SBorawski.Lukasz  *        are represented as bitsets. Each bit in the bitset corresponds to a
56aecb47a4SBorawski.Lukasz  *        unique privilege name.
57aecb47a4SBorawski.Lukasz  *
58aecb47a4SBorawski.Lukasz  *        A bit is set if the privilege is required (entity domain) or granted
59aecb47a4SBorawski.Lukasz  *        (user domain) and false otherwise.
60aecb47a4SBorawski.Lukasz  *
6186e1b661SBorawski.Lukasz  */
621abe55efSEd Tanous class Privileges
631abe55efSEd Tanous {
64aecb47a4SBorawski.Lukasz   public:
65aecb47a4SBorawski.Lukasz     /**
6643a095abSBorawski.Lukasz      * @brief Constructs object without any privileges active
6743a095abSBorawski.Lukasz      *
6843a095abSBorawski.Lukasz      */
6943a095abSBorawski.Lukasz     Privileges() = default;
7043a095abSBorawski.Lukasz 
7143a095abSBorawski.Lukasz     /**
7243a095abSBorawski.Lukasz      * @brief Constructs object with given privileges active
7343a095abSBorawski.Lukasz      *
7443a095abSBorawski.Lukasz      * @param[in] privilegeList  List of privileges to be activated
7543a095abSBorawski.Lukasz      *
7643a095abSBorawski.Lukasz      */
771abe55efSEd Tanous     Privileges(std::initializer_list<const char*> privilegeList)
781abe55efSEd Tanous     {
791abe55efSEd Tanous         for (const char* privilege : privilegeList)
801abe55efSEd Tanous         {
811abe55efSEd Tanous             if (!setSinglePrivilege(privilege))
821abe55efSEd Tanous             {
8355c7b7a2SEd Tanous                 BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
843ebd75f7SEd Tanous                                     << "in constructor";
8543a095abSBorawski.Lukasz             }
8643a095abSBorawski.Lukasz         }
873ebd75f7SEd Tanous     }
88aecb47a4SBorawski.Lukasz 
89aecb47a4SBorawski.Lukasz     /**
90aecb47a4SBorawski.Lukasz      * @brief Sets given privilege in the bitset
91aecb47a4SBorawski.Lukasz      *
92aecb47a4SBorawski.Lukasz      * @param[in] privilege  Privilege to be set
93aecb47a4SBorawski.Lukasz      *
94aecb47a4SBorawski.Lukasz      * @return               None
9543a095abSBorawski.Lukasz      *
96aecb47a4SBorawski.Lukasz      */
971abe55efSEd Tanous     bool setSinglePrivilege(const char* privilege)
981abe55efSEd Tanous     {
99*b01bf299SEd Tanous         for (int searchIndex = 0; searchIndex < privilegeNames.size();
1001abe55efSEd Tanous              searchIndex++)
1011abe55efSEd Tanous         {
1021abe55efSEd Tanous             if (privilege == privilegeNames[searchIndex])
1031abe55efSEd Tanous             {
10455c7b7a2SEd Tanous                 privilegeBitset.set(searchIndex);
1053ebd75f7SEd Tanous                 return true;
106aecb47a4SBorawski.Lukasz             }
107a692779fSEd Tanous         }
108aecb47a4SBorawski.Lukasz 
1093ebd75f7SEd Tanous         return false;
1103ebd75f7SEd Tanous     }
1113ebd75f7SEd Tanous 
1123ebd75f7SEd Tanous     /**
1133ebd75f7SEd Tanous      * @brief Sets given privilege in the bitset
1143ebd75f7SEd Tanous      *
1153ebd75f7SEd Tanous      * @param[in] privilege  Privilege to be set
1163ebd75f7SEd Tanous      *
1173ebd75f7SEd Tanous      * @return               None
1183ebd75f7SEd Tanous      *
1193ebd75f7SEd Tanous      */
1201abe55efSEd Tanous     bool setSinglePrivilege(const std::string& privilege)
1211abe55efSEd Tanous     {
1223ebd75f7SEd Tanous         return setSinglePrivilege(privilege.c_str());
123aecb47a4SBorawski.Lukasz     }
124aecb47a4SBorawski.Lukasz 
125aecb47a4SBorawski.Lukasz     /**
126aecb47a4SBorawski.Lukasz      * @brief Retrieves names of all active privileges for a given type
127aecb47a4SBorawski.Lukasz      *
128aecb47a4SBorawski.Lukasz      * @param[in] type    Base or OEM
129aecb47a4SBorawski.Lukasz      *
1303ebd75f7SEd Tanous      * @return            Vector of active privileges.  Pointers are valid until
131a692779fSEd Tanous      * the setSinglePrivilege is called, or the Privilege structure is destroyed
13243a095abSBorawski.Lukasz      *
133aecb47a4SBorawski.Lukasz      */
1341abe55efSEd Tanous     std::vector<const std::string*>
1351abe55efSEd Tanous         getActivePrivilegeNames(const PrivilegeType type) const
1361abe55efSEd Tanous     {
1373ebd75f7SEd Tanous         std::vector<const std::string*> activePrivileges;
138aecb47a4SBorawski.Lukasz 
139*b01bf299SEd Tanous         int searchIndex = 0;
140*b01bf299SEd Tanous         int endIndex = basePrivilegeCount;
1411abe55efSEd Tanous         if (type == PrivilegeType::OEM)
1421abe55efSEd Tanous         {
14355c7b7a2SEd Tanous             searchIndex = basePrivilegeCount - 1;
14455c7b7a2SEd Tanous             endIndex = privilegeNames.size();
145a692779fSEd Tanous         }
146a692779fSEd Tanous 
1471abe55efSEd Tanous         for (; searchIndex < endIndex; searchIndex++)
1481abe55efSEd Tanous         {
1491abe55efSEd Tanous             if (privilegeBitset.test(searchIndex))
1501abe55efSEd Tanous             {
15155c7b7a2SEd Tanous                 activePrivileges.emplace_back(&privilegeNames[searchIndex]);
152aecb47a4SBorawski.Lukasz             }
153aecb47a4SBorawski.Lukasz         }
154a692779fSEd Tanous 
155aecb47a4SBorawski.Lukasz         return activePrivileges;
156aecb47a4SBorawski.Lukasz     }
157aecb47a4SBorawski.Lukasz 
1583ebd75f7SEd Tanous     /**
1593ebd75f7SEd Tanous      * @brief Determines if this Privilege set is a superset of the given
1603ebd75f7SEd Tanous      * privilege set
1613ebd75f7SEd Tanous      *
1623ebd75f7SEd Tanous      * @param[in] privilege  Privilege to be checked
1633ebd75f7SEd Tanous      *
1643ebd75f7SEd Tanous      * @return               None
1653ebd75f7SEd Tanous      *
1663ebd75f7SEd Tanous      */
1671abe55efSEd Tanous     bool isSupersetOf(const Privileges& p) const
1681abe55efSEd Tanous     {
169a692779fSEd Tanous         return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
1703ebd75f7SEd Tanous     }
1713ebd75f7SEd Tanous 
17286e1b661SBorawski.Lukasz   private:
17355c7b7a2SEd Tanous     std::bitset<maxPrivilegeCount> privilegeBitset = 0;
17486e1b661SBorawski.Lukasz };
17586e1b661SBorawski.Lukasz 
176e0d918bcSEd Tanous using OperationMap = boost::container::flat_map<boost::beast::http::verb,
177e0d918bcSEd Tanous                                                 std::vector<Privileges>>;
17843a095abSBorawski.Lukasz 
17943a095abSBorawski.Lukasz /**
180aecb47a4SBorawski.Lukasz  * @brief Checks if given privileges allow to call an HTTP method
181aecb47a4SBorawski.Lukasz  *
182aecb47a4SBorawski.Lukasz  * @param[in] method       HTTP method
183aecb47a4SBorawski.Lukasz  * @param[in] user         Privileges
184aecb47a4SBorawski.Lukasz  *
185aecb47a4SBorawski.Lukasz  * @return                 True if method allowed, false otherwise
18643a095abSBorawski.Lukasz  *
187aecb47a4SBorawski.Lukasz  */
188e0d918bcSEd Tanous inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
1893ebd75f7SEd Tanous                                           const OperationMap& operationMap,
1901abe55efSEd Tanous                                           const Privileges& userPrivileges)
1911abe55efSEd Tanous {
1923ebd75f7SEd Tanous     const auto& it = operationMap.find(method);
1931abe55efSEd Tanous     if (it == operationMap.end())
1941abe55efSEd Tanous     {
19543a095abSBorawski.Lukasz         return false;
19643a095abSBorawski.Lukasz     }
197aecb47a4SBorawski.Lukasz 
1983ebd75f7SEd Tanous     // If there are no privileges assigned, assume no privileges required
1991abe55efSEd Tanous     if (it->second.empty())
2001abe55efSEd Tanous     {
20143a095abSBorawski.Lukasz         return true;
20243a095abSBorawski.Lukasz     }
2033ebd75f7SEd Tanous 
2041abe55efSEd Tanous     for (auto& requiredPrivileges : it->second)
2051abe55efSEd Tanous     {
2061abe55efSEd Tanous         if (userPrivileges.isSupersetOf(requiredPrivileges))
2071abe55efSEd Tanous         {
2083ebd75f7SEd Tanous             return true;
2093ebd75f7SEd Tanous         }
2103ebd75f7SEd Tanous     }
21143a095abSBorawski.Lukasz     return false;
21286e1b661SBorawski.Lukasz }
213aecb47a4SBorawski.Lukasz 
2143ebd75f7SEd Tanous /**
2153ebd75f7SEd Tanous  * @brief Checks if a user is allowed to call an HTTP method
2163ebd75f7SEd Tanous  *
2173ebd75f7SEd Tanous  * @param[in] method       HTTP method
2183ebd75f7SEd Tanous  * @param[in] user         Username
2193ebd75f7SEd Tanous  *
2203ebd75f7SEd Tanous  * @return                 True if method allowed, false otherwise
2213ebd75f7SEd Tanous  *
2223ebd75f7SEd Tanous  */
223e0d918bcSEd Tanous inline bool isMethodAllowedForUser(const boost::beast::http::verb method,
2243ebd75f7SEd Tanous                                    const OperationMap& operationMap,
2251abe55efSEd Tanous                                    const std::string& user)
2261abe55efSEd Tanous {
2273ebd75f7SEd Tanous     // TODO: load user privileges from configuration as soon as its available
2283ebd75f7SEd Tanous     // now we are granting all privileges to everyone.
2293ebd75f7SEd Tanous     Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
2303ebd75f7SEd Tanous                               "ConfigureUsers", "ConfigureComponents"};
2313ebd75f7SEd Tanous 
2323ebd75f7SEd Tanous     return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
23386e1b661SBorawski.Lukasz }
23486e1b661SBorawski.Lukasz 
23586e1b661SBorawski.Lukasz } // namespace redfish
236