From 5c79e34be9357c2a2cd9bac61cd0162dbd342a2d Mon Sep 17 00:00:00 2001 From: Jayaprakash Mutyala Date: Fri, 30 Jul 2021 17:33:16 +0000 Subject: [PATCH] Add/get IPMI session id's to Redfish As per existing implementation, Redfish supports to get only sessions created on Redfish & EWS. But as per Redfish schema Redfish should include to get IPMI sessions as well. So add support to display IPMI session Id's as well on Redfish. This commit will not impact any functionality/behavior of existing code. Below functionalities implemented in this commit. 1. Get IPMI session collection 2. Get individual IPMI session information 3. Delete IPMI sessions - Respond with not supported as we can't delete IPMI sessions from Redfish interface Tested: 1. Verified redfish validator passed with active IPMI session. 2. Get session details from Redfish GET: https:///redfish/v1/SessionService/Sessions Response: { "@odata.id": "/redfish/v1/SessionService/Sessions/", "@odata.type": "#SessionCollection.SessionCollection", "Description": "Session Collection", "Members": [ { "@odata.id": "/redfish/v1/SessionService/Sessions/TlFPbR9ZIn" }, { "@odata.id": "/redfish/v1/SessionService/Sessions/184U3014ub" }, { "@odata.id": "/redfish/v1/SessionService/Sessions/cV0xi5QoPy" }, { "@odata.id": "/redfish/v1/SessionService/Sessions/8f6234d7_81" } ], "Members@odata.count": 4, "Name": "Session Collection" } 3. Get session details from RedFish Case 1: RedFish session GET: https:///redfish/v1/SessionService/Sessions/TlFPbR9ZIn Response: { "@odata.id": "/redfish/v1/SessionService/Sessions/TlFPbR9ZIn", "@odata.type": "#Session.v1_3_0.Session", "ClientOriginIPAddress": "::ffff:10.213.91.40", "Description": "Manager User Session", "Id": "TlFPbR9ZIn", "Name": "User Session", "UserName": "root" } Case 2: IPMI session Verified and displayed IPMI session details on RedFish. GET: https:///redfish/v1/SessionService/Sessions/8f6234d7_81 Response: { "@odata.id": "/redfish/v1/SessionService/Sessions/8f6234d7_81", "@odata.type": "#Session.v1_3_0.Session", "ClientOriginIPAddress": "xx.xx.xx.xx", "Description": "Manager User Session", "Id": "8f6234d7_81", "Name": "User Session", "UserName": "root" } 4. Delete IPMI session: Verified IPMI session is not allowed to delete from Redfish DELETE: https:///redfish/v1/SessionService/Sessions/8f6234d7_81 Response: { "error": { "@Message.ExtendedInfo": [ { "@odata.type": "#Message.v1_1_1.Message", "Message": "The action deleting IPMI session from Redfish is not supported by the resource.", "MessageArgs": [ "deleting IPMI session from Redfish" ], "MessageId": "Base.1.8.1.ActionNotSupported", "MessageSeverity": "Critical", "Resolution": "The action supplied cannot be resubmitted to the implementation. Perhaps the action was invalid, the wrong resource was the target or the implementation documentation may be of assistance." } ], "code": "Base.1.8.1.ActionNotSupported", "message": "The action deleting IPMI session from Redfish is not supported by the resource." } } 5. Delete RedFish session Result: successfully deleted valid RedFish session. Signed-off-by: Jayaprakash Mutyala --- redfish-core/lib/redfish_sessions.hpp | 244 +++++++++++++++++++++++--- 1 file changed, 222 insertions(+), 22 deletions(-) diff --git a/redfish-core/lib/redfish_sessions.hpp b/redfish-core/lib/redfish_sessions.hpp index 929e0c8..3c7a968 100644 --- a/redfish-core/lib/redfish_sessions.hpp +++ b/redfish-core/lib/redfish_sessions.hpp @@ -56,14 +56,127 @@ inline void requestRoutesSession(App& app) auto session = persistent_data::SessionStore::getInstance() .getSessionByUid(sessionId); - if (session == nullptr) + if (session) { - messages::resourceNotFound(asyncResp->res, "Session", - sessionId); + fillSessionObject(asyncResp->res, *session); return; } - fillSessionObject(asyncResp->res, *session); + std::array interfaces = { + "xyz.openbmc_project.Ipmi.SessionInfo"}; + crow::connections::systemBus->async_method_call( + [asyncResp, sessionId](const boost::system::error_code ec, + const GetSubTreeType& subtree) { + if (ec) + { + BMCWEB_LOG_DEBUG + << "Error in querying GetSubTree with " + "Object Mapper. " + << ec; + messages::internalError(asyncResp->res); + return; + } + if (subtree.size() == 0) + { + BMCWEB_LOG_DEBUG + << "Can't find Session Info Attributes!"; + messages::resourceNotFound(asyncResp->res, + "Session", sessionId); + return; + } + bool ipmiSessionFound = false; + std::string ipmiSessionService; + std::string ipmiSessionInfPath; + for (const auto& [ipmiSessionPath, object] : subtree) + { + if (ipmiSessionPath.empty() || object.empty()) + { + BMCWEB_LOG_DEBUG + << "Session Info Attributes mapper error!"; + continue; + } + if (!boost::ends_with(ipmiSessionPath, sessionId)) + { + continue; + } + ipmiSessionFound = true; + ipmiSessionService = object[0].first; + ipmiSessionInfPath = ipmiSessionPath; + break; + } + if (!ipmiSessionFound) + { + messages::resourceNotFound(asyncResp->res, + "Session", sessionId); + return; + } + if (ipmiSessionService.empty()) + { + BMCWEB_LOG_DEBUG + << "Session Info Attributes mapper " + "error!"; + messages::internalError(asyncResp->res); + return; + } + crow::connections::systemBus->async_method_call( + [asyncResp, sessionId]( + const boost::system::error_code ec, + const std::vector>>& properties) { + if (ec) + { + BMCWEB_LOG_DEBUG + << "Error in querying Session " + "Info State property " + << ec; + messages::internalError(asyncResp->res); + return; + } + std::string userName = ""; + uint32_t remoteIpAddr; + try + { + sdbusplus::unpackProperties( + properties, "Username", userName, + "RemoteIPAddr", remoteIpAddr); + asyncResp->res.jsonValue["Id"] = sessionId; + asyncResp->res.jsonValue["UserName"] = + userName; + asyncResp->res.jsonValue["@odata.id"] = + "/redfish/v1/SessionService/" + "Sessions/" + + sessionId; + asyncResp->res.jsonValue["@odata.type"] = + "#Session.v1_3_0.Session"; + asyncResp->res.jsonValue["Name"] = + "User Session"; + asyncResp->res.jsonValue["Description"] = + "Manager User Session"; + struct in_addr ipAddr; + ipAddr.s_addr = remoteIpAddr; + asyncResp->res + .jsonValue["ClientOriginIPAddress"] = + inet_ntoa(ipAddr); + } + catch (const sdbusplus::exception:: + UnpackPropertyError& error) + { + BMCWEB_LOG_ERROR << error.what(); + messages::internalError(asyncResp->res); + return; + } + return; + }, + ipmiSessionService, ipmiSessionInfPath, + "org.freedesktop.DBus.Properties", "GetAll", + "xyz.openbmc_project.Ipmi.SessionInfo"); + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, + interfaces); }); BMCWEB_ROUTE(app, "/redfish/v1/SessionService/Sessions//") @@ -75,34 +188,79 @@ inline void requestRoutesSession(App& app) auto session = persistent_data::SessionStore::getInstance() .getSessionByUid(sessionId); - if (session == nullptr) - { - messages::resourceNotFound(asyncResp->res, "Session", - sessionId); - return; - } - // Perform a proper ConfigureSelf authority check. If a // session is being used to DELETE some other user's session, // then the ConfigureSelf privilege does not apply. In that // case, perform the authority check again without the user's // ConfigureSelf privilege. - if (session->username != req.session->username) + if (session) { - Privileges effectiveUserPrivileges = - redfish::getUserPrivileges(req.userRole); - - if (!effectiveUserPrivileges.isSupersetOf( - {"ConfigureUsers"})) + if (session->username != req.session->username) { - messages::insufficientPrivilege(asyncResp->res); - return; + Privileges effectiveUserPrivileges = + redfish::getUserPrivileges(req.userRole); + + if (!effectiveUserPrivileges.isSupersetOf( + {"ConfigureUsers"})) + { + messages::insufficientPrivilege(asyncResp->res); + return; + } } + persistent_data::SessionStore::getInstance().removeSession( + session); + messages::success(asyncResp->res); + return; } - persistent_data::SessionStore::getInstance().removeSession( - session); - messages::success(asyncResp->res); + std::array interfaces = { + "xyz.openbmc_project.Ipmi.SessionInfo"}; + crow::connections::systemBus->async_method_call( + [asyncResp, + sessionId](const boost::system::error_code ec, + const std::vector& ifaceList) { + if (ec) + { + BMCWEB_LOG_DEBUG + << "Error in querying GetSubTreePaths " + "with Object Mapper. " + << ec; + messages::internalError(asyncResp->res); + return; + } + if (ifaceList.size() == 0) + { + BMCWEB_LOG_DEBUG + << "Can't find Session Info Attributes!"; + return; + } + bool ipmiSessionFound = false; + for (const std::string& ipmiSessionPath : ifaceList) + { + if (!boost::ends_with(ipmiSessionPath, sessionId)) + { + continue; + } + ipmiSessionFound = true; + break; + } + if (ipmiSessionFound) + { + BMCWEB_LOG_DEBUG << "Deleting IPMI session from " + "Redfish is not allowed."; + messages::actionNotSupported( + asyncResp->res, + "deleting IPMI session from Redfish"); + return; + } + messages::resourceNotFound(asyncResp->res, "Session", + sessionId); + return; + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", + 0, interfaces); }); BMCWEB_ROUTE(app, "/redfish/v1/SessionService/Sessions/") @@ -131,6 +289,48 @@ inline void requestRoutesSession(App& app) "/redfish/v1/SessionService/Sessions/"; asyncResp->res.jsonValue["Name"] = "Session Collection"; asyncResp->res.jsonValue["Description"] = "Session Collection"; + + std::array interfaces = { + "xyz.openbmc_project.Ipmi.SessionInfo"}; + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec, + const std::vector& ifaceList) { + if (ec) + { + BMCWEB_LOG_DEBUG + << "Error in querying GetSubTreePaths " + "with Object Mapper. " + << ec; + messages::internalError(asyncResp->res); + return; + } + if (ifaceList.size() == 0) + { + BMCWEB_LOG_DEBUG + << "Can't find Session Info Attributes!"; + return; + } + for (const std::string& ipmiSessionPath : ifaceList) + { + std::filesystem::path filePath(ipmiSessionPath); + std::string ipmiSessionID = + filePath.has_filename() ? filePath.filename() + : ""; + if (!ipmiSessionID.empty() && ipmiSessionID != "0") + { + asyncResp->res.jsonValue["Members"].push_back( + {{"@odata.id", + "/redfish/v1/SessionService/Sessions/" + + ipmiSessionID}}); + } + } + asyncResp->res.jsonValue["Members@odata.count"] = + asyncResp->res.jsonValue["Members"].size(); + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", + 0, interfaces); }); BMCWEB_ROUTE(app, "/redfish/v1/SessionService/Sessions/") -- 2.17.1