Redfish SessionService

- added node version of the SessionService implementation
- added a default timeout member and a get timeout method
  to the SessionStore class

Change-Id: I532080789b3d687208510f8b748402735ed888d8
Signed-off-by: Borawski.Lukasz <lukasz.borawski@intel.com>
diff --git a/include/redfish_v1.hpp b/include/redfish_v1.hpp
index aa6da06..99e0b3c 100644
--- a/include/redfish_v1.hpp
+++ b/include/redfish_v1.hpp
@@ -140,28 +140,6 @@
         res.end();
       });
 
-  CROW_ROUTE(app, "/redfish/v1/SessionService/")
-      .methods(
-          "GET"_method)([&](const crow::request& req, crow::response& res) {
-        res.json_value = {
-            {"@odata.context",
-             "/redfish/v1/$metadata#SessionService.SessionService"},
-            {"@odata.id", "/redfish/v1/SessionService"},
-            {"@odata.type", "#SessionService.v1_1_1.SessionService"},
-            {"Id", "SessionService"},
-            {"Name", "SessionService"},
-            {"Description", "SessionService"},
-            {"Status",
-             {{"State", "Enabled"}, {"Health", "OK"}, {"HealthRollup", "OK"}}},
-            {"ServiceEnabled", true},
-            // TODO(ed) converge with session timeouts once they exist
-            // Bogus number for now
-            {"SessionTimeout", 1800}};
-        get_redfish_sub_routes(app, "/redfish/v1/AccountService",
-                               res.json_value);
-        res.end();
-      });
-
   CROW_ROUTE(app, "/redfish/v1/Managers/")
       .methods("GET"_method)(
           [&](const crow::request& req, crow::response& res) {
diff --git a/include/sessions.hpp b/include/sessions.hpp
index 90df93e..15ff9ca 100644
--- a/include/sessions.hpp
+++ b/include/sessions.hpp
@@ -86,6 +86,7 @@
 
 class SessionStore {
  public:
+  SessionStore() : timeout_in_minutes(60) {}
   const UserSession& generate_user_session(
       const std::string& username,
       PersistenceType persistence = PersistenceType::TIMEOUT) {
@@ -175,6 +176,9 @@
   }
 
   bool needs_write() { return need_write_; }
+  int get_timeout_in_seconds() const {
+    return std::chrono::seconds(timeout_in_minutes).count();
+  };
 
   // Persistent data middleware needs to be able to serialize our auth_tokens
   // structure, which is private
@@ -182,13 +186,13 @@
 
  private:
   void apply_session_timeouts() {
-    std::chrono::minutes timeout(60);
     auto time_now = std::chrono::steady_clock::now();
     if (time_now - last_timeout_update > std::chrono::minutes(1)) {
       last_timeout_update = time_now;
       auto auth_tokens_it = auth_tokens.begin();
       while (auth_tokens_it != auth_tokens.end()) {
-        if (time_now - auth_tokens_it->second.last_updated >= timeout) {
+        if (time_now - auth_tokens_it->second.last_updated >=
+            timeout_in_minutes) {
           auth_tokens_it = auth_tokens.erase(auth_tokens_it);
           need_write_ = true;
         } else {
@@ -201,6 +205,7 @@
   boost::container::flat_map<std::string, UserSession> auth_tokens;
   std::random_device rd;
   bool need_write_{false};
+  std::chrono::minutes timeout_in_minutes;
 };
 
 }  // namespaec PersistentData
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index e14845f..7714ab7 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -42,6 +42,7 @@
     nodes.emplace_back(std::make_unique<RoleCollection>(app));
     nodes.emplace_back(std::make_unique<ServiceRoot>(app));
     nodes.emplace_back(std::make_unique<NetworkProtocol>(app));
+    nodes.emplace_back(std::make_unique<SessionService>(app));
 
     for (auto& node : nodes) {
       node->getSubRoutes(nodes);
diff --git a/redfish-core/lib/redfish_sessions.hpp b/redfish-core/lib/redfish_sessions.hpp
index 75857a1..4225cc1 100644
--- a/redfish-core/lib/redfish_sessions.hpp
+++ b/redfish-core/lib/redfish_sessions.hpp
@@ -36,6 +36,14 @@
     {crow::HTTPMethod::DELETE, {{"ConfigureManager"}}},
     {crow::HTTPMethod::POST, {{}}}};
 
+static OperationMap sessionServiceOpMap = {
+    {crow::HTTPMethod::GET, {{"Login"}}},
+    {crow::HTTPMethod::HEAD, {{"Login"}}},
+    {crow::HTTPMethod::PATCH, {{"ConfigureManager"}}},
+    {crow::HTTPMethod::PUT, {{"ConfigureManager"}}},
+    {crow::HTTPMethod::DELETE, {{"ConfigureManager"}}},
+    {crow::HTTPMethod::POST, {{"ConfigureManager"}}}};
+
 class SessionCollection;
 
 class Sessions : public Node {
@@ -233,4 +241,31 @@
   Sessions memberSession;
 };
 
+class SessionService : public Node {
+ public:
+  SessionService(CrowApp& app)
+      : Node(app, EntityPrivileges(std::move(sessionServiceOpMap)),
+             "/redfish/v1/SessionService/") {
+    Node::json["@odata.type"] = "#SessionService.v1_0_2.SessionService";
+    Node::json["@odata.id"] = "/redfish/v1/SessionService/";
+    Node::json["@odata.context"] =
+        "/redfish/v1/$metadata#SessionService.SessionService";
+    Node::json["Name"] = "Session Service";
+    Node::json["Description"] = "Session Service";
+    Node::json["SessionTimeout"] =
+        crow::PersistentData::session_store->get_timeout_in_seconds();
+    Node::json["Status"]["State"] = "Enabled";
+    Node::json["Status"]["Health"] = "OK";
+    Node::json["Status"]["HealthRollup"] = "OK";
+    Node::json["ServiceEnabled"] = true;
+  }
+
+ private:
+  void doGet(crow::response& res, const crow::request& req,
+             const std::vector<std::string>& params) override {
+    res.json_value = Node::json;
+    res.end();
+  }
+};
+
 }  // namespace redfish