diff options
author | Kowalski, Kamil <kamil.kowalski@intel.com> | 2018-01-31 15:24:59 +0300 |
---|---|---|
committer | Ed Tanous <ed.tanous@intel.com> | 2018-02-06 02:40:03 +0300 |
commit | 2b7981f6e53f76c662d427ced8bd9cffc5dde695 (patch) | |
tree | 22412d4e43c4a963e01067487c6f9d1175d5409e /redfish-core/lib/redfish_sessions.hpp | |
parent | 109799e512a6abcad3303dffa0505fcf2a521a1a (diff) | |
download | bmcweb-2b7981f6e53f76c662d427ced8bd9cffc5dde695.tar.xz |
Session and SessionCollection
New Redfish-Core nodes added (removed from redfish_v1.hpp) - Session
and SessionCollection. Tested manually on x86 VM and Wolfpass Platform.
Behavior almost identical to what was before - differences:
- SessionCollection - now only returns TIMEOUT presistence sessions, not SINGLE
- Aquiring sessions from session storage now applies timeouts
Change-Id: I68bf4fa7fa1c8371216a7d4daa30bbfb653cfa72
Signed-off-by: Kowalski, Kamil <kamil.kowalski@intel.com>
Diffstat (limited to 'redfish-core/lib/redfish_sessions.hpp')
-rw-r--r-- | redfish-core/lib/redfish_sessions.hpp | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/redfish-core/lib/redfish_sessions.hpp b/redfish-core/lib/redfish_sessions.hpp new file mode 100644 index 0000000000..0835fa18a8 --- /dev/null +++ b/redfish-core/lib/redfish_sessions.hpp @@ -0,0 +1,226 @@ +/* +// Copyright (c) 2018 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ +#pragma once +#include <tuple> +#include "node.hpp" +#include "session_storage_singleton.hpp" + +namespace redfish { + +class SessionCollection; + +class Sessions : public Node { + public: + template <typename CrowApp, typename PrivilegeProvider> + Sessions(CrowApp& app, PrivilegeProvider& provider) + : Node(app, provider, "#Session.v1_0_2.Session", + "/redfish/v1/SessionService/Sessions/<str>", std::string()) { + nodeJson["@odata.type"] = Node::odataType; + nodeJson["@odata.context"] = "/redfish/v1/$metadata#Session.Session"; + nodeJson["Name"] = "User Session"; + nodeJson["Description"] = "Manager User Session"; + } + + private: + void doGet(crow::response& res, const crow::request& req, + const std::vector<std::string>& params) override { + auto session = + crow::PersistentData::session_store->get_session_by_uid(params[0]); + + if (session == nullptr) { + res.code = static_cast<int>(HttpRespCode::NOT_FOUND); + res.end(); + return; + } + + nodeJson["Id"] = session->unique_id; + nodeJson["UserName"] = session->username; + nodeJson["@odata.id"] = + "/redfish/v1/SessionService/Sessions/" + session->unique_id; + + res.json_value = nodeJson; + res.end(); + } + + void doDelete(crow::response& res, const crow::request& req, + const std::vector<std::string>& params) override { + // Need only 1 param which should be id of session to be deleted + if (params.size() != 1) { + res.code = static_cast<int>(HttpRespCode::BAD_REQUEST); + res.end(); + return; + } + + auto session = + crow::PersistentData::session_store->get_session_by_uid(params[0]); + + if (session == nullptr) { + res.code = static_cast<int>(HttpRespCode::NOT_FOUND); + res.end(); + return; + } + + crow::PersistentData::session_store->remove_session(session); + res.code = static_cast<int>(HttpRespCode::OK); + res.end(); + } + + /** + * This allows SessionCollection to reuse this class' doGet method, to + * maintain consistency of returned data, as Collection's doPost should return + * data for created member which should match member's doGet result in 100% + */ + friend SessionCollection; + + nlohmann::json nodeJson; +}; + +class SessionCollection : public Node { + public: + template <typename CrowApp, typename PrivilegeProvider> + SessionCollection(CrowApp& app, PrivilegeProvider& provider) + : Node(app, provider, "#SessionCollection.SessionCollection", + "/redfish/v1/SessionService/Sessions/"), + memberSession(app, provider) { + nodeJson["@odata.type"] = Node::odataType; + nodeJson["@odata.id"] = Node::odataId; + nodeJson["@odata.context"] = + "/redfish/v1/$metadata#SessionCollection.SessionCollection"; + nodeJson["Name"] = "Session Collection"; + nodeJson["Description"] = "Session Collection"; + nodeJson["Members@odata.count"] = 0; + nodeJson["Members"] = nlohmann::json::array(); + } + + private: + void doGet(crow::response& res, const crow::request& req, + const std::vector<std::string>& params) override { + std::vector<const std::string*> session_ids = + crow::PersistentData::session_store->get_unique_ids( + false, crow::PersistentData::PersistenceType::TIMEOUT); + + nodeJson["Members@odata.count"] = session_ids.size(); + nodeJson["Members"] = nlohmann::json::array(); + for (const auto& uid : session_ids) { + nodeJson["Members"].push_back( + {{"@odata.id", "/redfish/v1/SessionService/Sessions/" + *uid}}); + } + + res.json_value = nodeJson; + res.end(); + } + + void doPost(crow::response& res, const crow::request& req, + const std::vector<std::string>& params) override { + std::string username; + bool userAuthSuccessful = authenticateUser(req, &res.code, &username); + + if (!userAuthSuccessful) { + res.end(); + return; + } + + // User is authenticated - create session for him + auto session = + crow::PersistentData::session_store->generate_user_session(username); + res.add_header("X-Auth-Token", session.session_token); + + // Return data for created session + memberSession.doGet(res, req, {session.unique_id}); + + // No need for res.end(), as it is called by doGet() + } + + /** + * @brief Verifies data provided in request and tries to authenticate user + * + * @param[in] req Crow request containing authentication data + * @param[out] httpRespCode HTTP Code that should be returned in response + * @param[out] user Retrieved username - not filled on failure + * + * @return true if authentication was successful, false otherwise + */ + bool authenticateUser(const crow::request& req, int* httpRespCode, + std::string* user) { + // We need only UserName and Password - nothing more, nothing less + static constexpr const unsigned int numberOfRequiredFieldsInReq = 2; + + // call with exceptions disabled + auto login_credentials = nlohmann::json::parse(req.body, nullptr, false); + if (login_credentials.is_discarded()) { + *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST); + + return false; + } + + // Check that there are only as many fields as there should be + if (login_credentials.size() != numberOfRequiredFieldsInReq) { + *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST); + + return false; + } + + // Find fields that we need - UserName and Password + auto user_it = login_credentials.find("UserName"); + auto pass_it = login_credentials.find("Password"); + if (user_it == login_credentials.end() || + pass_it == login_credentials.end()) { + *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST); + + return false; + } + + // Check that given data is of valid type (string) + if (!user_it->is_string() || !pass_it->is_string()) { + *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST); + + return false; + } + + // Extract username and password + std::string username = user_it->get<const std::string>(); + std::string password = pass_it->get<const std::string>(); + + // Verify that required fields are not empty + if (username.empty() || password.empty()) { + *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST); + + return false; + } + + // Finally - try to authenticate user + if (!pam_authenticate_user(username, password)) { + *httpRespCode = static_cast<int>(HttpRespCode::UNAUTHORIZED); + + return false; + } + + // User authenticated successfully + *httpRespCode = static_cast<int>(HttpRespCode::OK); + *user = username; + + return true; + } + + /** + * Member session to ensure consistency between collection's doPost and + * member's doGet, as they should return 100% matching data + */ + Sessions memberSession; + nlohmann::json nodeJson; +}; + +} // namespace redfish |