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