summaryrefslogtreecommitdiff
path: root/include/token_authorization_middleware.hpp
diff options
context:
space:
mode:
authorEd Tanous <ed.tanous@intel.com>2018-09-05 18:30:59 +0300
committerEd Tanous <ed.tanous@intel.com>2018-09-05 18:44:12 +0300
commit1abe55ef9844afcddcab9d862ae06118f3a2390c (patch)
treed0b5fcfd0b1cd679a8995af3eb0b6d31b368380e /include/token_authorization_middleware.hpp
parenta38b0b206300c792979b900f506b85e535f5708a (diff)
downloadbmcweb-1abe55ef9844afcddcab9d862ae06118f3a2390c.tar.xz
Move to clang-format-6.0
This commit moves the codebase to the lastest clang-format file from upstream, as well as clang-format-6.0. Change-Id: Ice8313468097c0c42317fbb9e10ddf036e8cff4c Signed-off-by: Ed Tanous <ed.tanous@intel.com>
Diffstat (limited to 'include/token_authorization_middleware.hpp')
-rw-r--r--include/token_authorization_middleware.hpp711
1 files changed, 400 insertions, 311 deletions
diff --git a/include/token_authorization_middleware.hpp b/include/token_authorization_middleware.hpp
index 2e286e15ca..c419c97fa7 100644
--- a/include/token_authorization_middleware.hpp
+++ b/include/token_authorization_middleware.hpp
@@ -1,359 +1,448 @@
#pragma once
-#include <pam_authenticate.hpp>
-#include <persistent_data_middleware.hpp>
-#include <webassets.hpp>
-#include <random>
#include <crow/app.h>
#include <crow/common.h>
#include <crow/http_request.h>
#include <crow/http_response.h>
+
#include <boost/container/flat_set.hpp>
+#include <pam_authenticate.hpp>
+#include <persistent_data_middleware.hpp>
+#include <random>
+#include <webassets.hpp>
-namespace crow {
+namespace crow
+{
-namespace token_authorization {
+namespace token_authorization
+{
-class Middleware {
- public:
- struct Context {
- std::shared_ptr<crow::persistent_data::UserSession> session;
- };
+class Middleware
+{
+ public:
+ struct Context
+ {
+ std::shared_ptr<crow::persistent_data::UserSession> session;
+ };
- void beforeHandle(crow::Request& req, Response& res, Context& ctx) {
- if (isOnWhitelist(req)) {
- return;
- }
+ void beforeHandle(crow::Request& req, Response& res, Context& ctx)
+ {
+ if (isOnWhitelist(req))
+ {
+ return;
+ }
- ctx.session = performXtokenAuth(req);
- if (ctx.session == nullptr) {
- ctx.session = performCookieAuth(req);
- }
- if (ctx.session == nullptr) {
- boost::string_view authHeader = req.getHeaderValue("Authorization");
- if (!authHeader.empty()) {
- // Reject any kind of auth other than basic or token
- if (boost::starts_with(authHeader, "Token ")) {
- ctx.session = performTokenAuth(authHeader);
- } else if (boost::starts_with(authHeader, "Basic ")) {
- ctx.session = performBasicAuth(authHeader);
+ ctx.session = performXtokenAuth(req);
+ if (ctx.session == nullptr)
+ {
+ ctx.session = performCookieAuth(req);
}
- }
- }
+ if (ctx.session == nullptr)
+ {
+ boost::string_view authHeader = req.getHeaderValue("Authorization");
+ if (!authHeader.empty())
+ {
+ // Reject any kind of auth other than basic or token
+ if (boost::starts_with(authHeader, "Token "))
+ {
+ ctx.session = performTokenAuth(authHeader);
+ }
+ else if (boost::starts_with(authHeader, "Basic "))
+ {
+ ctx.session = performBasicAuth(authHeader);
+ }
+ }
+ }
+
+ if (ctx.session == nullptr)
+ {
+ BMCWEB_LOG_WARNING << "[AuthMiddleware] authorization failed";
+
+ // If it's a browser connecting, don't send the HTTP authenticate
+ // header, to avoid possible CSRF attacks with basic auth
+ if (http_helpers::requestPrefersHtml(req))
+ {
+ res.result(boost::beast::http::status::temporary_redirect);
+ res.addHeader("Location", "/#/login");
+ }
+ else
+ {
+ res.result(boost::beast::http::status::unauthorized);
+ // only send the WWW-authenticate header if this isn't a xhr
+ // from the browser. most scripts,
+ if (req.getHeaderValue("User-Agent").empty())
+ {
+ res.addHeader("WWW-Authenticate", "Basic");
+ }
+ }
- if (ctx.session == nullptr) {
- BMCWEB_LOG_WARNING << "[AuthMiddleware] authorization failed";
-
- // If it's a browser connecting, don't send the HTTP authenticate header,
- // to avoid possible CSRF attacks with basic auth
- if (http_helpers::requestPrefersHtml(req)) {
- res.result(boost::beast::http::status::temporary_redirect);
- res.addHeader("Location", "/#/login");
- } else {
- res.result(boost::beast::http::status::unauthorized);
- // only send the WWW-authenticate header if this isn't a xhr from the
- // browser. most scripts,
- if (req.getHeaderValue("User-Agent").empty()) {
- res.addHeader("WWW-Authenticate", "Basic");
+ res.end();
+ return;
}
- }
- res.end();
- return;
+ // TODO get user privileges here and propagate it via MW Context
+ // else let the request continue unharmed
}
- // TODO get user privileges here and propagate it via MW Context
- // else let the request continue unharmed
- }
-
- template <typename AllContext>
- void afterHandle(Request& req, Response& res, Context& ctx,
- AllContext& allctx) {
- // TODO(ed) THis should really be handled by the persistent data
- // middleware, but because it is upstream, it doesn't have access to the
- // session information. Should the data middleware persist the current
- // user session?
- if (ctx.session != nullptr &&
- ctx.session->persistence ==
- crow::persistent_data::PersistenceType::SINGLE_REQUEST) {
- persistent_data::SessionStore::getInstance().removeSession(ctx.session);
+ template <typename AllContext>
+ void afterHandle(Request& req, Response& res, Context& ctx,
+ AllContext& allctx)
+ {
+ // TODO(ed) THis should really be handled by the persistent data
+ // middleware, but because it is upstream, it doesn't have access to the
+ // session information. Should the data middleware persist the current
+ // user session?
+ if (ctx.session != nullptr &&
+ ctx.session->persistence ==
+ crow::persistent_data::PersistenceType::SINGLE_REQUEST)
+ {
+ persistent_data::SessionStore::getInstance().removeSession(
+ ctx.session);
+ }
}
- }
- private:
- const std::shared_ptr<crow::persistent_data::UserSession> performBasicAuth(
- boost::string_view auth_header) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Basic authentication";
+ private:
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performBasicAuth(boost::string_view auth_header) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Basic authentication";
+
+ std::string authData;
+ boost::string_view param = auth_header.substr(strlen("Basic "));
+ if (!crow::utility::base64Decode(param, authData))
+ {
+ return nullptr;
+ }
+ std::size_t separator = authData.find(':');
+ if (separator == std::string::npos)
+ {
+ return nullptr;
+ }
- std::string authData;
- boost::string_view param = auth_header.substr(strlen("Basic "));
- if (!crow::utility::base64Decode(param, authData)) {
- return nullptr;
- }
- std::size_t separator = authData.find(':');
- if (separator == std::string::npos) {
- return nullptr;
- }
+ std::string user = authData.substr(0, separator);
+ separator += 1;
+ if (separator > authData.size())
+ {
+ return nullptr;
+ }
+ std::string pass = authData.substr(separator);
- std::string user = authData.substr(0, separator);
- separator += 1;
- if (separator > authData.size()) {
- return nullptr;
- }
- std::string pass = authData.substr(separator);
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Authenticating user: " << user;
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Authenticating user: " << user;
+ if (!pamAuthenticateUser(user, pass))
+ {
+ return nullptr;
+ }
- if (!pamAuthenticateUser(user, pass)) {
- return nullptr;
+ // TODO(ed) generateUserSession is a little expensive for basic
+ // auth, as it generates some random identifiers that will never be
+ // used. This should have a "fast" path for when user tokens aren't
+ // needed.
+ // This whole flow needs to be revisited anyway, as we can't be
+ // calling directly into pam for every request
+ return persistent_data::SessionStore::getInstance().generateUserSession(
+ user, crow::persistent_data::PersistenceType::SINGLE_REQUEST);
}
- // TODO(ed) generateUserSession is a little expensive for basic
- // auth, as it generates some random identifiers that will never be
- // used. This should have a "fast" path for when user tokens aren't
- // needed.
- // This whole flow needs to be revisited anyway, as we can't be
- // calling directly into pam for every request
- return persistent_data::SessionStore::getInstance().generateUserSession(
- user, crow::persistent_data::PersistenceType::SINGLE_REQUEST);
- }
-
- const std::shared_ptr<crow::persistent_data::UserSession> performTokenAuth(
- boost::string_view auth_header) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Token authentication";
-
- boost::string_view token = auth_header.substr(strlen("Token "));
- auto session =
- persistent_data::SessionStore::getInstance().loginSessionByToken(token);
- return session;
- }
-
- const std::shared_ptr<crow::persistent_data::UserSession> performXtokenAuth(
- const crow::Request& req) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] X-Auth-Token authentication";
-
- boost::string_view token = req.getHeaderValue("X-Auth-Token");
- if (token.empty()) {
- return nullptr;
- }
- auto session =
- persistent_data::SessionStore::getInstance().loginSessionByToken(token);
- return session;
- }
-
- const std::shared_ptr<crow::persistent_data::UserSession> performCookieAuth(
- const crow::Request& req) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Cookie authentication";
-
- boost::string_view cookieValue = req.getHeaderValue("Cookie");
- if (cookieValue.empty()) {
- return nullptr;
- }
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performTokenAuth(boost::string_view auth_header) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Token authentication";
- auto startIndex = cookieValue.find("SESSION=");
- if (startIndex == std::string::npos) {
- return nullptr;
+ boost::string_view token = auth_header.substr(strlen("Token "));
+ auto session =
+ persistent_data::SessionStore::getInstance().loginSessionByToken(
+ token);
+ return session;
}
- startIndex += sizeof("SESSION=") - 1;
- auto endIndex = cookieValue.find(";", startIndex);
- if (endIndex == std::string::npos) {
- endIndex = cookieValue.size();
- }
- boost::string_view authKey =
- cookieValue.substr(startIndex, endIndex - startIndex);
-
- const std::shared_ptr<crow::persistent_data::UserSession> session =
- persistent_data::SessionStore::getInstance().loginSessionByToken(
- authKey);
- if (session == nullptr) {
- return nullptr;
+
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performXtokenAuth(const crow::Request& req) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] X-Auth-Token authentication";
+
+ boost::string_view token = req.getHeaderValue("X-Auth-Token");
+ if (token.empty())
+ {
+ return nullptr;
+ }
+ auto session =
+ persistent_data::SessionStore::getInstance().loginSessionByToken(
+ token);
+ return session;
}
+
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performCookieAuth(const crow::Request& req) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Cookie authentication";
+
+ boost::string_view cookieValue = req.getHeaderValue("Cookie");
+ if (cookieValue.empty())
+ {
+ return nullptr;
+ }
+
+ auto startIndex = cookieValue.find("SESSION=");
+ if (startIndex == std::string::npos)
+ {
+ return nullptr;
+ }
+ startIndex += sizeof("SESSION=") - 1;
+ auto endIndex = cookieValue.find(";", startIndex);
+ if (endIndex == std::string::npos)
+ {
+ endIndex = cookieValue.size();
+ }
+ boost::string_view authKey =
+ cookieValue.substr(startIndex, endIndex - startIndex);
+
+ const std::shared_ptr<crow::persistent_data::UserSession> session =
+ persistent_data::SessionStore::getInstance().loginSessionByToken(
+ authKey);
+ if (session == nullptr)
+ {
+ return nullptr;
+ }
#ifndef BMCWEB_INSECURE_DISABLE_CSRF_PREVENTION
- // RFC7231 defines methods that need csrf protection
- if (req.method() != "GET"_method) {
- boost::string_view csrf = req.getHeaderValue("X-XSRF-TOKEN");
- // Make sure both tokens are filled
- if (csrf.empty() || session->csrfToken.empty()) {
- return nullptr;
- }
- // Reject if csrf token not available
- if (csrf != session->csrfToken) {
- return nullptr;
- }
- }
+ // RFC7231 defines methods that need csrf protection
+ if (req.method() != "GET"_method)
+ {
+ boost::string_view csrf = req.getHeaderValue("X-XSRF-TOKEN");
+ // Make sure both tokens are filled
+ if (csrf.empty() || session->csrfToken.empty())
+ {
+ return nullptr;
+ }
+ // Reject if csrf token not available
+ if (csrf != session->csrfToken)
+ {
+ return nullptr;
+ }
+ }
#endif
- return session;
- }
-
- // checks if request can be forwarded without authentication
- bool isOnWhitelist(const crow::Request& req) const {
- // it's allowed to GET root node without authentica tion
- if ("GET"_method == req.method()) {
- if (req.url == "/redfish/v1" || req.url == "/redfish/v1/" ||
- req.url == "/redfish" || req.url == "/redfish/" ||
- req.url == "/redfish/v1/odata" || req.url == "/redfish/v1/odata/") {
- return true;
- } else if (crow::webassets::routes.find(std::string(req.url)) !=
- crow::webassets::routes.end()) {
- return true;
- }
+ return session;
}
- // it's allowed to POST on session collection & login without
- // authentication
- if ("POST"_method == req.method()) {
- if ((req.url == "/redfish/v1/SessionService/Sessions") ||
- (req.url == "/redfish/v1/SessionService/Sessions/") ||
- (req.url == "/login")) {
- return true;
- }
- }
+ // checks if request can be forwarded without authentication
+ bool isOnWhitelist(const crow::Request& req) const
+ {
+ // it's allowed to GET root node without authentica tion
+ if ("GET"_method == req.method())
+ {
+ if (req.url == "/redfish/v1" || req.url == "/redfish/v1/" ||
+ req.url == "/redfish" || req.url == "/redfish/" ||
+ req.url == "/redfish/v1/odata" ||
+ req.url == "/redfish/v1/odata/")
+ {
+ return true;
+ }
+ else if (crow::webassets::routes.find(std::string(req.url)) !=
+ crow::webassets::routes.end())
+ {
+ return true;
+ }
+ }
+
+ // it's allowed to POST on session collection & login without
+ // authentication
+ if ("POST"_method == req.method())
+ {
+ if ((req.url == "/redfish/v1/SessionService/Sessions") ||
+ (req.url == "/redfish/v1/SessionService/Sessions/") ||
+ (req.url == "/login"))
+ {
+ return true;
+ }
+ }
- return false;
- }
+ return false;
+ }
};
// TODO(ed) see if there is a better way to allow middlewares to request
// routes.
// Possibly an init function on first construction?
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- static_assert(
- black_magic::Contains<persistent_data::Middleware, Middlewares...>::value,
- "token_authorization middleware must be enabled in app to use "
- "auth routes");
- BMCWEB_ROUTE(app, "/login")
- .methods(
- "POST"_method)([&](const crow::Request& req, crow::Response& res) {
- boost::string_view contentType = req.getHeaderValue("content-type");
- boost::string_view username;
- boost::string_view password;
-
- bool looksLikeIbm = false;
-
- // This object needs to be declared at this scope so the strings
- // within it are not destroyed before we can use them
- nlohmann::json loginCredentials;
- // Check if auth was provided by a payload
- if (contentType == "application/json") {
- loginCredentials = nlohmann::json::parse(req.body, nullptr, false);
- if (loginCredentials.is_discarded()) {
- res.result(boost::beast::http::status::bad_request);
- res.end();
- return;
- }
-
- // check for username/password in the root object
- // THis method is how intel APIs authenticate
- nlohmann::json::iterator userIt = loginCredentials.find("username");
- nlohmann::json::iterator passIt = loginCredentials.find("password");
- if (userIt != loginCredentials.end() &&
- passIt != loginCredentials.end()) {
- const std::string* userStr = userIt->get_ptr<const std::string*>();
- const std::string* passStr = passIt->get_ptr<const std::string*>();
- if (userStr != nullptr && passStr != nullptr) {
- username = *userStr;
- password = *passStr;
- }
- } else {
- // Openbmc appears to push a data object that contains the same
- // keys (username and password), attempt to use that
- auto dataIt = loginCredentials.find("data");
- if (dataIt != loginCredentials.end()) {
- // Some apis produce an array of value ["username",
- // "password"]
- if (dataIt->is_array()) {
- if (dataIt->size() == 2) {
- nlohmann::json::iterator userIt2 = dataIt->begin();
- nlohmann::json::iterator passIt2 = dataIt->begin() + 1;
- looksLikeIbm = true;
- if (userIt2 != dataIt->end() && passIt2 != dataIt->end()) {
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ static_assert(
+ black_magic::Contains<persistent_data::Middleware,
+ Middlewares...>::value,
+ "token_authorization middleware must be enabled in app to use "
+ "auth routes");
+ BMCWEB_ROUTE(app, "/login")
+ .methods(
+ "POST"_method)([&](const crow::Request& req, crow::Response& res) {
+ boost::string_view contentType = req.getHeaderValue("content-type");
+ boost::string_view username;
+ boost::string_view password;
+
+ bool looksLikeIbm = false;
+
+ // This object needs to be declared at this scope so the strings
+ // within it are not destroyed before we can use them
+ nlohmann::json loginCredentials;
+ // Check if auth was provided by a payload
+ if (contentType == "application/json")
+ {
+ loginCredentials =
+ nlohmann::json::parse(req.body, nullptr, false);
+ if (loginCredentials.is_discarded())
+ {
+ res.result(boost::beast::http::status::bad_request);
+ res.end();
+ return;
+ }
+
+ // check for username/password in the root object
+ // THis method is how intel APIs authenticate
+ nlohmann::json::iterator userIt =
+ loginCredentials.find("username");
+ nlohmann::json::iterator passIt =
+ loginCredentials.find("password");
+ if (userIt != loginCredentials.end() &&
+ passIt != loginCredentials.end())
+ {
const std::string* userStr =
- userIt2->get_ptr<const std::string*>();
+ userIt->get_ptr<const std::string*>();
const std::string* passStr =
- passIt2->get_ptr<const std::string*>();
- if (userStr != nullptr && passStr != nullptr) {
- username = *userStr;
- password = *passStr;
+ passIt->get_ptr<const std::string*>();
+ if (userStr != nullptr && passStr != nullptr)
+ {
+ username = *userStr;
+ password = *passStr;
}
- }
}
-
- } else if (dataIt->is_object()) {
- nlohmann::json::iterator userIt2 = dataIt->find("username");
- nlohmann::json::iterator passIt2 = dataIt->find("password");
- if (userIt2 != dataIt->end() && passIt2 != dataIt->end()) {
- const std::string* userStr =
- userIt2->get_ptr<const std::string*>();
- const std::string* passStr =
- passIt2->get_ptr<const std::string*>();
- if (userStr != nullptr && passStr != nullptr) {
- username = *userStr;
- password = *passStr;
- }
+ else
+ {
+ // Openbmc appears to push a data object that contains the
+ // same keys (username and password), attempt to use that
+ auto dataIt = loginCredentials.find("data");
+ if (dataIt != loginCredentials.end())
+ {
+ // Some apis produce an array of value ["username",
+ // "password"]
+ if (dataIt->is_array())
+ {
+ if (dataIt->size() == 2)
+ {
+ nlohmann::json::iterator userIt2 =
+ dataIt->begin();
+ nlohmann::json::iterator passIt2 =
+ dataIt->begin() + 1;
+ looksLikeIbm = true;
+ if (userIt2 != dataIt->end() &&
+ passIt2 != dataIt->end())
+ {
+ const std::string* userStr =
+ userIt2->get_ptr<const std::string*>();
+ const std::string* passStr =
+ passIt2->get_ptr<const std::string*>();
+ if (userStr != nullptr &&
+ passStr != nullptr)
+ {
+ username = *userStr;
+ password = *passStr;
+ }
+ }
+ }
+ }
+ else if (dataIt->is_object())
+ {
+ nlohmann::json::iterator userIt2 =
+ dataIt->find("username");
+ nlohmann::json::iterator passIt2 =
+ dataIt->find("password");
+ if (userIt2 != dataIt->end() &&
+ passIt2 != dataIt->end())
+ {
+ const std::string* userStr =
+ userIt2->get_ptr<const std::string*>();
+ const std::string* passStr =
+ passIt2->get_ptr<const std::string*>();
+ if (userStr != nullptr && passStr != nullptr)
+ {
+ username = *userStr;
+ password = *passStr;
+ }
+ }
+ }
+ }
}
- }
}
- }
- } else {
- // check if auth was provided as a headers
- username = req.getHeaderValue("username");
- password = req.getHeaderValue("password");
- }
-
- if (!username.empty() && !password.empty()) {
- if (!pamAuthenticateUser(username, password)) {
- res.result(boost::beast::http::status::unauthorized);
- } else {
- auto session = persistent_data::SessionStore::getInstance()
- .generateUserSession(username);
-
- if (looksLikeIbm) {
- // IBM requires a very specific login structure, and doesn't
- // actually look at the status code. TODO(ed).... Fix that
- // upstream
- res.jsonValue = {
- {"data", "User '" + std::string(username) + "' logged in"},
- {"message", "200 OK"},
- {"status", "ok"}};
-
- // Hack alert. Boost beast by default doesn't let you declare
- // multiple headers of the same name, and in most cases this is
- // fine. Unfortunately here we need to set the Session cookie,
- // which requires the httpOnly attribute, as well as the XSRF
- // cookie, which requires it to not have an httpOnly attribute.
- // To get the behavior we want, we simply inject the second
- // "set-cookie" string into the value header, and get the result
- // we want, even though we are technicaly declaring two headers
- // here.
- res.addHeader("Set-Cookie",
- "XSRF-TOKEN=" + session->csrfToken +
- "; Secure\r\nSet-Cookie: SESSION=" +
- session->sessionToken + "; Secure; HttpOnly");
- } else {
- // if content type is json, assume json token
- res.jsonValue = {{"token", session->sessionToken}};
+ else
+ {
+ // check if auth was provided as a headers
+ username = req.getHeaderValue("username");
+ password = req.getHeaderValue("password");
}
- }
- } else {
- res.result(boost::beast::http::status::bad_request);
- }
- res.end();
- });
-
- BMCWEB_ROUTE(app, "/logout")
- .methods(
- "POST"_method)([&](const crow::Request& req, crow::Response& res) {
- auto& session =
- app.template getContext<token_authorization::Middleware>(req)
- .session;
- if (session != nullptr) {
- persistent_data::SessionStore::getInstance().removeSession(session);
- }
- res.end();
- return;
- });
+ if (!username.empty() && !password.empty())
+ {
+ if (!pamAuthenticateUser(username, password))
+ {
+ res.result(boost::beast::http::status::unauthorized);
+ }
+ else
+ {
+ auto session = persistent_data::SessionStore::getInstance()
+ .generateUserSession(username);
+
+ if (looksLikeIbm)
+ {
+ // IBM requires a very specific login structure, and
+ // doesn't actually look at the status code.
+ // TODO(ed).... Fix that upstream
+ res.jsonValue = {
+ {"data",
+ "User '" + std::string(username) + "' logged in"},
+ {"message", "200 OK"},
+ {"status", "ok"}};
+
+ // Hack alert. Boost beast by default doesn't let you
+ // declare multiple headers of the same name, and in
+ // most cases this is fine. Unfortunately here we need
+ // to set the Session cookie, which requires the
+ // httpOnly attribute, as well as the XSRF cookie, which
+ // requires it to not have an httpOnly attribute. To get
+ // the behavior we want, we simply inject the second
+ // "set-cookie" string into the value header, and get
+ // the result we want, even though we are technicaly
+ // declaring two headers here.
+ res.addHeader("Set-Cookie",
+ "XSRF-TOKEN=" + session->csrfToken +
+ "; Secure\r\nSet-Cookie: SESSION=" +
+ session->sessionToken +
+ "; Secure; HttpOnly");
+ }
+ else
+ {
+ // if content type is json, assume json token
+ res.jsonValue = {{"token", session->sessionToken}};
+ }
+ }
+ }
+ else
+ {
+ res.result(boost::beast::http::status::bad_request);
+ }
+ res.end();
+ });
+
+ BMCWEB_ROUTE(app, "/logout")
+ .methods(
+ "POST"_method)([&](const crow::Request& req, crow::Response& res) {
+ auto& session =
+ app.template getContext<token_authorization::Middleware>(req)
+ .session;
+ if (session != nullptr)
+ {
+ persistent_data::SessionStore::getInstance().removeSession(
+ session);
+ }
+ res.end();
+ return;
+ });
}
-} // namespace token_authorization
-} // namespace crow
+} // namespace token_authorization
+} // namespace crow