xref: /openbmc/bmcweb/features/redfish/lib/redfish_sessions.hpp (revision 9712f8ac42746e65f32c2bc3de0835846652568e)
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 
221abe55efSEd Tanous namespace redfish
231abe55efSEd Tanous {
242b7981f6SKowalski, Kamil 
252b7981f6SKowalski, Kamil class SessionCollection;
262b7981f6SKowalski, Kamil 
271abe55efSEd Tanous class Sessions : public Node
281abe55efSEd Tanous {
292b7981f6SKowalski, Kamil   public:
301abe55efSEd Tanous     Sessions(CrowApp& app) :
311abe55efSEd Tanous         Node(app, "/redfish/v1/SessionService/Sessions/<str>/", std::string())
321abe55efSEd 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,
491abe55efSEd Tanous                const std::vector<std::string>& params) override
501abe55efSEd Tanous     {
512b7981f6SKowalski, Kamil         auto session =
5255c7b7a2SEd Tanous             crow::persistent_data::SessionStore::getInstance().getSessionByUid(
534b1b8683SBorawski.Lukasz                 params[0]);
542b7981f6SKowalski, Kamil 
551abe55efSEd Tanous         if (session == nullptr)
561abe55efSEd Tanous         {
57f4c4dcf4SKowalski, Kamil             messages::addMessageToErrorJson(
581abe55efSEd Tanous                 res.jsonValue,
591abe55efSEd 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,
761abe55efSEd Tanous                   const std::vector<std::string>& params) override
771abe55efSEd Tanous     {
782b7981f6SKowalski, Kamil         // Need only 1 param which should be id of session to be deleted
791abe55efSEd Tanous         if (params.size() != 1)
801abe55efSEd Tanous         {
81f4c4dcf4SKowalski, Kamil             // This should be handled by crow and never happen
821abe55efSEd Tanous             BMCWEB_LOG_ERROR << "Session DELETE has been called with invalid "
831abe55efSEd Tanous                                 "number of params";
84f4c4dcf4SKowalski, Kamil 
85e0d918bcSEd Tanous             res.result(boost::beast::http::status::bad_request);
861abe55efSEd Tanous             messages::addMessageToErrorJson(res.jsonValue,
871abe55efSEd 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 
971abe55efSEd Tanous         if (session == nullptr)
981abe55efSEd Tanous         {
99f4c4dcf4SKowalski, Kamil             messages::addMessageToErrorJson(
1001abe55efSEd Tanous                 res.jsonValue,
1011abe55efSEd 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 
1111abe55efSEd Tanous         crow::persistent_data::SessionStore::getInstance().removeSession(
1121abe55efSEd Tanous             session);
1132b7981f6SKowalski, Kamil     }
1142b7981f6SKowalski, Kamil 
1152b7981f6SKowalski, Kamil     /**
1162b7981f6SKowalski, Kamil      * This allows SessionCollection to reuse this class' doGet method, to
1171abe55efSEd Tanous      * maintain consistency of returned data, as Collection's doPost should
1181abe55efSEd Tanous      * return data for created member which should match member's doGet result
1191abe55efSEd Tanous      * in 100%
1202b7981f6SKowalski, Kamil      */
1212b7981f6SKowalski, Kamil     friend SessionCollection;
1222b7981f6SKowalski, Kamil };
1232b7981f6SKowalski, Kamil 
1241abe55efSEd Tanous class SessionCollection : public Node
1251abe55efSEd Tanous {
1262b7981f6SKowalski, Kamil   public:
1271abe55efSEd Tanous     SessionCollection(CrowApp& app) :
1281abe55efSEd Tanous         Node(app, "/redfish/v1/SessionService/Sessions/"), memberSession(app)
1291abe55efSEd 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,
1501abe55efSEd Tanous                const std::vector<std::string>& params) override
1511abe55efSEd 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();
1581abe55efSEd Tanous         for (const std::string* uid : sessionIds)
1591abe55efSEd 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,
1691abe55efSEd Tanous                 const std::vector<std::string>& params) override
1701abe55efSEd Tanous     {
171*9712f8acSEd Tanous         std::string username;
172*9712f8acSEd Tanous         std::string password;
173*9712f8acSEd Tanous         if (!json_util::readJson(req, res, "UserName", username, "Password",
174*9712f8acSEd Tanous                                  password))
1751abe55efSEd Tanous         {
1762b7981f6SKowalski, Kamil             res.end();
1772b7981f6SKowalski, Kamil             return;
1782b7981f6SKowalski, Kamil         }
1792b7981f6SKowalski, Kamil 
180820ce598SEd Tanous         if (password.empty() || username.empty() ||
181820ce598SEd Tanous             res.result() != boost::beast::http::status::ok)
1821abe55efSEd Tanous         {
1831abe55efSEd Tanous             if (username.empty())
1841abe55efSEd Tanous             {
185820ce598SEd Tanous                 res.result(boost::beast::http::status::bad_request);
1861abe55efSEd Tanous                 messages::addMessageToErrorJson(
187820ce598SEd Tanous                     res.jsonValue, messages::propertyMissing("UserName"));
188f4c4dcf4SKowalski, Kamil             }
189f4c4dcf4SKowalski, Kamil 
1901abe55efSEd Tanous             if (password.empty())
1911abe55efSEd Tanous             {
192820ce598SEd Tanous                 res.result(boost::beast::http::status::bad_request);
1931abe55efSEd Tanous                 messages::addMessageToErrorJson(
194820ce598SEd Tanous                     res.jsonValue, messages::propertyMissing("Password"));
195820ce598SEd Tanous             }
196820ce598SEd Tanous             res.end();
197820ce598SEd Tanous 
198820ce598SEd Tanous             return;
199f4c4dcf4SKowalski, Kamil         }
2002b7981f6SKowalski, Kamil 
2011abe55efSEd Tanous         if (!pamAuthenticateUser(username, password))
2021abe55efSEd Tanous         {
203f4c4dcf4SKowalski, Kamil 
204820ce598SEd Tanous             res.result(boost::beast::http::status::unauthorized);
205f4c4dcf4SKowalski, Kamil             messages::addMessageToErrorJson(
206820ce598SEd Tanous                 res.jsonValue,
2071abe55efSEd Tanous                 messages::resourceAtUriUnauthorized(
208e0d918bcSEd Tanous                     std::string(req.url), "Invalid username or password"));
209820ce598SEd Tanous             res.end();
2102b7981f6SKowalski, Kamil 
211820ce598SEd Tanous             return;
2122b7981f6SKowalski, Kamil         }
2132b7981f6SKowalski, Kamil 
214820ce598SEd Tanous         // User is authenticated - create session
215820ce598SEd Tanous         std::shared_ptr<crow::persistent_data::UserSession> session =
216820ce598SEd Tanous             crow::persistent_data::SessionStore::getInstance()
217820ce598SEd Tanous                 .generateUserSession(username);
218820ce598SEd Tanous         res.addHeader("X-Auth-Token", session->sessionToken);
219820ce598SEd Tanous         res.addHeader("Location", "/redfish/v1/SessionService/Sessions/" +
220820ce598SEd Tanous                                       session->uniqueId);
221820ce598SEd Tanous         res.result(boost::beast::http::status::created);
222820ce598SEd Tanous         memberSession.doGet(res, req, {session->uniqueId});
2232b7981f6SKowalski, Kamil     }
2242b7981f6SKowalski, Kamil 
2252b7981f6SKowalski, Kamil     /**
2262b7981f6SKowalski, Kamil      * Member session to ensure consistency between collection's doPost and
2272b7981f6SKowalski, Kamil      * member's doGet, as they should return 100% matching data
2282b7981f6SKowalski, Kamil      */
2292b7981f6SKowalski, Kamil     Sessions memberSession;
2302b7981f6SKowalski, Kamil };
2312b7981f6SKowalski, Kamil 
2321abe55efSEd Tanous class SessionService : public Node
2331abe55efSEd Tanous {
2345d27b854SBorawski.Lukasz   public:
2351abe55efSEd Tanous     SessionService(CrowApp& app) : Node(app, "/redfish/v1/SessionService/")
2361abe55efSEd Tanous     {
2375d27b854SBorawski.Lukasz         Node::json["@odata.type"] = "#SessionService.v1_0_2.SessionService";
2385d27b854SBorawski.Lukasz         Node::json["@odata.id"] = "/redfish/v1/SessionService/";
2395d27b854SBorawski.Lukasz         Node::json["@odata.context"] =
2405d27b854SBorawski.Lukasz             "/redfish/v1/$metadata#SessionService.SessionService";
2415d27b854SBorawski.Lukasz         Node::json["Name"] = "Session Service";
2426c233015SEd Tanous         Node::json["Id"] = "SessionService";
2435d27b854SBorawski.Lukasz         Node::json["Description"] = "Session Service";
2445d27b854SBorawski.Lukasz         Node::json["SessionTimeout"] =
24555c7b7a2SEd Tanous             crow::persistent_data::SessionStore::getInstance()
24655c7b7a2SEd Tanous                 .getTimeoutInSeconds();
2475d27b854SBorawski.Lukasz         Node::json["ServiceEnabled"] = true;
2483ebd75f7SEd Tanous 
249e0d918bcSEd Tanous         entityPrivileges = {
250e0d918bcSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
251e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
252e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
253e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
254e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
255e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2565d27b854SBorawski.Lukasz     }
2575d27b854SBorawski.Lukasz 
2585d27b854SBorawski.Lukasz   private:
25955c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
2601abe55efSEd Tanous                const std::vector<std::string>& params) override
2611abe55efSEd Tanous     {
26255c7b7a2SEd Tanous         res.jsonValue = Node::json;
2635d27b854SBorawski.Lukasz         res.end();
2645d27b854SBorawski.Lukasz     }
2655d27b854SBorawski.Lukasz };
2665d27b854SBorawski.Lukasz 
2672b7981f6SKowalski, Kamil } // namespace redfish
268