xref: /openbmc/bmcweb/features/redfish/lib/redfish_sessions.hpp (revision 1abe55ef9844afcddcab9d862ae06118f3a2390c)
12b7981f6SKowalski, Kamil /*
22b7981f6SKowalski, Kamil // Copyright (c) 2018 Intel Corporation
32b7981f6SKowalski, Kamil //
42b7981f6SKowalski, Kamil // Licensed under the Apache License, Version 2.0 (the "License");
52b7981f6SKowalski, Kamil // you may not use this file except in compliance with the License.
62b7981f6SKowalski, Kamil // You may obtain a copy of the License at
72b7981f6SKowalski, Kamil //
82b7981f6SKowalski, Kamil //      http://www.apache.org/licenses/LICENSE-2.0
92b7981f6SKowalski, Kamil //
102b7981f6SKowalski, Kamil // Unless required by applicable law or agreed to in writing, software
112b7981f6SKowalski, Kamil // distributed under the License is distributed on an "AS IS" BASIS,
122b7981f6SKowalski, Kamil // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132b7981f6SKowalski, Kamil // See the License for the specific language governing permissions and
142b7981f6SKowalski, Kamil // limitations under the License.
152b7981f6SKowalski, Kamil */
162b7981f6SKowalski, Kamil #pragma once
1743a095abSBorawski.Lukasz 
18f4c4dcf4SKowalski, Kamil #include "error_messages.hpp"
192b7981f6SKowalski, Kamil #include "node.hpp"
204b1b8683SBorawski.Lukasz #include "persistent_data_middleware.hpp"
212b7981f6SKowalski, Kamil 
22*1abe55efSEd Tanous namespace redfish
23*1abe55efSEd Tanous {
242b7981f6SKowalski, Kamil 
252b7981f6SKowalski, Kamil class SessionCollection;
262b7981f6SKowalski, Kamil 
27*1abe55efSEd Tanous class Sessions : public Node
28*1abe55efSEd Tanous {
292b7981f6SKowalski, Kamil   public:
30*1abe55efSEd Tanous     Sessions(CrowApp& app) :
31*1abe55efSEd Tanous         Node(app, "/redfish/v1/SessionService/Sessions/<str>/", std::string())
32*1abe55efSEd Tanous     {
33c1a46bd2SBorawski.Lukasz         Node::json["@odata.type"] = "#Session.v1_0_2.Session";
34c1a46bd2SBorawski.Lukasz         Node::json["@odata.context"] = "/redfish/v1/$metadata#Session.Session";
35c1a46bd2SBorawski.Lukasz         Node::json["Name"] = "User Session";
36c1a46bd2SBorawski.Lukasz         Node::json["Description"] = "Manager User Session";
373ebd75f7SEd Tanous 
38e0d918bcSEd Tanous         entityPrivileges = {
39e0d918bcSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
40e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
41e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
42e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
43e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
44e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
452b7981f6SKowalski, Kamil     }
462b7981f6SKowalski, Kamil 
472b7981f6SKowalski, Kamil   private:
4855c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
49*1abe55efSEd Tanous                const std::vector<std::string>& params) override
50*1abe55efSEd Tanous     {
512b7981f6SKowalski, Kamil         auto session =
5255c7b7a2SEd Tanous             crow::persistent_data::SessionStore::getInstance().getSessionByUid(
534b1b8683SBorawski.Lukasz                 params[0]);
542b7981f6SKowalski, Kamil 
55*1abe55efSEd Tanous         if (session == nullptr)
56*1abe55efSEd Tanous         {
57f4c4dcf4SKowalski, Kamil             messages::addMessageToErrorJson(
58*1abe55efSEd Tanous                 res.jsonValue,
59*1abe55efSEd Tanous                 messages::resourceNotFound("Session", params[0]));
60f4c4dcf4SKowalski, Kamil 
61e0d918bcSEd Tanous             res.result(boost::beast::http::status::not_found);
622b7981f6SKowalski, Kamil             res.end();
632b7981f6SKowalski, Kamil             return;
642b7981f6SKowalski, Kamil         }
652b7981f6SKowalski, Kamil 
6655c7b7a2SEd Tanous         Node::json["Id"] = session->uniqueId;
67c1a46bd2SBorawski.Lukasz         Node::json["UserName"] = session->username;
68c1a46bd2SBorawski.Lukasz         Node::json["@odata.id"] =
6955c7b7a2SEd Tanous             "/redfish/v1/SessionService/Sessions/" + session->uniqueId;
702b7981f6SKowalski, Kamil 
7155c7b7a2SEd Tanous         res.jsonValue = Node::json;
722b7981f6SKowalski, Kamil         res.end();
732b7981f6SKowalski, Kamil     }
742b7981f6SKowalski, Kamil 
7555c7b7a2SEd Tanous     void doDelete(crow::Response& res, const crow::Request& req,
76*1abe55efSEd Tanous                   const std::vector<std::string>& params) override
77*1abe55efSEd Tanous     {
782b7981f6SKowalski, Kamil         // Need only 1 param which should be id of session to be deleted
79*1abe55efSEd Tanous         if (params.size() != 1)
80*1abe55efSEd Tanous         {
81f4c4dcf4SKowalski, Kamil             // This should be handled by crow and never happen
82*1abe55efSEd Tanous             BMCWEB_LOG_ERROR << "Session DELETE has been called with invalid "
83*1abe55efSEd Tanous                                 "number of params";
84f4c4dcf4SKowalski, Kamil 
85e0d918bcSEd Tanous             res.result(boost::beast::http::status::bad_request);
86*1abe55efSEd Tanous             messages::addMessageToErrorJson(res.jsonValue,
87*1abe55efSEd Tanous                                             messages::generalError());
88e0d918bcSEd Tanous 
892b7981f6SKowalski, Kamil             res.end();
902b7981f6SKowalski, Kamil             return;
912b7981f6SKowalski, Kamil         }
922b7981f6SKowalski, Kamil 
932b7981f6SKowalski, Kamil         auto session =
9455c7b7a2SEd Tanous             crow::persistent_data::SessionStore::getInstance().getSessionByUid(
954b1b8683SBorawski.Lukasz                 params[0]);
962b7981f6SKowalski, Kamil 
97*1abe55efSEd Tanous         if (session == nullptr)
98*1abe55efSEd Tanous         {
99f4c4dcf4SKowalski, Kamil             messages::addMessageToErrorJson(
100*1abe55efSEd Tanous                 res.jsonValue,
101*1abe55efSEd Tanous                 messages::resourceNotFound("Session", params[0]));
102f4c4dcf4SKowalski, Kamil 
103e0d918bcSEd Tanous             res.result(boost::beast::http::status::not_found);
1042b7981f6SKowalski, Kamil             res.end();
1052b7981f6SKowalski, Kamil             return;
1062b7981f6SKowalski, Kamil         }
1072b7981f6SKowalski, Kamil 
108f4c4dcf4SKowalski, Kamil         // DELETE should return representation of object that will be removed
109f4c4dcf4SKowalski, Kamil         doGet(res, req, params);
110f4c4dcf4SKowalski, Kamil 
111*1abe55efSEd Tanous         crow::persistent_data::SessionStore::getInstance().removeSession(
112*1abe55efSEd Tanous             session);
1132b7981f6SKowalski, Kamil     }
1142b7981f6SKowalski, Kamil 
1152b7981f6SKowalski, Kamil     /**
1162b7981f6SKowalski, Kamil      * This allows SessionCollection to reuse this class' doGet method, to
117*1abe55efSEd Tanous      * maintain consistency of returned data, as Collection's doPost should
118*1abe55efSEd Tanous      * return data for created member which should match member's doGet result
119*1abe55efSEd Tanous      * in 100%
1202b7981f6SKowalski, Kamil      */
1212b7981f6SKowalski, Kamil     friend SessionCollection;
1222b7981f6SKowalski, Kamil };
1232b7981f6SKowalski, Kamil 
124*1abe55efSEd Tanous class SessionCollection : public Node
125*1abe55efSEd Tanous {
1262b7981f6SKowalski, Kamil   public:
127*1abe55efSEd Tanous     SessionCollection(CrowApp& app) :
128*1abe55efSEd Tanous         Node(app, "/redfish/v1/SessionService/Sessions/"), memberSession(app)
129*1abe55efSEd Tanous     {
130c1a46bd2SBorawski.Lukasz         Node::json["@odata.type"] = "#SessionCollection.SessionCollection";
131c1a46bd2SBorawski.Lukasz         Node::json["@odata.id"] = "/redfish/v1/SessionService/Sessions/";
132c1a46bd2SBorawski.Lukasz         Node::json["@odata.context"] =
1332b7981f6SKowalski, Kamil             "/redfish/v1/$metadata#SessionCollection.SessionCollection";
134c1a46bd2SBorawski.Lukasz         Node::json["Name"] = "Session Collection";
135c1a46bd2SBorawski.Lukasz         Node::json["Description"] = "Session Collection";
136c1a46bd2SBorawski.Lukasz         Node::json["Members@odata.count"] = 0;
137c1a46bd2SBorawski.Lukasz         Node::json["Members"] = nlohmann::json::array();
1383ebd75f7SEd Tanous 
139e0d918bcSEd Tanous         entityPrivileges = {
140e0d918bcSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
141e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
142e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
143e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
144e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
145e0d918bcSEd Tanous             {boost::beast::http::verb::post, {}}};
1462b7981f6SKowalski, Kamil     }
1472b7981f6SKowalski, Kamil 
1482b7981f6SKowalski, Kamil   private:
14955c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
150*1abe55efSEd Tanous                const std::vector<std::string>& params) override
151*1abe55efSEd Tanous     {
15255c7b7a2SEd Tanous         std::vector<const std::string*> sessionIds =
15355c7b7a2SEd Tanous             crow::persistent_data::SessionStore::getInstance().getUniqueIds(
15455c7b7a2SEd Tanous                 false, crow::persistent_data::PersistenceType::TIMEOUT);
1552b7981f6SKowalski, Kamil 
15655c7b7a2SEd Tanous         Node::json["Members@odata.count"] = sessionIds.size();
157c1a46bd2SBorawski.Lukasz         Node::json["Members"] = nlohmann::json::array();
158*1abe55efSEd Tanous         for (const std::string* uid : sessionIds)
159*1abe55efSEd Tanous         {
160c1a46bd2SBorawski.Lukasz             Node::json["Members"].push_back(
1612b7981f6SKowalski, Kamil                 {{"@odata.id", "/redfish/v1/SessionService/Sessions/" + *uid}});
1622b7981f6SKowalski, Kamil         }
1632b7981f6SKowalski, Kamil 
16455c7b7a2SEd Tanous         res.jsonValue = Node::json;
1652b7981f6SKowalski, Kamil         res.end();
1662b7981f6SKowalski, Kamil     }
1672b7981f6SKowalski, Kamil 
16855c7b7a2SEd Tanous     void doPost(crow::Response& res, const crow::Request& req,
169*1abe55efSEd Tanous                 const std::vector<std::string>& params) override
170*1abe55efSEd Tanous     {
171e0d918bcSEd Tanous         boost::beast::http::status status;
1722b7981f6SKowalski, Kamil         std::string username;
173f4c4dcf4SKowalski, Kamil         bool userAuthSuccessful =
17455c7b7a2SEd Tanous             authenticateUser(req, status, username, res.jsonValue);
175e0d918bcSEd Tanous         res.result(status);
176e0d918bcSEd Tanous 
177*1abe55efSEd Tanous         if (!userAuthSuccessful)
178*1abe55efSEd Tanous         {
1792b7981f6SKowalski, Kamil             res.end();
1802b7981f6SKowalski, Kamil             return;
1812b7981f6SKowalski, Kamil         }
1822b7981f6SKowalski, Kamil 
1832b7981f6SKowalski, Kamil         // User is authenticated - create session for him
184*1abe55efSEd Tanous         auto session = crow::persistent_data::SessionStore::getInstance()
185*1abe55efSEd Tanous                            .generateUserSession(username);
18655c7b7a2SEd Tanous         res.addHeader("X-Auth-Token", session->sessionToken);
1872b7981f6SKowalski, Kamil 
188*1abe55efSEd Tanous         res.addHeader("Location", "/redfish/v1/SessionService/Sessions/" +
189*1abe55efSEd Tanous                                       session->uniqueId);
190b9845d9eSEd Tanous 
1912b7981f6SKowalski, Kamil         // Return data for created session
19255c7b7a2SEd Tanous         memberSession.doGet(res, req, {session->uniqueId});
1932b7981f6SKowalski, Kamil 
1942b7981f6SKowalski, Kamil         // No need for res.end(), as it is called by doGet()
1952b7981f6SKowalski, Kamil     }
1962b7981f6SKowalski, Kamil 
1972b7981f6SKowalski, Kamil     /**
1982b7981f6SKowalski, Kamil      * @brief Verifies data provided in request and tries to authenticate user
1992b7981f6SKowalski, Kamil      *
2002b7981f6SKowalski, Kamil      * @param[in]  req            Crow request containing authentication data
2012b7981f6SKowalski, Kamil      * @param[out] httpRespCode   HTTP Code that should be returned in response
2022b7981f6SKowalski, Kamil      * @param[out] user           Retrieved username - not filled on failure
203f4c4dcf4SKowalski, Kamil      * @param[out] errJson        JSON to which error messages will be written
2042b7981f6SKowalski, Kamil      *
2052b7981f6SKowalski, Kamil      * @return true if authentication was successful, false otherwise
2062b7981f6SKowalski, Kamil      */
20755c7b7a2SEd Tanous     bool authenticateUser(const crow::Request& req,
208e0d918bcSEd Tanous                           boost::beast::http::status& httpRespCode,
209*1abe55efSEd Tanous                           std::string& user, nlohmann::json& errJson)
210*1abe55efSEd Tanous     {
2112b7981f6SKowalski, Kamil         // We need only UserName and Password - nothing more, nothing less
2122b7981f6SKowalski, Kamil         static constexpr const unsigned int numberOfRequiredFieldsInReq = 2;
2132b7981f6SKowalski, Kamil 
2142b7981f6SKowalski, Kamil         // call with exceptions disabled
21555c7b7a2SEd Tanous         auto loginCredentials = nlohmann::json::parse(req.body, nullptr, false);
216*1abe55efSEd Tanous         if (loginCredentials.is_discarded())
217*1abe55efSEd Tanous         {
218e0d918bcSEd Tanous             httpRespCode = boost::beast::http::status::bad_request;
219f4c4dcf4SKowalski, Kamil 
220f4c4dcf4SKowalski, Kamil             messages::addMessageToErrorJson(errJson, messages::malformedJSON());
2212b7981f6SKowalski, Kamil 
2222b7981f6SKowalski, Kamil             return false;
2232b7981f6SKowalski, Kamil         }
2242b7981f6SKowalski, Kamil 
2252b7981f6SKowalski, Kamil         // Check that there are only as many fields as there should be
226*1abe55efSEd Tanous         if (loginCredentials.size() != numberOfRequiredFieldsInReq)
227*1abe55efSEd Tanous         {
228e0d918bcSEd Tanous             httpRespCode = boost::beast::http::status::bad_request;
229f4c4dcf4SKowalski, Kamil 
230f4c4dcf4SKowalski, Kamil             messages::addMessageToErrorJson(errJson, messages::malformedJSON());
2312b7981f6SKowalski, Kamil 
2322b7981f6SKowalski, Kamil             return false;
2332b7981f6SKowalski, Kamil         }
2342b7981f6SKowalski, Kamil 
2352b7981f6SKowalski, Kamil         // Find fields that we need - UserName and Password
23655c7b7a2SEd Tanous         auto userIt = loginCredentials.find("UserName");
23755c7b7a2SEd Tanous         auto passIt = loginCredentials.find("Password");
238*1abe55efSEd Tanous         if (userIt == loginCredentials.end() ||
239*1abe55efSEd Tanous             passIt == loginCredentials.end())
240*1abe55efSEd Tanous         {
241e0d918bcSEd Tanous             httpRespCode = boost::beast::http::status::bad_request;
242f4c4dcf4SKowalski, Kamil 
243*1abe55efSEd Tanous             if (userIt == loginCredentials.end())
244*1abe55efSEd Tanous             {
245*1abe55efSEd Tanous                 messages::addMessageToErrorJson(
246*1abe55efSEd Tanous                     errJson, messages::propertyMissing("UserName"));
247f4c4dcf4SKowalski, Kamil             }
248f4c4dcf4SKowalski, Kamil 
249*1abe55efSEd Tanous             if (passIt == loginCredentials.end())
250*1abe55efSEd Tanous             {
251*1abe55efSEd Tanous                 messages::addMessageToErrorJson(
252*1abe55efSEd Tanous                     errJson, messages::propertyMissing("Password"));
253f4c4dcf4SKowalski, Kamil             }
2542b7981f6SKowalski, Kamil 
2552b7981f6SKowalski, Kamil             return false;
2562b7981f6SKowalski, Kamil         }
2572b7981f6SKowalski, Kamil 
2582b7981f6SKowalski, Kamil         // Check that given data is of valid type (string)
259*1abe55efSEd Tanous         if (!userIt->is_string() || !passIt->is_string())
260*1abe55efSEd Tanous         {
261e0d918bcSEd Tanous             httpRespCode = boost::beast::http::status::bad_request;
262f4c4dcf4SKowalski, Kamil 
263*1abe55efSEd Tanous             if (!userIt->is_string())
264*1abe55efSEd Tanous             {
265f4c4dcf4SKowalski, Kamil                 messages::addMessageToErrorJson(
266*1abe55efSEd Tanous                     errJson, messages::propertyValueTypeError(userIt->dump(),
267*1abe55efSEd Tanous                                                               "UserName"));
268f4c4dcf4SKowalski, Kamil             }
269f4c4dcf4SKowalski, Kamil 
270*1abe55efSEd Tanous             if (!passIt->is_string())
271*1abe55efSEd Tanous             {
272f4c4dcf4SKowalski, Kamil                 messages::addMessageToErrorJson(
273*1abe55efSEd Tanous                     errJson, messages::propertyValueTypeError(userIt->dump(),
274*1abe55efSEd Tanous                                                               "Password"));
275f4c4dcf4SKowalski, Kamil             }
2762b7981f6SKowalski, Kamil 
2772b7981f6SKowalski, Kamil             return false;
2782b7981f6SKowalski, Kamil         }
2792b7981f6SKowalski, Kamil 
2802b7981f6SKowalski, Kamil         // Extract username and password
28155c7b7a2SEd Tanous         std::string username = userIt->get<const std::string>();
28255c7b7a2SEd Tanous         std::string password = passIt->get<const std::string>();
2832b7981f6SKowalski, Kamil 
2842b7981f6SKowalski, Kamil         // Verify that required fields are not empty
285*1abe55efSEd Tanous         if (username.empty() || password.empty())
286*1abe55efSEd Tanous         {
287e0d918bcSEd Tanous             httpRespCode = boost::beast::http::status::bad_request;
288f4c4dcf4SKowalski, Kamil 
289*1abe55efSEd Tanous             if (username.empty())
290*1abe55efSEd Tanous             {
291*1abe55efSEd Tanous                 messages::addMessageToErrorJson(
292*1abe55efSEd Tanous                     errJson, messages::propertyMissing("UserName"));
293f4c4dcf4SKowalski, Kamil             }
294f4c4dcf4SKowalski, Kamil 
295*1abe55efSEd Tanous             if (password.empty())
296*1abe55efSEd Tanous             {
297*1abe55efSEd Tanous                 messages::addMessageToErrorJson(
298*1abe55efSEd Tanous                     errJson, messages::propertyMissing("Password"));
299f4c4dcf4SKowalski, Kamil             }
3002b7981f6SKowalski, Kamil 
3012b7981f6SKowalski, Kamil             return false;
3022b7981f6SKowalski, Kamil         }
3032b7981f6SKowalski, Kamil 
3042b7981f6SKowalski, Kamil         // Finally - try to authenticate user
305*1abe55efSEd Tanous         if (!pamAuthenticateUser(username, password))
306*1abe55efSEd Tanous         {
307e0d918bcSEd Tanous             httpRespCode = boost::beast::http::status::unauthorized;
308f4c4dcf4SKowalski, Kamil 
309f4c4dcf4SKowalski, Kamil             messages::addMessageToErrorJson(
310*1abe55efSEd Tanous                 errJson,
311*1abe55efSEd Tanous                 messages::resourceAtUriUnauthorized(
312e0d918bcSEd Tanous                     std::string(req.url), "Invalid username or password"));
3132b7981f6SKowalski, Kamil 
3142b7981f6SKowalski, Kamil             return false;
3152b7981f6SKowalski, Kamil         }
3162b7981f6SKowalski, Kamil 
3172b7981f6SKowalski, Kamil         // User authenticated successfully
318e0d918bcSEd Tanous         httpRespCode = boost::beast::http::status::ok;
319f4c4dcf4SKowalski, Kamil         user = username;
3202b7981f6SKowalski, Kamil 
3212b7981f6SKowalski, Kamil         return true;
3222b7981f6SKowalski, Kamil     }
3232b7981f6SKowalski, Kamil 
3242b7981f6SKowalski, Kamil     /**
3252b7981f6SKowalski, Kamil      * Member session to ensure consistency between collection's doPost and
3262b7981f6SKowalski, Kamil      * member's doGet, as they should return 100% matching data
3272b7981f6SKowalski, Kamil      */
3282b7981f6SKowalski, Kamil     Sessions memberSession;
3292b7981f6SKowalski, Kamil };
3302b7981f6SKowalski, Kamil 
331*1abe55efSEd Tanous class SessionService : public Node
332*1abe55efSEd Tanous {
3335d27b854SBorawski.Lukasz   public:
334*1abe55efSEd Tanous     SessionService(CrowApp& app) : Node(app, "/redfish/v1/SessionService/")
335*1abe55efSEd Tanous     {
3365d27b854SBorawski.Lukasz         Node::json["@odata.type"] = "#SessionService.v1_0_2.SessionService";
3375d27b854SBorawski.Lukasz         Node::json["@odata.id"] = "/redfish/v1/SessionService/";
3385d27b854SBorawski.Lukasz         Node::json["@odata.context"] =
3395d27b854SBorawski.Lukasz             "/redfish/v1/$metadata#SessionService.SessionService";
3405d27b854SBorawski.Lukasz         Node::json["Name"] = "Session Service";
3416c233015SEd Tanous         Node::json["Id"] = "SessionService";
3425d27b854SBorawski.Lukasz         Node::json["Description"] = "Session Service";
3435d27b854SBorawski.Lukasz         Node::json["SessionTimeout"] =
34455c7b7a2SEd Tanous             crow::persistent_data::SessionStore::getInstance()
34555c7b7a2SEd Tanous                 .getTimeoutInSeconds();
3465d27b854SBorawski.Lukasz         Node::json["ServiceEnabled"] = true;
3473ebd75f7SEd Tanous 
348e0d918bcSEd Tanous         entityPrivileges = {
349e0d918bcSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
350e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
351e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
352e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
353e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
354e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3555d27b854SBorawski.Lukasz     }
3565d27b854SBorawski.Lukasz 
3575d27b854SBorawski.Lukasz   private:
35855c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
359*1abe55efSEd Tanous                const std::vector<std::string>& params) override
360*1abe55efSEd Tanous     {
36155c7b7a2SEd Tanous         res.jsonValue = Node::json;
3625d27b854SBorawski.Lukasz         res.end();
3635d27b854SBorawski.Lukasz     }
3645d27b854SBorawski.Lukasz };
3655d27b854SBorawski.Lukasz 
3662b7981f6SKowalski, Kamil } // namespace redfish
367