Introduce Redfish Error messages definitions

Added a python script that should be use to generate error_messages.cpp na .hpp
files. These files as are not subject to change in a dynamic manner, should be
regenerated only when MessageRegistry changes.

Tested on x86 Ubuntu VM and Wolfpass platform:
a) No regression in BMCWeb interface
- Went through WebUI observed no changes in functionality
b) No regression in Redfish functionality
- Went through nodes and observed no changes in functionality
- Sessions now return error messages in addition to HTTP codes

Change-Id: I4aba9ee247b6cd2c46a9c158d14bdc7546e9b11b
Signed-off-by: Kowalski, Kamil <kamil.kowalski@intel.com>
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
diff --git a/redfish-core/lib/redfish_sessions.hpp b/redfish-core/lib/redfish_sessions.hpp
index 4e429e8..507116d 100644
--- a/redfish-core/lib/redfish_sessions.hpp
+++ b/redfish-core/lib/redfish_sessions.hpp
@@ -15,6 +15,7 @@
 */
 #pragma once
 
+#include "error_messages.hpp"
 #include "node.hpp"
 #include "session_storage_singleton.hpp"
 
@@ -46,6 +47,9 @@
         crow::PersistentData::session_store->get_session_by_uid(params[0]);
 
     if (session == nullptr) {
+      messages::addMessageToErrorJson(
+          res.json_value, messages::resourceNotFound("Session", params[0]));
+
       res.code = static_cast<int>(HttpRespCode::NOT_FOUND);
       res.end();
       return;
@@ -64,7 +68,12 @@
                 const std::vector<std::string>& params) override {
     // Need only 1 param which should be id of session to be deleted
     if (params.size() != 1) {
+      // This should be handled by crow and never happen
+      CROW_LOG_ERROR
+          << "Session DELETE has been called with invalid number of params";
+
       res.code = static_cast<int>(HttpRespCode::BAD_REQUEST);
+      messages::addMessageToErrorJson(res.json_value, messages::generalError());
       res.end();
       return;
     }
@@ -73,14 +82,18 @@
         crow::PersistentData::session_store->get_session_by_uid(params[0]);
 
     if (session == nullptr) {
+      messages::addMessageToErrorJson(
+          res.json_value, messages::resourceNotFound("Session", params[0]));
+
       res.code = static_cast<int>(HttpRespCode::NOT_FOUND);
       res.end();
       return;
     }
 
+    // DELETE should return representation of object that will be removed
+    doGet(res, req, params);
+
     crow::PersistentData::session_store->remove_session(session);
-    res.code = static_cast<int>(HttpRespCode::OK);
-    res.end();
   }
 
   /**
@@ -133,7 +146,8 @@
   void doPost(crow::response& res, const crow::request& req,
               const std::vector<std::string>& params) override {
     std::string username;
-    bool userAuthSuccessful = authenticateUser(req, &res.code, &username);
+    bool userAuthSuccessful =
+        authenticateUser(req, res.code, username, res.json_value);
     if (!userAuthSuccessful) {
       res.end();
       return;
@@ -156,25 +170,30 @@
    * @param[in]  req            Crow request containing authentication data
    * @param[out] httpRespCode   HTTP Code that should be returned in response
    * @param[out] user           Retrieved username - not filled on failure
+   * @param[out] errJson        JSON to which error messages will be written
    *
    * @return true if authentication was successful, false otherwise
    */
-  bool authenticateUser(const crow::request& req, int* httpRespCode,
-                        std::string* user) {
+  bool authenticateUser(const crow::request& req, int& httpRespCode,
+                        std::string& user, nlohmann::json& errJson) {
     // We need only UserName and Password - nothing more, nothing less
     static constexpr const unsigned int numberOfRequiredFieldsInReq = 2;
 
     // call with exceptions disabled
     auto login_credentials = nlohmann::json::parse(req.body, nullptr, false);
     if (login_credentials.is_discarded()) {
-      *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
+      httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
+
+      messages::addMessageToErrorJson(errJson, messages::malformedJSON());
 
       return false;
     }
 
     // Check that there are only as many fields as there should be
     if (login_credentials.size() != numberOfRequiredFieldsInReq) {
-      *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
+      httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
+
+      messages::addMessageToErrorJson(errJson, messages::malformedJSON());
 
       return false;
     }
@@ -184,14 +203,36 @@
     auto pass_it = login_credentials.find("Password");
     if (user_it == login_credentials.end() ||
         pass_it == login_credentials.end()) {
-      *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
+      httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
+
+      if (user_it == login_credentials.end()) {
+        messages::addMessageToErrorJson(errJson,
+                                        messages::propertyMissing("UserName"));
+      }
+
+      if (pass_it == login_credentials.end()) {
+        messages::addMessageToErrorJson(errJson,
+                                        messages::propertyMissing("Password"));
+      }
 
       return false;
     }
 
     // Check that given data is of valid type (string)
     if (!user_it->is_string() || !pass_it->is_string()) {
-      *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
+      httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
+
+      if (!user_it->is_string()) {
+        messages::addMessageToErrorJson(
+            errJson,
+            messages::propertyValueTypeError(user_it->dump(), "UserName"));
+      }
+
+      if (!pass_it->is_string()) {
+        messages::addMessageToErrorJson(
+            errJson,
+            messages::propertyValueTypeError(user_it->dump(), "Password"));
+      }
 
       return false;
     }
@@ -202,21 +243,35 @@
 
     // Verify that required fields are not empty
     if (username.empty() || password.empty()) {
-      *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
+      httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
+
+      if (username.empty()) {
+        messages::addMessageToErrorJson(errJson,
+                                        messages::propertyMissing("UserName"));
+      }
+
+      if (password.empty()) {
+        messages::addMessageToErrorJson(errJson,
+                                        messages::propertyMissing("Password"));
+      }
 
       return false;
     }
 
     // Finally - try to authenticate user
     if (!pam_authenticate_user(username, password)) {
-      *httpRespCode = static_cast<int>(HttpRespCode::UNAUTHORIZED);
+      httpRespCode = static_cast<int>(HttpRespCode::UNAUTHORIZED);
+
+      messages::addMessageToErrorJson(
+          errJson, messages::resourceAtUriUnauthorized(
+                       req.url, "Invalid username or password"));
 
       return false;
     }
 
     // User authenticated successfully
-    *httpRespCode = static_cast<int>(HttpRespCode::OK);
-    *user = username;
+    httpRespCode = static_cast<int>(HttpRespCode::OK);
+    user = username;
 
     return true;
   }