| Kowalski, Kamil | 2b7981f | 2018-01-31 13:24:59 +0100 | [diff] [blame] | 1 | #pragma once | 
|  | 2 |  | 
| Ed Tanous | 04e438c | 2020-10-03 08:06:26 -0700 | [diff] [blame] | 3 | #include "logging.hpp" | 
| Ed Tanous | fc76b8a | 2020-09-28 17:21:52 -0700 | [diff] [blame] | 4 | #include "random.hpp" | 
| Ed Tanous | 04e438c | 2020-10-03 08:06:26 -0700 | [diff] [blame] | 5 | #include "utility.hpp" | 
| Ed Tanous | fc76b8a | 2020-09-28 17:21:52 -0700 | [diff] [blame] | 6 |  | 
| James Feist | a68a804 | 2020-04-15 15:46:44 -0700 | [diff] [blame] | 7 | #include <openssl/rand.h> | 
|  | 8 |  | 
| Kowalski, Kamil | 2b7981f | 2018-01-31 13:24:59 +0100 | [diff] [blame] | 9 | #include <boost/container/flat_map.hpp> | 
|  | 10 | #include <boost/uuid/uuid.hpp> | 
|  | 11 | #include <boost/uuid/uuid_generators.hpp> | 
|  | 12 | #include <boost/uuid/uuid_io.hpp> | 
| Ratan Gupta | 12c04ef | 2019-04-03 10:08:11 +0530 | [diff] [blame] | 13 | #include <dbus_singleton.hpp> | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 14 | #include <nlohmann/json.hpp> | 
|  | 15 | #include <pam_authenticate.hpp> | 
| RAJESWARAN THILLAIGOVINDAN | 7052517 | 2019-07-09 13:15:05 -0500 | [diff] [blame] | 16 | #include <sdbusplus/bus/match.hpp> | 
| Ratan Gupta | 12c04ef | 2019-04-03 10:08:11 +0530 | [diff] [blame] | 17 |  | 
| Gunnar Mills | 1214b7e | 2020-06-04 10:11:30 -0500 | [diff] [blame] | 18 | #include <csignal> | 
|  | 19 | #include <random> | 
| Ratan Gupta | 07386c6 | 2019-12-14 14:06:09 +0530 | [diff] [blame] | 20 | #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE | 
|  | 21 | #include <ibm/locks.hpp> | 
|  | 22 | #endif | 
| Kowalski, Kamil | 2b7981f | 2018-01-31 13:24:59 +0100 | [diff] [blame] | 23 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 24 | namespace persistent_data | 
|  | 25 | { | 
| Kowalski, Kamil | 2b7981f | 2018-01-31 13:24:59 +0100 | [diff] [blame] | 26 |  | 
| Ed Tanous | 51dae67 | 2018-09-05 16:07:32 -0700 | [diff] [blame] | 27 | // entropy: 20 characters, 62 possibilities.  log2(62^20) = 119 bits of | 
|  | 28 | // entropy.  OWASP recommends at least 64 | 
|  | 29 | // https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#session-id-entropy | 
|  | 30 | constexpr std::size_t sessionTokenSize = 20; | 
|  | 31 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 32 | enum class PersistenceType | 
|  | 33 | { | 
|  | 34 | TIMEOUT, // User session times out after a predetermined amount of time | 
|  | 35 | SINGLE_REQUEST // User times out once this request is completed. | 
| Kowalski, Kamil | 2b7981f | 2018-01-31 13:24:59 +0100 | [diff] [blame] | 36 | }; | 
|  | 37 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 38 | struct UserSession | 
|  | 39 | { | 
|  | 40 | std::string uniqueId; | 
|  | 41 | std::string sessionToken; | 
|  | 42 | std::string username; | 
|  | 43 | std::string csrfToken; | 
| Sunitha Harish | 08bdcc7 | 2020-05-12 05:17:57 -0500 | [diff] [blame] | 44 | std::string clientId; | 
| Sunitha Harish | 92f6822 | 2020-05-28 05:09:09 -0500 | [diff] [blame] | 45 | std::string clientIp; | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 46 | std::chrono::time_point<std::chrono::steady_clock> lastUpdated; | 
|  | 47 | PersistenceType persistence; | 
| James Feist | f8aa3d2 | 2020-04-08 18:32:33 -0700 | [diff] [blame] | 48 | bool cookieAuth = false; | 
| Joseph Reynolds | 3bf4e63 | 2020-02-06 14:44:32 -0600 | [diff] [blame] | 49 | bool isConfigureSelfOnly = false; | 
|  | 50 |  | 
|  | 51 | // There are two sources of truth for isConfigureSelfOnly: | 
|  | 52 | //  1. When pamAuthenticateUser() returns PAM_NEW_AUTHTOK_REQD. | 
|  | 53 | //  2. D-Bus User.Manager.GetUserInfo property UserPasswordExpired. | 
|  | 54 | // These should be in sync, but the underlying condition can change at any | 
|  | 55 | // time.  For example, a password can expire or be changed outside of | 
|  | 56 | // bmcweb.  The value stored here is updated at the start of each | 
|  | 57 | // operation and used as the truth within bmcweb. | 
| Kowalski, Kamil | 5cef0f7 | 2018-02-15 15:26:51 +0100 | [diff] [blame] | 58 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 59 | /** | 
|  | 60 | * @brief Fills object with data from UserSession's JSON representation | 
|  | 61 | * | 
|  | 62 | * This replaces nlohmann's from_json to ensure no-throw approach | 
|  | 63 | * | 
|  | 64 | * @param[in] j   JSON object from which data should be loaded | 
|  | 65 | * | 
|  | 66 | * @return a shared pointer if data has been loaded properly, nullptr | 
|  | 67 | * otherwise | 
|  | 68 | */ | 
|  | 69 | static std::shared_ptr<UserSession> fromJson(const nlohmann::json& j) | 
|  | 70 | { | 
|  | 71 | std::shared_ptr<UserSession> userSession = | 
|  | 72 | std::make_shared<UserSession>(); | 
|  | 73 | for (const auto& element : j.items()) | 
|  | 74 | { | 
|  | 75 | const std::string* thisValue = | 
|  | 76 | element.value().get_ptr<const std::string*>(); | 
|  | 77 | if (thisValue == nullptr) | 
|  | 78 | { | 
|  | 79 | BMCWEB_LOG_ERROR << "Error reading persistent store.  Property " | 
|  | 80 | << element.key() << " was not of type string"; | 
| Ed Tanous | dc511aa | 2020-10-21 12:33:42 -0700 | [diff] [blame] | 81 | continue; | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 82 | } | 
|  | 83 | if (element.key() == "unique_id") | 
|  | 84 | { | 
|  | 85 | userSession->uniqueId = *thisValue; | 
|  | 86 | } | 
|  | 87 | else if (element.key() == "session_token") | 
|  | 88 | { | 
|  | 89 | userSession->sessionToken = *thisValue; | 
|  | 90 | } | 
|  | 91 | else if (element.key() == "csrf_token") | 
|  | 92 | { | 
|  | 93 | userSession->csrfToken = *thisValue; | 
|  | 94 | } | 
|  | 95 | else if (element.key() == "username") | 
|  | 96 | { | 
|  | 97 | userSession->username = *thisValue; | 
|  | 98 | } | 
| Ed Tanous | dc511aa | 2020-10-21 12:33:42 -0700 | [diff] [blame] | 99 | #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE | 
| Sunitha Harish | 08bdcc7 | 2020-05-12 05:17:57 -0500 | [diff] [blame] | 100 | else if (element.key() == "client_id") | 
|  | 101 | { | 
|  | 102 | userSession->clientId = *thisValue; | 
|  | 103 | } | 
| Ed Tanous | dc511aa | 2020-10-21 12:33:42 -0700 | [diff] [blame] | 104 | #endif | 
| Sunitha Harish | 92f6822 | 2020-05-28 05:09:09 -0500 | [diff] [blame] | 105 | else if (element.key() == "client_ip") | 
|  | 106 | { | 
|  | 107 | userSession->clientIp = *thisValue; | 
|  | 108 | } | 
|  | 109 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 110 | else | 
|  | 111 | { | 
|  | 112 | BMCWEB_LOG_ERROR | 
|  | 113 | << "Got unexpected property reading persistent file: " | 
|  | 114 | << element.key(); | 
| Ed Tanous | dc511aa | 2020-10-21 12:33:42 -0700 | [diff] [blame] | 115 | continue; | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 116 | } | 
|  | 117 | } | 
| Ed Tanous | dc511aa | 2020-10-21 12:33:42 -0700 | [diff] [blame] | 118 | // If any of these fields are missing, we can't restore the session, as | 
|  | 119 | // we don't have enough information.  These 4 fields have been present | 
|  | 120 | // in every version of this file in bmcwebs history, so any file, even | 
|  | 121 | // on upgrade, should have these present | 
|  | 122 | if (userSession->uniqueId.empty() || userSession->username.empty() || | 
|  | 123 | userSession->sessionToken.empty() || userSession->csrfToken.empty()) | 
|  | 124 | { | 
|  | 125 | BMCWEB_LOG_DEBUG << "Session missing required security " | 
|  | 126 | "information, refusing to restore"; | 
|  | 127 | return nullptr; | 
|  | 128 | } | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 129 |  | 
|  | 130 | // For now, sessions that were persisted through a reboot get their idle | 
|  | 131 | // timer reset.  This could probably be overcome with a better | 
|  | 132 | // understanding of wall clock time and steady timer time, possibly | 
|  | 133 | // persisting values with wall clock time instead of steady timer, but | 
|  | 134 | // the tradeoffs of all the corner cases involved are non-trivial, so | 
|  | 135 | // this is done temporarily | 
|  | 136 | userSession->lastUpdated = std::chrono::steady_clock::now(); | 
|  | 137 | userSession->persistence = PersistenceType::TIMEOUT; | 
|  | 138 |  | 
|  | 139 | return userSession; | 
| Kowalski, Kamil | 5cef0f7 | 2018-02-15 15:26:51 +0100 | [diff] [blame] | 140 | } | 
| Kowalski, Kamil | 2b7981f | 2018-01-31 13:24:59 +0100 | [diff] [blame] | 141 | }; | 
|  | 142 |  | 
| Zbigniew Kurzynski | 7815863 | 2019-11-05 12:57:37 +0100 | [diff] [blame] | 143 | struct AuthConfigMethods | 
|  | 144 | { | 
| Alan Kuo | f16f626 | 2020-12-08 19:29:59 +0800 | [diff] [blame] | 145 | #ifdef BMCWEB_ENABLE_BASIC_AUTHENTICATION | 
| Zbigniew Kurzynski | 7815863 | 2019-11-05 12:57:37 +0100 | [diff] [blame] | 146 | bool basic = true; | 
| Alan Kuo | f16f626 | 2020-12-08 19:29:59 +0800 | [diff] [blame] | 147 | #else | 
|  | 148 | bool basic = false; | 
|  | 149 | #endif | 
|  | 150 |  | 
|  | 151 | #ifdef BMCWEB_ENABLE_SESSION_AUTHENTICATION | 
|  | 152 | bool sessionToken = true; | 
|  | 153 | #else | 
|  | 154 | bool sessionToken = false; | 
|  | 155 | #endif | 
|  | 156 |  | 
|  | 157 | #ifdef BMCWEB_ENABLE_XTOKEN_AUTHENTICATION | 
|  | 158 | bool xtoken = true; | 
|  | 159 | #else | 
|  | 160 | bool xtoken = false; | 
|  | 161 | #endif | 
|  | 162 |  | 
|  | 163 | #ifdef BMCWEB_ENABLE_COOKIE_AUTHENTICATION | 
|  | 164 | bool cookie = true; | 
|  | 165 | #else | 
|  | 166 | bool cookie = false; | 
|  | 167 | #endif | 
|  | 168 |  | 
|  | 169 | #ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION | 
|  | 170 | bool tls = true; | 
|  | 171 | #else | 
| Zbigniew Kurzynski | cac94c5 | 2019-11-07 12:55:04 +0100 | [diff] [blame] | 172 | bool tls = false; | 
| Alan Kuo | f16f626 | 2020-12-08 19:29:59 +0800 | [diff] [blame] | 173 | #endif | 
| Zbigniew Kurzynski | 7815863 | 2019-11-05 12:57:37 +0100 | [diff] [blame] | 174 |  | 
|  | 175 | void fromJson(const nlohmann::json& j) | 
|  | 176 | { | 
|  | 177 | for (const auto& element : j.items()) | 
|  | 178 | { | 
|  | 179 | const bool* value = element.value().get_ptr<const bool*>(); | 
|  | 180 | if (value == nullptr) | 
|  | 181 | { | 
|  | 182 | continue; | 
|  | 183 | } | 
|  | 184 |  | 
|  | 185 | if (element.key() == "XToken") | 
|  | 186 | { | 
|  | 187 | xtoken = *value; | 
|  | 188 | } | 
|  | 189 | else if (element.key() == "Cookie") | 
|  | 190 | { | 
|  | 191 | cookie = *value; | 
|  | 192 | } | 
|  | 193 | else if (element.key() == "SessionToken") | 
|  | 194 | { | 
|  | 195 | sessionToken = *value; | 
|  | 196 | } | 
|  | 197 | else if (element.key() == "BasicAuth") | 
|  | 198 | { | 
|  | 199 | basic = *value; | 
|  | 200 | } | 
| Zbigniew Kurzynski | 501f1e5 | 2019-10-02 11:22:11 +0200 | [diff] [blame] | 201 | else if (element.key() == "TLS") | 
|  | 202 | { | 
|  | 203 | tls = *value; | 
|  | 204 | } | 
| Zbigniew Kurzynski | 7815863 | 2019-11-05 12:57:37 +0100 | [diff] [blame] | 205 | } | 
|  | 206 | } | 
|  | 207 | }; | 
|  | 208 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 209 | class SessionStore | 
|  | 210 | { | 
|  | 211 | public: | 
|  | 212 | std::shared_ptr<UserSession> generateUserSession( | 
| Sunitha Harish | d323922 | 2021-02-24 15:33:29 +0530 | [diff] [blame] | 213 | const std::string_view username, const std::string_view clientIp, | 
|  | 214 | const std::string_view clientId, | 
| Joseph Reynolds | 3bf4e63 | 2020-02-06 14:44:32 -0600 | [diff] [blame] | 215 | PersistenceType persistence = PersistenceType::TIMEOUT, | 
| Sunitha Harish | d323922 | 2021-02-24 15:33:29 +0530 | [diff] [blame] | 216 | bool isConfigureSelfOnly = false) | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 217 | { | 
|  | 218 | // TODO(ed) find a secure way to not generate session identifiers if | 
|  | 219 | // persistence is set to SINGLE_REQUEST | 
|  | 220 | static constexpr std::array<char, 62> alphanum = { | 
| Joseph Reynolds | 368b1d4 | 2019-08-15 15:29:06 -0500 | [diff] [blame] | 221 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', | 
|  | 222 | 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', | 
|  | 223 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 224 | 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', | 
|  | 225 | 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; | 
| Kowalski, Kamil | 2b7981f | 2018-01-31 13:24:59 +0100 | [diff] [blame] | 226 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 227 | std::string sessionToken; | 
| Ed Tanous | 51dae67 | 2018-09-05 16:07:32 -0700 | [diff] [blame] | 228 | sessionToken.resize(sessionTokenSize, '0'); | 
| Ed Tanous | 271584a | 2019-07-09 16:24:22 -0700 | [diff] [blame] | 229 | std::uniform_int_distribution<size_t> dist(0, alphanum.size() - 1); | 
| James Feist | a68a804 | 2020-04-15 15:46:44 -0700 | [diff] [blame] | 230 |  | 
| Ed Tanous | fc76b8a | 2020-09-28 17:21:52 -0700 | [diff] [blame] | 231 | bmcweb::OpenSSLGenerator gen; | 
| James Feist | a68a804 | 2020-04-15 15:46:44 -0700 | [diff] [blame] | 232 |  | 
| Ed Tanous | 0dfeda6 | 2019-10-24 11:21:38 -0700 | [diff] [blame] | 233 | for (char& sessionChar : sessionToken) | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 234 | { | 
| Ed Tanous | 0dfeda6 | 2019-10-24 11:21:38 -0700 | [diff] [blame] | 235 | sessionChar = alphanum[dist(gen)]; | 
| James Feist | a68a804 | 2020-04-15 15:46:44 -0700 | [diff] [blame] | 236 | if (gen.error()) | 
|  | 237 | { | 
|  | 238 | return nullptr; | 
|  | 239 | } | 
| Kowalski, Kamil | 2b7981f | 2018-01-31 13:24:59 +0100 | [diff] [blame] | 240 | } | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 241 | // Only need csrf tokens for cookie based auth, token doesn't matter | 
|  | 242 | std::string csrfToken; | 
| Ed Tanous | 51dae67 | 2018-09-05 16:07:32 -0700 | [diff] [blame] | 243 | csrfToken.resize(sessionTokenSize, '0'); | 
| Ed Tanous | 0dfeda6 | 2019-10-24 11:21:38 -0700 | [diff] [blame] | 244 | for (char& csrfChar : csrfToken) | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 245 | { | 
| Ed Tanous | 0dfeda6 | 2019-10-24 11:21:38 -0700 | [diff] [blame] | 246 | csrfChar = alphanum[dist(gen)]; | 
| James Feist | a68a804 | 2020-04-15 15:46:44 -0700 | [diff] [blame] | 247 | if (gen.error()) | 
|  | 248 | { | 
|  | 249 | return nullptr; | 
|  | 250 | } | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 251 | } | 
|  | 252 |  | 
|  | 253 | std::string uniqueId; | 
|  | 254 | uniqueId.resize(10, '0'); | 
| Ed Tanous | 0dfeda6 | 2019-10-24 11:21:38 -0700 | [diff] [blame] | 255 | for (char& uidChar : uniqueId) | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 256 | { | 
| Ed Tanous | 0dfeda6 | 2019-10-24 11:21:38 -0700 | [diff] [blame] | 257 | uidChar = alphanum[dist(gen)]; | 
| James Feist | a68a804 | 2020-04-15 15:46:44 -0700 | [diff] [blame] | 258 | if (gen.error()) | 
|  | 259 | { | 
|  | 260 | return nullptr; | 
|  | 261 | } | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 262 | } | 
| Sunitha Harish | 92f6822 | 2020-05-28 05:09:09 -0500 | [diff] [blame] | 263 | auto session = std::make_shared<UserSession>( | 
|  | 264 | UserSession{uniqueId, sessionToken, std::string(username), | 
|  | 265 | csrfToken, std::string(clientId), std::string(clientIp), | 
|  | 266 | std::chrono::steady_clock::now(), persistence, false, | 
|  | 267 | isConfigureSelfOnly}); | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 268 | auto it = authTokens.emplace(std::make_pair(sessionToken, session)); | 
|  | 269 | // Only need to write to disk if session isn't about to be destroyed. | 
|  | 270 | needWrite = persistence == PersistenceType::TIMEOUT; | 
|  | 271 | return it.first->second; | 
| Kowalski, Kamil | 2b7981f | 2018-01-31 13:24:59 +0100 | [diff] [blame] | 272 | } | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 273 |  | 
|  | 274 | std::shared_ptr<UserSession> | 
| Ed Tanous | 39e7750 | 2019-03-04 17:35:53 -0800 | [diff] [blame] | 275 | loginSessionByToken(const std::string_view token) | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 276 | { | 
|  | 277 | applySessionTimeouts(); | 
| Ed Tanous | 51dae67 | 2018-09-05 16:07:32 -0700 | [diff] [blame] | 278 | if (token.size() != sessionTokenSize) | 
|  | 279 | { | 
|  | 280 | return nullptr; | 
|  | 281 | } | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 282 | auto sessionIt = authTokens.find(std::string(token)); | 
|  | 283 | if (sessionIt == authTokens.end()) | 
|  | 284 | { | 
|  | 285 | return nullptr; | 
|  | 286 | } | 
|  | 287 | std::shared_ptr<UserSession> userSession = sessionIt->second; | 
|  | 288 | userSession->lastUpdated = std::chrono::steady_clock::now(); | 
|  | 289 | return userSession; | 
|  | 290 | } | 
|  | 291 |  | 
| Ed Tanous | 39e7750 | 2019-03-04 17:35:53 -0800 | [diff] [blame] | 292 | std::shared_ptr<UserSession> getSessionByUid(const std::string_view uid) | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 293 | { | 
|  | 294 | applySessionTimeouts(); | 
|  | 295 | // TODO(Ed) this is inefficient | 
|  | 296 | auto sessionIt = authTokens.begin(); | 
|  | 297 | while (sessionIt != authTokens.end()) | 
|  | 298 | { | 
|  | 299 | if (sessionIt->second->uniqueId == uid) | 
|  | 300 | { | 
|  | 301 | return sessionIt->second; | 
|  | 302 | } | 
|  | 303 | sessionIt++; | 
|  | 304 | } | 
|  | 305 | return nullptr; | 
|  | 306 | } | 
|  | 307 |  | 
| Ed Tanous | b5a7693 | 2020-09-29 16:16:58 -0700 | [diff] [blame] | 308 | void removeSession(const std::shared_ptr<UserSession>& session) | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 309 | { | 
| Ratan Gupta | 07386c6 | 2019-12-14 14:06:09 +0530 | [diff] [blame] | 310 | #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE | 
|  | 311 | crow::ibm_mc_lock::Lock::getInstance().releaseLock(session->uniqueId); | 
|  | 312 | #endif | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 313 | authTokens.erase(session->sessionToken); | 
|  | 314 | needWrite = true; | 
|  | 315 | } | 
|  | 316 |  | 
|  | 317 | std::vector<const std::string*> getUniqueIds( | 
|  | 318 | bool getAll = true, | 
|  | 319 | const PersistenceType& type = PersistenceType::SINGLE_REQUEST) | 
|  | 320 | { | 
|  | 321 | applySessionTimeouts(); | 
|  | 322 |  | 
|  | 323 | std::vector<const std::string*> ret; | 
|  | 324 | ret.reserve(authTokens.size()); | 
|  | 325 | for (auto& session : authTokens) | 
|  | 326 | { | 
|  | 327 | if (getAll || type == session.second->persistence) | 
|  | 328 | { | 
|  | 329 | ret.push_back(&session.second->uniqueId); | 
|  | 330 | } | 
|  | 331 | } | 
|  | 332 | return ret; | 
|  | 333 | } | 
|  | 334 |  | 
| Zbigniew Kurzynski | 7815863 | 2019-11-05 12:57:37 +0100 | [diff] [blame] | 335 | void updateAuthMethodsConfig(const AuthConfigMethods& config) | 
|  | 336 | { | 
| Zbigniew Kurzynski | 009c2a4 | 2019-11-14 13:37:15 +0100 | [diff] [blame] | 337 | bool isTLSchanged = (authMethodsConfig.tls != config.tls); | 
| Zbigniew Kurzynski | 7815863 | 2019-11-05 12:57:37 +0100 | [diff] [blame] | 338 | authMethodsConfig = config; | 
|  | 339 | needWrite = true; | 
| Zbigniew Kurzynski | 009c2a4 | 2019-11-14 13:37:15 +0100 | [diff] [blame] | 340 | if (isTLSchanged) | 
|  | 341 | { | 
|  | 342 | // recreate socket connections with new settings | 
|  | 343 | std::raise(SIGHUP); | 
|  | 344 | } | 
| Zbigniew Kurzynski | 7815863 | 2019-11-05 12:57:37 +0100 | [diff] [blame] | 345 | } | 
|  | 346 |  | 
|  | 347 | AuthConfigMethods& getAuthMethodsConfig() | 
|  | 348 | { | 
|  | 349 | return authMethodsConfig; | 
|  | 350 | } | 
|  | 351 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 352 | bool needsWrite() | 
|  | 353 | { | 
|  | 354 | return needWrite; | 
|  | 355 | } | 
| Ed Tanous | 271584a | 2019-07-09 16:24:22 -0700 | [diff] [blame] | 356 | int64_t getTimeoutInSeconds() const | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 357 | { | 
| Manojkiran Eda | f2a4a60 | 2020-08-27 16:04:26 +0530 | [diff] [blame] | 358 | return std::chrono::seconds(timeoutInSeconds).count(); | 
|  | 359 | } | 
|  | 360 |  | 
|  | 361 | void updateSessionTimeout(std::chrono::seconds newTimeoutInSeconds) | 
|  | 362 | { | 
|  | 363 | timeoutInSeconds = newTimeoutInSeconds; | 
|  | 364 | needWrite = true; | 
| Ed Tanous | 23a21a1 | 2020-07-25 04:45:05 +0000 | [diff] [blame] | 365 | } | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 366 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 367 | static SessionStore& getInstance() | 
|  | 368 | { | 
|  | 369 | static SessionStore sessionStore; | 
|  | 370 | return sessionStore; | 
|  | 371 | } | 
|  | 372 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 373 | void applySessionTimeouts() | 
|  | 374 | { | 
|  | 375 | auto timeNow = std::chrono::steady_clock::now(); | 
| Manojkiran Eda | f2a4a60 | 2020-08-27 16:04:26 +0530 | [diff] [blame] | 376 | if (timeNow - lastTimeoutUpdate > std::chrono::seconds(1)) | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 377 | { | 
|  | 378 | lastTimeoutUpdate = timeNow; | 
|  | 379 | auto authTokensIt = authTokens.begin(); | 
|  | 380 | while (authTokensIt != authTokens.end()) | 
|  | 381 | { | 
|  | 382 | if (timeNow - authTokensIt->second->lastUpdated >= | 
| Manojkiran Eda | f2a4a60 | 2020-08-27 16:04:26 +0530 | [diff] [blame] | 383 | timeoutInSeconds) | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 384 | { | 
| Ratan Gupta | 07386c6 | 2019-12-14 14:06:09 +0530 | [diff] [blame] | 385 | #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE | 
|  | 386 | crow::ibm_mc_lock::Lock::getInstance().releaseLock( | 
|  | 387 | authTokensIt->second->uniqueId); | 
|  | 388 | #endif | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 389 | authTokensIt = authTokens.erase(authTokensIt); | 
| Ratan Gupta | 07386c6 | 2019-12-14 14:06:09 +0530 | [diff] [blame] | 390 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 391 | needWrite = true; | 
|  | 392 | } | 
|  | 393 | else | 
|  | 394 | { | 
|  | 395 | authTokensIt++; | 
|  | 396 | } | 
|  | 397 | } | 
|  | 398 | } | 
|  | 399 | } | 
| Gunnar Mills | 83cf818 | 2020-11-11 15:37:34 -0600 | [diff] [blame] | 400 |  | 
|  | 401 | SessionStore(const SessionStore&) = delete; | 
|  | 402 | SessionStore& operator=(const SessionStore&) = delete; | 
|  | 403 |  | 
|  | 404 | std::unordered_map<std::string, std::shared_ptr<UserSession>, | 
|  | 405 | std::hash<std::string>, | 
|  | 406 | crow::utility::ConstantTimeCompare> | 
|  | 407 | authTokens; | 
|  | 408 |  | 
|  | 409 | std::chrono::time_point<std::chrono::steady_clock> lastTimeoutUpdate; | 
|  | 410 | bool needWrite{false}; | 
|  | 411 | std::chrono::seconds timeoutInSeconds; | 
|  | 412 | AuthConfigMethods authMethodsConfig; | 
|  | 413 |  | 
|  | 414 | private: | 
|  | 415 | SessionStore() : timeoutInSeconds(3600) | 
|  | 416 | {} | 
| Kowalski, Kamil | 2b7981f | 2018-01-31 13:24:59 +0100 | [diff] [blame] | 417 | }; | 
|  | 418 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 419 | } // namespace persistent_data |