From 828252d54597049ef67e4ff43050eae312b70f07 Mon Sep 17 00:00:00 2001 From: Jiaqing Zhao Date: Fri, 30 Sep 2022 13:59:19 +0800 Subject: certificate: Replace lambda with inline function For API endpoints, it is suggested to break out the entire handlers into a function, and not rely on a lambda at all. This brings more readability as it reduces indents. Tested: Code compiles, and Redfish Service Validator passed. Change-Id: I5132149c00b6f553931dae562b83bc7aee678105 Signed-off-by: Jiaqing Zhao --- redfish-core/include/redfish.hpp | 6 - redfish-core/lib/certificate_service.hpp | 1480 +++++++++++++++--------------- 2 files changed, 732 insertions(+), 754 deletions(-) (limited to 'redfish-core') diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp index ed42b89a2f..796df8d87f 100644 --- a/redfish-core/include/redfish.hpp +++ b/redfish-core/include/redfish.hpp @@ -190,14 +190,8 @@ class RedfishService requestRoutesMessageRegistry(app); requestRoutesCertificateService(app); - requestRoutesCertificateActionGenerateCSR(app); - requestRoutesCertificateActionsReplaceCertificate(app); requestRoutesHTTPSCertificate(app); - requestRoutesHTTPSCertificateCollection(app); - requestRoutesCertificateLocations(app); - requestRoutesLDAPCertificateCollection(app); requestRoutesLDAPCertificate(app); - requestRoutesTrustStoreCertificateCollection(app); requestRoutesTrustStoreCertificate(app); requestRoutesSystemPCIeFunctionCollection(app); diff --git a/redfish-core/lib/certificate_service.hpp b/redfish-core/lib/certificate_service.hpp index d3aedd00a7..8701f59f17 100644 --- a/redfish-core/lib/certificate_service.hpp +++ b/redfish-core/lib/certificate_service.hpp @@ -47,50 +47,6 @@ constexpr char const* authorityObjectPath = // "redfish standard registries". Need to modify after DMTF // publish Privilege details for certificate service -inline void requestRoutesCertificateService(App& app) -{ - BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/") - .privileges(redfish::privileges::getCertificateService) - .methods(boost::beast::http::verb::get)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } - - asyncResp->res.jsonValue["@odata.type"] = - "#CertificateService.v1_0_0.CertificateService"; - asyncResp->res.jsonValue["@odata.id"] = - "/redfish/v1/CertificateService"; - asyncResp->res.jsonValue["Id"] = "CertificateService"; - asyncResp->res.jsonValue["Name"] = "Certificate Service"; - asyncResp->res.jsonValue["Description"] = - "Actions available to manage certificates"; - // /redfish/v1/CertificateService/CertificateLocations is something - // only ConfigureManager can access then only display when the user - // has permissions ConfigureManager - Privileges effectiveUserPrivileges = - redfish::getUserPrivileges(req.userRole); - if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, - effectiveUserPrivileges)) - { - asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] = - "/redfish/v1/CertificateService/CertificateLocations"; - } - nlohmann::json& actions = asyncResp->res.jsonValue["Actions"]; - nlohmann::json& replace = - actions["#CertificateService.ReplaceCertificate"]; - replace["target"] = - "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"; - nlohmann::json::array_t allowed; - allowed.push_back("PEM"); - replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed); - actions["#CertificateService.GenerateCSR"]["target"] = - "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"; - }); -} // requestRoutesCertificateService - inline std::string getCertificateFromReqBody( const std::shared_ptr& asyncResp, const crow::Request& req) @@ -180,293 +136,6 @@ class CertificateFile std::filesystem::path certDirectory; }; -static std::unique_ptr csrMatcher; -/** - * @brief Read data from CSR D-bus object and set to response - * - * @param[in] asyncResp Shared pointer to the response message - * @param[in] certURI Link to certifiate collection URI - * @param[in] service D-Bus service name - * @param[in] certObjPath certificate D-Bus object path - * @param[in] csrObjPath CSR D-Bus object path - * @return None - */ -static void getCSR(const std::shared_ptr& asyncResp, - const std::string& certURI, const std::string& service, - const std::string& certObjPath, - const std::string& csrObjPath) -{ - BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath - << " CSRObjectPath=" << csrObjPath - << " service=" << service; - crow::connections::systemBus->async_method_call( - [asyncResp, certURI](const boost::system::error_code ec, - const std::string& csr) { - if (ec) - { - BMCWEB_LOG_ERROR << "DBUS response error: " << ec; - messages::internalError(asyncResp->res); - return; - } - if (csr.empty()) - { - BMCWEB_LOG_ERROR << "CSR read is empty"; - messages::internalError(asyncResp->res); - return; - } - asyncResp->res.jsonValue["CSRString"] = csr; - asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] = - certURI; - }, - service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR"); -} - -/** - * Action to Generate CSR - */ -inline void requestRoutesCertificateActionGenerateCSR(App& app) -{ - BMCWEB_ROUTE( - app, - "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/") - .privileges(redfish::privileges::postCertificateService) - .methods(boost::beast::http::verb::post)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } - static const int rsaKeyBitLength = 2048; - - // Required parameters - std::string city; - std::string commonName; - std::string country; - std::string organization; - std::string organizationalUnit; - std::string state; - nlohmann::json certificateCollection; - - // Optional parameters - std::optional> optAlternativeNames = - std::vector(); - std::optional optContactPerson = ""; - std::optional optChallengePassword = ""; - std::optional optEmail = ""; - std::optional optGivenName = ""; - std::optional optInitials = ""; - std::optional optKeyBitLength = rsaKeyBitLength; - std::optional optKeyCurveId = "secp384r1"; - std::optional optKeyPairAlgorithm = "EC"; - std::optional> optKeyUsage = - std::vector(); - std::optional optSurname = ""; - std::optional optUnstructuredName = ""; - if (!json_util::readJsonAction( - req, asyncResp->res, "City", city, "CommonName", commonName, - "ContactPerson", optContactPerson, "Country", country, - "Organization", organization, "OrganizationalUnit", - organizationalUnit, "State", state, "CertificateCollection", - certificateCollection, "AlternativeNames", optAlternativeNames, - "ChallengePassword", optChallengePassword, "Email", optEmail, - "GivenName", optGivenName, "Initials", optInitials, - "KeyBitLength", optKeyBitLength, "KeyCurveId", optKeyCurveId, - "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage", - optKeyUsage, "Surname", optSurname, "UnstructuredName", - optUnstructuredName)) - { - return; - } - - // bmcweb has no way to store or decode a private key challenge - // password, which will likely cause bmcweb to crash on startup - // if this is not set on a post so not allowing the user to set - // value - if (!optChallengePassword->empty()) - { - messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR", - "ChallengePassword"); - return; - } - - std::string certURI; - if (!redfish::json_util::readJson(certificateCollection, asyncResp->res, - "@odata.id", certURI)) - { - return; - } - - std::string objectPath; - std::string service; - if (certURI.starts_with( - "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) - { - objectPath = certs::httpsObjectPath; - service = certs::httpsServiceName; - } - else if (certURI.starts_with( - "/redfish/v1/AccountService/LDAP/Certificates")) - { - objectPath = certs::ldapObjectPath; - service = certs::ldapServiceName; - } - else - { - messages::actionParameterNotSupported( - asyncResp->res, "CertificateCollection", "GenerateCSR"); - return; - } - - // supporting only EC and RSA algorithm - if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA") - { - messages::actionParameterNotSupported( - asyncResp->res, "KeyPairAlgorithm", "GenerateCSR"); - return; - } - - // supporting only 2048 key bit length for RSA algorithm due to - // time consumed in generating private key - if (*optKeyPairAlgorithm == "RSA" && - *optKeyBitLength != rsaKeyBitLength) - { - messages::propertyValueNotInList(asyncResp->res, - std::to_string(*optKeyBitLength), - "KeyBitLength"); - return; - } - - // validate KeyUsage supporting only 1 type based on URL - if (certURI.starts_with( - "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) - { - if (optKeyUsage->empty()) - { - optKeyUsage->push_back("ServerAuthentication"); - } - else if (optKeyUsage->size() == 1) - { - if ((*optKeyUsage)[0] != "ServerAuthentication") - { - messages::propertyValueNotInList( - asyncResp->res, (*optKeyUsage)[0], "KeyUsage"); - return; - } - } - else - { - messages::actionParameterNotSupported( - asyncResp->res, "KeyUsage", "GenerateCSR"); - return; - } - } - else if (certURI.starts_with( - "/redfish/v1/AccountService/LDAP/Certificates")) - { - if (optKeyUsage->empty()) - { - optKeyUsage->push_back("ClientAuthentication"); - } - else if (optKeyUsage->size() == 1) - { - if ((*optKeyUsage)[0] != "ClientAuthentication") - { - messages::propertyValueNotInList( - asyncResp->res, (*optKeyUsage)[0], "KeyUsage"); - return; - } - } - else - { - messages::actionParameterNotSupported( - asyncResp->res, "KeyUsage", "GenerateCSR"); - return; - } - } - - // Only allow one CSR matcher at a time so setting retry - // time-out and timer expiry to 10 seconds for now. - static const int timeOut = 10; - if (csrMatcher) - { - messages::serviceTemporarilyUnavailable(asyncResp->res, - std::to_string(timeOut)); - return; - } - - // Make this static so it survives outside this method - static boost::asio::steady_timer timeout(*req.ioService); - timeout.expires_after(std::chrono::seconds(timeOut)); - timeout.async_wait([asyncResp](const boost::system::error_code& ec) { - csrMatcher = nullptr; - if (ec) - { - // operation_aborted is expected if timer is canceled - // before completion. - if (ec != boost::asio::error::operation_aborted) - { - BMCWEB_LOG_ERROR << "Async_wait failed " << ec; - } - return; - } - BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR"; - messages::internalError(asyncResp->res); - }); - - // create a matcher to wait on CSR object - BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath; - std::string match("type='signal'," - "interface='org.freedesktop.DBus.ObjectManager'," - "path='" + - objectPath + - "'," - "member='InterfacesAdded'"); - csrMatcher = std::make_unique( - *crow::connections::systemBus, match, - [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) { - timeout.cancel(); - if (m.is_method_error()) - { - BMCWEB_LOG_ERROR << "Dbus method error!!!"; - messages::internalError(asyncResp->res); - return; - } - - dbus::utility::DBusInteracesMap interfacesProperties; - - sdbusplus::message::object_path csrObjectPath; - m.read(csrObjectPath, interfacesProperties); - BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str; - for (const auto& interface : interfacesProperties) - { - if (interface.first == "xyz.openbmc_project.Certs.CSR") - { - getCSR(asyncResp, certURI, service, objectPath, - csrObjectPath.str); - break; - } - } - }); - crow::connections::systemBus->async_method_call( - [asyncResp](const boost::system::error_code ec, - const std::string&) { - if (ec) - { - BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message(); - messages::internalError(asyncResp->res); - return; - } - }, - service, objectPath, "xyz.openbmc_project.Certs.CSR.Create", - "GenerateCSR", *optAlternativeNames, *optChallengePassword, city, - commonName, *optContactPerson, country, *optEmail, *optGivenName, - *optInitials, *optKeyBitLength, *optKeyCurveId, - *optKeyPairAlgorithm, *optKeyUsage, organization, - organizationalUnit, state, *optSurname, *optUnstructuredName); - }); -} // requestRoutesCertificateActionGenerateCSR - /** * @brief Parse and update Certificate Issue/Subject property * @@ -707,512 +376,827 @@ static void getCertificateProperties( }); } -/** - * Action to replace an existing certificate - */ -inline void requestRoutesCertificateActionsReplaceCertificate(App& app) +inline void handleCertificateServiceGet( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp) { - BMCWEB_ROUTE( - app, - "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/") - .privileges(redfish::privileges::postCertificateService) - .methods(boost::beast::http::verb::post)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } - std::string certificate; - nlohmann::json certificateUri; - std::optional certificateType = "PEM"; - - if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString", - certificate, "CertificateUri", - certificateUri, "CertificateType", - certificateType)) + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + + asyncResp->res.jsonValue["@odata.type"] = + "#CertificateService.v1_0_0.CertificateService"; + asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService"; + asyncResp->res.jsonValue["Id"] = "CertificateService"; + asyncResp->res.jsonValue["Name"] = "Certificate Service"; + asyncResp->res.jsonValue["Description"] = + "Actions available to manage certificates"; + // /redfish/v1/CertificateService/CertificateLocations is something + // only ConfigureManager can access then only display when the user + // has permissions ConfigureManager + Privileges effectiveUserPrivileges = + redfish::getUserPrivileges(req.userRole); + if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, + effectiveUserPrivileges)) + { + asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] = + "/redfish/v1/CertificateService/CertificateLocations"; + } + nlohmann::json& actions = asyncResp->res.jsonValue["Actions"]; + nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"]; + replace["target"] = + "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"; + nlohmann::json::array_t allowed; + allowed.push_back("PEM"); + replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed); + actions["#CertificateService.GenerateCSR"]["target"] = + "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"; +} + +inline void handleCertificateLocationsGet( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + asyncResp->res.jsonValue["@odata.id"] = + "/redfish/v1/CertificateService/CertificateLocations"; + asyncResp->res.jsonValue["@odata.type"] = + "#CertificateLocations.v1_0_0.CertificateLocations"; + asyncResp->res.jsonValue["Name"] = "Certificate Locations"; + asyncResp->res.jsonValue["Id"] = "CertificateLocations"; + asyncResp->res.jsonValue["Description"] = + "Defines a resource that an administrator can use in order to " + "locate all certificates installed on a given service"; + + getCertificateList(asyncResp, certs::baseObjectPath, + "/Links/Certificates"_json_pointer, + "/Links/Certificates@odata.count"_json_pointer); +} + +inline void handleReplaceCertificateAction( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + std::string certificate; + nlohmann::json certificateUri; + std::optional certificateType = "PEM"; + + if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString", + certificate, "CertificateUri", + certificateUri, "CertificateType", + certificateType)) + { + BMCWEB_LOG_ERROR << "Required parameters are missing"; + messages::internalError(asyncResp->res); + return; + } + + if (!certificateType) + { + // should never happen, but it never hurts to be paranoid. + return; + } + if (certificateType != "PEM") + { + messages::actionParameterNotSupported(asyncResp->res, "CertificateType", + "ReplaceCertificate"); + return; + } + + std::string certURI; + if (!redfish::json_util::readJson(certificateUri, asyncResp->res, + "@odata.id", certURI)) + { + messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate", + "CertificateUri"); + return; + } + BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI; + + boost::urls::result parsedUrl = + boost::urls::parse_relative_ref(certURI); + if (!parsedUrl) + { + messages::actionParameterValueFormatError( + asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate"); + return; + } + + std::string id; + sdbusplus::message::object_path objectPath; + std::string name; + std::string service; + if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers", + "bmc", "NetworkProtocol", "HTTPS", + "Certificates", std::ref(id))) + { + objectPath = + sdbusplus::message::object_path(certs::httpsObjectPath) / id; + name = "HTTPS certificate"; + service = certs::httpsServiceName; + } + else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", + "AccountService", "LDAP", + "Certificates", std::ref(id))) + { + objectPath = + sdbusplus::message::object_path(certs::ldapObjectPath) / id; + name = "LDAP certificate"; + service = certs::ldapServiceName; + } + else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", + "Managers", "bmc", "Truststore", + "Certificates", std::ref(id))) + { + objectPath = + sdbusplus::message::object_path(certs::authorityObjectPath) / id; + name = "TrustStore certificate"; + service = certs::authorityServiceName; + } + else + { + messages::actionParameterNotSupported(asyncResp->res, "CertificateUri", + "ReplaceCertificate"); + return; + } + + std::shared_ptr certFile = + std::make_shared(certificate); + crow::connections::systemBus->async_method_call( + [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id, + name](const boost::system::error_code ec) { + if (ec) { - BMCWEB_LOG_ERROR << "Required parameters are missing"; + BMCWEB_LOG_ERROR << "DBUS response error: " << ec; + if (ec.value() == + boost::system::linux_error::bad_request_descriptor) + { + messages::resourceNotFound(asyncResp->res, "Certificate", id); + return; + } messages::internalError(asyncResp->res); return; } + getCertificateProperties(asyncResp, objectPath, service, id, url, name); + BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" + << certFile->getCertFilePath(); + }, + service, objectPath, certs::certReplaceIntf, "Replace", + certFile->getCertFilePath()); +} - if (!certificateType) +static std::unique_ptr csrMatcher; +/** + * @brief Read data from CSR D-bus object and set to response + * + * @param[in] asyncResp Shared pointer to the response message + * @param[in] certURI Link to certifiate collection URI + * @param[in] service D-Bus service name + * @param[in] certObjPath certificate D-Bus object path + * @param[in] csrObjPath CSR D-Bus object path + * @return None + */ +static void getCSR(const std::shared_ptr& asyncResp, + const std::string& certURI, const std::string& service, + const std::string& certObjPath, + const std::string& csrObjPath) +{ + BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath + << " CSRObjectPath=" << csrObjPath + << " service=" << service; + crow::connections::systemBus->async_method_call( + [asyncResp, certURI](const boost::system::error_code ec, + const std::string& csr) { + if (ec) { - // should never happen, but it never hurts to be paranoid. + BMCWEB_LOG_ERROR << "DBUS response error: " << ec; + messages::internalError(asyncResp->res); return; } - if (certificateType != "PEM") + if (csr.empty()) { - messages::actionParameterNotSupported( - asyncResp->res, "CertificateType", "ReplaceCertificate"); + BMCWEB_LOG_ERROR << "CSR read is empty"; + messages::internalError(asyncResp->res); return; } + asyncResp->res.jsonValue["CSRString"] = csr; + asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] = + certURI; + }, + service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR"); +} - std::string certURI; - if (!redfish::json_util::readJson(certificateUri, asyncResp->res, - "@odata.id", certURI)) - { - messages::actionParameterMissing( - asyncResp->res, "ReplaceCertificate", "CertificateUri"); - return; - } - BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI; +inline void + handleGenerateCSRAction(App& app, const crow::Request& req, + const std::shared_ptr& asyncResp) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + static const int rsaKeyBitLength = 2048; + + // Required parameters + std::string city; + std::string commonName; + std::string country; + std::string organization; + std::string organizationalUnit; + std::string state; + nlohmann::json certificateCollection; + + // Optional parameters + std::optional> optAlternativeNames = + std::vector(); + std::optional optContactPerson = ""; + std::optional optChallengePassword = ""; + std::optional optEmail = ""; + std::optional optGivenName = ""; + std::optional optInitials = ""; + std::optional optKeyBitLength = rsaKeyBitLength; + std::optional optKeyCurveId = "secp384r1"; + std::optional optKeyPairAlgorithm = "EC"; + std::optional> optKeyUsage = + std::vector(); + std::optional optSurname = ""; + std::optional optUnstructuredName = ""; + if (!json_util::readJsonAction( + req, asyncResp->res, "City", city, "CommonName", commonName, + "ContactPerson", optContactPerson, "Country", country, + "Organization", organization, "OrganizationalUnit", + organizationalUnit, "State", state, "CertificateCollection", + certificateCollection, "AlternativeNames", optAlternativeNames, + "ChallengePassword", optChallengePassword, "Email", optEmail, + "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength", + optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm", + optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname, + "UnstructuredName", optUnstructuredName)) + { + return; + } - boost::urls::result parsedUrl = - boost::urls::parse_relative_ref(certURI); - if (!parsedUrl) - { - messages::actionParameterValueFormatError(asyncResp->res, certURI, - "CertificateUri", - "ReplaceCertificate"); - return; - } + // bmcweb has no way to store or decode a private key challenge + // password, which will likely cause bmcweb to crash on startup + // if this is not set on a post so not allowing the user to set + // value + if (!optChallengePassword->empty()) + { + messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR", + "ChallengePassword"); + return; + } - std::string id; - sdbusplus::message::object_path objectPath; - std::string name; - std::string service; - if (crow::utility::readUrlSegments( - *parsedUrl, "redfish", "v1", "Managers", "bmc", - "NetworkProtocol", "HTTPS", "Certificates", std::ref(id))) - { - objectPath = - sdbusplus::message::object_path(certs::httpsObjectPath) / id; - name = "HTTPS certificate"; - service = certs::httpsServiceName; - } - else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", - "AccountService", "LDAP", - "Certificates", std::ref(id))) - { - objectPath = - sdbusplus::message::object_path(certs::ldapObjectPath) / id; - name = "LDAP certificate"; - service = certs::ldapServiceName; + std::string certURI; + if (!redfish::json_util::readJson(certificateCollection, asyncResp->res, + "@odata.id", certURI)) + { + return; + } + + std::string objectPath; + std::string service; + if (certURI.starts_with( + "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) + { + objectPath = certs::httpsObjectPath; + service = certs::httpsServiceName; + } + else if (certURI.starts_with( + "/redfish/v1/AccountService/LDAP/Certificates")) + { + objectPath = certs::ldapObjectPath; + service = certs::ldapServiceName; + } + else + { + messages::actionParameterNotSupported( + asyncResp->res, "CertificateCollection", "GenerateCSR"); + return; + } + + // supporting only EC and RSA algorithm + if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA") + { + messages::actionParameterNotSupported( + asyncResp->res, "KeyPairAlgorithm", "GenerateCSR"); + return; + } + + // supporting only 2048 key bit length for RSA algorithm due to + // time consumed in generating private key + if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength) + { + messages::propertyValueNotInList( + asyncResp->res, std::to_string(*optKeyBitLength), "KeyBitLength"); + return; + } + + // validate KeyUsage supporting only 1 type based on URL + if (certURI.starts_with( + "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) + { + if (optKeyUsage->empty()) + { + optKeyUsage->push_back("ServerAuthentication"); } - else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", - "Managers", "bmc", "Truststore", - "Certificates", std::ref(id))) + else if (optKeyUsage->size() == 1) { - objectPath = - sdbusplus::message::object_path(certs::authorityObjectPath) / - id; - name = "TrustStore certificate"; - service = certs::authorityServiceName; + if ((*optKeyUsage)[0] != "ServerAuthentication") + { + messages::propertyValueNotInList(asyncResp->res, + (*optKeyUsage)[0], "KeyUsage"); + return; + } } else { - messages::actionParameterNotSupported( - asyncResp->res, "CertificateUri", "ReplaceCertificate"); + messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", + "GenerateCSR"); return; } - - std::shared_ptr certFile = - std::make_shared(certificate); - crow::connections::systemBus->async_method_call( - [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id, - name](const boost::system::error_code ec) { - if (ec) + } + else if (certURI.starts_with( + "/redfish/v1/AccountService/LDAP/Certificates")) + { + if (optKeyUsage->empty()) + { + optKeyUsage->push_back("ClientAuthentication"); + } + else if (optKeyUsage->size() == 1) + { + if ((*optKeyUsage)[0] != "ClientAuthentication") { - BMCWEB_LOG_ERROR << "DBUS response error: " << ec; - if (ec.value() == - boost::system::linux_error::bad_request_descriptor) - { - messages::resourceNotFound(asyncResp->res, "Certificate", - id); - return; - } - messages::internalError(asyncResp->res); + messages::propertyValueNotInList(asyncResp->res, + (*optKeyUsage)[0], "KeyUsage"); return; } - getCertificateProperties(asyncResp, objectPath, service, id, url, - name); - BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" - << certFile->getCertFilePath(); - }, - service, objectPath, certs::certReplaceIntf, "Replace", - certFile->getCertFilePath()); - }); -} // requestRoutesCertificateActionsReplaceCertificate - -/** - * Certificate resource describes a certificate used to prove the identity - * of a component, account or service. - */ - -inline void requestRoutesHTTPSCertificate(App& app) -{ - BMCWEB_ROUTE( - app, - "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates//") - .privileges(redfish::privileges::getCertificate) - .methods(boost::beast::http::verb::get)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp, - const std::string& id) -> void { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } - - BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id; - const boost::urls::url certURL = crow::utility::urlFromPieces( - "redfish", "v1", "Managers", "bmc", "NetworkProtocol", - "HTTPS", "Certificates", id); - std::string objPath = - sdbusplus::message::object_path(certs::httpsObjectPath) / - id; - getCertificateProperties(asyncResp, objPath, - certs::httpsServiceName, id, certURL, - "HTTPS Certificate"); - }); -} - -/** - * Collection of HTTPS certificates - */ -inline void requestRoutesHTTPSCertificateCollection(App& app) -{ - BMCWEB_ROUTE(app, - "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") - .privileges(redfish::privileges::getCertificateCollection) - .methods(boost::beast::http::verb::get)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + } + else { + messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", + "GenerateCSR"); return; } + } - asyncResp->res.jsonValue["@odata.id"] = - "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"; - asyncResp->res.jsonValue["@odata.type"] = - "#CertificateCollection.CertificateCollection"; - asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection"; - asyncResp->res.jsonValue["Description"] = - "A Collection of HTTPS certificate instances"; - - getCertificateList(asyncResp, certs::httpsObjectPath, - "/Members"_json_pointer, - "/Members@odata.count"_json_pointer); - }); + // Only allow one CSR matcher at a time so setting retry + // time-out and timer expiry to 10 seconds for now. + static const int timeOut = 10; + if (csrMatcher) + { + messages::serviceTemporarilyUnavailable(asyncResp->res, + std::to_string(timeOut)); + return; + } - BMCWEB_ROUTE(app, - "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") - .privileges(redfish::privileges::postCertificateCollection) - .methods(boost::beast::http::verb::post)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + // Make this static so it survives outside this method + static boost::asio::steady_timer timeout(*req.ioService); + timeout.expires_after(std::chrono::seconds(timeOut)); + timeout.async_wait([asyncResp](const boost::system::error_code& ec) { + csrMatcher = nullptr; + if (ec) { + // operation_aborted is expected if timer is canceled + // before completion. + if (ec != boost::asio::error::operation_aborted) + { + BMCWEB_LOG_ERROR << "Async_wait failed " << ec; + } return; } - BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost"; - - asyncResp->res.jsonValue["Name"] = "HTTPS Certificate"; - asyncResp->res.jsonValue["Description"] = "HTTPS Certificate"; - - std::string certFileBody = getCertificateFromReqBody(asyncResp, req); - - if (certFileBody.empty()) + BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR"; + messages::internalError(asyncResp->res); + }); + + // create a matcher to wait on CSR object + BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath; + std::string match("type='signal'," + "interface='org.freedesktop.DBus.ObjectManager'," + "path='" + + objectPath + + "'," + "member='InterfacesAdded'"); + csrMatcher = std::make_unique( + *crow::connections::systemBus, match, + [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) { + timeout.cancel(); + if (m.is_method_error()) { - BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; - messages::unrecognizedRequestBody(asyncResp->res); + BMCWEB_LOG_ERROR << "Dbus method error!!!"; + messages::internalError(asyncResp->res); return; } - std::shared_ptr certFile = - std::make_shared(certFileBody); + dbus::utility::DBusInteracesMap interfacesProperties; - crow::connections::systemBus->async_method_call( - [asyncResp, certFile](const boost::system::error_code ec, - const std::string& objectPath) { - if (ec) + sdbusplus::message::object_path csrObjectPath; + m.read(csrObjectPath, interfacesProperties); + BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str; + for (const auto& interface : interfacesProperties) + { + if (interface.first == "xyz.openbmc_project.Certs.CSR") { - BMCWEB_LOG_ERROR << "DBUS response error: " << ec; - messages::internalError(asyncResp->res); - return; + getCSR(asyncResp, certURI, service, objectPath, + csrObjectPath.str); + break; } - - sdbusplus::message::object_path path(objectPath); - std::string certId = path.filename(); - const boost::urls::url certURL = crow::utility::urlFromPieces( - "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS", - "Certificates", certId); - getCertificateProperties(asyncResp, objectPath, - certs::httpsServiceName, certId, certURL, - "HTTPS Certificate"); - BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" - << certFile->getCertFilePath(); - }, - certs::httpsServiceName, certs::httpsObjectPath, - certs::certInstallIntf, "Install", certFile->getCertFilePath()); + } }); -} // requestRoutesHTTPSCertificateCollection + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec, const std::string&) { + if (ec) + { + BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message(); + messages::internalError(asyncResp->res); + return; + } + }, + service, objectPath, "xyz.openbmc_project.Certs.CSR.Create", + "GenerateCSR", *optAlternativeNames, *optChallengePassword, city, + commonName, *optContactPerson, country, *optEmail, *optGivenName, + *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm, + *optKeyUsage, organization, organizationalUnit, state, *optSurname, + *optUnstructuredName); +} -/** - * The certificate location schema defines a resource that an administrator - * can use in order to locate all certificates installed on a given service. - */ -inline void requestRoutesCertificateLocations(App& app) +inline void requestRoutesCertificateService(App& app) { + BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/") + .privileges(redfish::privileges::getCertificateService) + .methods(boost::beast::http::verb::get)( + std::bind_front(handleCertificateServiceGet, std::ref(app))); + BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/") .privileges(redfish::privileges::getCertificateLocations) .methods(boost::beast::http::verb::get)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + std::bind_front(handleCertificateLocationsGet, std::ref(app))); + + BMCWEB_ROUTE( + app, + "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/") + .privileges(redfish::privileges::postCertificateService) + .methods(boost::beast::http::verb::post)( + std::bind_front(handleReplaceCertificateAction, std::ref(app))); + + BMCWEB_ROUTE( + app, + "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/") + .privileges(redfish::privileges::postCertificateService) + .methods(boost::beast::http::verb::post)( + std::bind_front(handleGenerateCSRAction, std::ref(app))); +} // requestRoutesCertificateService + +inline void handleHTTPSCertificateCollectionGet( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + + asyncResp->res.jsonValue["@odata.id"] = + "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"; + asyncResp->res.jsonValue["@odata.type"] = + "#CertificateCollection.CertificateCollection"; + asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection"; + asyncResp->res.jsonValue["Description"] = + "A Collection of HTTPS certificate instances"; + + getCertificateList(asyncResp, certs::httpsObjectPath, + "/Members"_json_pointer, + "/Members@odata.count"_json_pointer); +} + +inline void handleHTTPSCertificateCollectionPost( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost"; + + asyncResp->res.jsonValue["Name"] = "HTTPS Certificate"; + asyncResp->res.jsonValue["Description"] = "HTTPS Certificate"; + + std::string certFileBody = getCertificateFromReqBody(asyncResp, req); + + if (certFileBody.empty()) + { + BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; + messages::unrecognizedRequestBody(asyncResp->res); + return; + } + + std::shared_ptr certFile = + std::make_shared(certFileBody); + + crow::connections::systemBus->async_method_call( + [asyncResp, certFile](const boost::system::error_code ec, + const std::string& objectPath) { + if (ec) { + BMCWEB_LOG_ERROR << "DBUS response error: " << ec; + messages::internalError(asyncResp->res); return; } - asyncResp->res.jsonValue["@odata.id"] = - "/redfish/v1/CertificateService/CertificateLocations"; - asyncResp->res.jsonValue["@odata.type"] = - "#CertificateLocations.v1_0_0.CertificateLocations"; - asyncResp->res.jsonValue["Name"] = "Certificate Locations"; - asyncResp->res.jsonValue["Id"] = "CertificateLocations"; - asyncResp->res.jsonValue["Description"] = - "Defines a resource that an administrator can use in order to " - "locate all certificates installed on a given service"; - - getCertificateList(asyncResp, certs::baseObjectPath, - "/Links/Certificates"_json_pointer, - "/Links/Certificates@odata.count"_json_pointer); - }); + + sdbusplus::message::object_path path(objectPath); + std::string certId = path.filename(); + const boost::urls::url certURL = crow::utility::urlFromPieces( + "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS", + "Certificates", certId); + getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName, + certId, certURL, "HTTPS Certificate"); + BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" + << certFile->getCertFilePath(); + }, + certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf, + "Install", certFile->getCertFilePath()); } -// requestRoutesCertificateLocations -/** - * Collection of LDAP certificates - */ -inline void requestRoutesLDAPCertificateCollection(App& app) +inline void handleHTTPSCertificateGet( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp, const std::string& id) { - BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + + BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id; + const boost::urls::url certURL = crow::utility::urlFromPieces( + "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS", + "Certificates", id); + std::string objPath = + sdbusplus::message::object_path(certs::httpsObjectPath) / id; + getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id, + certURL, "HTTPS Certificate"); +} + +inline void requestRoutesHTTPSCertificate(App& app) +{ + BMCWEB_ROUTE(app, + "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") .privileges(redfish::privileges::getCertificateCollection) + .methods(boost::beast::http::verb::get)(std::bind_front( + handleHTTPSCertificateCollectionGet, std::ref(app))); + + BMCWEB_ROUTE(app, + "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") + .privileges(redfish::privileges::postCertificateCollection) + .methods(boost::beast::http::verb::post)(std::bind_front( + handleHTTPSCertificateCollectionPost, std::ref(app))); + + BMCWEB_ROUTE( + app, + "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates//") + .privileges(redfish::privileges::getCertificate) .methods(boost::beast::http::verb::get)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } + std::bind_front(handleHTTPSCertificateGet, std::ref(app))); +} - asyncResp->res.jsonValue["@odata.id"] = - "/redfish/v1/AccountService/LDAP/Certificates"; - asyncResp->res.jsonValue["@odata.type"] = - "#CertificateCollection.CertificateCollection"; - asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection"; - asyncResp->res.jsonValue["Description"] = - "A Collection of LDAP certificate instances"; - - getCertificateList(asyncResp, certs::ldapObjectPath, - "/Members"_json_pointer, - "/Members@odata.count"_json_pointer); - }); +inline void handleLDAPCertificateCollectionGet( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } - BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") - .privileges(redfish::privileges::postCertificateCollection) - .methods(boost::beast::http::verb::post)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } - std::string certFileBody = getCertificateFromReqBody(asyncResp, req); + asyncResp->res.jsonValue["@odata.id"] = + "/redfish/v1/AccountService/LDAP/Certificates"; + asyncResp->res.jsonValue["@odata.type"] = + "#CertificateCollection.CertificateCollection"; + asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection"; + asyncResp->res.jsonValue["Description"] = + "A Collection of LDAP certificate instances"; + + getCertificateList(asyncResp, certs::ldapObjectPath, + "/Members"_json_pointer, + "/Members@odata.count"_json_pointer); +} + +inline void handleLDAPCertificateCollectionPost( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + std::string certFileBody = getCertificateFromReqBody(asyncResp, req); + + if (certFileBody.empty()) + { + BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; + messages::unrecognizedRequestBody(asyncResp->res); + return; + } + + std::shared_ptr certFile = + std::make_shared(certFileBody); - if (certFileBody.empty()) + crow::connections::systemBus->async_method_call( + [asyncResp, certFile](const boost::system::error_code ec, + const std::string& objectPath) { + if (ec) { - BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; - messages::unrecognizedRequestBody(asyncResp->res); + BMCWEB_LOG_ERROR << "DBUS response error: " << ec; + messages::internalError(asyncResp->res); return; } - std::shared_ptr certFile = - std::make_shared(certFileBody); + sdbusplus::message::object_path path(objectPath); + std::string certId = path.filename(); + const boost::urls::url certURL = crow::utility::urlFromPieces( + "redfish", "v1", "AccountService", "LDAP", "Certificates", certId); + getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName, + certId, certURL, "LDAP Certificate"); + BMCWEB_LOG_DEBUG << "LDAP certificate install file=" + << certFile->getCertFilePath(); + }, + certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf, + "Install", certFile->getCertFilePath()); +} - crow::connections::systemBus->async_method_call( - [asyncResp, certFile](const boost::system::error_code ec, - const std::string& objectPath) { - if (ec) - { - BMCWEB_LOG_ERROR << "DBUS response error: " << ec; - messages::internalError(asyncResp->res); - return; - } +inline void handleLDAPCertificateGet( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp, const std::string& id) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } - sdbusplus::message::object_path path(objectPath); - std::string certId = path.filename(); - const boost::urls::url certURL = - crow::utility::urlFromPieces("redfish", "v1", "AccountService", - "LDAP", "Certificates", certId); - getCertificateProperties(asyncResp, objectPath, - certs::ldapServiceName, certId, certURL, - "LDAP Certificate"); - BMCWEB_LOG_DEBUG << "LDAP certificate install file=" - << certFile->getCertFilePath(); - }, - certs::ldapServiceName, certs::ldapObjectPath, - certs::certInstallIntf, "Install", certFile->getCertFilePath()); - }); -} // requestRoutesLDAPCertificateCollection + BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id; + const boost::urls::url certURL = crow::utility::urlFromPieces( + "redfish", "v1", "AccountService", "LDAP", "Certificates", id); + std::string objPath = + sdbusplus::message::object_path(certs::ldapObjectPath) / id; + getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id, + certURL, "LDAP Certificate"); +} -/** - * Certificate resource describes a certificate used to prove the identity - * of a component, account or service. - */ inline void requestRoutesLDAPCertificate(App& app) { + BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") + .privileges(redfish::privileges::getCertificateCollection) + .methods(boost::beast::http::verb::get)( + std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app))); + + BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") + .privileges(redfish::privileges::postCertificateCollection) + .methods(boost::beast::http::verb::post)(std::bind_front( + handleLDAPCertificateCollectionPost, std::ref(app))); + BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates//") .privileges(redfish::privileges::getCertificate) .methods(boost::beast::http::verb::get)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp, - const std::string& id) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } - - BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id; - const boost::urls::url certURL = crow::utility::urlFromPieces( - "redfish", "v1", "AccountService", "LDAP", "Certificates", id); - std::string objPath = - sdbusplus::message::object_path(certs::ldapObjectPath) / id; - getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id, - certURL, "LDAP Certificate"); - }); + std::bind_front(handleLDAPCertificateGet, std::ref(app))); } // requestRoutesLDAPCertificate -/** - * Collection of TrustStoreCertificate certificates - */ -inline void requestRoutesTrustStoreCertificateCollection(App& app) + +inline void handleTrustStoreCertificateCollectionGet( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp) { - BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") - .privileges(redfish::privileges::getCertificate) - .methods(boost::beast::http::verb::get)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } - asyncResp->res.jsonValue["@odata.id"] = - "/redfish/v1/Managers/bmc/Truststore/Certificates/"; - asyncResp->res.jsonValue["@odata.type"] = - "#CertificateCollection.CertificateCollection"; - asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection"; - asyncResp->res.jsonValue["Description"] = - "A Collection of TrustStore certificate instances"; - - getCertificateList(asyncResp, certs::authorityObjectPath, - "/Members"_json_pointer, - "/Members@odata.count"_json_pointer); - }); + asyncResp->res.jsonValue["@odata.id"] = + "/redfish/v1/Managers/bmc/Truststore/Certificates/"; + asyncResp->res.jsonValue["@odata.type"] = + "#CertificateCollection.CertificateCollection"; + asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection"; + asyncResp->res.jsonValue["Description"] = + "A Collection of TrustStore certificate instances"; + + getCertificateList(asyncResp, certs::authorityObjectPath, + "/Members"_json_pointer, + "/Members@odata.count"_json_pointer); +} - BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") - .privileges(redfish::privileges::postCertificateCollection) - .methods(boost::beast::http::verb::post)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) +inline void handleTrustStoreCertificateCollectionPost( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + std::string certFileBody = getCertificateFromReqBody(asyncResp, req); + + if (certFileBody.empty()) + { + BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; + messages::unrecognizedRequestBody(asyncResp->res); + return; + } + + std::shared_ptr certFile = + std::make_shared(certFileBody); + crow::connections::systemBus->async_method_call( + [asyncResp, certFile](const boost::system::error_code ec, + const std::string& objectPath) { + if (ec) { + BMCWEB_LOG_ERROR << "DBUS response error: " << ec; + messages::internalError(asyncResp->res); return; } - std::string certFileBody = getCertificateFromReqBody(asyncResp, req); - if (certFileBody.empty()) + sdbusplus::message::object_path path(objectPath); + std::string certId = path.filename(); + const boost::urls::url certURL = + crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc", + "Truststore", "Certificates", certId); + getCertificateProperties(asyncResp, objectPath, + certs::authorityServiceName, certId, certURL, + "TrustStore Certificate"); + BMCWEB_LOG_DEBUG << "TrustStore certificate install file=" + << certFile->getCertFilePath(); + }, + certs::authorityServiceName, certs::authorityObjectPath, + certs::certInstallIntf, "Install", certFile->getCertFilePath()); +} + +inline void handleTrustStoreCertificateGet( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp, const std::string& id) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + + BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id; + const boost::urls::url certURL = crow::utility::urlFromPieces( + "redfish", "v1", "Managers", "bmc", "Truststore", "Certificates", id); + std::string objPath = + sdbusplus::message::object_path(certs::authorityObjectPath) / id; + getCertificateProperties(asyncResp, objPath, certs::authorityServiceName, + id, certURL, "TrustStore Certificate"); +} + +inline void handleTrustStoreCertificateDelete( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp, const std::string& id) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + + BMCWEB_LOG_DEBUG << "Delete TrustStore Certificate ID=" << id; + std::string objPath = + sdbusplus::message::object_path(certs::authorityObjectPath) / id; + + crow::connections::systemBus->async_method_call( + [asyncResp, id](const boost::system::error_code ec) { + if (ec) { - BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; - messages::unrecognizedRequestBody(asyncResp->res); + messages::resourceNotFound(asyncResp->res, "Certificate", id); return; } + BMCWEB_LOG_INFO << "Certificate deleted"; + asyncResp->res.result(boost::beast::http::status::no_content); + }, + certs::authorityServiceName, objPath, certs::objDeleteIntf, "Delete"); +} - std::shared_ptr certFile = - std::make_shared(certFileBody); - crow::connections::systemBus->async_method_call( - [asyncResp, certFile](const boost::system::error_code ec, - const std::string& objectPath) { - if (ec) - { - BMCWEB_LOG_ERROR << "DBUS response error: " << ec; - messages::internalError(asyncResp->res); - return; - } - - sdbusplus::message::object_path path(objectPath); - std::string certId = path.filename(); - const boost::urls::url certURL = crow::utility::urlFromPieces( - "redfish", "v1", "Managers", "bmc", "Truststore", - "Certificates", certId); - getCertificateProperties(asyncResp, objectPath, - certs::authorityServiceName, certId, - certURL, "TrustStore Certificate"); - BMCWEB_LOG_DEBUG << "TrustStore certificate install file=" - << certFile->getCertFilePath(); - }, - certs::authorityServiceName, certs::authorityObjectPath, - certs::certInstallIntf, "Install", certFile->getCertFilePath()); - }); -} // requestRoutesTrustStoreCertificateCollection - -/** - * Certificate resource describes a certificate used to prove the identity - * of a component, account or service. - */ inline void requestRoutesTrustStoreCertificate(App& app) { + BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") + .privileges(redfish::privileges::getCertificate) + .methods(boost::beast::http::verb::get)(std::bind_front( + handleTrustStoreCertificateCollectionGet, std::ref(app))); + + BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") + .privileges(redfish::privileges::postCertificateCollection) + .methods(boost::beast::http::verb::post)(std::bind_front( + handleTrustStoreCertificateCollectionPost, std::ref(app))); + BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates//") .privileges(redfish::privileges::getCertificate) .methods(boost::beast::http::verb::get)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp, - const std::string& id) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } - - BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id; - const boost::urls::url certURL = - crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc", - "Truststore", "Certificates", id); - std::string objPath = - sdbusplus::message::object_path(certs::authorityObjectPath) / id; - getCertificateProperties(asyncResp, objPath, - certs::authorityServiceName, id, certURL, - "TrustStore Certificate"); - }); + std::bind_front(handleTrustStoreCertificateGet, std::ref(app))); BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates//") .privileges(redfish::privileges::deleteCertificate) .methods(boost::beast::http::verb::delete_)( - [&app](const crow::Request& req, - const std::shared_ptr& asyncResp, - const std::string& id) { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } - - BMCWEB_LOG_DEBUG << "Delete TrustStore Certificate ID=" << id; - std::string objPath = - sdbusplus::message::object_path(certs::authorityObjectPath) / id; - - crow::connections::systemBus->async_method_call( - [asyncResp, id](const boost::system::error_code ec) { - if (ec) - { - messages::resourceNotFound(asyncResp->res, "Certificate", id); - return; - } - BMCWEB_LOG_INFO << "Certificate deleted"; - asyncResp->res.result(boost::beast::http::status::no_content); - }, - certs::authorityServiceName, objPath, certs::objDeleteIntf, - "Delete"); - }); + std::bind_front(handleTrustStoreCertificateDelete, std::ref(app))); } // requestRoutesTrustStoreCertificate } // namespace redfish -- cgit v1.2.3