blob: 19c424a2025b4e5a102f4061d95cfacca1cbea9d [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 {
36 if (persistent_data::SessionStore::getInstance().needsWrite())
37 {
38 writeData();
Kowalski, Kamil5cef0f72018-02-15 15:26:51 +010039 }
Ed Tanousc963aa42017-10-27 16:00:19 -070040 }
Ed Tanousc963aa42017-10-27 16:00:19 -070041
Ed Tanous1abe55e2018-09-05 08:30:59 -070042 // TODO(ed) this should really use protobuf, or some other serialization
43 // library, but adding another dependency is somewhat outside the scope of
44 // this application for the moment
45 void readData()
46 {
47 std::ifstream persistentFile(filename);
Ed Tanous271584a2019-07-09 16:24:22 -070048 uint64_t fileRevision = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 if (persistentFile.is_open())
50 {
51 // call with exceptions disabled
52 auto data = nlohmann::json::parse(persistentFile, nullptr, false);
53 if (data.is_discarded())
54 {
55 BMCWEB_LOG_ERROR
56 << "Error parsing persistent data in json file.";
57 }
58 else
59 {
60 for (const auto& item : data.items())
61 {
62 if (item.key() == "revision")
63 {
64 fileRevision = 0;
65
66 const uint64_t* uintPtr =
67 item.value().get_ptr<const uint64_t*>();
68 if (uintPtr == nullptr)
69 {
70 BMCWEB_LOG_ERROR << "Failed to read revision flag";
71 }
72 else
73 {
74 fileRevision = *uintPtr;
75 }
76 }
77 else if (item.key() == "system_uuid")
78 {
79 const std::string* jSystemUuid =
80 item.value().get_ptr<const std::string*>();
81 if (jSystemUuid != nullptr)
82 {
83 systemUuid = *jSystemUuid;
84 }
85 }
Zbigniew Kurzynski78158632019-11-05 12:57:37 +010086 else if (item.key() == "auth_config")
87 {
88 SessionStore::getInstance()
89 .getAuthMethodsConfig()
90 .fromJson(item.value());
91 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070092 else if (item.key() == "sessions")
93 {
94 for (const auto& elem : item.value())
95 {
96 std::shared_ptr<UserSession> newSession =
97 UserSession::fromJson(elem);
98
99 if (newSession == nullptr)
100 {
101 BMCWEB_LOG_ERROR << "Problem reading session "
102 "from persistent store";
103 continue;
104 }
105
106 BMCWEB_LOG_DEBUG
107 << "Restored session: " << newSession->csrfToken
108 << " " << newSession->uniqueId << " "
109 << newSession->sessionToken;
110 SessionStore::getInstance().authTokens.emplace(
111 newSession->sessionToken, newSession);
112 }
113 }
Manojkiran Edaf2a4a602020-08-27 16:04:26 +0530114 else if (item.key() == "timeout")
115 {
116 const int64_t* jTimeout =
117 item.value().get_ptr<int64_t*>();
118 if (jTimeout == nullptr)
119 {
120 BMCWEB_LOG_DEBUG
121 << "Problem reading session timeout value";
122 continue;
123 }
124 std::chrono::seconds sessionTimeoutInseconds(*jTimeout);
125 BMCWEB_LOG_DEBUG << "Restored Session Timeout: "
126 << sessionTimeoutInseconds.count();
127 SessionStore::getInstance().updateSessionTimeout(
128 sessionTimeoutInseconds);
129 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 else
131 {
132 // Do nothing in the case of extra fields. We may have
133 // cases where fields are added in the future, and we
134 // want to at least attempt to gracefully support
135 // downgrades in that case, even if we don't officially
136 // support it
137 }
138 }
139 }
140 }
141 bool needWrite = false;
142
143 if (systemUuid.empty())
144 {
145 systemUuid =
146 boost::uuids::to_string(boost::uuids::random_generator()());
147 needWrite = true;
148 }
149 if (fileRevision < jsonRevision)
150 {
151 needWrite = true;
152 }
153 // write revision changes or system uuid changes immediately
154 if (needWrite)
155 {
156 writeData();
157 }
158 }
159
160 void writeData()
161 {
162 std::ofstream persistentFile(filename);
Ratan Gupta845cb7d2019-07-12 00:32:25 +0530163
164 // set the permission of the file to 640
Ed Tanous52cc1122020-07-18 13:51:21 -0700165 std::filesystem::perms permission =
166 std::filesystem::perms::owner_read |
167 std::filesystem::perms::owner_write |
168 std::filesystem::perms::group_read;
169 std::filesystem::permissions(filename, permission);
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700170 const auto& c = SessionStore::getInstance().getAuthMethodsConfig();
Ed Tanousdc511aa2020-10-21 12:33:42 -0700171 nlohmann::json data{
172 {"auth_config",
173 {{"XToken", c.xtoken},
174 {"Cookie", c.cookie},
175 {"SessionToken", c.sessionToken},
176 {"BasicAuth", c.basic},
177 {"TLS", c.tls}}
Ratan Gupta845cb7d2019-07-12 00:32:25 +0530178
Ed Tanousdc511aa2020-10-21 12:33:42 -0700179 },
180 {"system_uuid", systemUuid},
181 {"revision", jsonRevision},
182 {"timeout", SessionStore::getInstance().getTimeoutInSeconds()}};
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700183
184 nlohmann::json& sessions = data["sessions"];
185 sessions = nlohmann::json::array();
186 for (const auto& p : SessionStore::getInstance().authTokens)
187 {
188 if (p.second->persistence !=
189 persistent_data::PersistenceType::SINGLE_REQUEST)
190 {
191 sessions.push_back({
192 {"unique_id", p.second->uniqueId},
193 {"session_token", p.second->sessionToken},
194 {"username", p.second->username},
195 {"csrf_token", p.second->csrfToken},
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700196#ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
197 {"client_id", p.second->clientId},
198#endif
199 });
200 }
201 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700202 persistentFile << data;
203 }
204
205 std::string systemUuid{""};
Ed Tanousba9f9a62017-10-11 16:40:35 -0700206};
207
Ed Tanous52cc1122020-07-18 13:51:21 -0700208inline ConfigFile& getConfig()
209{
210 static ConfigFile f;
211 return f;
212}
213
Ed Tanous1abe55e2018-09-05 08:30:59 -0700214} // namespace persistent_data