blob: 038fcc612df9ed862bfa41335141196f1dfeb640 [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>
Ed Tanous1abe55e2018-09-05 08:30:59 -070011#include <nlohmann/json.hpp>
12#include <pam_authenticate.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070013#include <sessions.hpp>
Ed Tanousba9f9a62017-10-11 16:40:35 -070014
Gunnar Mills1214b7e2020-06-04 10:11:30 -050015#include <filesystem>
James Feist3909dc82020-04-03 10:58:55 -070016#include <fstream>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050017#include <random>
18
Ed Tanous1abe55e2018-09-05 08:30:59 -070019namespace persistent_data
20{
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010021
Ed Tanous52cc1122020-07-18 13:51:21 -070022class ConfigFile
Ed Tanous1abe55e2018-09-05 08:30:59 -070023{
Ed Tanous271584a2019-07-09 16:24:22 -070024 uint64_t jsonRevision = 1;
Ed Tanousc963aa42017-10-27 16:00:19 -070025
Ed Tanous1abe55e2018-09-05 08:30:59 -070026 public:
Ratan Gupta845cb7d2019-07-12 00:32:25 +053027 // todo(ed) should read this from a fixed location somewhere, not CWD
28 static constexpr const char* filename = "bmcweb_persistent_data.json";
29
Ed Tanous52cc1122020-07-18 13:51:21 -070030 ConfigFile()
Ed Tanous1abe55e2018-09-05 08:30:59 -070031 {
32 readData();
Ed Tanousc963aa42017-10-27 16:00:19 -070033 }
Ed Tanousc963aa42017-10-27 16:00:19 -070034
Ed Tanous52cc1122020-07-18 13:51:21 -070035 ~ConfigFile()
Ed Tanous1abe55e2018-09-05 08:30:59 -070036 {
37 if (persistent_data::SessionStore::getInstance().needsWrite())
38 {
39 writeData();
Kowalski, Kamil5cef0f72018-02-15 15:26:51 +010040 }
Ed Tanousc963aa42017-10-27 16:00:19 -070041 }
Ed Tanousc963aa42017-10-27 16:00:19 -070042
Ed Tanous1abe55e2018-09-05 08:30:59 -070043 // TODO(ed) this should really use protobuf, or some other serialization
44 // library, but adding another dependency is somewhat outside the scope of
45 // this application for the moment
46 void readData()
47 {
48 std::ifstream persistentFile(filename);
Ed Tanous271584a2019-07-09 16:24:22 -070049 uint64_t fileRevision = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -070050 if (persistentFile.is_open())
51 {
52 // call with exceptions disabled
53 auto data = nlohmann::json::parse(persistentFile, nullptr, false);
54 if (data.is_discarded())
55 {
56 BMCWEB_LOG_ERROR
57 << "Error parsing persistent data in json file.";
58 }
59 else
60 {
61 for (const auto& item : data.items())
62 {
63 if (item.key() == "revision")
64 {
65 fileRevision = 0;
66
67 const uint64_t* uintPtr =
68 item.value().get_ptr<const uint64_t*>();
69 if (uintPtr == nullptr)
70 {
71 BMCWEB_LOG_ERROR << "Failed to read revision flag";
72 }
73 else
74 {
75 fileRevision = *uintPtr;
76 }
77 }
78 else if (item.key() == "system_uuid")
79 {
80 const std::string* jSystemUuid =
81 item.value().get_ptr<const std::string*>();
82 if (jSystemUuid != nullptr)
83 {
84 systemUuid = *jSystemUuid;
85 }
86 }
Zbigniew Kurzynski78158632019-11-05 12:57:37 +010087 else if (item.key() == "auth_config")
88 {
89 SessionStore::getInstance()
90 .getAuthMethodsConfig()
91 .fromJson(item.value());
92 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070093 else if (item.key() == "sessions")
94 {
95 for (const auto& elem : item.value())
96 {
97 std::shared_ptr<UserSession> newSession =
98 UserSession::fromJson(elem);
99
100 if (newSession == nullptr)
101 {
102 BMCWEB_LOG_ERROR << "Problem reading session "
103 "from persistent store";
104 continue;
105 }
106
107 BMCWEB_LOG_DEBUG
108 << "Restored session: " << newSession->csrfToken
109 << " " << newSession->uniqueId << " "
110 << newSession->sessionToken;
111 SessionStore::getInstance().authTokens.emplace(
112 newSession->sessionToken, newSession);
113 }
114 }
Manojkiran Edaf2a4a602020-08-27 16:04:26 +0530115 else if (item.key() == "timeout")
116 {
117 const int64_t* jTimeout =
118 item.value().get_ptr<int64_t*>();
119 if (jTimeout == nullptr)
120 {
121 BMCWEB_LOG_DEBUG
122 << "Problem reading session timeout value";
123 continue;
124 }
125 std::chrono::seconds sessionTimeoutInseconds(*jTimeout);
126 BMCWEB_LOG_DEBUG << "Restored Session Timeout: "
127 << sessionTimeoutInseconds.count();
128 SessionStore::getInstance().updateSessionTimeout(
129 sessionTimeoutInseconds);
130 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700131 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
Ed Tanous52cc1122020-07-18 13:51:21 -0700166 std::filesystem::perms permission =
167 std::filesystem::perms::owner_read |
168 std::filesystem::perms::owner_write |
169 std::filesystem::perms::group_read;
170 std::filesystem::permissions(filename, permission);
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700171 const auto& c = SessionStore::getInstance().getAuthMethodsConfig();
Ed Tanousdc511aa2020-10-21 12:33:42 -0700172 nlohmann::json data{
173 {"auth_config",
174 {{"XToken", c.xtoken},
175 {"Cookie", c.cookie},
176 {"SessionToken", c.sessionToken},
177 {"BasicAuth", c.basic},
178 {"TLS", c.tls}}
Ratan Gupta845cb7d2019-07-12 00:32:25 +0530179
Ed Tanousdc511aa2020-10-21 12:33:42 -0700180 },
181 {"system_uuid", systemUuid},
182 {"revision", jsonRevision},
183 {"timeout", SessionStore::getInstance().getTimeoutInSeconds()}};
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700184
185 nlohmann::json& sessions = data["sessions"];
186 sessions = nlohmann::json::array();
187 for (const auto& p : SessionStore::getInstance().authTokens)
188 {
189 if (p.second->persistence !=
190 persistent_data::PersistenceType::SINGLE_REQUEST)
191 {
192 sessions.push_back({
193 {"unique_id", p.second->uniqueId},
194 {"session_token", p.second->sessionToken},
195 {"username", p.second->username},
196 {"csrf_token", p.second->csrfToken},
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700197#ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
198 {"client_id", p.second->clientId},
199#endif
200 });
201 }
202 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700203 persistentFile << data;
204 }
205
206 std::string systemUuid{""};
Ed Tanousba9f9a62017-10-11 16:40:35 -0700207};
208
Ed Tanous52cc1122020-07-18 13:51:21 -0700209inline ConfigFile& getConfig()
210{
211 static ConfigFile f;
212 return f;
213}
214
Ed Tanous1abe55e2018-09-05 08:30:59 -0700215} // namespace persistent_data