xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 5968caee7ccf978755a9a63d225965101a0c0378)
1*5968caeeSMarri Devender Rao /*
2*5968caeeSMarri Devender Rao // Copyright (c) 2018 IBM Corporation
3*5968caeeSMarri Devender Rao //
4*5968caeeSMarri Devender Rao // Licensed under the Apache License, Version 2.0 (the "License");
5*5968caeeSMarri Devender Rao // you may not use this file except in compliance with the License.
6*5968caeeSMarri Devender Rao // You may obtain a copy of the License at
7*5968caeeSMarri Devender Rao //
8*5968caeeSMarri Devender Rao //      http://www.apache.org/licenses/LICENSE-2.0
9*5968caeeSMarri Devender Rao //
10*5968caeeSMarri Devender Rao // Unless required by applicable law or agreed to in writing, software
11*5968caeeSMarri Devender Rao // distributed under the License is distributed on an "AS IS" BASIS,
12*5968caeeSMarri Devender Rao // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5968caeeSMarri Devender Rao // See the License for the specific language governing permissions and
14*5968caeeSMarri Devender Rao // limitations under the License.
15*5968caeeSMarri Devender Rao */
16*5968caeeSMarri Devender Rao #pragma once
17*5968caeeSMarri Devender Rao 
18*5968caeeSMarri Devender Rao #include "node.hpp"
19*5968caeeSMarri Devender Rao 
20*5968caeeSMarri Devender Rao #include <variant>
21*5968caeeSMarri Devender Rao namespace redfish
22*5968caeeSMarri Devender Rao {
23*5968caeeSMarri Devender Rao namespace certs
24*5968caeeSMarri Devender Rao {
25*5968caeeSMarri Devender Rao constexpr char const *httpsObjectPath =
26*5968caeeSMarri Devender Rao     "/xyz/openbmc_project/certs/server/https";
27*5968caeeSMarri Devender Rao constexpr char const *certInstallIntf = "xyz.openbmc_project.Certs.Install";
28*5968caeeSMarri Devender Rao constexpr char const *certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
29*5968caeeSMarri Devender Rao constexpr char const *certPropIntf = "xyz.openbmc_project.Certs.Certificate";
30*5968caeeSMarri Devender Rao constexpr char const *dbusPropIntf = "org.freedesktop.DBus.Properties";
31*5968caeeSMarri Devender Rao constexpr char const *dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
32*5968caeeSMarri Devender Rao constexpr char const *mapperBusName = "xyz.openbmc_project.ObjectMapper";
33*5968caeeSMarri Devender Rao constexpr char const *mapperObjectPath = "/xyz/openbmc_project/object_mapper";
34*5968caeeSMarri Devender Rao constexpr char const *mapperIntf = "xyz.openbmc_project.ObjectMapper";
35*5968caeeSMarri Devender Rao } // namespace certs
36*5968caeeSMarri Devender Rao 
37*5968caeeSMarri Devender Rao /**
38*5968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
39*5968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
40*5968caeeSMarri Devender Rao  * are installed.
41*5968caeeSMarri Devender Rao  */
42*5968caeeSMarri Devender Rao class CertificateService : public Node
43*5968caeeSMarri Devender Rao {
44*5968caeeSMarri Devender Rao   public:
45*5968caeeSMarri Devender Rao     CertificateService(CrowApp &app) :
46*5968caeeSMarri Devender Rao         Node(app, "/redfish/v1/CertificateService/")
47*5968caeeSMarri Devender Rao     {
48*5968caeeSMarri Devender Rao         // TODO: Issue#61 No entries are available for Certificate
49*5968caeeSMarri Devender Rao         // sevice at https://www.dmtf.org/standards/redfish
50*5968caeeSMarri Devender Rao         // "redfish standard registries". Need to modify after DMTF
51*5968caeeSMarri Devender Rao         // publish Privilege details for certificate service
52*5968caeeSMarri Devender Rao         entityPrivileges = {
53*5968caeeSMarri Devender Rao             {boost::beast::http::verb::get, {{"Login"}}},
54*5968caeeSMarri Devender Rao             {boost::beast::http::verb::head, {{"Login"}}},
55*5968caeeSMarri Devender Rao             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
56*5968caeeSMarri Devender Rao             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
57*5968caeeSMarri Devender Rao             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
58*5968caeeSMarri Devender Rao             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
59*5968caeeSMarri Devender Rao     }
60*5968caeeSMarri Devender Rao 
61*5968caeeSMarri Devender Rao   private:
62*5968caeeSMarri Devender Rao     void doGet(crow::Response &res, const crow::Request &req,
63*5968caeeSMarri Devender Rao                const std::vector<std::string> &params) override
64*5968caeeSMarri Devender Rao     {
65*5968caeeSMarri Devender Rao         res.jsonValue = {
66*5968caeeSMarri Devender Rao             {"@odata.type", "#CertificateService.v1_0_0.CertificateService"},
67*5968caeeSMarri Devender Rao             {"@odata.id", "/redfish/v1/CertificateService"},
68*5968caeeSMarri Devender Rao             {"@odata.context",
69*5968caeeSMarri Devender Rao              "/redfish/v1/$metadata#CertificateService.CertificateService"},
70*5968caeeSMarri Devender Rao             {"Id", "CertificateService"},
71*5968caeeSMarri Devender Rao             {"Name", "Certificate Service"},
72*5968caeeSMarri Devender Rao             {"Description", "Actions available to manage certificates"}};
73*5968caeeSMarri Devender Rao         res.jsonValue["CertificateLocations"] = {
74*5968caeeSMarri Devender Rao             {"@odata.id",
75*5968caeeSMarri Devender Rao              "/redfish/v1/CertificateService/CertificateLocations"}};
76*5968caeeSMarri Devender Rao         res.jsonValue["Actions"]["#CertificateService.ReplaceCertificate"] = {
77*5968caeeSMarri Devender Rao             {"target", "/redfish/v1/CertificateService/Actions/"
78*5968caeeSMarri Devender Rao                        "CertificateService.ReplaceCertificate"},
79*5968caeeSMarri Devender Rao             {"CertificateType@Redfish.AllowableValues", {"PEM"}}};
80*5968caeeSMarri Devender Rao         res.end();
81*5968caeeSMarri Devender Rao     }
82*5968caeeSMarri Devender Rao }; // CertificateService
83*5968caeeSMarri Devender Rao /**
84*5968caeeSMarri Devender Rao  * @brief Find the ID specified in the URL
85*5968caeeSMarri Devender Rao  * Finds the numbers specified after the last "/" in the URL and returns.
86*5968caeeSMarri Devender Rao  * @param[in] path URL
87*5968caeeSMarri Devender Rao  * @return -1 on failure and number on success
88*5968caeeSMarri Devender Rao  */
89*5968caeeSMarri Devender Rao long getIDFromURL(const std::string_view url)
90*5968caeeSMarri Devender Rao {
91*5968caeeSMarri Devender Rao     std::size_t found = url.rfind("/");
92*5968caeeSMarri Devender Rao     if (found == std::string::npos)
93*5968caeeSMarri Devender Rao     {
94*5968caeeSMarri Devender Rao         return -1;
95*5968caeeSMarri Devender Rao     }
96*5968caeeSMarri Devender Rao     if ((found + 1) < url.length())
97*5968caeeSMarri Devender Rao     {
98*5968caeeSMarri Devender Rao         char *endPtr;
99*5968caeeSMarri Devender Rao         std::string_view str = url.substr(found + 1);
100*5968caeeSMarri Devender Rao         long value = std::strtol(str.data(), &endPtr, 10);
101*5968caeeSMarri Devender Rao         if (endPtr != &str.back())
102*5968caeeSMarri Devender Rao         {
103*5968caeeSMarri Devender Rao             return -1;
104*5968caeeSMarri Devender Rao         }
105*5968caeeSMarri Devender Rao         return value;
106*5968caeeSMarri Devender Rao     }
107*5968caeeSMarri Devender Rao     return -1;
108*5968caeeSMarri Devender Rao }
109*5968caeeSMarri Devender Rao 
110*5968caeeSMarri Devender Rao /**
111*5968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
112*5968caeeSMarri Devender Rao  */
113*5968caeeSMarri Devender Rao class CertificateFile
114*5968caeeSMarri Devender Rao {
115*5968caeeSMarri Devender Rao   public:
116*5968caeeSMarri Devender Rao     CertificateFile() = delete;
117*5968caeeSMarri Devender Rao     CertificateFile(const CertificateFile &) = delete;
118*5968caeeSMarri Devender Rao     CertificateFile &operator=(const CertificateFile &) = delete;
119*5968caeeSMarri Devender Rao     CertificateFile(CertificateFile &&) = delete;
120*5968caeeSMarri Devender Rao     CertificateFile &operator=(CertificateFile &&) = delete;
121*5968caeeSMarri Devender Rao     CertificateFile(const std::string &certString)
122*5968caeeSMarri Devender Rao     {
123*5968caeeSMarri Devender Rao         char dirTemplate[] = "/tmp/Certs.XXXXXX";
124*5968caeeSMarri Devender Rao         char *tempDirectory = mkdtemp(dirTemplate);
125*5968caeeSMarri Devender Rao         if (tempDirectory)
126*5968caeeSMarri Devender Rao         {
127*5968caeeSMarri Devender Rao             certDirectory = tempDirectory;
128*5968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
129*5968caeeSMarri Devender Rao             std::ofstream out(certificateFile, std::ofstream::out |
130*5968caeeSMarri Devender Rao                                                    std::ofstream::binary |
131*5968caeeSMarri Devender Rao                                                    std::ofstream::trunc);
132*5968caeeSMarri Devender Rao             out << certString;
133*5968caeeSMarri Devender Rao             out.close();
134*5968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "Creating certificate file" << certificateFile;
135*5968caeeSMarri Devender Rao         }
136*5968caeeSMarri Devender Rao     }
137*5968caeeSMarri Devender Rao     ~CertificateFile()
138*5968caeeSMarri Devender Rao     {
139*5968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
140*5968caeeSMarri Devender Rao         {
141*5968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "Removing certificate file" << certificateFile;
142*5968caeeSMarri Devender Rao             try
143*5968caeeSMarri Devender Rao             {
144*5968caeeSMarri Devender Rao                 std::filesystem::remove_all(certDirectory);
145*5968caeeSMarri Devender Rao             }
146*5968caeeSMarri Devender Rao             catch (const std::filesystem::filesystem_error &e)
147*5968caeeSMarri Devender Rao             {
148*5968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
149*5968caeeSMarri Devender Rao                                  << certDirectory;
150*5968caeeSMarri Devender Rao             }
151*5968caeeSMarri Devender Rao         }
152*5968caeeSMarri Devender Rao     }
153*5968caeeSMarri Devender Rao     std::string getCertFilePath()
154*5968caeeSMarri Devender Rao     {
155*5968caeeSMarri Devender Rao         return certificateFile;
156*5968caeeSMarri Devender Rao     }
157*5968caeeSMarri Devender Rao 
158*5968caeeSMarri Devender Rao   private:
159*5968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
160*5968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
161*5968caeeSMarri Devender Rao };
162*5968caeeSMarri Devender Rao 
163*5968caeeSMarri Devender Rao /**
164*5968caeeSMarri Devender Rao  * @brief Parse and update Certficate Issue/Subject property
165*5968caeeSMarri Devender Rao  *
166*5968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
167*5968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
168*5968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
169*5968caeeSMarri Devender Rao  * @return None
170*5968caeeSMarri Devender Rao  */
171*5968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json &out,
172*5968caeeSMarri Devender Rao                                       const std::string_view value)
173*5968caeeSMarri Devender Rao {
174*5968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
175*5968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
176*5968caeeSMarri Devender Rao     while (i != value.end())
177*5968caeeSMarri Devender Rao     {
178*5968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
179*5968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
180*5968caeeSMarri Devender Rao         {
181*5968caeeSMarri Devender Rao             i++;
182*5968caeeSMarri Devender Rao         }
183*5968caeeSMarri Devender Rao         if (i == value.end())
184*5968caeeSMarri Devender Rao         {
185*5968caeeSMarri Devender Rao             break;
186*5968caeeSMarri Devender Rao         }
187*5968caeeSMarri Devender Rao         const std::string_view key(tokenBegin, i - tokenBegin);
188*5968caeeSMarri Devender Rao         i++;
189*5968caeeSMarri Devender Rao         tokenBegin = i;
190*5968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
191*5968caeeSMarri Devender Rao         {
192*5968caeeSMarri Devender Rao             i++;
193*5968caeeSMarri Devender Rao         }
194*5968caeeSMarri Devender Rao         const std::string_view val(tokenBegin, i - tokenBegin);
195*5968caeeSMarri Devender Rao         if (key == "L")
196*5968caeeSMarri Devender Rao         {
197*5968caeeSMarri Devender Rao             out["City"] = val;
198*5968caeeSMarri Devender Rao         }
199*5968caeeSMarri Devender Rao         else if (key == "CN")
200*5968caeeSMarri Devender Rao         {
201*5968caeeSMarri Devender Rao             out["CommonName"] = val;
202*5968caeeSMarri Devender Rao         }
203*5968caeeSMarri Devender Rao         else if (key == "C")
204*5968caeeSMarri Devender Rao         {
205*5968caeeSMarri Devender Rao             out["Country"] = val;
206*5968caeeSMarri Devender Rao         }
207*5968caeeSMarri Devender Rao         else if (key == "O")
208*5968caeeSMarri Devender Rao         {
209*5968caeeSMarri Devender Rao             out["Organization"] = val;
210*5968caeeSMarri Devender Rao         }
211*5968caeeSMarri Devender Rao         else if (key == "OU")
212*5968caeeSMarri Devender Rao         {
213*5968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
214*5968caeeSMarri Devender Rao         }
215*5968caeeSMarri Devender Rao         else if (key == "ST")
216*5968caeeSMarri Devender Rao         {
217*5968caeeSMarri Devender Rao             out["State"] = val;
218*5968caeeSMarri Devender Rao         }
219*5968caeeSMarri Devender Rao         // skip comma character
220*5968caeeSMarri Devender Rao         if (i != value.end())
221*5968caeeSMarri Devender Rao         {
222*5968caeeSMarri Devender Rao             i++;
223*5968caeeSMarri Devender Rao         }
224*5968caeeSMarri Devender Rao     }
225*5968caeeSMarri Devender Rao }
226*5968caeeSMarri Devender Rao 
227*5968caeeSMarri Devender Rao /**
228*5968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
229*5968caeeSMarri Devender Rao  * message
230*5968caeeSMarri Devender Rao  *
231*5968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
232*5968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
233*5968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
234*5968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
235*5968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
236*5968caeeSMarri Devender Rao  * @return None
237*5968caeeSMarri Devender Rao  */
238*5968caeeSMarri Devender Rao static void getCertificateProperties(
239*5968caeeSMarri Devender Rao     const std::shared_ptr<AsyncResp> &asyncResp, const std::string &objectPath,
240*5968caeeSMarri Devender Rao     long certId, const std::string &certURL, const std::string &name)
241*5968caeeSMarri Devender Rao {
242*5968caeeSMarri Devender Rao     using PropertyType =
243*5968caeeSMarri Devender Rao         std::variant<std::string, uint64_t, std::vector<std::string>>;
244*5968caeeSMarri Devender Rao     using PropertiesMap = boost::container::flat_map<std::string, PropertyType>;
245*5968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
246*5968caeeSMarri Devender Rao                      << " certId=" << certId << " certURl=" << certURL;
247*5968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
248*5968caeeSMarri Devender Rao         [asyncResp, objectPath, certURL, certId,
249*5968caeeSMarri Devender Rao          name](const boost::system::error_code ec, const GetObjectType &resp) {
250*5968caeeSMarri Devender Rao             if (ec)
251*5968caeeSMarri Devender Rao             {
252*5968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
253*5968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
254*5968caeeSMarri Devender Rao                 return;
255*5968caeeSMarri Devender Rao             }
256*5968caeeSMarri Devender Rao             if (resp.size() > 1 || resp.empty())
257*5968caeeSMarri Devender Rao             {
258*5968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Invalid number of objects found "
259*5968caeeSMarri Devender Rao                                  << resp.size();
260*5968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
261*5968caeeSMarri Devender Rao                 return;
262*5968caeeSMarri Devender Rao             }
263*5968caeeSMarri Devender Rao             const std::string &service = resp.begin()->first;
264*5968caeeSMarri Devender Rao             crow::connections::systemBus->async_method_call(
265*5968caeeSMarri Devender Rao                 [asyncResp, certURL, certId,
266*5968caeeSMarri Devender Rao                  name](const boost::system::error_code ec,
267*5968caeeSMarri Devender Rao                        const PropertiesMap &properties) {
268*5968caeeSMarri Devender Rao                     if (ec)
269*5968caeeSMarri Devender Rao                     {
270*5968caeeSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
271*5968caeeSMarri Devender Rao                         messages::internalError(asyncResp->res);
272*5968caeeSMarri Devender Rao                         return;
273*5968caeeSMarri Devender Rao                     }
274*5968caeeSMarri Devender Rao                     asyncResp->res.jsonValue = {
275*5968caeeSMarri Devender Rao                         {"@odata.id", certURL},
276*5968caeeSMarri Devender Rao                         {"@odata.type", "#Certificate.v1_0_0.Certificate"},
277*5968caeeSMarri Devender Rao                         {"@odata.context",
278*5968caeeSMarri Devender Rao                          "/redfish/v1/$metadata#Certificate.Certificate"},
279*5968caeeSMarri Devender Rao                         {"Id", std::to_string(certId)},
280*5968caeeSMarri Devender Rao                         {"Name", name},
281*5968caeeSMarri Devender Rao                         {"Description", name}};
282*5968caeeSMarri Devender Rao                     for (const auto &property : properties)
283*5968caeeSMarri Devender Rao                     {
284*5968caeeSMarri Devender Rao                         if (property.first == "CertificateString")
285*5968caeeSMarri Devender Rao                         {
286*5968caeeSMarri Devender Rao                             asyncResp->res.jsonValue["CertificateString"] = "";
287*5968caeeSMarri Devender Rao                             const std::string *value =
288*5968caeeSMarri Devender Rao                                 std::get_if<std::string>(&property.second);
289*5968caeeSMarri Devender Rao                             if (value)
290*5968caeeSMarri Devender Rao                             {
291*5968caeeSMarri Devender Rao                                 asyncResp->res.jsonValue["CertificateString"] =
292*5968caeeSMarri Devender Rao                                     *value;
293*5968caeeSMarri Devender Rao                             }
294*5968caeeSMarri Devender Rao                         }
295*5968caeeSMarri Devender Rao                         else if (property.first == "KeyUsage")
296*5968caeeSMarri Devender Rao                         {
297*5968caeeSMarri Devender Rao                             nlohmann::json &keyUsage =
298*5968caeeSMarri Devender Rao                                 asyncResp->res.jsonValue["KeyUsage"];
299*5968caeeSMarri Devender Rao                             keyUsage = nlohmann::json::array();
300*5968caeeSMarri Devender Rao                             const std::vector<std::string> *value =
301*5968caeeSMarri Devender Rao                                 std::get_if<std::vector<std::string>>(
302*5968caeeSMarri Devender Rao                                     &property.second);
303*5968caeeSMarri Devender Rao                             if (value)
304*5968caeeSMarri Devender Rao                             {
305*5968caeeSMarri Devender Rao                                 for (const std::string &usage : *value)
306*5968caeeSMarri Devender Rao                                 {
307*5968caeeSMarri Devender Rao                                     keyUsage.push_back(usage);
308*5968caeeSMarri Devender Rao                                 }
309*5968caeeSMarri Devender Rao                             }
310*5968caeeSMarri Devender Rao                         }
311*5968caeeSMarri Devender Rao                         else if (property.first == "Issuer")
312*5968caeeSMarri Devender Rao                         {
313*5968caeeSMarri Devender Rao                             const std::string *value =
314*5968caeeSMarri Devender Rao                                 std::get_if<std::string>(&property.second);
315*5968caeeSMarri Devender Rao                             if (value)
316*5968caeeSMarri Devender Rao                             {
317*5968caeeSMarri Devender Rao                                 updateCertIssuerOrSubject(
318*5968caeeSMarri Devender Rao                                     asyncResp->res.jsonValue["Issuer"], *value);
319*5968caeeSMarri Devender Rao                             }
320*5968caeeSMarri Devender Rao                         }
321*5968caeeSMarri Devender Rao                         else if (property.first == "Subject")
322*5968caeeSMarri Devender Rao                         {
323*5968caeeSMarri Devender Rao                             const std::string *value =
324*5968caeeSMarri Devender Rao                                 std::get_if<std::string>(&property.second);
325*5968caeeSMarri Devender Rao                             if (value)
326*5968caeeSMarri Devender Rao                             {
327*5968caeeSMarri Devender Rao                                 updateCertIssuerOrSubject(
328*5968caeeSMarri Devender Rao                                     asyncResp->res.jsonValue["Subject"],
329*5968caeeSMarri Devender Rao                                     *value);
330*5968caeeSMarri Devender Rao                             }
331*5968caeeSMarri Devender Rao                         }
332*5968caeeSMarri Devender Rao                         else if (property.first == "ValidNotAfter")
333*5968caeeSMarri Devender Rao                         {
334*5968caeeSMarri Devender Rao                             const uint64_t *value =
335*5968caeeSMarri Devender Rao                                 std::get_if<uint64_t>(&property.second);
336*5968caeeSMarri Devender Rao                             if (value)
337*5968caeeSMarri Devender Rao                             {
338*5968caeeSMarri Devender Rao                                 std::time_t time =
339*5968caeeSMarri Devender Rao                                     static_cast<std::time_t>(*value);
340*5968caeeSMarri Devender Rao                                 asyncResp->res.jsonValue["ValidNotAfter"] =
341*5968caeeSMarri Devender Rao                                     crow::utility::getDateTime(time);
342*5968caeeSMarri Devender Rao                             }
343*5968caeeSMarri Devender Rao                         }
344*5968caeeSMarri Devender Rao                         else if (property.first == "ValidNotBefore")
345*5968caeeSMarri Devender Rao                         {
346*5968caeeSMarri Devender Rao                             const uint64_t *value =
347*5968caeeSMarri Devender Rao                                 std::get_if<uint64_t>(&property.second);
348*5968caeeSMarri Devender Rao                             if (value)
349*5968caeeSMarri Devender Rao                             {
350*5968caeeSMarri Devender Rao                                 std::time_t time =
351*5968caeeSMarri Devender Rao                                     static_cast<std::time_t>(*value);
352*5968caeeSMarri Devender Rao                                 asyncResp->res.jsonValue["ValidNotBefore"] =
353*5968caeeSMarri Devender Rao                                     crow::utility::getDateTime(time);
354*5968caeeSMarri Devender Rao                             }
355*5968caeeSMarri Devender Rao                         }
356*5968caeeSMarri Devender Rao                     }
357*5968caeeSMarri Devender Rao                     asyncResp->res.addHeader("Location", certURL);
358*5968caeeSMarri Devender Rao                 },
359*5968caeeSMarri Devender Rao                 service, objectPath, certs::dbusPropIntf, "GetAll",
360*5968caeeSMarri Devender Rao                 certs::certPropIntf);
361*5968caeeSMarri Devender Rao         },
362*5968caeeSMarri Devender Rao         certs::mapperBusName, certs::mapperObjectPath, certs::mapperIntf,
363*5968caeeSMarri Devender Rao         "GetObject", objectPath,
364*5968caeeSMarri Devender Rao         std::array<const char *, 1>{certs::certPropIntf});
365*5968caeeSMarri Devender Rao }
366*5968caeeSMarri Devender Rao 
367*5968caeeSMarri Devender Rao using GetObjectType =
368*5968caeeSMarri Devender Rao     std::vector<std::pair<std::string, std::vector<std::string>>>;
369*5968caeeSMarri Devender Rao 
370*5968caeeSMarri Devender Rao /**
371*5968caeeSMarri Devender Rao  * Action to replace an existing certificate
372*5968caeeSMarri Devender Rao  */
373*5968caeeSMarri Devender Rao class CertificateActionsReplaceCertificate : public Node
374*5968caeeSMarri Devender Rao {
375*5968caeeSMarri Devender Rao   public:
376*5968caeeSMarri Devender Rao     CertificateActionsReplaceCertificate(CrowApp &app) :
377*5968caeeSMarri Devender Rao         Node(app, "/redfish/v1/CertificateService/Actions/"
378*5968caeeSMarri Devender Rao                   "CertificateService.ReplaceCertificate/")
379*5968caeeSMarri Devender Rao     {
380*5968caeeSMarri Devender Rao         entityPrivileges = {
381*5968caeeSMarri Devender Rao             {boost::beast::http::verb::get, {{"Login"}}},
382*5968caeeSMarri Devender Rao             {boost::beast::http::verb::head, {{"Login"}}},
383*5968caeeSMarri Devender Rao             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
384*5968caeeSMarri Devender Rao             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
385*5968caeeSMarri Devender Rao             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
386*5968caeeSMarri Devender Rao             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
387*5968caeeSMarri Devender Rao     }
388*5968caeeSMarri Devender Rao 
389*5968caeeSMarri Devender Rao   private:
390*5968caeeSMarri Devender Rao     void doPost(crow::Response &res, const crow::Request &req,
391*5968caeeSMarri Devender Rao                 const std::vector<std::string> &params) override
392*5968caeeSMarri Devender Rao     {
393*5968caeeSMarri Devender Rao         std::string certificate;
394*5968caeeSMarri Devender Rao         nlohmann::json certificateUri;
395*5968caeeSMarri Devender Rao         std::optional<std::string> certificateType = "PEM";
396*5968caeeSMarri Devender Rao         auto asyncResp = std::make_shared<AsyncResp>(res);
397*5968caeeSMarri Devender Rao         if (!json_util::readJson(req, asyncResp->res, "CertificateString",
398*5968caeeSMarri Devender Rao                                  certificate, "CertificateUri", certificateUri,
399*5968caeeSMarri Devender Rao                                  "CertificateType", certificateType))
400*5968caeeSMarri Devender Rao         {
401*5968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "Required parameters are missing";
402*5968caeeSMarri Devender Rao             messages::internalError(asyncResp->res);
403*5968caeeSMarri Devender Rao             return;
404*5968caeeSMarri Devender Rao         }
405*5968caeeSMarri Devender Rao 
406*5968caeeSMarri Devender Rao         if (!certificateType)
407*5968caeeSMarri Devender Rao         {
408*5968caeeSMarri Devender Rao             // should never happen, but it never hurts to be paranoid.
409*5968caeeSMarri Devender Rao             return;
410*5968caeeSMarri Devender Rao         }
411*5968caeeSMarri Devender Rao         if (certificateType != "PEM")
412*5968caeeSMarri Devender Rao         {
413*5968caeeSMarri Devender Rao             messages::actionParameterNotSupported(
414*5968caeeSMarri Devender Rao                 asyncResp->res, "CertificateType", "ReplaceCertificate");
415*5968caeeSMarri Devender Rao             return;
416*5968caeeSMarri Devender Rao         }
417*5968caeeSMarri Devender Rao 
418*5968caeeSMarri Devender Rao         std::string certURI;
419*5968caeeSMarri Devender Rao         if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
420*5968caeeSMarri Devender Rao                                           "@odata.id", certURI))
421*5968caeeSMarri Devender Rao         {
422*5968caeeSMarri Devender Rao             messages::actionParameterMissing(
423*5968caeeSMarri Devender Rao                 asyncResp->res, "ReplaceCertificate", "CertificateUri");
424*5968caeeSMarri Devender Rao             return;
425*5968caeeSMarri Devender Rao         }
426*5968caeeSMarri Devender Rao 
427*5968caeeSMarri Devender Rao         if (!boost::starts_with(
428*5968caeeSMarri Devender Rao                 certURI,
429*5968caeeSMarri Devender Rao                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"))
430*5968caeeSMarri Devender Rao         {
431*5968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "Unsupported certificate URI" << certURI;
432*5968caeeSMarri Devender Rao             messages::actionParameterValueFormatError(asyncResp->res, certURI,
433*5968caeeSMarri Devender Rao                                                       "CertificateUri",
434*5968caeeSMarri Devender Rao                                                       "ReplaceCertificate");
435*5968caeeSMarri Devender Rao             return;
436*5968caeeSMarri Devender Rao         }
437*5968caeeSMarri Devender Rao 
438*5968caeeSMarri Devender Rao         BMCWEB_LOG_INFO << "Certificate URI to replace" << certURI;
439*5968caeeSMarri Devender Rao         long id = getIDFromURL(certURI);
440*5968caeeSMarri Devender Rao         if (id < 0)
441*5968caeeSMarri Devender Rao         {
442*5968caeeSMarri Devender Rao             messages::actionParameterValueFormatError(asyncResp->res, certURI,
443*5968caeeSMarri Devender Rao                                                       "CertificateUri",
444*5968caeeSMarri Devender Rao                                                       "ReplaceCertificate");
445*5968caeeSMarri Devender Rao             return;
446*5968caeeSMarri Devender Rao         }
447*5968caeeSMarri Devender Rao         std::string objectPath;
448*5968caeeSMarri Devender Rao         std::string name;
449*5968caeeSMarri Devender Rao         if (boost::starts_with(
450*5968caeeSMarri Devender Rao                 certURI,
451*5968caeeSMarri Devender Rao                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"))
452*5968caeeSMarri Devender Rao         {
453*5968caeeSMarri Devender Rao             objectPath =
454*5968caeeSMarri Devender Rao                 std::string(certs::httpsObjectPath) + "/" + std::to_string(id);
455*5968caeeSMarri Devender Rao             name = "HTTPS certificate";
456*5968caeeSMarri Devender Rao         }
457*5968caeeSMarri Devender Rao         else
458*5968caeeSMarri Devender Rao         {
459*5968caeeSMarri Devender Rao             messages::actionParameterNotSupported(
460*5968caeeSMarri Devender Rao                 asyncResp->res, "CertificateUri", "ReplaceCertificate");
461*5968caeeSMarri Devender Rao             return;
462*5968caeeSMarri Devender Rao         }
463*5968caeeSMarri Devender Rao 
464*5968caeeSMarri Devender Rao         std::shared_ptr<CertificateFile> certFile =
465*5968caeeSMarri Devender Rao             std::make_shared<CertificateFile>(certificate);
466*5968caeeSMarri Devender Rao 
467*5968caeeSMarri Devender Rao         crow::connections::systemBus->async_method_call(
468*5968caeeSMarri Devender Rao             [asyncResp, objectPath, certFile, id, certURI, name](
469*5968caeeSMarri Devender Rao                 const boost::system::error_code ec, const GetObjectType &resp) {
470*5968caeeSMarri Devender Rao                 if (ec)
471*5968caeeSMarri Devender Rao                 {
472*5968caeeSMarri Devender Rao                     BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
473*5968caeeSMarri Devender Rao                     messages::internalError(asyncResp->res);
474*5968caeeSMarri Devender Rao                     return;
475*5968caeeSMarri Devender Rao                 }
476*5968caeeSMarri Devender Rao                 if (resp.size() > 1 || resp.empty())
477*5968caeeSMarri Devender Rao                 {
478*5968caeeSMarri Devender Rao                     BMCWEB_LOG_ERROR << "Invalid number of objects found "
479*5968caeeSMarri Devender Rao                                      << resp.size();
480*5968caeeSMarri Devender Rao                     messages::internalError(asyncResp->res);
481*5968caeeSMarri Devender Rao                     return;
482*5968caeeSMarri Devender Rao                 }
483*5968caeeSMarri Devender Rao                 const std::string &service = resp.begin()->first;
484*5968caeeSMarri Devender Rao                 crow::connections::systemBus->async_method_call(
485*5968caeeSMarri Devender Rao                     [asyncResp, certFile, objectPath, certURI, id,
486*5968caeeSMarri Devender Rao                      name](const boost::system::error_code ec) {
487*5968caeeSMarri Devender Rao                         if (ec)
488*5968caeeSMarri Devender Rao                         {
489*5968caeeSMarri Devender Rao                             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
490*5968caeeSMarri Devender Rao                             messages::internalError(asyncResp->res);
491*5968caeeSMarri Devender Rao                             return;
492*5968caeeSMarri Devender Rao                         }
493*5968caeeSMarri Devender Rao                         getCertificateProperties(asyncResp, objectPath, id,
494*5968caeeSMarri Devender Rao                                                  certURI, name);
495*5968caeeSMarri Devender Rao                         BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
496*5968caeeSMarri Devender Rao                                          << certFile->getCertFilePath();
497*5968caeeSMarri Devender Rao                     },
498*5968caeeSMarri Devender Rao                     service, objectPath, certs::certReplaceIntf, "Replace",
499*5968caeeSMarri Devender Rao                     certFile->getCertFilePath());
500*5968caeeSMarri Devender Rao             },
501*5968caeeSMarri Devender Rao             certs::mapperBusName, certs::mapperObjectPath, certs::mapperIntf,
502*5968caeeSMarri Devender Rao             "GetObject", objectPath,
503*5968caeeSMarri Devender Rao             std::array<std::string, 1>({certs::certReplaceIntf}));
504*5968caeeSMarri Devender Rao     }
505*5968caeeSMarri Devender Rao }; // CertificateActionsReplaceCertificate
506*5968caeeSMarri Devender Rao 
507*5968caeeSMarri Devender Rao /**
508*5968caeeSMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
509*5968caeeSMarri Devender Rao  * of a component, account or service.
510*5968caeeSMarri Devender Rao  */
511*5968caeeSMarri Devender Rao class HTTPSCertificate : public Node
512*5968caeeSMarri Devender Rao {
513*5968caeeSMarri Devender Rao   public:
514*5968caeeSMarri Devender Rao     template <typename CrowApp>
515*5968caeeSMarri Devender Rao     HTTPSCertificate(CrowApp &app) :
516*5968caeeSMarri Devender Rao         Node(app,
517*5968caeeSMarri Devender Rao              "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"
518*5968caeeSMarri Devender Rao              "<str>/",
519*5968caeeSMarri Devender Rao              std::string())
520*5968caeeSMarri Devender Rao     {
521*5968caeeSMarri Devender Rao         entityPrivileges = {
522*5968caeeSMarri Devender Rao             {boost::beast::http::verb::get, {{"Login"}}},
523*5968caeeSMarri Devender Rao             {boost::beast::http::verb::head, {{"Login"}}},
524*5968caeeSMarri Devender Rao             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
525*5968caeeSMarri Devender Rao             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
526*5968caeeSMarri Devender Rao             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
527*5968caeeSMarri Devender Rao             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
528*5968caeeSMarri Devender Rao     }
529*5968caeeSMarri Devender Rao 
530*5968caeeSMarri Devender Rao     void doGet(crow::Response &res, const crow::Request &req,
531*5968caeeSMarri Devender Rao                const std::vector<std::string> &params) override
532*5968caeeSMarri Devender Rao     {
533*5968caeeSMarri Devender Rao         auto asyncResp = std::make_shared<AsyncResp>(res);
534*5968caeeSMarri Devender Rao         if (params.size() != 1)
535*5968caeeSMarri Devender Rao         {
536*5968caeeSMarri Devender Rao             messages::internalError(asyncResp->res);
537*5968caeeSMarri Devender Rao             return;
538*5968caeeSMarri Devender Rao         }
539*5968caeeSMarri Devender Rao         long id = getIDFromURL(req.url);
540*5968caeeSMarri Devender Rao 
541*5968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPSCertificate::doGet ID=" << std::to_string(id);
542*5968caeeSMarri Devender Rao         std::string certURL =
543*5968caeeSMarri Devender Rao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
544*5968caeeSMarri Devender Rao             std::to_string(id);
545*5968caeeSMarri Devender Rao         std::string objectPath = certs::httpsObjectPath;
546*5968caeeSMarri Devender Rao         objectPath += "/";
547*5968caeeSMarri Devender Rao         objectPath += std::to_string(id);
548*5968caeeSMarri Devender Rao         getCertificateProperties(asyncResp, objectPath, id, certURL,
549*5968caeeSMarri Devender Rao                                  "HTTPS Certificate");
550*5968caeeSMarri Devender Rao     }
551*5968caeeSMarri Devender Rao 
552*5968caeeSMarri Devender Rao }; // namespace redfish
553*5968caeeSMarri Devender Rao 
554*5968caeeSMarri Devender Rao /**
555*5968caeeSMarri Devender Rao  * Collection of HTTPS certificates
556*5968caeeSMarri Devender Rao  */
557*5968caeeSMarri Devender Rao class HTTPSCertificateCollection : public Node
558*5968caeeSMarri Devender Rao {
559*5968caeeSMarri Devender Rao   public:
560*5968caeeSMarri Devender Rao     template <typename CrowApp>
561*5968caeeSMarri Devender Rao     HTTPSCertificateCollection(CrowApp &app) :
562*5968caeeSMarri Devender Rao         Node(app,
563*5968caeeSMarri Devender Rao              "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
564*5968caeeSMarri Devender Rao     {
565*5968caeeSMarri Devender Rao         entityPrivileges = {
566*5968caeeSMarri Devender Rao             {boost::beast::http::verb::get, {{"Login"}}},
567*5968caeeSMarri Devender Rao             {boost::beast::http::verb::head, {{"Login"}}},
568*5968caeeSMarri Devender Rao             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
569*5968caeeSMarri Devender Rao             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
570*5968caeeSMarri Devender Rao             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
571*5968caeeSMarri Devender Rao             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
572*5968caeeSMarri Devender Rao     }
573*5968caeeSMarri Devender Rao     void doGet(crow::Response &res, const crow::Request &req,
574*5968caeeSMarri Devender Rao                const std::vector<std::string> &params) override
575*5968caeeSMarri Devender Rao     {
576*5968caeeSMarri Devender Rao         res.jsonValue = {
577*5968caeeSMarri Devender Rao             {"@odata.id",
578*5968caeeSMarri Devender Rao              "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"},
579*5968caeeSMarri Devender Rao             {"@odata.type", "#CertificateCollection.CertificateCollection"},
580*5968caeeSMarri Devender Rao             {"@odata.context",
581*5968caeeSMarri Devender Rao              "/redfish/v1/"
582*5968caeeSMarri Devender Rao              "$metadata#CertificateCollection.CertificateCollection"},
583*5968caeeSMarri Devender Rao             {"Name", "HTTPS Certificates Collection"},
584*5968caeeSMarri Devender Rao             {"Description", "A Collection of HTTPS certificate instances"}};
585*5968caeeSMarri Devender Rao         auto asyncResp = std::make_shared<AsyncResp>(res);
586*5968caeeSMarri Devender Rao         crow::connections::systemBus->async_method_call(
587*5968caeeSMarri Devender Rao             [asyncResp](const boost::system::error_code ec,
588*5968caeeSMarri Devender Rao                         const GetObjectType &resp) {
589*5968caeeSMarri Devender Rao                 if (ec)
590*5968caeeSMarri Devender Rao                 {
591*5968caeeSMarri Devender Rao                     BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
592*5968caeeSMarri Devender Rao                     messages::internalError(asyncResp->res);
593*5968caeeSMarri Devender Rao                     return;
594*5968caeeSMarri Devender Rao                 }
595*5968caeeSMarri Devender Rao                 if (resp.size() > 1 || resp.empty())
596*5968caeeSMarri Devender Rao                 {
597*5968caeeSMarri Devender Rao                     BMCWEB_LOG_ERROR << "Invalid number of objects found "
598*5968caeeSMarri Devender Rao                                      << resp.size();
599*5968caeeSMarri Devender Rao                     messages::internalError(asyncResp->res);
600*5968caeeSMarri Devender Rao                     return;
601*5968caeeSMarri Devender Rao                 }
602*5968caeeSMarri Devender Rao                 const std::string &service = resp.begin()->first;
603*5968caeeSMarri Devender Rao                 crow::connections::systemBus->async_method_call(
604*5968caeeSMarri Devender Rao                     [asyncResp](const boost::system::error_code ec,
605*5968caeeSMarri Devender Rao                                 const ManagedObjectType &certs) {
606*5968caeeSMarri Devender Rao                         if (ec)
607*5968caeeSMarri Devender Rao                         {
608*5968caeeSMarri Devender Rao                             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
609*5968caeeSMarri Devender Rao                             messages::internalError(asyncResp->res);
610*5968caeeSMarri Devender Rao                             return;
611*5968caeeSMarri Devender Rao                         }
612*5968caeeSMarri Devender Rao                         nlohmann::json &members =
613*5968caeeSMarri Devender Rao                             asyncResp->res.jsonValue["Members"];
614*5968caeeSMarri Devender Rao                         members = nlohmann::json::array();
615*5968caeeSMarri Devender Rao                         for (const auto &cert : certs)
616*5968caeeSMarri Devender Rao                         {
617*5968caeeSMarri Devender Rao                             long id = getIDFromURL(cert.first.str);
618*5968caeeSMarri Devender Rao                             if (id != -1)
619*5968caeeSMarri Devender Rao                             {
620*5968caeeSMarri Devender Rao                                 members.push_back(
621*5968caeeSMarri Devender Rao                                     {{"@odata.id",
622*5968caeeSMarri Devender Rao                                       "/redfish/v1/Managers/bmc/"
623*5968caeeSMarri Devender Rao                                       "NetworkProtocol/HTTPS/Certificates/" +
624*5968caeeSMarri Devender Rao                                           std::to_string(id)}});
625*5968caeeSMarri Devender Rao                             }
626*5968caeeSMarri Devender Rao                         }
627*5968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["Members@odata.count"] =
628*5968caeeSMarri Devender Rao                             members.size();
629*5968caeeSMarri Devender Rao                     },
630*5968caeeSMarri Devender Rao                     service, certs::httpsObjectPath, certs::dbusObjManagerIntf,
631*5968caeeSMarri Devender Rao                     "GetManagedObjects");
632*5968caeeSMarri Devender Rao             },
633*5968caeeSMarri Devender Rao             certs::mapperBusName, certs::mapperObjectPath, certs::mapperIntf,
634*5968caeeSMarri Devender Rao             "GetObject", certs::httpsObjectPath,
635*5968caeeSMarri Devender Rao             std::array<const char *, 1>{certs::certInstallIntf});
636*5968caeeSMarri Devender Rao     }
637*5968caeeSMarri Devender Rao 
638*5968caeeSMarri Devender Rao     void doPost(crow::Response &res, const crow::Request &req,
639*5968caeeSMarri Devender Rao                 const std::vector<std::string> &params) override
640*5968caeeSMarri Devender Rao     {
641*5968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
642*5968caeeSMarri Devender Rao         auto asyncResp = std::make_shared<AsyncResp>(res);
643*5968caeeSMarri Devender Rao         asyncResp->res.jsonValue = {{"Name", "HTTPS Certificate"},
644*5968caeeSMarri Devender Rao                                     {"Description", "HTTPS Certificate"}};
645*5968caeeSMarri Devender Rao 
646*5968caeeSMarri Devender Rao         std::shared_ptr<CertificateFile> certFile =
647*5968caeeSMarri Devender Rao             std::make_shared<CertificateFile>(req.body);
648*5968caeeSMarri Devender Rao 
649*5968caeeSMarri Devender Rao         crow::connections::systemBus->async_method_call(
650*5968caeeSMarri Devender Rao             [asyncResp, certFile](const boost::system::error_code ec,
651*5968caeeSMarri Devender Rao                                   const GetObjectType &resp) {
652*5968caeeSMarri Devender Rao                 if (ec)
653*5968caeeSMarri Devender Rao                 {
654*5968caeeSMarri Devender Rao                     BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
655*5968caeeSMarri Devender Rao                     messages::internalError(asyncResp->res);
656*5968caeeSMarri Devender Rao                     return;
657*5968caeeSMarri Devender Rao                 }
658*5968caeeSMarri Devender Rao                 if (resp.size() > 1 || resp.empty())
659*5968caeeSMarri Devender Rao                 {
660*5968caeeSMarri Devender Rao                     BMCWEB_LOG_ERROR << "Invalid number of objects found "
661*5968caeeSMarri Devender Rao                                      << resp.size();
662*5968caeeSMarri Devender Rao                     messages::internalError(asyncResp->res);
663*5968caeeSMarri Devender Rao                     return;
664*5968caeeSMarri Devender Rao                 }
665*5968caeeSMarri Devender Rao                 const std::string &service = resp.begin()->first;
666*5968caeeSMarri Devender Rao                 crow::connections::systemBus->async_method_call(
667*5968caeeSMarri Devender Rao                     [asyncResp, certFile](const boost::system::error_code ec) {
668*5968caeeSMarri Devender Rao                         if (ec)
669*5968caeeSMarri Devender Rao                         {
670*5968caeeSMarri Devender Rao                             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
671*5968caeeSMarri Devender Rao                             messages::internalError(asyncResp->res);
672*5968caeeSMarri Devender Rao                             return;
673*5968caeeSMarri Devender Rao                         }
674*5968caeeSMarri Devender Rao                         // TODO: Issue#84 supporting only 1 certificate
675*5968caeeSMarri Devender Rao                         long certId = 1;
676*5968caeeSMarri Devender Rao                         std::string certURL =
677*5968caeeSMarri Devender Rao                             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/"
678*5968caeeSMarri Devender Rao                             "Certificates/" +
679*5968caeeSMarri Devender Rao                             std::to_string(certId);
680*5968caeeSMarri Devender Rao                         std::string objectPath =
681*5968caeeSMarri Devender Rao                             std::string(certs::httpsObjectPath) + "/" +
682*5968caeeSMarri Devender Rao                             std::to_string(certId);
683*5968caeeSMarri Devender Rao                         getCertificateProperties(asyncResp, objectPath, certId,
684*5968caeeSMarri Devender Rao                                                  certURL, "HTTPS Certificate");
685*5968caeeSMarri Devender Rao                         BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
686*5968caeeSMarri Devender Rao                                          << certFile->getCertFilePath();
687*5968caeeSMarri Devender Rao                     },
688*5968caeeSMarri Devender Rao                     service, certs::httpsObjectPath, certs::certInstallIntf,
689*5968caeeSMarri Devender Rao                     "Install", certFile->getCertFilePath());
690*5968caeeSMarri Devender Rao             },
691*5968caeeSMarri Devender Rao             certs::mapperBusName, certs::mapperObjectPath, certs::mapperIntf,
692*5968caeeSMarri Devender Rao             "GetObject", certs::httpsObjectPath,
693*5968caeeSMarri Devender Rao             std::array<const char *, 1>{certs::certInstallIntf});
694*5968caeeSMarri Devender Rao     }
695*5968caeeSMarri Devender Rao }; // HTTPSCertificateCollection
696*5968caeeSMarri Devender Rao 
697*5968caeeSMarri Devender Rao /**
698*5968caeeSMarri Devender Rao  * @brief Retrieve the certificates installed list and append to the response
699*5968caeeSMarri Devender Rao  *
700*5968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
701*5968caeeSMarri Devender Rao  * @param[in] certURL  Path of the certificate object
702*5968caeeSMarri Devender Rao  * @param[in] path  Path of the D-Bus service object
703*5968caeeSMarri Devender Rao  * @return None
704*5968caeeSMarri Devender Rao  */
705*5968caeeSMarri Devender Rao static void getCertificateLocations(std::shared_ptr<AsyncResp> &asyncResp,
706*5968caeeSMarri Devender Rao                                     const std::string &certURL,
707*5968caeeSMarri Devender Rao                                     const std::string &path)
708*5968caeeSMarri Devender Rao {
709*5968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateLocations URI=" << certURL
710*5968caeeSMarri Devender Rao                      << " Path=" << path;
711*5968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
712*5968caeeSMarri Devender Rao         [asyncResp, path, certURL](const boost::system::error_code ec,
713*5968caeeSMarri Devender Rao                                    const GetObjectType &resp) {
714*5968caeeSMarri Devender Rao             if (ec)
715*5968caeeSMarri Devender Rao             {
716*5968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
717*5968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
718*5968caeeSMarri Devender Rao                 return;
719*5968caeeSMarri Devender Rao             }
720*5968caeeSMarri Devender Rao             if (resp.size() > 1 || resp.empty())
721*5968caeeSMarri Devender Rao             {
722*5968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Invalid number of objects found "
723*5968caeeSMarri Devender Rao                                  << resp.size();
724*5968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
725*5968caeeSMarri Devender Rao                 return;
726*5968caeeSMarri Devender Rao             }
727*5968caeeSMarri Devender Rao             const std::string &service = resp.begin()->first;
728*5968caeeSMarri Devender Rao             crow::connections::systemBus->async_method_call(
729*5968caeeSMarri Devender Rao                 [asyncResp, certURL](const boost::system::error_code ec,
730*5968caeeSMarri Devender Rao                                      const ManagedObjectType &certs) {
731*5968caeeSMarri Devender Rao                     if (ec)
732*5968caeeSMarri Devender Rao                     {
733*5968caeeSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
734*5968caeeSMarri Devender Rao                         messages::internalError(asyncResp->res);
735*5968caeeSMarri Devender Rao                         return;
736*5968caeeSMarri Devender Rao                     }
737*5968caeeSMarri Devender Rao                     nlohmann::json &links =
738*5968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["Links"]["Certificates"];
739*5968caeeSMarri Devender Rao                     for (auto &cert : certs)
740*5968caeeSMarri Devender Rao                     {
741*5968caeeSMarri Devender Rao                         long id = getIDFromURL(cert.first.str);
742*5968caeeSMarri Devender Rao                         if (id != -1)
743*5968caeeSMarri Devender Rao                         {
744*5968caeeSMarri Devender Rao                             links.push_back(
745*5968caeeSMarri Devender Rao                                 {{"@odata.id", certURL + std::to_string(id)}});
746*5968caeeSMarri Devender Rao                         }
747*5968caeeSMarri Devender Rao                     }
748*5968caeeSMarri Devender Rao                     asyncResp->res
749*5968caeeSMarri Devender Rao                         .jsonValue["Links"]["Certificates@odata.count"] =
750*5968caeeSMarri Devender Rao                         links.size();
751*5968caeeSMarri Devender Rao                 },
752*5968caeeSMarri Devender Rao                 service, path, certs::dbusObjManagerIntf, "GetManagedObjects");
753*5968caeeSMarri Devender Rao         },
754*5968caeeSMarri Devender Rao         certs::mapperBusName, certs::mapperObjectPath, certs::mapperIntf,
755*5968caeeSMarri Devender Rao         "GetObject", path, std::array<std::string, 0>());
756*5968caeeSMarri Devender Rao }
757*5968caeeSMarri Devender Rao 
758*5968caeeSMarri Devender Rao /**
759*5968caeeSMarri Devender Rao  * The certificate location schema defines a resource that an administrator
760*5968caeeSMarri Devender Rao  * can use in order to locate all certificates installed on a given service.
761*5968caeeSMarri Devender Rao  */
762*5968caeeSMarri Devender Rao class CertificateLocations : public Node
763*5968caeeSMarri Devender Rao {
764*5968caeeSMarri Devender Rao   public:
765*5968caeeSMarri Devender Rao     template <typename CrowApp>
766*5968caeeSMarri Devender Rao     CertificateLocations(CrowApp &app) :
767*5968caeeSMarri Devender Rao         Node(app, "/redfish/v1/CertificateService/CertificateLocations/")
768*5968caeeSMarri Devender Rao     {
769*5968caeeSMarri Devender Rao         entityPrivileges = {
770*5968caeeSMarri Devender Rao             {boost::beast::http::verb::get, {{"Login"}}},
771*5968caeeSMarri Devender Rao             {boost::beast::http::verb::head, {{"Login"}}},
772*5968caeeSMarri Devender Rao             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
773*5968caeeSMarri Devender Rao             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
774*5968caeeSMarri Devender Rao             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
775*5968caeeSMarri Devender Rao             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
776*5968caeeSMarri Devender Rao     }
777*5968caeeSMarri Devender Rao 
778*5968caeeSMarri Devender Rao   private:
779*5968caeeSMarri Devender Rao     void doGet(crow::Response &res, const crow::Request &req,
780*5968caeeSMarri Devender Rao                const std::vector<std::string> &params) override
781*5968caeeSMarri Devender Rao     {
782*5968caeeSMarri Devender Rao         res.jsonValue = {
783*5968caeeSMarri Devender Rao             {"@odata.id",
784*5968caeeSMarri Devender Rao              "/redfish/v1/CertificateService/CertificateLocations"},
785*5968caeeSMarri Devender Rao             {"@odata.type",
786*5968caeeSMarri Devender Rao              "#CertificateLocations.v1_0_0.CertificateLocations"},
787*5968caeeSMarri Devender Rao             {"@odata.context",
788*5968caeeSMarri Devender Rao              "/redfish/v1/$metadata#CertificateLocations.CertificateLocations"},
789*5968caeeSMarri Devender Rao             {"Name", "Certificate Locations"},
790*5968caeeSMarri Devender Rao             {"Id", "CertificateLocations"},
791*5968caeeSMarri Devender Rao             {"Description",
792*5968caeeSMarri Devender Rao              "Defines a resource that an administrator can use in order to "
793*5968caeeSMarri Devender Rao              "locate all certificates installed on a given service"}};
794*5968caeeSMarri Devender Rao         auto asyncResp = std::make_shared<AsyncResp>(res);
795*5968caeeSMarri Devender Rao         nlohmann::json &links =
796*5968caeeSMarri Devender Rao             asyncResp->res.jsonValue["Links"]["Certificates"];
797*5968caeeSMarri Devender Rao         links = nlohmann::json::array();
798*5968caeeSMarri Devender Rao         getCertificateLocations(
799*5968caeeSMarri Devender Rao             asyncResp,
800*5968caeeSMarri Devender Rao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/",
801*5968caeeSMarri Devender Rao             certs::httpsObjectPath);
802*5968caeeSMarri Devender Rao     }
803*5968caeeSMarri Devender Rao }; // CertificateLocations
804*5968caeeSMarri Devender Rao } // namespace redfish
805