Add option for validating content-type header

For systems implementing to the OWASP security guidelines[1] (of which all
should ideally) we should be checking the content-type header all times
that we parse a request as JSON.

This commit adds an option for parsing content-type, and sets a default
of "must get content-type".  Ideally this would not be a breaking
change, but given the number of guides and scripts that omit the content
type, it seems worthwhile to add a trapdoor, such that people can opt
into their own model on how they would like to see this checking work.

Tested:
```
curl --insecure -H "Content-Type: application/json" -X POST -D headers.txt https://${bmc}/redfish/v1/SessionService/Sessions -d    '{"UserName":"root", "Password":"0penBmc"}'
```

Succeeds.

Removing Content-Type argument causes bmc to return
Base.1.13.0.UnrecognizedRequestBody.

[1] cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html

Change-Id: Iaa47dd563b40036ff2fc2cacb70d941fd8853038
Signed-off-by: Ed Tanous <edtanous@google.com>
diff --git a/redfish-core/lib/certificate_service.hpp b/redfish-core/lib/certificate_service.hpp
index 65f5262..16f26e3 100644
--- a/redfish-core/lib/certificate_service.hpp
+++ b/redfish-core/lib/certificate_service.hpp
@@ -3,6 +3,7 @@
 #include "app.hpp"
 #include "async_resp.hpp"
 #include "dbus_utility.hpp"
+#include "http/parsing.hpp"
 #include "http_response.hpp"
 #include "query.hpp"
 #include "registries/privilege_registry.hpp"
@@ -53,9 +54,9 @@
     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
     const crow::Request& req)
 {
-    nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false);
-
-    if (reqJson.is_discarded())
+    nlohmann::json reqJson;
+    JsonParseResult ret = parseRequestAsJson(req, reqJson);
+    if (ret != JsonParseResult::Success)
     {
         // We did not receive JSON request, proceed as it is RAW data
         return req.body;
diff --git a/redfish-core/lib/task.hpp b/redfish-core/lib/task.hpp
index cfe6c3e..950eac3 100644
--- a/redfish-core/lib/task.hpp
+++ b/redfish-core/lib/task.hpp
@@ -19,6 +19,7 @@
 #include "dbus_utility.hpp"
 #include "event_service_manager.hpp"
 #include "health.hpp"
+#include "http/parsing.hpp"
 #include "query.hpp"
 #include "registries/privilege_registry.hpp"
 #include "task_messages.hpp"
@@ -47,8 +48,7 @@
 {
     explicit Payload(const crow::Request& req) :
         targetUri(req.url), httpOperation(req.methodString()),
-        httpHeaders(nlohmann::json::array()),
-        jsonBody(nlohmann::json::parse(req.body, nullptr, false))
+        httpHeaders(nlohmann::json::array())
     {
         using field_ns = boost::beast::http::field;
         constexpr const std::array<boost::beast::http::field, 7>
@@ -57,9 +57,10 @@
                                field_ns::connection, field_ns::content_length,
                                field_ns::upgrade};
 
-        if (jsonBody.is_discarded())
+        JsonParseResult ret = parseRequestAsJson(req, jsonBody);
+        if (ret != JsonParseResult::Success)
         {
-            jsonBody = nullptr;
+            return;
         }
 
         for (const auto& field : req.fields)
diff --git a/redfish-core/src/utils/json_utils.cpp b/redfish-core/src/utils/json_utils.cpp
index a47b4d8..89723cc 100644
--- a/redfish-core/src/utils/json_utils.cpp
+++ b/redfish-core/src/utils/json_utils.cpp
@@ -15,6 +15,13 @@
 */
 #include "utils/json_utils.hpp"
 
+#include "error_messages.hpp"
+#include "http/http_request.hpp"
+#include "http/http_response.hpp"
+#include "http/parsing.hpp"
+
+#include <nlohmann/json.hpp>
+
 namespace redfish
 {
 
@@ -24,14 +31,17 @@
 bool processJsonFromRequest(crow::Response& res, const crow::Request& req,
                             nlohmann::json& reqJson)
 {
+    JsonParseResult ret = parseRequestAsJson(req, reqJson);
+    if (ret == JsonParseResult::BadContentType)
+    {
+        messages::unrecognizedRequestBody(res);
+        return false;
+    }
     reqJson = nlohmann::json::parse(req.body, nullptr, false);
 
     if (reqJson.is_discarded())
     {
         messages::malformedJSON(res);
-
-        res.end();
-
         return false;
     }