140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
32b7981f6SKowalski, Kamil #pragma once
42b7981f6SKowalski, Kamil
5d7857201SEd Tanous #include "bmcweb_config.h"
6d7857201SEd Tanous
704e438cbSEd Tanous #include "logging.hpp"
82c6ffdb0SEd Tanous #include "ossl_random.hpp"
93ccb3adbSEd Tanous #include "utils/ip_utils.hpp"
10fc76b8acSEd Tanous
11d7857201SEd Tanous #include <boost/asio/ip/address.hpp>
121abe55efSEd Tanous #include <nlohmann/json.hpp>
1312c04ef5SRatan Gupta
14d7857201SEd Tanous #include <chrono>
151214b7e7SGunnar Mills #include <csignal>
16d7857201SEd Tanous #include <cstddef>
17d7857201SEd Tanous #include <cstdint>
18d7857201SEd Tanous #include <functional>
1989cda63dSEd Tanous #include <memory>
20bb759e3aSEd Tanous #include <optional>
21b7f3a82bSEd Tanous #include <string>
22d7857201SEd Tanous #include <string_view>
23d7857201SEd Tanous #include <unordered_map>
2489cda63dSEd Tanous #include <vector>
252b7981f6SKowalski, Kamil
261abe55efSEd Tanous namespace persistent_data
271abe55efSEd Tanous {
282b7981f6SKowalski, Kamil
2951dae67dSEd Tanous // entropy: 20 characters, 62 possibilities. log2(62^20) = 119 bits of
3051dae67dSEd Tanous // entropy. OWASP recommends at least 64
3151dae67dSEd Tanous // https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#session-id-entropy
3251dae67dSEd Tanous constexpr std::size_t sessionTokenSize = 20;
3351dae67dSEd Tanous
3489cda63dSEd Tanous enum class SessionType
351abe55efSEd Tanous {
3689cda63dSEd Tanous None,
3789cda63dSEd Tanous Basic,
3889cda63dSEd Tanous Session,
3989cda63dSEd Tanous Cookie,
4089cda63dSEd Tanous MutualTLS
412b7981f6SKowalski, Kamil };
422b7981f6SKowalski, Kamil
431abe55efSEd Tanous struct UserSession
441abe55efSEd Tanous {
4555c7b7a2SEd Tanous std::string uniqueId;
4655c7b7a2SEd Tanous std::string sessionToken;
472b7981f6SKowalski, Kamil std::string username;
4855c7b7a2SEd Tanous std::string csrfToken;
49bb759e3aSEd Tanous std::optional<std::string> clientId;
5092f68223SSunitha Harish std::string clientIp;
5155c7b7a2SEd Tanous std::chrono::time_point<std::chrono::steady_clock> lastUpdated;
5289cda63dSEd Tanous SessionType sessionType{SessionType::None};
537e9c08edSEd Tanous bool cookieAuth = false;
543bf4e632SJoseph Reynolds bool isConfigureSelfOnly = false;
5547f2934cSEd Tanous std::string userRole;
5647f2934cSEd Tanous std::vector<std::string> userGroups;
573bf4e632SJoseph Reynolds
583bf4e632SJoseph Reynolds // There are two sources of truth for isConfigureSelfOnly:
593bf4e632SJoseph Reynolds // 1. When pamAuthenticateUser() returns PAM_NEW_AUTHTOK_REQD.
603bf4e632SJoseph Reynolds // 2. D-Bus User.Manager.GetUserInfo property UserPasswordExpired.
613bf4e632SJoseph Reynolds // These should be in sync, but the underlying condition can change at any
623bf4e632SJoseph Reynolds // time. For example, a password can expire or be changed outside of
633bf4e632SJoseph Reynolds // bmcweb. The value stored here is updated at the start of each
643bf4e632SJoseph Reynolds // operation and used as the truth within bmcweb.
655cef0f7dSKowalski, Kamil
665cef0f7dSKowalski, Kamil /**
675cef0f7dSKowalski, Kamil * @brief Fills object with data from UserSession's JSON representation
685cef0f7dSKowalski, Kamil *
695cef0f7dSKowalski, Kamil * This replaces nlohmann's from_json to ensure no-throw approach
705cef0f7dSKowalski, Kamil *
715cef0f7dSKowalski, Kamil * @param[in] j JSON object from which data should be loaded
725cef0f7dSKowalski, Kamil *
73a434f2bdSEd Tanous * @return a shared pointer if data has been loaded properly, nullptr
74a434f2bdSEd Tanous * otherwise
755cef0f7dSKowalski, Kamil */
fromJsonpersistent_data::UserSession76504af5a0SPatrick Williams static std::shared_ptr<UserSession> fromJson(
77504af5a0SPatrick Williams const nlohmann::json::object_t& j)
781abe55efSEd Tanous {
791abe55efSEd Tanous std::shared_ptr<UserSession> userSession =
801abe55efSEd Tanous std::make_shared<UserSession>();
810bdda665SEd Tanous for (const auto& element : j)
821abe55efSEd Tanous {
83e1ae5338SEd Tanous const std::string* thisValue =
840bdda665SEd Tanous element.second.get_ptr<const std::string*>();
851abe55efSEd Tanous if (thisValue == nullptr)
861abe55efSEd Tanous {
8762598e31SEd Tanous BMCWEB_LOG_ERROR(
8862598e31SEd Tanous "Error reading persistent store. Property {} was not of type string",
890bdda665SEd Tanous element.first);
90dc511aa7SEd Tanous continue;
91e1ae5338SEd Tanous }
920bdda665SEd Tanous if (element.first == "unique_id")
931abe55efSEd Tanous {
9455c7b7a2SEd Tanous userSession->uniqueId = *thisValue;
951abe55efSEd Tanous }
960bdda665SEd Tanous else if (element.first == "session_token")
971abe55efSEd Tanous {
9855c7b7a2SEd Tanous userSession->sessionToken = *thisValue;
991abe55efSEd Tanous }
1000bdda665SEd Tanous else if (element.first == "csrf_token")
1011abe55efSEd Tanous {
10255c7b7a2SEd Tanous userSession->csrfToken = *thisValue;
1031abe55efSEd Tanous }
1040bdda665SEd Tanous else if (element.first == "username")
1051abe55efSEd Tanous {
106e1ae5338SEd Tanous userSession->username = *thisValue;
1071abe55efSEd Tanous }
1080bdda665SEd Tanous else if (element.first == "client_id")
10908bdcc71SSunitha Harish {
11008bdcc71SSunitha Harish userSession->clientId = *thisValue;
11108bdcc71SSunitha Harish }
1120bdda665SEd Tanous else if (element.first == "client_ip")
11392f68223SSunitha Harish {
11492f68223SSunitha Harish userSession->clientIp = *thisValue;
11592f68223SSunitha Harish }
11692f68223SSunitha Harish
1171abe55efSEd Tanous else
1181abe55efSEd Tanous {
11962598e31SEd Tanous BMCWEB_LOG_ERROR(
12062598e31SEd Tanous "Got unexpected property reading persistent file: {}",
1210bdda665SEd Tanous element.first);
122dc511aa7SEd Tanous continue;
123e1ae5338SEd Tanous }
1245cef0f7dSKowalski, Kamil }
125dc511aa7SEd Tanous // If any of these fields are missing, we can't restore the session, as
126dc511aa7SEd Tanous // we don't have enough information. These 4 fields have been present
127dc511aa7SEd Tanous // in every version of this file in bmcwebs history, so any file, even
128dc511aa7SEd Tanous // on upgrade, should have these present
129dc511aa7SEd Tanous if (userSession->uniqueId.empty() || userSession->username.empty() ||
130dc511aa7SEd Tanous userSession->sessionToken.empty() || userSession->csrfToken.empty())
131dc511aa7SEd Tanous {
13262598e31SEd Tanous BMCWEB_LOG_DEBUG("Session missing required security "
13362598e31SEd Tanous "information, refusing to restore");
134dc511aa7SEd Tanous return nullptr;
135dc511aa7SEd Tanous }
1365cef0f7dSKowalski, Kamil
137e1ae5338SEd Tanous // For now, sessions that were persisted through a reboot get their idle
1381abe55efSEd Tanous // timer reset. This could probably be overcome with a better
1391abe55efSEd Tanous // understanding of wall clock time and steady timer time, possibly
1401abe55efSEd Tanous // persisting values with wall clock time instead of steady timer, but
1411abe55efSEd Tanous // the tradeoffs of all the corner cases involved are non-trivial, so
1421abe55efSEd Tanous // this is done temporarily
14355c7b7a2SEd Tanous userSession->lastUpdated = std::chrono::steady_clock::now();
14489cda63dSEd Tanous userSession->sessionType = SessionType::Session;
1455cef0f7dSKowalski, Kamil
146e1ae5338SEd Tanous return userSession;
1475cef0f7dSKowalski, Kamil }
1482b7981f6SKowalski, Kamil };
1492b7981f6SKowalski, Kamil
1503ce3688aSEd Tanous enum class MTLSCommonNameParseMode
1513ce3688aSEd Tanous {
1523ce3688aSEd Tanous Invalid = 0,
1533ce3688aSEd Tanous // This section approximately matches Redfish AccountService
1543ce3688aSEd Tanous // CertificateMappingAttribute, plus bmcweb defined OEM ones.
1553ce3688aSEd Tanous // Note, IDs in this enum must be maintained between versions, as they are
1563ce3688aSEd Tanous // persisted to disk
1573ce3688aSEd Tanous Whole = 1,
1583ce3688aSEd Tanous CommonName = 2,
1593ce3688aSEd Tanous UserPrincipalName = 3,
1603ce3688aSEd Tanous
1613ce3688aSEd Tanous // Intentional gap for future DMTF-defined enums
1623ce3688aSEd Tanous
1633ce3688aSEd Tanous // OEM parsing modes for various OEMs
1643ce3688aSEd Tanous Meta = 100,
1653ce3688aSEd Tanous };
1663ce3688aSEd Tanous
getMTLSCommonNameParseMode(std::string_view name)1673ce3688aSEd Tanous inline MTLSCommonNameParseMode getMTLSCommonNameParseMode(std::string_view name)
1683ce3688aSEd Tanous {
1693ce3688aSEd Tanous if (name == "CommonName")
1703ce3688aSEd Tanous {
1713ce3688aSEd Tanous return MTLSCommonNameParseMode::CommonName;
1723ce3688aSEd Tanous }
1733ce3688aSEd Tanous if (name == "Whole")
1743ce3688aSEd Tanous {
1753ce3688aSEd Tanous // Not yet supported
1763ce3688aSEd Tanous // return MTLSCommonNameParseMode::Whole;
1773ce3688aSEd Tanous }
1783ce3688aSEd Tanous if (name == "UserPrincipalName")
1793ce3688aSEd Tanous {
180*4d7b5ddbSMalik Akbar Hashemi Rafsanjani return MTLSCommonNameParseMode::UserPrincipalName;
1813ce3688aSEd Tanous }
1823ce3688aSEd Tanous if constexpr (BMCWEB_META_TLS_COMMON_NAME_PARSING)
1833ce3688aSEd Tanous {
1843ce3688aSEd Tanous if (name == "Meta")
1853ce3688aSEd Tanous {
1863ce3688aSEd Tanous return MTLSCommonNameParseMode::Meta;
1873ce3688aSEd Tanous }
1883ce3688aSEd Tanous }
1893ce3688aSEd Tanous return MTLSCommonNameParseMode::Invalid;
1903ce3688aSEd Tanous }
1913ce3688aSEd Tanous
19278158631SZbigniew Kurzynski struct AuthConfigMethods
19378158631SZbigniew Kurzynski {
1943281bcf1SEd Tanous // Authentication paths
19525b54dbaSEd Tanous bool basic = BMCWEB_BASIC_AUTH;
19625b54dbaSEd Tanous bool sessionToken = BMCWEB_SESSION_AUTH;
19725b54dbaSEd Tanous bool xtoken = BMCWEB_XTOKEN_AUTH;
19825b54dbaSEd Tanous bool cookie = BMCWEB_COOKIE_AUTH;
19925b54dbaSEd Tanous bool tls = BMCWEB_MUTUAL_TLS_AUTH;
20078158631SZbigniew Kurzynski
2013281bcf1SEd Tanous // Whether or not unauthenticated TLS should be accepted
2023281bcf1SEd Tanous // true = reject connections if mutual tls is not provided
2033281bcf1SEd Tanous // false = allow connection, and allow user to use other auth method
2043281bcf1SEd Tanous // Always default to false, because root certificates will not
2053281bcf1SEd Tanous // be provisioned at startup
2063281bcf1SEd Tanous bool tlsStrict = false;
2073281bcf1SEd Tanous
2083ce3688aSEd Tanous MTLSCommonNameParseMode mTLSCommonNameParsingMode =
2093ce3688aSEd Tanous getMTLSCommonNameParseMode(
2103ce3688aSEd Tanous BMCWEB_MUTUAL_TLS_COMMON_NAME_PARSING_DEFAULT);
2113ce3688aSEd Tanous
fromJsonpersistent_data::AuthConfigMethods2120bdda665SEd Tanous void fromJson(const nlohmann::json::object_t& j)
21378158631SZbigniew Kurzynski {
2140bdda665SEd Tanous for (const auto& element : j)
21578158631SZbigniew Kurzynski {
2160bdda665SEd Tanous const bool* value = element.second.get_ptr<const bool*>();
2173ce3688aSEd Tanous if (value != nullptr)
21878158631SZbigniew Kurzynski {
2190bdda665SEd Tanous if (element.first == "XToken")
22078158631SZbigniew Kurzynski {
22178158631SZbigniew Kurzynski xtoken = *value;
22278158631SZbigniew Kurzynski }
2230bdda665SEd Tanous else if (element.first == "Cookie")
22478158631SZbigniew Kurzynski {
22578158631SZbigniew Kurzynski cookie = *value;
22678158631SZbigniew Kurzynski }
2270bdda665SEd Tanous else if (element.first == "SessionToken")
22878158631SZbigniew Kurzynski {
22978158631SZbigniew Kurzynski sessionToken = *value;
23078158631SZbigniew Kurzynski }
2310bdda665SEd Tanous else if (element.first == "BasicAuth")
23278158631SZbigniew Kurzynski {
23378158631SZbigniew Kurzynski basic = *value;
23478158631SZbigniew Kurzynski }
2350bdda665SEd Tanous else if (element.first == "TLS")
236501f1e58SZbigniew Kurzynski {
237501f1e58SZbigniew Kurzynski tls = *value;
238501f1e58SZbigniew Kurzynski }
2393281bcf1SEd Tanous else if (element.first == "TLSStrict")
2403281bcf1SEd Tanous {
2413281bcf1SEd Tanous tlsStrict = *value;
2423281bcf1SEd Tanous }
24378158631SZbigniew Kurzynski }
2443ce3688aSEd Tanous const uint64_t* intValue =
2453ce3688aSEd Tanous element.second.get_ptr<const uint64_t*>();
2463ce3688aSEd Tanous if (intValue != nullptr)
2473ce3688aSEd Tanous {
2483ce3688aSEd Tanous if (element.first == "MTLSCommonNameParseMode")
2493ce3688aSEd Tanous {
250*4d7b5ddbSMalik Akbar Hashemi Rafsanjani MTLSCommonNameParseMode tmpMTLSCommonNameParseMode =
2513ce3688aSEd Tanous static_cast<MTLSCommonNameParseMode>(*intValue);
252*4d7b5ddbSMalik Akbar Hashemi Rafsanjani if (tmpMTLSCommonNameParseMode <=
253*4d7b5ddbSMalik Akbar Hashemi Rafsanjani MTLSCommonNameParseMode::UserPrincipalName ||
254*4d7b5ddbSMalik Akbar Hashemi Rafsanjani tmpMTLSCommonNameParseMode ==
255*4d7b5ddbSMalik Akbar Hashemi Rafsanjani MTLSCommonNameParseMode::Meta)
256*4d7b5ddbSMalik Akbar Hashemi Rafsanjani {
257*4d7b5ddbSMalik Akbar Hashemi Rafsanjani mTLSCommonNameParsingMode = tmpMTLSCommonNameParseMode;
2583ce3688aSEd Tanous }
2593ce3688aSEd Tanous else
2603ce3688aSEd Tanous {
261*4d7b5ddbSMalik Akbar Hashemi Rafsanjani BMCWEB_LOG_WARNING(
2623ce3688aSEd Tanous "Json value of {} was out of range of the enum. Ignoring",
2633ce3688aSEd Tanous *intValue);
2643ce3688aSEd Tanous }
2653ce3688aSEd Tanous }
2663ce3688aSEd Tanous }
2673ce3688aSEd Tanous }
26878158631SZbigniew Kurzynski }
26978158631SZbigniew Kurzynski };
27078158631SZbigniew Kurzynski
2711abe55efSEd Tanous class SessionStore
2721abe55efSEd Tanous {
2732b7981f6SKowalski, Kamil public:
generateUserSession(std::string_view username,const boost::asio::ip::address & clientIp,const std::optional<std::string> & clientId,SessionType sessionType,bool isConfigureSelfOnly=false)27455c7b7a2SEd Tanous std::shared_ptr<UserSession> generateUserSession(
27526ccae32SEd Tanous std::string_view username, const boost::asio::ip::address& clientIp,
27689cda63dSEd Tanous const std::optional<std::string>& clientId, SessionType sessionType,
277d3239224SSunitha Harish bool isConfigureSelfOnly = false)
2781abe55efSEd Tanous {
2792b7981f6SKowalski, Kamil // Only need csrf tokens for cookie based auth, token doesn't matter
280b7f3a82bSEd Tanous std::string sessionToken =
281b7f3a82bSEd Tanous bmcweb::getRandomIdOfLength(sessionTokenSize);
282b7f3a82bSEd Tanous std::string csrfToken = bmcweb::getRandomIdOfLength(sessionTokenSize);
283b7f3a82bSEd Tanous std::string uniqueId = bmcweb::getRandomIdOfLength(10);
2842b7981f6SKowalski, Kamil
285b7f3a82bSEd Tanous //
286b7f3a82bSEd Tanous if (sessionToken.empty() || csrfToken.empty() || uniqueId.empty())
2871abe55efSEd Tanous {
288b7f3a82bSEd Tanous BMCWEB_LOG_ERROR("Failed to generate session tokens");
289a68a8045SJames Feist return nullptr;
290a68a8045SJames Feist }
29141d61c82SJiaqing Zhao
292bd79bce8SPatrick Williams auto session = std::make_shared<UserSession>(UserSession{
293bd79bce8SPatrick Williams uniqueId,
29447f2934cSEd Tanous sessionToken,
29547f2934cSEd Tanous std::string(username),
29647f2934cSEd Tanous csrfToken,
29747f2934cSEd Tanous clientId,
298bb759e3aSEd Tanous redfish::ip_util::toString(clientIp),
29947f2934cSEd Tanous std::chrono::steady_clock::now(),
30089cda63dSEd Tanous sessionType,
30147f2934cSEd Tanous false,
30247f2934cSEd Tanous isConfigureSelfOnly,
30347f2934cSEd Tanous "",
30447f2934cSEd Tanous {}});
30541713dd7SPatrick Williams auto it = authTokens.emplace(sessionToken, session);
3062b7981f6SKowalski, Kamil // Only need to write to disk if session isn't about to be destroyed.
30789cda63dSEd Tanous needWrite = sessionType != SessionType::Basic &&
30889cda63dSEd Tanous sessionType != SessionType::MutualTLS;
309e0d918bcSEd Tanous return it.first->second;
3102b7981f6SKowalski, Kamil }
3112b7981f6SKowalski, Kamil
loginSessionByToken(std::string_view token)31226ccae32SEd Tanous std::shared_ptr<UserSession> loginSessionByToken(std::string_view token)
3131abe55efSEd Tanous {
31455c7b7a2SEd Tanous applySessionTimeouts();
31551dae67dSEd Tanous if (token.size() != sessionTokenSize)
31651dae67dSEd Tanous {
31751dae67dSEd Tanous return nullptr;
31851dae67dSEd Tanous }
31955c7b7a2SEd Tanous auto sessionIt = authTokens.find(std::string(token));
3201abe55efSEd Tanous if (sessionIt == authTokens.end())
3211abe55efSEd Tanous {
3222b7981f6SKowalski, Kamil return nullptr;
3232b7981f6SKowalski, Kamil }
32455c7b7a2SEd Tanous std::shared_ptr<UserSession> userSession = sessionIt->second;
32555c7b7a2SEd Tanous userSession->lastUpdated = std::chrono::steady_clock::now();
32655c7b7a2SEd Tanous return userSession;
3272b7981f6SKowalski, Kamil }
3282b7981f6SKowalski, Kamil
getSessionByUid(std::string_view uid)32926ccae32SEd Tanous std::shared_ptr<UserSession> getSessionByUid(std::string_view uid)
3301abe55efSEd Tanous {
33155c7b7a2SEd Tanous applySessionTimeouts();
3322b7981f6SKowalski, Kamil // TODO(Ed) this is inefficient
33355c7b7a2SEd Tanous auto sessionIt = authTokens.begin();
3341abe55efSEd Tanous while (sessionIt != authTokens.end())
3351abe55efSEd Tanous {
3361abe55efSEd Tanous if (sessionIt->second->uniqueId == uid)
3371abe55efSEd Tanous {
33855c7b7a2SEd Tanous return sessionIt->second;
3392b7981f6SKowalski, Kamil }
34055c7b7a2SEd Tanous sessionIt++;
3412b7981f6SKowalski, Kamil }
3422b7981f6SKowalski, Kamil return nullptr;
3432b7981f6SKowalski, Kamil }
3442b7981f6SKowalski, Kamil
removeSession(const std::shared_ptr<UserSession> & session)345b5a76932SEd Tanous void removeSession(const std::shared_ptr<UserSession>& session)
3461abe55efSEd Tanous {
34755c7b7a2SEd Tanous authTokens.erase(session->sessionToken);
34855c7b7a2SEd Tanous needWrite = true;
3492b7981f6SKowalski, Kamil }
3502b7981f6SKowalski, Kamil
getAllUniqueIds()35189cda63dSEd Tanous std::vector<std::string> getAllUniqueIds()
3521abe55efSEd Tanous {
35355c7b7a2SEd Tanous applySessionTimeouts();
35489cda63dSEd Tanous std::vector<std::string> ret;
35555c7b7a2SEd Tanous ret.reserve(authTokens.size());
3561abe55efSEd Tanous for (auto& session : authTokens)
3571abe55efSEd Tanous {
35889cda63dSEd Tanous ret.push_back(session.second->uniqueId);
35989cda63dSEd Tanous }
36089cda63dSEd Tanous return ret;
36189cda63dSEd Tanous }
36289cda63dSEd Tanous
getUniqueIdsBySessionType(SessionType type)36389cda63dSEd Tanous std::vector<std::string> getUniqueIdsBySessionType(SessionType type)
3641abe55efSEd Tanous {
36589cda63dSEd Tanous applySessionTimeouts();
36689cda63dSEd Tanous
36789cda63dSEd Tanous std::vector<std::string> ret;
36889cda63dSEd Tanous ret.reserve(authTokens.size());
36989cda63dSEd Tanous for (auto& session : authTokens)
37089cda63dSEd Tanous {
37189cda63dSEd Tanous if (type == session.second->sessionType)
37289cda63dSEd Tanous {
37389cda63dSEd Tanous ret.push_back(session.second->uniqueId);
3742b7981f6SKowalski, Kamil }
3752b7981f6SKowalski, Kamil }
3762b7981f6SKowalski, Kamil return ret;
3772b7981f6SKowalski, Kamil }
3782b7981f6SKowalski, Kamil
getSessions()37989cda63dSEd Tanous std::vector<std::shared_ptr<UserSession>> getSessions()
38089cda63dSEd Tanous {
38189cda63dSEd Tanous std::vector<std::shared_ptr<UserSession>> sessions;
38289cda63dSEd Tanous sessions.reserve(authTokens.size());
38389cda63dSEd Tanous for (auto& session : authTokens)
38489cda63dSEd Tanous {
38589cda63dSEd Tanous sessions.push_back(session.second);
38689cda63dSEd Tanous }
38789cda63dSEd Tanous return sessions;
38889cda63dSEd Tanous }
38989cda63dSEd Tanous
removeSessionsByUsername(std::string_view username)3909fa06f19SXie Ning void removeSessionsByUsername(std::string_view username)
3919fa06f19SXie Ning {
3929fa06f19SXie Ning std::erase_if(authTokens, [username](const auto& value) {
3939fa06f19SXie Ning if (value.second == nullptr)
3949fa06f19SXie Ning {
3959fa06f19SXie Ning return false;
3969fa06f19SXie Ning }
3979fa06f19SXie Ning return value.second->username == username;
3989fa06f19SXie Ning });
3999fa06f19SXie Ning }
4009fa06f19SXie Ning
removeSessionsByUsernameExceptSession(std::string_view username,const std::shared_ptr<UserSession> & session)401e518ef32SRavi Teja void removeSessionsByUsernameExceptSession(
402e518ef32SRavi Teja std::string_view username, const std::shared_ptr<UserSession>& session)
403e518ef32SRavi Teja {
404e518ef32SRavi Teja std::erase_if(authTokens, [username, session](const auto& value) {
405e518ef32SRavi Teja if (value.second == nullptr)
406e518ef32SRavi Teja {
407e518ef32SRavi Teja return false;
408e518ef32SRavi Teja }
409e518ef32SRavi Teja
410e518ef32SRavi Teja return value.second->username == username &&
411e518ef32SRavi Teja value.second->uniqueId != session->uniqueId;
412e518ef32SRavi Teja });
413e518ef32SRavi Teja }
414e518ef32SRavi Teja
updateAuthMethodsConfig(const AuthConfigMethods & config)41578158631SZbigniew Kurzynski void updateAuthMethodsConfig(const AuthConfigMethods& config)
41678158631SZbigniew Kurzynski {
417009c2a4dSZbigniew Kurzynski bool isTLSchanged = (authMethodsConfig.tls != config.tls);
41878158631SZbigniew Kurzynski authMethodsConfig = config;
41978158631SZbigniew Kurzynski needWrite = true;
420009c2a4dSZbigniew Kurzynski if (isTLSchanged)
421009c2a4dSZbigniew Kurzynski {
422009c2a4dSZbigniew Kurzynski // recreate socket connections with new settings
42392e11bf8SMyung Bae // NOLINTNEXTLINE(misc-include-cleaner)
424009c2a4dSZbigniew Kurzynski std::raise(SIGHUP);
425009c2a4dSZbigniew Kurzynski }
42678158631SZbigniew Kurzynski }
42778158631SZbigniew Kurzynski
getAuthMethodsConfig()42878158631SZbigniew Kurzynski AuthConfigMethods& getAuthMethodsConfig()
42978158631SZbigniew Kurzynski {
43078158631SZbigniew Kurzynski return authMethodsConfig;
43178158631SZbigniew Kurzynski }
43278158631SZbigniew Kurzynski
needsWrite() const4339eb808c1SEd Tanous bool needsWrite() const
4341abe55efSEd Tanous {
4351abe55efSEd Tanous return needWrite;
4361abe55efSEd Tanous }
getTimeoutInSeconds() const437271584abSEd Tanous int64_t getTimeoutInSeconds() const
4381abe55efSEd Tanous {
439f2a4a606SManojkiran Eda return std::chrono::seconds(timeoutInSeconds).count();
440f2a4a606SManojkiran Eda }
441f2a4a606SManojkiran Eda
updateSessionTimeout(std::chrono::seconds newTimeoutInSeconds)442f2a4a606SManojkiran Eda void updateSessionTimeout(std::chrono::seconds newTimeoutInSeconds)
443f2a4a606SManojkiran Eda {
444f2a4a606SManojkiran Eda timeoutInSeconds = newTimeoutInSeconds;
445f2a4a606SManojkiran Eda needWrite = true;
44623a21a1cSEd Tanous }
4472b7981f6SKowalski, Kamil
getInstance()4481abe55efSEd Tanous static SessionStore& getInstance()
4491abe55efSEd Tanous {
4504b1b8683SBorawski.Lukasz static SessionStore sessionStore;
4514b1b8683SBorawski.Lukasz return sessionStore;
4524b1b8683SBorawski.Lukasz }
4534b1b8683SBorawski.Lukasz
applySessionTimeouts()4541abe55efSEd Tanous void applySessionTimeouts()
4551abe55efSEd Tanous {
45655c7b7a2SEd Tanous auto timeNow = std::chrono::steady_clock::now();
457f2a4a606SManojkiran Eda if (timeNow - lastTimeoutUpdate > std::chrono::seconds(1))
4581abe55efSEd Tanous {
45955c7b7a2SEd Tanous lastTimeoutUpdate = timeNow;
46055c7b7a2SEd Tanous auto authTokensIt = authTokens.begin();
4611abe55efSEd Tanous while (authTokensIt != authTokens.end())
4621abe55efSEd Tanous {
4631abe55efSEd Tanous if (timeNow - authTokensIt->second->lastUpdated >=
464f2a4a606SManojkiran Eda timeoutInSeconds)
4651abe55efSEd Tanous {
46655c7b7a2SEd Tanous authTokensIt = authTokens.erase(authTokensIt);
46707386c67SRatan Gupta
46855c7b7a2SEd Tanous needWrite = true;
4691abe55efSEd Tanous }
4701abe55efSEd Tanous else
4711abe55efSEd Tanous {
47255c7b7a2SEd Tanous authTokensIt++;
4732b7981f6SKowalski, Kamil }
4742b7981f6SKowalski, Kamil }
4752b7981f6SKowalski, Kamil }
4762b7981f6SKowalski, Kamil }
47783cf8189SGunnar Mills
47883cf8189SGunnar Mills SessionStore(const SessionStore&) = delete;
47983cf8189SGunnar Mills SessionStore& operator=(const SessionStore&) = delete;
480ecd6a3a2SEd Tanous SessionStore(SessionStore&&) = delete;
481ecd6a3a2SEd Tanous SessionStore& operator=(const SessionStore&&) = delete;
482ecd6a3a2SEd Tanous ~SessionStore() = default;
48383cf8189SGunnar Mills
48483cf8189SGunnar Mills std::unordered_map<std::string, std::shared_ptr<UserSession>,
485724985ffSEd Tanous std::hash<std::string>, bmcweb::ConstantTimeCompare>
48683cf8189SGunnar Mills authTokens;
48783cf8189SGunnar Mills
48883cf8189SGunnar Mills std::chrono::time_point<std::chrono::steady_clock> lastTimeoutUpdate;
48983cf8189SGunnar Mills bool needWrite{false};
49083cf8189SGunnar Mills std::chrono::seconds timeoutInSeconds;
49183cf8189SGunnar Mills AuthConfigMethods authMethodsConfig;
49283cf8189SGunnar Mills
49383cf8189SGunnar Mills private:
SessionStore()49489492a15SPatrick Williams SessionStore() : timeoutInSeconds(1800) {}
4952b7981f6SKowalski, Kamil };
4962b7981f6SKowalski, Kamil
49755c7b7a2SEd Tanous } // namespace persistent_data
498