diff options
author | Ed Tanous <ed.tanous@intel.com> | 2018-03-28 03:41:04 +0300 |
---|---|---|
committer | Ed Tanous <ed.tanous@intel.com> | 2018-06-29 21:18:14 +0300 |
commit | e0d918bc397350aa21af3dab9faa6e21748f6373 (patch) | |
tree | bdc13d1e9937c0f153e89f3ab1be050d4bf52ee7 /include | |
parent | 77dd8813e9a1f2baec63d959de15af39a8cd12d0 (diff) | |
download | bmcweb-e0d918bc397350aa21af3dab9faa6e21748f6373.tar.xz |
Boost beast
This commit is the beginings of attempting to transition away from
crow, and toward boost::beast. Unit tests are passing, and
implementation appears to be slightly faster than crow.
Change-Id: Ic8d946dc7a04f514c67b1098f181eee1ced69171
Diffstat (limited to 'include')
-rw-r--r-- | include/ast_video_puller.hpp | 2 | ||||
-rw-r--r-- | include/openbmc_dbus_rest.hpp | 45 | ||||
-rw-r--r-- | include/pam_authenticate.hpp | 13 | ||||
-rw-r--r-- | include/persistent_data_middleware.hpp | 8 | ||||
-rw-r--r-- | include/redfish_v1.hpp | 36 | ||||
-rw-r--r-- | include/sessions.hpp | 59 | ||||
-rw-r--r-- | include/token_authorization_middleware.hpp | 187 | ||||
-rw-r--r-- | include/webassets.hpp | 8 |
8 files changed, 175 insertions, 183 deletions
diff --git a/include/ast_video_puller.hpp b/include/ast_video_puller.hpp index 759aaebb00..6cd7f37c35 100644 --- a/include/ast_video_puller.hpp +++ b/include/ast_video_puller.hpp @@ -148,7 +148,7 @@ class AsyncVideoPuller { boost::asio::async_read( dev_video, mutable_buffer, [this](const boost::system::error_code &ec, std::size_t bytes_transferred) { - if (ec != nullptr) { + if (ec) { std::cerr << "Read failed with status " << ec << "\n"; } else { this->read_done(); diff --git a/include/openbmc_dbus_rest.hpp b/include/openbmc_dbus_rest.hpp index 4257127c81..e6052f13b5 100644 --- a/include/openbmc_dbus_rest.hpp +++ b/include/openbmc_dbus_rest.hpp @@ -2,6 +2,7 @@ #include <tinyxml2.h> #include <dbus_singleton.hpp> +#include <boost/algorithm/string.hpp> #include <boost/container/flat_set.hpp> namespace crow { @@ -130,7 +131,7 @@ void handle_enumerate(crow::response &res, const std::string &object_path) { const boost::system::error_code ec, const GetSubTreeType &object_names) { if (ec) { - res.code = 500; + res.result(boost::beast::http::status::internal_server_error); res.end(); return; } @@ -144,7 +145,7 @@ void handle_enumerate(crow::response &res, const std::string &object_path) { } if (connections.size() <= 0) { - res.code = 404; + res.result(boost::beast::http::status::not_found); res.end(); return; } @@ -163,10 +164,10 @@ void handle_enumerate(crow::response &res, const std::string &object_path) { template <typename... Middlewares> void request_routes(Crow<Middlewares...> &app) { - CROW_ROUTE(app, "/bus/").methods("GET"_method)([](const crow::request &req) { - return nlohmann::json{{"busses", {{{"name", "system"}}}}, {"status", "ok"}}; - - }); + CROW_ROUTE(app, "/bus/") + .methods("GET"_method)([](const crow::request &req, crow::response &res) { + res.json_value = {{"busses", {{{"name", "system"}}}}, {"status", "ok"}}; + }); CROW_ROUTE(app, "/bus/system/") .methods("GET"_method)([](const crow::request &req, crow::response &res) { @@ -174,7 +175,7 @@ void request_routes(Crow<Middlewares...> &app) { auto myCallback = [&res](const boost::system::error_code ec, std::vector<std::string> &names) { if (ec) { - res.code = 500; + res.result(boost::beast::http::status::internal_server_error); } else { std::sort(names.begin(), names.end()); nlohmann::json j{{"status", "ok"}}; @@ -197,7 +198,7 @@ void request_routes(Crow<Middlewares...> &app) { [&res](const boost::system::error_code ec, const std::vector<std::string> &object_paths) { if (ec) { - res.code = 500; + res.result(boost::beast::http::status::internal_server_error); } else { res.json_value = {{"status", "ok"}, {"message", "200 OK"}, @@ -232,21 +233,21 @@ void request_routes(Crow<Middlewares...> &app) { auto request_dbus_data = nlohmann::json::parse(req.body, nullptr, false); if (request_dbus_data.is_discarded()) { - res.code = 400; + res.result(boost::beast::http::status::unauthorized); res.end(); return; } auto property_value_it = request_dbus_data.find("data"); if (property_value_it == request_dbus_data.end()) { - res.code = 400; + res.result(boost::beast::http::status::unauthorized); res.end(); return; } property_set_value = property_value_it->get<const std::string>(); if (property_set_value.empty()) { - res.code = 400; + res.result(boost::beast::http::status::unauthorized); res.end(); return; } @@ -266,16 +267,16 @@ void request_routes(Crow<Middlewares...> &app) { ](const boost::system::error_code ec, const GetObjectType &object_names) { if (ec) { - res.code = 500; + res.result(boost::beast::http::status::internal_server_error); res.end(); return; } if (object_names.size() != 1) { - res.code = 404; + res.result(boost::beast::http::status::not_found); res.end(); return; } - if (req.method == "GET"_method) { + if (req.method() == "GET"_method) { for (auto &interface : object_names[0].second) { crow::connections::system_bus->async_method_call( [&res, transaction]( @@ -303,7 +304,7 @@ void request_routes(Crow<Middlewares...> &app) { object_names[0].first, object_path, "org.freedesktop.DBus.Properties", "GetAll", interface); } - } else if (req.method == "PUT"_method) { + } else if (req.method() == "PUT"_method) { for (auto &interface : object_names[0].second) { crow::connections::system_bus->async_method_call( [ @@ -351,7 +352,7 @@ void request_routes(Crow<Middlewares...> &app) { // if nobody filled in the property, all calls either // errored, or failed if (transaction == nullptr) { - res.code = 403; + res.result(boost::beast::http::status::forbidden); res.json_value = {{"status", "error"}, {"message", "403 Forbidden"}, {"data", @@ -426,7 +427,7 @@ void request_routes(Crow<Middlewares...> &app) { if (it != strs.end()) { // if there is more levels past the method name, something went // wrong, throw an error - res.code = 404; + res.result(boost::beast::http::status::not_found); res.end(); return; } @@ -452,8 +453,9 @@ void request_routes(Crow<Middlewares...> &app) { CROW_LOG_ERROR << "XML document failed to parse " << process_name << " " << object_path << "\n"; - res.write(nlohmann::json{{"status", "XML parse error"}}); - res.code = 500; + res.json_value = {{"status", "XML parse error"}}; + res.result( + boost::beast::http::status::internal_server_error); } else { nlohmann::json interfaces_array = nlohmann::json::array(); tinyxml2::XMLElement *interface = @@ -498,7 +500,8 @@ void request_routes(Crow<Middlewares...> &app) { CROW_LOG_ERROR << "XML document failed to parse " << process_name << " " << object_path << "\n"; - res.code = 500; + res.result( + boost::beast::http::status::internal_server_error); } else { tinyxml2::XMLElement *node = @@ -575,7 +578,7 @@ void request_routes(Crow<Middlewares...> &app) { if (interface == nullptr) { // if we got to the end of the list and never found a // match, throw 404 - res.code = 404; + res.result(boost::beast::http::status::not_found); } } } diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp index 5b4b454ab4..997c2974bd 100644 --- a/include/pam_authenticate.hpp +++ b/include/pam_authenticate.hpp @@ -1,8 +1,9 @@ #pragma once #include <security/pam_appl.h> -#include <memory> #include <cstring> +#include <memory> +#include <boost/utility/string_view.hpp> // function used to get user input inline int pam_function_conversation(int num_msg, @@ -32,13 +33,15 @@ inline int pam_function_conversation(int num_msg, return PAM_SUCCESS; } -inline bool pam_authenticate_user(const std::string& username, - const std::string& password) { +inline bool pam_authenticate_user(const boost::string_view username, + const boost::string_view password) { + std::string user_str(username); + std::string pass_str(password); const struct pam_conv local_conversation = { - pam_function_conversation, const_cast<char*>(password.c_str())}; + pam_function_conversation, const_cast<char*>(pass_str.c_str())}; pam_handle_t* local_auth_handle = NULL; // this gets set by pam_start - if (pam_start("dropbear", username.c_str(), &local_conversation, + if (pam_start("dropbear", user_str.c_str(), &local_conversation, &local_auth_handle) != PAM_SUCCESS) { return false; } diff --git a/include/persistent_data_middleware.hpp b/include/persistent_data_middleware.hpp index fcab52fa61..77a5bbbf0a 100644 --- a/include/persistent_data_middleware.hpp +++ b/include/persistent_data_middleware.hpp @@ -68,11 +68,11 @@ class Middleware { if (jSessions != data.end()) { if (jSessions->is_object()) { for (const auto& elem : *jSessions) { - UserSession newSession; + std::shared_ptr<UserSession> newSession = std::make_shared<UserSession>(); - if (newSession.fromJson(elem)) { - session_store->auth_tokens.emplace(newSession.unique_id, - std::move(newSession)); + if (newSession->fromJson(elem)) { + session_store->auth_tokens.emplace(newSession->unique_id, + newSession); } } } diff --git a/include/redfish_v1.hpp b/include/redfish_v1.hpp index 49a5a15e81..e8f4d7fd35 100644 --- a/include/redfish_v1.hpp +++ b/include/redfish_v1.hpp @@ -11,36 +11,6 @@ namespace crow { namespace redfish { -template <typename... Middlewares> -void get_redfish_sub_routes(Crow<Middlewares...>& app, const std::string& url, - nlohmann::json& j) { - std::vector<const std::string*> routes = app.get_routes(url); - for (auto route : routes) { - auto redfish_sub_route = - route->substr(url.size(), route->size() - url.size() - 1); - // check if the route is at this level, and we didn't find and exact match - // also, filter out resources that start with $ to remove $metadata - if (!redfish_sub_route.empty() && redfish_sub_route[0] != '$' && - redfish_sub_route.find('/') == std::string::npos) { - j[redfish_sub_route] = nlohmann::json{{"@odata.id", *route}}; - } - } -} - -std::string execute_process(const char* cmd) { - std::array<char, 128> buffer; - std::string result; - std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose); - if (!pipe) throw std::runtime_error("popen() failed!"); - while (!feof(pipe.get())) { - if (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) - result += buffer.data(); - } - return result; -} - -// GetManagedObjects unpack type. Observe that variant has only one bool type, -// because we don't actually use the values it provides using ManagedObjectType = std::vector<std::pair< sdbusplus::message::object_path, boost::container::flat_map< @@ -62,7 +32,7 @@ void request_routes(Crow<Middlewares...>& app) { [&](const boost::system::error_code ec, const ManagedObjectType& users) { if (ec) { - res.code = 500; + res.result(boost::beast::http::status::internal_server_error); } else { res.json_value = { {"@odata.context", @@ -107,7 +77,7 @@ void request_routes(Crow<Middlewares...>& app) { const boost::system::error_code ec, const ManagedObjectType& users) { if (ec) { - res.code = 500; + res.result(boost::beast::http::status::internal_server_error); } else { for (auto& user : users) { const std::string& path = @@ -141,7 +111,7 @@ void request_routes(Crow<Middlewares...>& app) { } } if (res.json_value.is_null()) { - res.code = 404; + res.result(boost::beast::http::status::not_found); } } res.end(); diff --git a/include/sessions.hpp b/include/sessions.hpp index 15ff9cad38..fdd12000f4 100644 --- a/include/sessions.hpp +++ b/include/sessions.hpp @@ -73,12 +73,12 @@ struct UserSession { } }; -void to_json(nlohmann::json& j, const UserSession& p) { - if (p.persistence != PersistenceType::SINGLE_REQUEST) { - j = nlohmann::json{{"unique_id", p.unique_id}, - {"session_token", p.session_token}, - {"username", p.username}, - {"csrf_token", p.csrf_token}}; +void to_json(nlohmann::json& j, const std::shared_ptr<UserSession> p) { + if (p->persistence != PersistenceType::SINGLE_REQUEST) { + j = {{"unique_id", p->unique_id}, + {"session_token", p->session_token}, + {"username", p->username}, + {"csrf_token", p->csrf_token}}; } } @@ -87,8 +87,8 @@ class Middleware; class SessionStore { public: SessionStore() : timeout_in_minutes(60) {} - const UserSession& generate_user_session( - const std::string& username, + std::shared_ptr<UserSession> generate_user_session( + const boost::string_view username, PersistenceType persistence = PersistenceType::TIMEOUT) { // TODO(ed) find a secure way to not generate session identifiers if // persistence is set to SINGLE_REQUEST @@ -120,42 +120,42 @@ class SessionStore { for (int i = 0; i < unique_id.size(); ++i) { unique_id[i] = alphanum[dist(rd)]; } - - const auto session_it = auth_tokens.emplace( - session_token, - std::move(UserSession{unique_id, session_token, username, csrf_token, - std::chrono::steady_clock::now(), persistence})); - const UserSession& user = (session_it).first->second; + auto session = std::make_shared<UserSession>( + UserSession{unique_id, session_token, std::string(username), csrf_token, + std::chrono::steady_clock::now(), persistence}); + auto it = auth_tokens.emplace(std::make_pair(session_token, session)); // Only need to write to disk if session isn't about to be destroyed. need_write_ = persistence == PersistenceType::TIMEOUT; - return user; + return it.first->second; } - const UserSession* login_session_by_token(const std::string& token) { + std::shared_ptr<UserSession> login_session_by_token( + const boost::string_view token) { apply_session_timeouts(); - auto session_it = auth_tokens.find(token); + auto session_it = auth_tokens.find(std::string(token)); if (session_it == auth_tokens.end()) { return nullptr; } - UserSession& foo = session_it->second; - foo.last_updated = std::chrono::steady_clock::now(); - return &foo; + std::shared_ptr<UserSession> user_session = session_it->second; + user_session->last_updated = std::chrono::steady_clock::now(); + return user_session; } - const UserSession* get_session_by_uid(const std::string& uid) { + std::shared_ptr<UserSession> get_session_by_uid( + const boost::string_view uid) { apply_session_timeouts(); // TODO(Ed) this is inefficient auto session_it = auth_tokens.begin(); while (session_it != auth_tokens.end()) { - if (session_it->second.unique_id == uid) { - return &session_it->second; + if (session_it->second->unique_id == uid) { + return session_it->second; } session_it++; } return nullptr; } - void remove_session(const UserSession* session) { + void remove_session(std::shared_ptr<UserSession> session) { auth_tokens.erase(session->session_token); need_write_ = true; } @@ -168,8 +168,8 @@ class SessionStore { std::vector<const std::string*> ret; ret.reserve(auth_tokens.size()); for (auto& session : auth_tokens) { - if (getAll || type == session.second.persistence) { - ret.push_back(&session.second.unique_id); + if (getAll || type == session.second->persistence) { + ret.push_back(&session.second->unique_id); } } return ret; @@ -191,7 +191,7 @@ class SessionStore { last_timeout_update = time_now; auto auth_tokens_it = auth_tokens.begin(); while (auth_tokens_it != auth_tokens.end()) { - if (time_now - auth_tokens_it->second.last_updated >= + if (time_now - auth_tokens_it->second->last_updated >= timeout_in_minutes) { auth_tokens_it = auth_tokens.erase(auth_tokens_it); need_write_ = true; @@ -202,11 +202,12 @@ class SessionStore { } } std::chrono::time_point<std::chrono::steady_clock> last_timeout_update; - boost::container::flat_map<std::string, UserSession> auth_tokens; + boost::container::flat_map<std::string, std::shared_ptr<UserSession>> + auth_tokens; std::random_device rd; bool need_write_{false}; std::chrono::minutes timeout_in_minutes; }; -} // namespaec PersistentData +} // namespace PersistentData } // namespace crow diff --git a/include/token_authorization_middleware.hpp b/include/token_authorization_middleware.hpp index 07540d42b0..49649dd978 100644 --- a/include/token_authorization_middleware.hpp +++ b/include/token_authorization_middleware.hpp @@ -5,10 +5,9 @@ #include <webassets.hpp> #include <random> #include <crow/app.h> -#include <crow/http_codes.h> +#include <crow/common.h> #include <crow/http_request.h> #include <crow/http_response.h> -#include <boost/bimap.hpp> #include <boost/container/flat_set.hpp> namespace crow { @@ -18,7 +17,7 @@ namespace TokenAuthorization { class Middleware { public: struct context { - const crow::PersistentData::UserSession* session; + std::shared_ptr<crow::PersistentData::UserSession> session; }; void before_handle(crow::request& req, response& res, context& ctx) { @@ -27,25 +26,27 @@ class Middleware { } ctx.session = perform_xtoken_auth(req); - if (ctx.session == nullptr) { ctx.session = perform_cookie_auth(req); } - - const std::string& auth_header = req.get_header_value("Authorization"); - // Reject any kind of auth other than basic or token - if (ctx.session == nullptr && boost::starts_with(auth_header, "Token ")) { - ctx.session = perform_token_auth(auth_header); - } - - if (ctx.session == nullptr && boost::starts_with(auth_header, "Basic ")) { - ctx.session = perform_basic_auth(auth_header); + if (ctx.session == nullptr) { + boost::string_view auth_header = req.get_header_value("Authorization"); + if (!auth_header.empty()) { + // Reject any kind of auth other than basic or token + if (boost::starts_with(auth_header, "Token ")) { + ctx.session = perform_token_auth(auth_header); + } else if (boost::starts_with(auth_header, "Basic ")) { + ctx.session = perform_basic_auth(auth_header); + } + } } if (ctx.session == nullptr) { CROW_LOG_WARNING << "[AuthMiddleware] authorization failed"; - res.code = static_cast<int>(HttpRespCode::UNAUTHORIZED); + + res.result(boost::beast::http::status::unauthorized); res.add_header("WWW-Authenticate", "Basic"); + res.end(); return; } @@ -57,10 +58,10 @@ class Middleware { template <typename AllContext> void after_handle(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? + // 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::PersistentData::PersistenceType::SINGLE_REQUEST) { @@ -69,12 +70,12 @@ class Middleware { } private: - const crow::PersistentData::UserSession* perform_basic_auth( - const std::string& auth_header) const { + const std::shared_ptr<crow::PersistentData::UserSession> perform_basic_auth( + boost::string_view auth_header) const { CROW_LOG_DEBUG << "[AuthMiddleware] Basic authentication"; std::string auth_data; - std::string param = auth_header.substr(strlen("Basic ")); + boost::string_view param = auth_header.substr(strlen("Basic ")); if (!crow::utility::base64_decode(param, auth_data)) { return nullptr; } @@ -102,24 +103,24 @@ class Middleware { // needed. // This whole flow needs to be revisited anyway, as we can't be // calling directly into pam for every request - return &(PersistentData::session_store->generate_user_session( - user, crow::PersistentData::PersistenceType::SINGLE_REQUEST)); + return PersistentData::session_store->generate_user_session( + user, crow::PersistentData::PersistenceType::SINGLE_REQUEST); } - const crow::PersistentData::UserSession* perform_token_auth( - const std::string& auth_header) const { + const std::shared_ptr<crow::PersistentData::UserSession> perform_token_auth( + boost::string_view auth_header) const { CROW_LOG_DEBUG << "[AuthMiddleware] Token authentication"; - std::string token = auth_header.substr(strlen("Token ")); + boost::string_view token = auth_header.substr(strlen("Token ")); auto session = PersistentData::session_store->login_session_by_token(token); return session; } - const crow::PersistentData::UserSession* perform_xtoken_auth( + const std::shared_ptr<crow::PersistentData::UserSession> perform_xtoken_auth( const crow::request& req) const { CROW_LOG_DEBUG << "[AuthMiddleware] X-Auth-Token authentication"; - const std::string& token = req.get_header_value("X-Auth-Token"); + boost::string_view token = req.get_header_value("X-Auth-Token"); if (token.empty()) { return nullptr; } @@ -127,11 +128,11 @@ class Middleware { return session; } - const crow::PersistentData::UserSession* perform_cookie_auth( + const std::shared_ptr<crow::PersistentData::UserSession> perform_cookie_auth( const crow::request& req) const { CROW_LOG_DEBUG << "[AuthMiddleware] Cookie authentication"; - auto& cookie_value = req.get_header_value("Cookie"); + boost::string_view cookie_value = req.get_header_value("Cookie"); if (cookie_value.empty()) { return nullptr; } @@ -145,18 +146,18 @@ class Middleware { if (end_index == std::string::npos) { end_index = cookie_value.size(); } - std::string auth_key = + boost::string_view auth_key = cookie_value.substr(start_index, end_index - start_index); - const crow::PersistentData::UserSession* session = + const std::shared_ptr<crow::PersistentData::UserSession> session = PersistentData::session_store->login_session_by_token(auth_key); if (session == nullptr) { return nullptr; } // RFC7231 defines methods that need csrf protection - if (req.method != "GET"_method) { - const std::string& csrf = req.get_header_value("X-XSRF-TOKEN"); + if (req.method() != "GET"_method) { + boost::string_view csrf = req.get_header_value("X-XSRF-TOKEN"); // Make sure both tokens are filled if (csrf.empty() || session->csrf_token.empty()) { return nullptr; @@ -171,21 +172,21 @@ class Middleware { // checks if request can be forwarded without authentication bool is_on_whitelist(const crow::request& req) const { - // it's allowed to GET root node without authentication - if ("GET"_method == req.method) { - CROW_LOG_DEBUG << "TESTING ROUTE " << req.url; + // it's allowed to GET root node without authentica tion + if ("GET"_method == req.method()) { if (req.url == "/redfish/v1" || req.url == "/redfish/v1/") { return true; - } else if (crow::webassets::routes.find(req.url) != + } 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/") || + // 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") || (req.url == "/logout")) { return true; } @@ -207,35 +208,38 @@ void request_routes(Crow<Middlewares...>& app) { CROW_ROUTE(app, "/login") .methods( "POST"_method)([&](const crow::request& req, crow::response& res) { - std::string content_type; - auto content_type_it = req.headers.find("content-type"); - if (content_type_it != req.headers.end()) { - content_type = content_type_it->second; - boost::algorithm::to_lower(content_type); - } - const std::string* username; - const std::string* password; + boost::string_view content_type = req.get_header_value("content-type"); + boost::string_view username; + boost::string_view password; + bool looks_like_ibm = false; - // This object needs to be declared at this scope so the strings within - // it are not destroyed before we can use them + // This object needs to be declared at this scope so the strings + // within it are not destroyed before we can use them nlohmann::json login_credentials; // Check if auth was provided by a payload if (content_type == "application/json") { login_credentials = nlohmann::json::parse(req.body, nullptr, false); if (login_credentials.is_discarded()) { - res.code = 400; + 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 - auto user_it = login_credentials.find("username"); - auto pass_it = login_credentials.find("password"); + nlohmann::json::iterator user_it = login_credentials.find("username"); + nlohmann::json::iterator pass_it = login_credentials.find("password"); if (user_it != login_credentials.end() && pass_it != login_credentials.end()) { - username = user_it->get_ptr<const std::string*>(); - password = pass_it->get_ptr<const std::string*>(); + const std::string* user_str = + user_it->get_ptr<const std::string*>(); + const std::string* pass_str = + pass_it->get_ptr<const std::string*>(); + if (user_str != nullptr && pass_str != nullptr) { + username = *user_str; + password = *pass_str; + } } else { // Openbmc appears to push a data object that contains the same // keys (username and password), attempt to use that @@ -245,56 +249,70 @@ void request_routes(Crow<Middlewares...>& app) { // "password"] if (data_it->is_array()) { if (data_it->size() == 2) { - username = (*data_it)[0].get_ptr<const std::string*>(); - password = (*data_it)[1].get_ptr<const std::string*>(); + nlohmann::json::iterator user_it2 = data_it->begin(); + nlohmann::json::iterator pass_it2 = data_it->begin() + 1; looks_like_ibm = true; + if (user_it2 != data_it->end() && + pass_it2 != data_it->end()) { + const std::string* user_str = + user_it2->get_ptr<const std::string*>(); + const std::string* pass_str = + pass_it2->get_ptr<const std::string*>(); + if (user_str != nullptr && pass_str != nullptr) { + username = *user_str; + password = *pass_str; + } + } } + } else if (data_it->is_object()) { - auto user_it = data_it->find("username"); - auto pass_it = data_it->find("password"); - if (user_it != data_it->end() && pass_it != data_it->end()) { - username = user_it->get_ptr<const std::string*>(); - password = pass_it->get_ptr<const std::string*>(); + nlohmann::json::iterator user_it2 = data_it->find("username"); + nlohmann::json::iterator pass_it2 = data_it->find("password"); + if (user_it2 != data_it->end() && pass_it2 != data_it->end()) { + const std::string* user_str = + user_it2->get_ptr<const std::string*>(); + const std::string* pass_str = + pass_it2->get_ptr<const std::string*>(); + if (user_str != nullptr && pass_str != nullptr) { + username = *user_str; + password = *pass_str; + } } } } } } else { - // check if auth was provided as a query string - auto user_it = req.headers.find("username"); - auto pass_it = req.headers.find("password"); - if (user_it != req.headers.end() && pass_it != req.headers.end()) { - username = &user_it->second; - password = &pass_it->second; - } + // check if auth was provided as a headers + username = req.get_header_value("username"); + password = req.get_header_value("password"); } - if (username != nullptr && !username->empty() && password != nullptr && - !password->empty()) { - if (!pam_authenticate_user(*username, *password)) { - res.code = res.code = static_cast<int>(HttpRespCode::UNAUTHORIZED); + if (!username.empty() && !password.empty()) { + if (!pam_authenticate_user(username, password)) { + res.result(boost::beast::http::status::unauthorized); } else { - auto& session = - PersistentData::session_store->generate_user_session(*username); + auto session = + PersistentData::session_store->generate_user_session(username); if (looks_like_ibm) { // IBM requires a very specific login structure, and doesn't // actually look at the status code. TODO(ed).... Fix that // upstream - res.json_value = {{"data", "User '" + *username + "' logged in"}, - {"message", "200 OK"}, - {"status", "ok"}}; - res.add_header("Set-Cookie", "XSRF-TOKEN=" + session.csrf_token); - res.add_header("Set-Cookie", "SESSION=" + session.session_token + + res.json_value = { + {"data", "User '" + std::string(username) + "' logged in"}, + {"message", "200 OK"}, + {"status", "ok"}}; + res.add_header("Set-Cookie", "XSRF-TOKEN=" + session->csrf_token); + res.add_header("Set-Cookie", "SESSION=" + session->session_token + "; Secure; HttpOnly"); } else { // if content type is json, assume json token - res.json_value = {{"token", session.session_token}}; + res.json_value = {{"token", session->session_token}}; } } } else { - res.code = static_cast<int>(HttpRespCode::BAD_REQUEST); + res.result(boost::beast::http::status::bad_request); } res.end(); }); @@ -308,7 +326,6 @@ void request_routes(Crow<Middlewares...>& app) { if (session != nullptr) { PersistentData::session_store->remove_session(session); } - res.code = static_cast<int>(HttpRespCode::OK); res.end(); return; diff --git a/include/webassets.hpp b/include/webassets.hpp index 6384f3abc3..85de3addf4 100644 --- a/include/webassets.hpp +++ b/include/webassets.hpp @@ -4,7 +4,6 @@ #include <fstream> #include <string> #include <crow/app.h> -#include <crow/http_codes.h> #include <crow/http_request.h> #include <crow/http_response.h> #include <crow/routing.h> @@ -88,7 +87,7 @@ void request_routes(Crow<Middlewares...>& app) { auto content_type_it = content_types.find(extension.c_str()); if (content_type_it == content_types.end()) { - CROW_LOG_ERROR << "Cannot determine content-type for " << webpath + CROW_LOG_ERROR << "Cannot determine content-type for " << absolute_path << " with extension " << extension; } else { content_type = content_type_it->second; @@ -109,13 +108,12 @@ void request_routes(Crow<Middlewares...>& app) { std::ifstream inf(absolute_path); if (!inf) { CROW_LOG_DEBUG << "failed to read file"; - res.code = static_cast<int>(HttpRespCode::NOT_FOUND); - res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR); + res.result(boost::beast::http::status::internal_server_error); res.end(); return; } - res.body = {std::istreambuf_iterator<char>(inf), + res.body() = {std::istreambuf_iterator<char>(inf), std::istreambuf_iterator<char>()}; res.end(); }); |