blob: 348079ba612e992fea7617c72fc9eece5950aa10 [file] [log] [blame]
Ed Tanousba9f9a62017-10-11 16:40:35 -07001#pragma once
2
Ed Tanousc94ad492019-10-10 15:39:33 -07003#include <app.h>
4#include <http_request.h>
5#include <http_response.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -07006
Ed Tanousba9f9a62017-10-11 16:40:35 -07007#include <boost/container/flat_map.hpp>
8#include <boost/uuid/uuid.hpp>
9#include <boost/uuid/uuid_generators.hpp>
10#include <boost/uuid/uuid_io.hpp>
Ratan Gupta845cb7d2019-07-12 00:32:25 +053011#include <filesystem>
Ed Tanous1abe55e2018-09-05 08:30:59 -070012#include <nlohmann/json.hpp>
13#include <pam_authenticate.hpp>
14#include <random>
15#include <sessions.hpp>
16#include <webassets.hpp>
Ed Tanousba9f9a62017-10-11 16:40:35 -070017
Ed Tanous1abe55e2018-09-05 08:30:59 -070018namespace crow
19{
Ed Tanousba9f9a62017-10-11 16:40:35 -070020
Ed Tanous1abe55e2018-09-05 08:30:59 -070021namespace persistent_data
22{
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010023
Ratan Gupta845cb7d2019-07-12 00:32:25 +053024namespace fs = std::filesystem;
25
Ed Tanous1abe55e2018-09-05 08:30:59 -070026class Middleware
27{
Ed Tanous271584a2019-07-09 16:24:22 -070028 uint64_t jsonRevision = 1;
Ed Tanousc963aa42017-10-27 16:00:19 -070029
Ed Tanous1abe55e2018-09-05 08:30:59 -070030 public:
Ratan Gupta845cb7d2019-07-12 00:32:25 +053031 // todo(ed) should read this from a fixed location somewhere, not CWD
32 static constexpr const char* filename = "bmcweb_persistent_data.json";
33
Ed Tanous1abe55e2018-09-05 08:30:59 -070034 struct Context
35 {
36 };
Ed Tanousc963aa42017-10-27 16:00:19 -070037
Ed Tanous1abe55e2018-09-05 08:30:59 -070038 Middleware()
39 {
40 readData();
Ed Tanousc963aa42017-10-27 16:00:19 -070041 }
Ed Tanousc963aa42017-10-27 16:00:19 -070042
Ed Tanous1abe55e2018-09-05 08:30:59 -070043 ~Middleware()
44 {
45 if (persistent_data::SessionStore::getInstance().needsWrite())
46 {
47 writeData();
Kowalski, Kamil5cef0f72018-02-15 15:26:51 +010048 }
Ed Tanousc963aa42017-10-27 16:00:19 -070049 }
Ed Tanousc963aa42017-10-27 16:00:19 -070050
Ed Tanous1abe55e2018-09-05 08:30:59 -070051 void beforeHandle(crow::Request& req, Response& res, Context& ctx)
52 {
Ed Tanousc963aa42017-10-27 16:00:19 -070053 }
Ed Tanousc963aa42017-10-27 16:00:19 -070054
Ed Tanous1abe55e2018-09-05 08:30:59 -070055 void afterHandle(Request& req, Response& res, Context& ctx)
56 {
57 }
Ed Tanousc963aa42017-10-27 16:00:19 -070058
Ed Tanous1abe55e2018-09-05 08:30:59 -070059 // TODO(ed) this should really use protobuf, or some other serialization
60 // library, but adding another dependency is somewhat outside the scope of
61 // this application for the moment
62 void readData()
63 {
64 std::ifstream persistentFile(filename);
Ed Tanous271584a2019-07-09 16:24:22 -070065 uint64_t fileRevision = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -070066 if (persistentFile.is_open())
67 {
68 // call with exceptions disabled
69 auto data = nlohmann::json::parse(persistentFile, nullptr, false);
70 if (data.is_discarded())
71 {
72 BMCWEB_LOG_ERROR
73 << "Error parsing persistent data in json file.";
74 }
75 else
76 {
77 for (const auto& item : data.items())
78 {
79 if (item.key() == "revision")
80 {
81 fileRevision = 0;
82
83 const uint64_t* uintPtr =
84 item.value().get_ptr<const uint64_t*>();
85 if (uintPtr == nullptr)
86 {
87 BMCWEB_LOG_ERROR << "Failed to read revision flag";
88 }
89 else
90 {
91 fileRevision = *uintPtr;
92 }
93 }
94 else if (item.key() == "system_uuid")
95 {
96 const std::string* jSystemUuid =
97 item.value().get_ptr<const std::string*>();
98 if (jSystemUuid != nullptr)
99 {
100 systemUuid = *jSystemUuid;
101 }
102 }
Zbigniew Kurzynski78158632019-11-05 12:57:37 +0100103 else if (item.key() == "auth_config")
104 {
105 SessionStore::getInstance()
106 .getAuthMethodsConfig()
107 .fromJson(item.value());
108 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 else if (item.key() == "sessions")
110 {
111 for (const auto& elem : item.value())
112 {
113 std::shared_ptr<UserSession> newSession =
114 UserSession::fromJson(elem);
115
116 if (newSession == nullptr)
117 {
118 BMCWEB_LOG_ERROR << "Problem reading session "
119 "from persistent store";
120 continue;
121 }
122
123 BMCWEB_LOG_DEBUG
124 << "Restored session: " << newSession->csrfToken
125 << " " << newSession->uniqueId << " "
126 << newSession->sessionToken;
127 SessionStore::getInstance().authTokens.emplace(
128 newSession->sessionToken, newSession);
129 }
130 }
131 else
132 {
133 // Do nothing in the case of extra fields. We may have
134 // cases where fields are added in the future, and we
135 // want to at least attempt to gracefully support
136 // downgrades in that case, even if we don't officially
137 // support it
138 }
139 }
140 }
141 }
142 bool needWrite = false;
143
144 if (systemUuid.empty())
145 {
146 systemUuid =
147 boost::uuids::to_string(boost::uuids::random_generator()());
148 needWrite = true;
149 }
150 if (fileRevision < jsonRevision)
151 {
152 needWrite = true;
153 }
154 // write revision changes or system uuid changes immediately
155 if (needWrite)
156 {
157 writeData();
158 }
159 }
160
161 void writeData()
162 {
163 std::ofstream persistentFile(filename);
Ratan Gupta845cb7d2019-07-12 00:32:25 +0530164
165 // set the permission of the file to 640
166 fs::perms permission = fs::perms::owner_read | fs::perms::owner_write |
167 fs::perms::group_read;
168 fs::permissions(filename, permission);
169
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 nlohmann::json data{
171 {"sessions", SessionStore::getInstance().authTokens},
Zbigniew Kurzynski78158632019-11-05 12:57:37 +0100172 {"auth_config", SessionStore::getInstance().getAuthMethodsConfig()},
Ed Tanous1abe55e2018-09-05 08:30:59 -0700173 {"system_uuid", systemUuid},
174 {"revision", jsonRevision}};
175 persistentFile << data;
176 }
177
178 std::string systemUuid{""};
Ed Tanousba9f9a62017-10-11 16:40:35 -0700179};
180
Ed Tanous1abe55e2018-09-05 08:30:59 -0700181} // namespace persistent_data
182} // namespace crow