blob: 2e286e15ca03c0b4730fdf43969482dc3bb6b9dc [file] [log] [blame]
Ed Tanousf9273472017-02-28 16:05:13 -08001#pragma once
2
Ed Tanous911ac312017-08-15 09:37:42 -07003#include <pam_authenticate.hpp>
Ed Tanousba9f9a62017-10-11 16:40:35 -07004#include <persistent_data_middleware.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -07005#include <webassets.hpp>
6#include <random>
7#include <crow/app.h>
Ed Tanouse0d918b2018-03-27 17:41:04 -07008#include <crow/common.h>
Ed Tanousf9273472017-02-28 16:05:13 -08009#include <crow/http_request.h>
10#include <crow/http_response.h>
Ed Tanous4758d5b2017-06-06 15:28:13 -070011#include <boost/container/flat_set.hpp>
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010012
Ed Tanous99923322017-03-03 14:21:24 -080013namespace crow {
Ed Tanousb4d29f42017-03-24 16:39:25 -070014
Ed Tanous55c7b7a2018-05-22 15:27:24 -070015namespace token_authorization {
Ed Tanousb4d29f42017-03-24 16:39:25 -070016
Ed Tanous911ac312017-08-15 09:37:42 -070017class Middleware {
Ed Tanous3dac7492017-08-02 13:46:20 -070018 public:
Ed Tanous55c7b7a2018-05-22 15:27:24 -070019 struct Context {
20 std::shared_ptr<crow::persistent_data::UserSession> session;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010021 };
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +010022
Ed Tanous55c7b7a2018-05-22 15:27:24 -070023 void beforeHandle(crow::Request& req, Response& res, Context& ctx) {
24 if (isOnWhitelist(req)) {
Ed Tanousbae064e2018-03-22 15:44:39 -070025 return;
26 }
27
Ed Tanous55c7b7a2018-05-22 15:27:24 -070028 ctx.session = performXtokenAuth(req);
Ed Tanous1ea9f062018-03-27 17:45:20 -070029 if (ctx.session == nullptr) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070030 ctx.session = performCookieAuth(req);
Ed Tanous1ea9f062018-03-27 17:45:20 -070031 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070032 if (ctx.session == nullptr) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070033 boost::string_view authHeader = req.getHeaderValue("Authorization");
34 if (!authHeader.empty()) {
Ed Tanouse0d918b2018-03-27 17:41:04 -070035 // Reject any kind of auth other than basic or token
Ed Tanous55c7b7a2018-05-22 15:27:24 -070036 if (boost::starts_with(authHeader, "Token ")) {
37 ctx.session = performTokenAuth(authHeader);
38 } else if (boost::starts_with(authHeader, "Basic ")) {
39 ctx.session = performBasicAuth(authHeader);
Ed Tanouse0d918b2018-03-27 17:41:04 -070040 }
41 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010042 }
43
Ed Tanousbae064e2018-03-22 15:44:39 -070044 if (ctx.session == nullptr) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070045 BMCWEB_LOG_WARNING << "[AuthMiddleware] authorization failed";
Ed Tanouse0d918b2018-03-27 17:41:04 -070046
Ed Tanous9bd21fc2018-04-26 16:08:56 -070047 // If it's a browser connecting, don't send the HTTP authenticate header,
48 // to avoid possible CSRF attacks with basic auth
Ed Tanous55c7b7a2018-05-22 15:27:24 -070049 if (http_helpers::requestPrefersHtml(req)) {
Ed Tanous9bd21fc2018-04-26 16:08:56 -070050 res.result(boost::beast::http::status::temporary_redirect);
Ed Tanous55c7b7a2018-05-22 15:27:24 -070051 res.addHeader("Location", "/#/login");
Ed Tanous9bd21fc2018-04-26 16:08:56 -070052 } else {
53 res.result(boost::beast::http::status::unauthorized);
54 // only send the WWW-authenticate header if this isn't a xhr from the
55 // browser. most scripts,
Ed Tanous55c7b7a2018-05-22 15:27:24 -070056 if (req.getHeaderValue("User-Agent").empty()) {
57 res.addHeader("WWW-Authenticate", "Basic");
Ed Tanous9bd21fc2018-04-26 16:08:56 -070058 }
59 }
Ed Tanouse0d918b2018-03-27 17:41:04 -070060
Ed Tanousf3d847c2017-06-12 16:01:42 -070061 res.end();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010062 return;
63 }
Ed Tanousf9273472017-02-28 16:05:13 -080064
Ed Tanous55c7b7a2018-05-22 15:27:24 -070065 // TODO get user privileges here and propagate it via MW Context
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010066 // else let the request continue unharmed
67 }
Ed Tanousf3d847c2017-06-12 16:01:42 -070068
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010069 template <typename AllContext>
Ed Tanous55c7b7a2018-05-22 15:27:24 -070070 void afterHandle(Request& req, Response& res, Context& ctx,
71 AllContext& allctx) {
Ed Tanouse0d918b2018-03-27 17:41:04 -070072 // TODO(ed) THis should really be handled by the persistent data
73 // middleware, but because it is upstream, it doesn't have access to the
74 // session information. Should the data middleware persist the current
75 // user session?
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010076 if (ctx.session != nullptr &&
77 ctx.session->persistence ==
Ed Tanous55c7b7a2018-05-22 15:27:24 -070078 crow::persistent_data::PersistenceType::SINGLE_REQUEST) {
79 persistent_data::SessionStore::getInstance().removeSession(ctx.session);
Ed Tanousf3d847c2017-06-12 16:01:42 -070080 }
81 }
82
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010083 private:
Ed Tanous55c7b7a2018-05-22 15:27:24 -070084 const std::shared_ptr<crow::persistent_data::UserSession> performBasicAuth(
Ed Tanouse0d918b2018-03-27 17:41:04 -070085 boost::string_view auth_header) const {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070086 BMCWEB_LOG_DEBUG << "[AuthMiddleware] Basic authentication";
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010087
Ed Tanous55c7b7a2018-05-22 15:27:24 -070088 std::string authData;
Ed Tanouse0d918b2018-03-27 17:41:04 -070089 boost::string_view param = auth_header.substr(strlen("Basic "));
Ed Tanous55c7b7a2018-05-22 15:27:24 -070090 if (!crow::utility::base64Decode(param, authData)) {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010091 return nullptr;
92 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -070093 std::size_t separator = authData.find(':');
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010094 if (separator == std::string::npos) {
95 return nullptr;
96 }
97
Ed Tanous55c7b7a2018-05-22 15:27:24 -070098 std::string user = authData.substr(0, separator);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010099 separator += 1;
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700100 if (separator > authData.size()) {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100101 return nullptr;
102 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700103 std::string pass = authData.substr(separator);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100104
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700105 BMCWEB_LOG_DEBUG << "[AuthMiddleware] Authenticating user: " << user;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100106
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700107 if (!pamAuthenticateUser(user, pass)) {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100108 return nullptr;
109 }
110
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700111 // TODO(ed) generateUserSession is a little expensive for basic
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100112 // auth, as it generates some random identifiers that will never be
113 // used. This should have a "fast" path for when user tokens aren't
114 // needed.
115 // This whole flow needs to be revisited anyway, as we can't be
116 // calling directly into pam for every request
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700117 return persistent_data::SessionStore::getInstance().generateUserSession(
118 user, crow::persistent_data::PersistenceType::SINGLE_REQUEST);
Ed Tanousf3d847c2017-06-12 16:01:42 -0700119 }
Ed Tanous8041f312017-04-03 09:47:01 -0700120
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700121 const std::shared_ptr<crow::persistent_data::UserSession> performTokenAuth(
Ed Tanouse0d918b2018-03-27 17:41:04 -0700122 boost::string_view auth_header) const {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700123 BMCWEB_LOG_DEBUG << "[AuthMiddleware] Token authentication";
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100124
Ed Tanouse0d918b2018-03-27 17:41:04 -0700125 boost::string_view token = auth_header.substr(strlen("Token "));
Borawski.Lukasz4b1b8682018-04-04 12:50:16 +0200126 auto session =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700127 persistent_data::SessionStore::getInstance().loginSessionByToken(token);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100128 return session;
129 }
130
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700131 const std::shared_ptr<crow::persistent_data::UserSession> performXtokenAuth(
132 const crow::Request& req) const {
133 BMCWEB_LOG_DEBUG << "[AuthMiddleware] X-Auth-Token authentication";
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100134
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700135 boost::string_view token = req.getHeaderValue("X-Auth-Token");
Ed Tanous1ea9f062018-03-27 17:45:20 -0700136 if (token.empty()) {
137 return nullptr;
138 }
Borawski.Lukasz4b1b8682018-04-04 12:50:16 +0200139 auto session =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700140 persistent_data::SessionStore::getInstance().loginSessionByToken(token);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100141 return session;
142 }
143
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700144 const std::shared_ptr<crow::persistent_data::UserSession> performCookieAuth(
145 const crow::Request& req) const {
146 BMCWEB_LOG_DEBUG << "[AuthMiddleware] Cookie authentication";
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100147
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700148 boost::string_view cookieValue = req.getHeaderValue("Cookie");
149 if (cookieValue.empty()) {
Ed Tanous1ea9f062018-03-27 17:45:20 -0700150 return nullptr;
151 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100152
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700153 auto startIndex = cookieValue.find("SESSION=");
154 if (startIndex == std::string::npos) {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100155 return nullptr;
156 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700157 startIndex += sizeof("SESSION=") - 1;
158 auto endIndex = cookieValue.find(";", startIndex);
159 if (endIndex == std::string::npos) {
160 endIndex = cookieValue.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100161 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700162 boost::string_view authKey =
163 cookieValue.substr(startIndex, endIndex - startIndex);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100164
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700165 const std::shared_ptr<crow::persistent_data::UserSession> session =
166 persistent_data::SessionStore::getInstance().loginSessionByToken(
167 authKey);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100168 if (session == nullptr) {
169 return nullptr;
170 }
Ed Tanous1e439872018-05-18 11:48:52 -0700171#ifndef BMCWEB_INSECURE_DISABLE_CSRF_PREVENTION
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100172 // RFC7231 defines methods that need csrf protection
Ed Tanouse0d918b2018-03-27 17:41:04 -0700173 if (req.method() != "GET"_method) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700174 boost::string_view csrf = req.getHeaderValue("X-XSRF-TOKEN");
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100175 // Make sure both tokens are filled
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700176 if (csrf.empty() || session->csrfToken.empty()) {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100177 return nullptr;
178 }
179 // Reject if csrf token not available
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700180 if (csrf != session->csrfToken) {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100181 return nullptr;
182 }
183 }
Ed Tanous1e439872018-05-18 11:48:52 -0700184#endif
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100185 return session;
186 }
187
188 // checks if request can be forwarded without authentication
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700189 bool isOnWhitelist(const crow::Request& req) const {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700190 // it's allowed to GET root node without authentica tion
191 if ("GET"_method == req.method()) {
Ed Tanouseb1eb782018-07-24 14:28:08 -0700192 if (req.url == "/redfish/v1" || req.url == "/redfish/v1/" ||
193 req.url == "/redfish" || req.url == "/redfish/" ||
194 req.url == "/redfish/v1/odata" || req.url == "/redfish/v1/odata/") {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100195 return true;
Ed Tanouse0d918b2018-03-27 17:41:04 -0700196 } else if (crow::webassets::routes.find(std::string(req.url)) !=
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100197 crow::webassets::routes.end()) {
198 return true;
199 }
200 }
201
Ed Tanouse0d918b2018-03-27 17:41:04 -0700202 // it's allowed to POST on session collection & login without
203 // authentication
204 if ("POST"_method == req.method()) {
205 if ((req.url == "/redfish/v1/SessionService/Sessions") ||
206 (req.url == "/redfish/v1/SessionService/Sessions/") ||
Ed Tanous9bd21fc2018-04-26 16:08:56 -0700207 (req.url == "/login")) {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100208 return true;
209 }
210 }
211
212 return false;
213 }
Ed Tanous99923322017-03-03 14:21:24 -0800214};
Ed Tanousf3d847c2017-06-12 16:01:42 -0700215
Ed Tanousba9f9a62017-10-11 16:40:35 -0700216// TODO(ed) see if there is a better way to allow middlewares to request
217// routes.
Ed Tanous911ac312017-08-15 09:37:42 -0700218// Possibly an init function on first construction?
219template <typename... Middlewares>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700220void requestRoutes(Crow<Middlewares...>& app) {
Ed Tanousba9f9a62017-10-11 16:40:35 -0700221 static_assert(
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700222 black_magic::Contains<persistent_data::Middleware, Middlewares...>::value,
223 "token_authorization middleware must be enabled in app to use "
Ed Tanousba9f9a62017-10-11 16:40:35 -0700224 "auth routes");
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700225 BMCWEB_ROUTE(app, "/login")
Ed Tanous911ac312017-08-15 09:37:42 -0700226 .methods(
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700227 "POST"_method)([&](const crow::Request& req, crow::Response& res) {
228 boost::string_view contentType = req.getHeaderValue("content-type");
Ed Tanouse0d918b2018-03-27 17:41:04 -0700229 boost::string_view username;
230 boost::string_view password;
231
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700232 bool looksLikeIbm = false;
Ed Tanousdb024a52018-03-06 12:50:34 -0800233
Ed Tanouse0d918b2018-03-27 17:41:04 -0700234 // This object needs to be declared at this scope so the strings
235 // within it are not destroyed before we can use them
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700236 nlohmann::json loginCredentials;
Ed Tanous911ac312017-08-15 09:37:42 -0700237 // Check if auth was provided by a payload
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700238 if (contentType == "application/json") {
239 loginCredentials = nlohmann::json::parse(req.body, nullptr, false);
240 if (loginCredentials.is_discarded()) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700241 res.result(boost::beast::http::status::bad_request);
Ed Tanous911ac312017-08-15 09:37:42 -0700242 res.end();
243 return;
244 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700245
Ed Tanousba9f9a62017-10-11 16:40:35 -0700246 // check for username/password in the root object
247 // THis method is how intel APIs authenticate
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700248 nlohmann::json::iterator userIt = loginCredentials.find("username");
249 nlohmann::json::iterator passIt = loginCredentials.find("password");
250 if (userIt != loginCredentials.end() &&
251 passIt != loginCredentials.end()) {
252 const std::string* userStr = userIt->get_ptr<const std::string*>();
253 const std::string* passStr = passIt->get_ptr<const std::string*>();
254 if (userStr != nullptr && passStr != nullptr) {
255 username = *userStr;
256 password = *passStr;
Ed Tanouse0d918b2018-03-27 17:41:04 -0700257 }
Ed Tanousba9f9a62017-10-11 16:40:35 -0700258 } else {
259 // Openbmc appears to push a data object that contains the same
260 // keys (username and password), attempt to use that
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700261 auto dataIt = loginCredentials.find("data");
262 if (dataIt != loginCredentials.end()) {
Ed Tanousba9f9a62017-10-11 16:40:35 -0700263 // Some apis produce an array of value ["username",
264 // "password"]
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700265 if (dataIt->is_array()) {
266 if (dataIt->size() == 2) {
267 nlohmann::json::iterator userIt2 = dataIt->begin();
268 nlohmann::json::iterator passIt2 = dataIt->begin() + 1;
269 looksLikeIbm = true;
270 if (userIt2 != dataIt->end() && passIt2 != dataIt->end()) {
271 const std::string* userStr =
272 userIt2->get_ptr<const std::string*>();
273 const std::string* passStr =
274 passIt2->get_ptr<const std::string*>();
275 if (userStr != nullptr && passStr != nullptr) {
276 username = *userStr;
277 password = *passStr;
Ed Tanouse0d918b2018-03-27 17:41:04 -0700278 }
279 }
Ed Tanousba9f9a62017-10-11 16:40:35 -0700280 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700281
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700282 } else if (dataIt->is_object()) {
283 nlohmann::json::iterator userIt2 = dataIt->find("username");
284 nlohmann::json::iterator passIt2 = dataIt->find("password");
285 if (userIt2 != dataIt->end() && passIt2 != dataIt->end()) {
286 const std::string* userStr =
287 userIt2->get_ptr<const std::string*>();
288 const std::string* passStr =
289 passIt2->get_ptr<const std::string*>();
290 if (userStr != nullptr && passStr != nullptr) {
291 username = *userStr;
292 password = *passStr;
Ed Tanouse0d918b2018-03-27 17:41:04 -0700293 }
Ed Tanousba9f9a62017-10-11 16:40:35 -0700294 }
295 }
296 }
297 }
Ed Tanous911ac312017-08-15 09:37:42 -0700298 } else {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700299 // check if auth was provided as a headers
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700300 username = req.getHeaderValue("username");
301 password = req.getHeaderValue("password");
Ed Tanous911ac312017-08-15 09:37:42 -0700302 }
303
Ed Tanouse0d918b2018-03-27 17:41:04 -0700304 if (!username.empty() && !password.empty()) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700305 if (!pamAuthenticateUser(username, password)) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700306 res.result(boost::beast::http::status::unauthorized);
Ed Tanous911ac312017-08-15 09:37:42 -0700307 } else {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700308 auto session = persistent_data::SessionStore::getInstance()
309 .generateUserSession(username);
Ed Tanous911ac312017-08-15 09:37:42 -0700310
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700311 if (looksLikeIbm) {
Ed Tanousba9f9a62017-10-11 16:40:35 -0700312 // IBM requires a very specific login structure, and doesn't
313 // actually look at the status code. TODO(ed).... Fix that
314 // upstream
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700315 res.jsonValue = {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700316 {"data", "User '" + std::string(username) + "' logged in"},
317 {"message", "200 OK"},
318 {"status", "ok"}};
Ed Tanous9bd21fc2018-04-26 16:08:56 -0700319
320 // Hack alert. Boost beast by default doesn't let you declare
321 // multiple headers of the same name, and in most cases this is
322 // fine. Unfortunately here we need to set the Session cookie,
323 // which requires the httpOnly attribute, as well as the XSRF
324 // cookie, which requires it to not have an httpOnly attribute.
325 // To get the behavior we want, we simply inject the second
326 // "set-cookie" string into the value header, and get the result
327 // we want, even though we are technicaly declaring two headers
328 // here.
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700329 res.addHeader("Set-Cookie",
330 "XSRF-TOKEN=" + session->csrfToken +
331 "; Secure\r\nSet-Cookie: SESSION=" +
332 session->sessionToken + "; Secure; HttpOnly");
Ed Tanousba9f9a62017-10-11 16:40:35 -0700333 } else {
334 // if content type is json, assume json token
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700335 res.jsonValue = {{"token", session->sessionToken}};
Ed Tanous911ac312017-08-15 09:37:42 -0700336 }
337 }
338
339 } else {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700340 res.result(boost::beast::http::status::bad_request);
Ed Tanous911ac312017-08-15 09:37:42 -0700341 }
342 res.end();
343 });
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100344
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700345 BMCWEB_ROUTE(app, "/logout")
Borawski.Lukasz4b1b8682018-04-04 12:50:16 +0200346 .methods(
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700347 "POST"_method)([&](const crow::Request& req, crow::Response& res) {
Borawski.Lukasz4b1b8682018-04-04 12:50:16 +0200348 auto& session =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700349 app.template getContext<token_authorization::Middleware>(req)
Borawski.Lukasz4b1b8682018-04-04 12:50:16 +0200350 .session;
351 if (session != nullptr) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700352 persistent_data::SessionStore::getInstance().removeSession(session);
Borawski.Lukasz4b1b8682018-04-04 12:50:16 +0200353 }
354 res.end();
355 return;
356 });
Ed Tanous911ac312017-08-15 09:37:42 -0700357}
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700358} // namespace token_authorization
Ed Tanousba9f9a62017-10-11 16:40:35 -0700359} // namespace crow