blob: 24f7afd46013cb52085fb9d4c91f570d4335a225 [file] [log] [blame]
Ed Tanousba9f9a62017-10-11 16:40:35 -07001#pragma once
2
Ed Tanous04e438c2020-10-03 08:06:26 -07003#include <app.hpp>
Ed Tanousba9f9a62017-10-11 16:40:35 -07004#include <boost/container/flat_map.hpp>
5#include <boost/uuid/uuid.hpp>
6#include <boost/uuid/uuid_generators.hpp>
7#include <boost/uuid/uuid_io.hpp>
Ed Tanous04e438c2020-10-03 08:06:26 -07008#include <http_request.hpp>
9#include <http_response.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070010#include <nlohmann/json.hpp>
11#include <pam_authenticate.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070012#include <sessions.hpp>
Ed Tanousba9f9a62017-10-11 16:40:35 -070013
Gunnar Mills1214b7e2020-06-04 10:11:30 -050014#include <filesystem>
James Feist3909dc82020-04-03 10:58:55 -070015#include <fstream>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050016#include <random>
17
Ed Tanous1abe55e2018-09-05 08:30:59 -070018namespace persistent_data
19{
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010020
Ed Tanous52cc1122020-07-18 13:51:21 -070021class ConfigFile
Ed Tanous1abe55e2018-09-05 08:30:59 -070022{
Ed Tanous271584a2019-07-09 16:24:22 -070023 uint64_t jsonRevision = 1;
Ed Tanousc963aa42017-10-27 16:00:19 -070024
Ed Tanous1abe55e2018-09-05 08:30:59 -070025 public:
Ratan Gupta845cb7d2019-07-12 00:32:25 +053026 // todo(ed) should read this from a fixed location somewhere, not CWD
27 static constexpr const char* filename = "bmcweb_persistent_data.json";
28
Ed Tanous52cc1122020-07-18 13:51:21 -070029 ConfigFile()
Ed Tanous1abe55e2018-09-05 08:30:59 -070030 {
31 readData();
Ed Tanousc963aa42017-10-27 16:00:19 -070032 }
Ed Tanousc963aa42017-10-27 16:00:19 -070033
Ed Tanous52cc1122020-07-18 13:51:21 -070034 ~ConfigFile()
Ed Tanous1abe55e2018-09-05 08:30:59 -070035 {
Gunnar Mills83cf8182020-11-11 15:37:34 -060036 // Make sure we aren't writing stale sessions
37 persistent_data::SessionStore::getInstance().applySessionTimeouts();
Ed Tanous1abe55e2018-09-05 08:30:59 -070038 if (persistent_data::SessionStore::getInstance().needsWrite())
39 {
40 writeData();
Kowalski, Kamil5cef0f72018-02-15 15:26:51 +010041 }
Ed Tanousc963aa42017-10-27 16:00:19 -070042 }
Ed Tanousc963aa42017-10-27 16:00:19 -070043
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 // TODO(ed) this should really use protobuf, or some other serialization
45 // library, but adding another dependency is somewhat outside the scope of
46 // this application for the moment
47 void readData()
48 {
49 std::ifstream persistentFile(filename);
Ed Tanous271584a2019-07-09 16:24:22 -070050 uint64_t fileRevision = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -070051 if (persistentFile.is_open())
52 {
53 // call with exceptions disabled
54 auto data = nlohmann::json::parse(persistentFile, nullptr, false);
55 if (data.is_discarded())
56 {
57 BMCWEB_LOG_ERROR
58 << "Error parsing persistent data in json file.";
59 }
60 else
61 {
62 for (const auto& item : data.items())
63 {
64 if (item.key() == "revision")
65 {
66 fileRevision = 0;
67
68 const uint64_t* uintPtr =
69 item.value().get_ptr<const uint64_t*>();
70 if (uintPtr == nullptr)
71 {
72 BMCWEB_LOG_ERROR << "Failed to read revision flag";
73 }
74 else
75 {
76 fileRevision = *uintPtr;
77 }
78 }
79 else if (item.key() == "system_uuid")
80 {
81 const std::string* jSystemUuid =
82 item.value().get_ptr<const std::string*>();
83 if (jSystemUuid != nullptr)
84 {
85 systemUuid = *jSystemUuid;
86 }
87 }
Zbigniew Kurzynski78158632019-11-05 12:57:37 +010088 else if (item.key() == "auth_config")
89 {
90 SessionStore::getInstance()
91 .getAuthMethodsConfig()
92 .fromJson(item.value());
93 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070094 else if (item.key() == "sessions")
95 {
96 for (const auto& elem : item.value())
97 {
98 std::shared_ptr<UserSession> newSession =
99 UserSession::fromJson(elem);
100
101 if (newSession == nullptr)
102 {
103 BMCWEB_LOG_ERROR << "Problem reading session "
104 "from persistent store";
105 continue;
106 }
107
108 BMCWEB_LOG_DEBUG
109 << "Restored session: " << newSession->csrfToken
110 << " " << newSession->uniqueId << " "
111 << newSession->sessionToken;
112 SessionStore::getInstance().authTokens.emplace(
113 newSession->sessionToken, newSession);
114 }
115 }
Manojkiran Edaf2a4a602020-08-27 16:04:26 +0530116 else if (item.key() == "timeout")
117 {
118 const int64_t* jTimeout =
119 item.value().get_ptr<int64_t*>();
120 if (jTimeout == nullptr)
121 {
122 BMCWEB_LOG_DEBUG
123 << "Problem reading session timeout value";
124 continue;
125 }
126 std::chrono::seconds sessionTimeoutInseconds(*jTimeout);
127 BMCWEB_LOG_DEBUG << "Restored Session Timeout: "
128 << sessionTimeoutInseconds.count();
129 SessionStore::getInstance().updateSessionTimeout(
130 sessionTimeoutInseconds);
131 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132 else
133 {
134 // Do nothing in the case of extra fields. We may have
135 // cases where fields are added in the future, and we
136 // want to at least attempt to gracefully support
137 // downgrades in that case, even if we don't officially
138 // support it
139 }
140 }
141 }
142 }
143 bool needWrite = false;
144
145 if (systemUuid.empty())
146 {
147 systemUuid =
148 boost::uuids::to_string(boost::uuids::random_generator()());
149 needWrite = true;
150 }
151 if (fileRevision < jsonRevision)
152 {
153 needWrite = true;
154 }
155 // write revision changes or system uuid changes immediately
156 if (needWrite)
157 {
158 writeData();
159 }
160 }
161
162 void writeData()
163 {
164 std::ofstream persistentFile(filename);
Ratan Gupta845cb7d2019-07-12 00:32:25 +0530165
166 // set the permission of the file to 640
Ed Tanous52cc1122020-07-18 13:51:21 -0700167 std::filesystem::perms permission =
168 std::filesystem::perms::owner_read |
169 std::filesystem::perms::owner_write |
170 std::filesystem::perms::group_read;
171 std::filesystem::permissions(filename, permission);
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700172 const auto& c = SessionStore::getInstance().getAuthMethodsConfig();
Ed Tanousdc511aa2020-10-21 12:33:42 -0700173 nlohmann::json data{
174 {"auth_config",
175 {{"XToken", c.xtoken},
176 {"Cookie", c.cookie},
177 {"SessionToken", c.sessionToken},
178 {"BasicAuth", c.basic},
179 {"TLS", c.tls}}
Ratan Gupta845cb7d2019-07-12 00:32:25 +0530180
Ed Tanousdc511aa2020-10-21 12:33:42 -0700181 },
182 {"system_uuid", systemUuid},
183 {"revision", jsonRevision},
184 {"timeout", SessionStore::getInstance().getTimeoutInSeconds()}};
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700185
186 nlohmann::json& sessions = data["sessions"];
187 sessions = nlohmann::json::array();
188 for (const auto& p : SessionStore::getInstance().authTokens)
189 {
190 if (p.second->persistence !=
191 persistent_data::PersistenceType::SINGLE_REQUEST)
192 {
193 sessions.push_back({
194 {"unique_id", p.second->uniqueId},
195 {"session_token", p.second->sessionToken},
196 {"username", p.second->username},
197 {"csrf_token", p.second->csrfToken},
Sunitha Harishc0ea7ae2020-10-30 02:37:30 -0500198 {"client_ip", p.second->clientIp},
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700199#ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
200 {"client_id", p.second->clientId},
201#endif
202 });
203 }
204 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700205 persistentFile << data;
206 }
207
208 std::string systemUuid{""};
Ed Tanousba9f9a62017-10-11 16:40:35 -0700209};
210
Ed Tanous52cc1122020-07-18 13:51:21 -0700211inline ConfigFile& getConfig()
212{
213 static ConfigFile f;
214 return f;
215}
216
Ed Tanous1abe55e2018-09-05 08:30:59 -0700217} // namespace persistent_data