summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Tanous <ed.tanous@intel.com>2018-10-05 01:54:21 +0300
committerEd Tanous <ed.tanous@intel.com>2018-10-22 19:04:03 +0300
commit820ce598b31a6f9bf4d3715d337b8e5ee47196c7 (patch)
treebf9999bac3c38e21b5841bf565a372ad79730831
parentc85eb8b739db9b0d42d27bf79439508075bbb0eb (diff)
downloadbmcweb-820ce598b31a6f9bf4d3715d337b8e5ee47196c7.tar.xz
Clean up SessionService POST
Previously, SessionService would return a json decode error for all errors, even if certain keys were incorrect. This updates the POST handler to use a better method, and should reduce the binary size a little, given that we're removing the possibly throwing get<> code. This needs a very good review. This endpoint is available pre-auth, and needs to be secure regardless of input. Tested By: curl --noproxy "*" -k -X POST -d '{"UserName": "root", "Password": "0penBmc"}' https://10.243.48.30/redfish/v1/SessionService/Sessions/ Returns correct response. Tested several variations, including extra parameters, missing username, missing password, ect. Got correct error code in all cases. Change-Id: Ic8e6edd9f7badc0d22aa8dafa9c0c260386712ac Signed-off-by: Ed Tanous <ed.tanous@intel.com>
-rw-r--r--redfish-core/lib/redfish_sessions.hpp167
1 files changed, 53 insertions, 114 deletions
diff --git a/redfish-core/lib/redfish_sessions.hpp b/redfish-core/lib/redfish_sessions.hpp
index 2406250fa3..145bbb1755 100644
--- a/redfish-core/lib/redfish_sessions.hpp
+++ b/redfish-core/lib/redfish_sessions.hpp
@@ -168,157 +168,96 @@ class SessionCollection : public Node
void doPost(crow::Response& res, const crow::Request& req,
const std::vector<std::string>& params) override
{
- boost::beast::http::status status;
- std::string username;
- bool userAuthSuccessful =
- authenticateUser(req, status, username, res.jsonValue);
- res.result(status);
-
- if (!userAuthSuccessful)
+ nlohmann::json postRequest;
+ if (!json_util::processJsonFromRequest(res, req, postRequest))
{
res.end();
return;
}
- // User is authenticated - create session for him
- auto session = crow::persistent_data::SessionStore::getInstance()
- .generateUserSession(username);
- res.addHeader("X-Auth-Token", session->sessionToken);
-
- res.addHeader("Location", "/redfish/v1/SessionService/Sessions/" +
- session->uniqueId);
-
- // Return data for created session
- memberSession.doGet(res, req, {session->uniqueId});
-
- // 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
- * @param[out] errJson JSON to which error messages will be written
- *
- * @return true if authentication was successful, false otherwise
- */
- bool authenticateUser(const crow::Request& req,
- boost::beast::http::status& httpRespCode,
- std::string& user, nlohmann::json& errJson)
- {
- // We need only UserName and Password - nothing more, nothing less
- static constexpr const unsigned int numberOfRequiredFieldsInReq = 2;
-
- // call with exceptions disabled
- auto loginCredentials = nlohmann::json::parse(req.body, nullptr, false);
- if (loginCredentials.is_discarded())
- {
- httpRespCode = boost::beast::http::status::bad_request;
-
- messages::addMessageToErrorJson(errJson, messages::malformedJSON());
-
- return false;
- }
-
- // Check that there are only as many fields as there should be
- if (loginCredentials.size() != numberOfRequiredFieldsInReq)
- {
- httpRespCode = boost::beast::http::status::bad_request;
-
- messages::addMessageToErrorJson(errJson, messages::malformedJSON());
-
- return false;
- }
-
- // Find fields that we need - UserName and Password
- auto userIt = loginCredentials.find("UserName");
- auto passIt = loginCredentials.find("Password");
- if (userIt == loginCredentials.end() ||
- passIt == loginCredentials.end())
+ std::string username;
+ std::string password;
+ for (const auto& item : postRequest.items())
{
- httpRespCode = boost::beast::http::status::bad_request;
-
- if (userIt == loginCredentials.end())
+ const std::string* strVal =
+ item.value().get_ptr<const std::string*>();
+ if (item.key() == "UserName")
{
- messages::addMessageToErrorJson(
- errJson, messages::propertyMissing("UserName"));
+ if (strVal == nullptr)
+ {
+ res.result(boost::beast::http::status::bad_request);
+ messages::addMessageToErrorJson(
+ res.jsonValue, messages::propertyValueTypeError(
+ item.value().dump(), item.key()));
+ continue;
+ }
+ username = *strVal;
}
-
- if (passIt == loginCredentials.end())
+ else if (item.key() == "Password")
{
- messages::addMessageToErrorJson(
- errJson, messages::propertyMissing("Password"));
+ if (strVal == nullptr)
+ {
+ res.result(boost::beast::http::status::bad_request);
+ messages::addMessageToErrorJson(
+ res.jsonValue, messages::propertyValueTypeError(
+ item.value().dump(), item.key()));
+ continue;
+ }
+
+ password = *strVal;
}
-
- return false;
- }
-
- // Check that given data is of valid type (string)
- if (!userIt->is_string() || !passIt->is_string())
- {
- httpRespCode = boost::beast::http::status::bad_request;
-
- if (!userIt->is_string())
- {
- messages::addMessageToErrorJson(
- errJson, messages::propertyValueTypeError(userIt->dump(),
- "UserName"));
- }
-
- if (!passIt->is_string())
+ else
{
+ res.result(boost::beast::http::status::bad_request);
messages::addMessageToErrorJson(
- errJson, messages::propertyValueTypeError(userIt->dump(),
- "Password"));
+ res.jsonValue, messages::propertyUnknown(item.key()));
+ continue;
}
-
- return false;
}
- // Extract username and password
- std::string username = userIt->get<const std::string>();
- std::string password = passIt->get<const std::string>();
-
- // Verify that required fields are not empty
- if (username.empty() || password.empty())
+ if (password.empty() || username.empty() ||
+ res.result() != boost::beast::http::status::ok)
{
- httpRespCode = boost::beast::http::status::bad_request;
-
if (username.empty())
{
+ res.result(boost::beast::http::status::bad_request);
messages::addMessageToErrorJson(
- errJson, messages::propertyMissing("UserName"));
+ res.jsonValue, messages::propertyMissing("UserName"));
}
if (password.empty())
{
+ res.result(boost::beast::http::status::bad_request);
messages::addMessageToErrorJson(
- errJson, messages::propertyMissing("Password"));
+ res.jsonValue, messages::propertyMissing("Password"));
}
+ res.end();
- return false;
+ return;
}
- // Finally - try to authenticate user
if (!pamAuthenticateUser(username, password))
{
- httpRespCode = boost::beast::http::status::unauthorized;
+ res.result(boost::beast::http::status::unauthorized);
messages::addMessageToErrorJson(
- errJson,
+ res.jsonValue,
messages::resourceAtUriUnauthorized(
std::string(req.url), "Invalid username or password"));
+ res.end();
- return false;
+ return;
}
- // User authenticated successfully
- httpRespCode = boost::beast::http::status::ok;
- user = username;
-
- return true;
+ // User is authenticated - create session
+ std::shared_ptr<crow::persistent_data::UserSession> session =
+ crow::persistent_data::SessionStore::getInstance()
+ .generateUserSession(username);
+ res.addHeader("X-Auth-Token", session->sessionToken);
+ res.addHeader("Location", "/redfish/v1/SessionService/Sessions/" +
+ session->uniqueId);
+ res.result(boost::beast::http::status::created);
+ memberSession.doGet(res, req, {session->uniqueId});
}
/**