blob: 4e429e8f72947c92072df1d5d41d23809234bd1b [file] [log] [blame]
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010017
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +010018#include "node.hpp"
19#include "session_storage_singleton.hpp"
20
21namespace redfish {
22
23class SessionCollection;
24
25class Sessions : public Node {
26 public:
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010027 Sessions(CrowApp& app)
Ed Tanous6c233012018-03-15 14:43:56 -070028 : Node(app, "/redfish/v1/SessionService/Sessions/<str>/", std::string()) {
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010029 Node::json["@odata.type"] = "#Session.v1_0_2.Session";
30 Node::json["@odata.context"] = "/redfish/v1/$metadata#Session.Session";
31 Node::json["Name"] = "User Session";
32 Node::json["Description"] = "Manager User Session";
Ed Tanous3ebd75f2018-03-05 18:20:01 -080033
34 entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}},
35 {crow::HTTPMethod::HEAD, {{"Login"}}},
36 {crow::HTTPMethod::PATCH, {{"ConfigureManager"}}},
37 {crow::HTTPMethod::PUT, {{"ConfigureManager"}}},
38 {crow::HTTPMethod::DELETE, {{"ConfigureManager"}}},
39 {crow::HTTPMethod::POST, {{"ConfigureManager"}}}};
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +010040 }
41
42 private:
43 void doGet(crow::response& res, const crow::request& req,
44 const std::vector<std::string>& params) override {
45 auto session =
46 crow::PersistentData::session_store->get_session_by_uid(params[0]);
47
48 if (session == nullptr) {
49 res.code = static_cast<int>(HttpRespCode::NOT_FOUND);
50 res.end();
51 return;
52 }
53
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010054 Node::json["Id"] = session->unique_id;
55 Node::json["UserName"] = session->username;
56 Node::json["@odata.id"] =
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +010057 "/redfish/v1/SessionService/Sessions/" + session->unique_id;
58
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010059 res.json_value = Node::json;
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +010060 res.end();
61 }
62
63 void doDelete(crow::response& res, const crow::request& req,
64 const std::vector<std::string>& params) override {
65 // Need only 1 param which should be id of session to be deleted
66 if (params.size() != 1) {
67 res.code = static_cast<int>(HttpRespCode::BAD_REQUEST);
68 res.end();
69 return;
70 }
71
72 auto session =
73 crow::PersistentData::session_store->get_session_by_uid(params[0]);
74
75 if (session == nullptr) {
76 res.code = static_cast<int>(HttpRespCode::NOT_FOUND);
77 res.end();
78 return;
79 }
80
81 crow::PersistentData::session_store->remove_session(session);
82 res.code = static_cast<int>(HttpRespCode::OK);
83 res.end();
84 }
85
86 /**
87 * This allows SessionCollection to reuse this class' doGet method, to
88 * maintain consistency of returned data, as Collection's doPost should return
89 * data for created member which should match member's doGet result in 100%
90 */
91 friend SessionCollection;
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +010092};
93
94class SessionCollection : public Node {
95 public:
Borawski.Lukasz43a095a2018-02-19 15:39:01 +010096 SessionCollection(CrowApp& app)
Ed Tanous3ebd75f2018-03-05 18:20:01 -080097 : Node(app, "/redfish/v1/SessionService/Sessions/"), memberSession(app) {
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +010098 Node::json["@odata.type"] = "#SessionCollection.SessionCollection";
99 Node::json["@odata.id"] = "/redfish/v1/SessionService/Sessions/";
100 Node::json["@odata.context"] =
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +0100101 "/redfish/v1/$metadata#SessionCollection.SessionCollection";
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +0100102 Node::json["Name"] = "Session Collection";
103 Node::json["Description"] = "Session Collection";
104 Node::json["Members@odata.count"] = 0;
105 Node::json["Members"] = nlohmann::json::array();
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800106
107 entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}},
108 {crow::HTTPMethod::HEAD, {{"Login"}}},
109 {crow::HTTPMethod::PATCH, {{"ConfigureManager"}}},
110 {crow::HTTPMethod::PUT, {{"ConfigureManager"}}},
111 {crow::HTTPMethod::DELETE, {{"ConfigureManager"}}},
112 {crow::HTTPMethod::POST, {}}};
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +0100113 }
114
115 private:
116 void doGet(crow::response& res, const crow::request& req,
117 const std::vector<std::string>& params) override {
118 std::vector<const std::string*> session_ids =
119 crow::PersistentData::session_store->get_unique_ids(
120 false, crow::PersistentData::PersistenceType::TIMEOUT);
121
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +0100122 Node::json["Members@odata.count"] = session_ids.size();
123 Node::json["Members"] = nlohmann::json::array();
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +0100124 for (const auto& uid : session_ids) {
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +0100125 Node::json["Members"].push_back(
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +0100126 {{"@odata.id", "/redfish/v1/SessionService/Sessions/" + *uid}});
127 }
128
Borawski.Lukaszc1a46bd2018-02-08 13:31:59 +0100129 res.json_value = Node::json;
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +0100130 res.end();
131 }
132
133 void doPost(crow::response& res, const crow::request& req,
134 const std::vector<std::string>& params) override {
135 std::string username;
136 bool userAuthSuccessful = authenticateUser(req, &res.code, &username);
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +0100137 if (!userAuthSuccessful) {
138 res.end();
139 return;
140 }
141
142 // User is authenticated - create session for him
143 auto session =
144 crow::PersistentData::session_store->generate_user_session(username);
145 res.add_header("X-Auth-Token", session.session_token);
146
147 // Return data for created session
148 memberSession.doGet(res, req, {session.unique_id});
149
150 // No need for res.end(), as it is called by doGet()
151 }
152
153 /**
154 * @brief Verifies data provided in request and tries to authenticate user
155 *
156 * @param[in] req Crow request containing authentication data
157 * @param[out] httpRespCode HTTP Code that should be returned in response
158 * @param[out] user Retrieved username - not filled on failure
159 *
160 * @return true if authentication was successful, false otherwise
161 */
162 bool authenticateUser(const crow::request& req, int* httpRespCode,
163 std::string* user) {
164 // We need only UserName and Password - nothing more, nothing less
165 static constexpr const unsigned int numberOfRequiredFieldsInReq = 2;
166
167 // call with exceptions disabled
168 auto login_credentials = nlohmann::json::parse(req.body, nullptr, false);
169 if (login_credentials.is_discarded()) {
170 *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
171
172 return false;
173 }
174
175 // Check that there are only as many fields as there should be
176 if (login_credentials.size() != numberOfRequiredFieldsInReq) {
177 *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
178
179 return false;
180 }
181
182 // Find fields that we need - UserName and Password
183 auto user_it = login_credentials.find("UserName");
184 auto pass_it = login_credentials.find("Password");
185 if (user_it == login_credentials.end() ||
186 pass_it == login_credentials.end()) {
187 *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
188
189 return false;
190 }
191
192 // Check that given data is of valid type (string)
193 if (!user_it->is_string() || !pass_it->is_string()) {
194 *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
195
196 return false;
197 }
198
199 // Extract username and password
200 std::string username = user_it->get<const std::string>();
201 std::string password = pass_it->get<const std::string>();
202
203 // Verify that required fields are not empty
204 if (username.empty() || password.empty()) {
205 *httpRespCode = static_cast<int>(HttpRespCode::BAD_REQUEST);
206
207 return false;
208 }
209
210 // Finally - try to authenticate user
211 if (!pam_authenticate_user(username, password)) {
212 *httpRespCode = static_cast<int>(HttpRespCode::UNAUTHORIZED);
213
214 return false;
215 }
216
217 // User authenticated successfully
218 *httpRespCode = static_cast<int>(HttpRespCode::OK);
219 *user = username;
220
221 return true;
222 }
223
224 /**
225 * Member session to ensure consistency between collection's doPost and
226 * member's doGet, as they should return 100% matching data
227 */
228 Sessions memberSession;
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +0100229};
230
Borawski.Lukasz5d27b852018-02-08 13:24:24 +0100231class SessionService : public Node {
232 public:
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800233 SessionService(CrowApp& app) : Node(app, "/redfish/v1/SessionService/") {
Borawski.Lukasz5d27b852018-02-08 13:24:24 +0100234 Node::json["@odata.type"] = "#SessionService.v1_0_2.SessionService";
235 Node::json["@odata.id"] = "/redfish/v1/SessionService/";
236 Node::json["@odata.context"] =
237 "/redfish/v1/$metadata#SessionService.SessionService";
238 Node::json["Name"] = "Session Service";
Ed Tanous6c233012018-03-15 14:43:56 -0700239 Node::json["Id"] = "SessionService";
Borawski.Lukasz5d27b852018-02-08 13:24:24 +0100240 Node::json["Description"] = "Session Service";
241 Node::json["SessionTimeout"] =
242 crow::PersistentData::session_store->get_timeout_in_seconds();
Borawski.Lukasz5d27b852018-02-08 13:24:24 +0100243 Node::json["ServiceEnabled"] = true;
Ed Tanous3ebd75f2018-03-05 18:20:01 -0800244
245 entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}},
246 {crow::HTTPMethod::HEAD, {{"Login"}}},
247 {crow::HTTPMethod::PATCH, {{"ConfigureManager"}}},
248 {crow::HTTPMethod::PUT, {{"ConfigureManager"}}},
249 {crow::HTTPMethod::DELETE, {{"ConfigureManager"}}},
250 {crow::HTTPMethod::POST, {{"ConfigureManager"}}}};
Borawski.Lukasz5d27b852018-02-08 13:24:24 +0100251 }
252
253 private:
254 void doGet(crow::response& res, const crow::request& req,
255 const std::vector<std::string>& params) override {
256 res.json_value = Node::json;
257 res.end();
258 }
259};
260
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +0100261} // namespace redfish