}
// This will generate the response holding JSON content.
HttpResponsePtr response(new HttpResponseJson(http_version, status_code));
+ // Add extra headers.
+ if (config_) {
+ copyHttpHeaders(config_->getHttpHeaders(), *response);
+ }
return (response);
}
HttpResponsePtr
HttpCommandResponseCreator::createDynamicHttpResponse(HttpRequestPtr request) {
+ CfgHttpHeaders headers;
HttpResponseJsonPtr http_response;
// Check the basic HTTP authentication.
if (config_) {
+ headers = config_->getHttpHeaders();
const HttpAuthConfigPtr& auth = config_->getAuthConfig();
if (auth) {
http_response = auth->checkAuth(*this, request);
}
}
+ // Pass extra headers to the hook.
+ bool auth_failed = false;
+ if (http_response) {
+ auth_failed = true;
+ copyHttpHeaders(headers, *http_response);
+ }
+
// Callout point for "http_auth".
bool reset_handle = false;
if (HooksManager::calloutsPresent(Hooks.hook_index_http_auth_)) {
// The basic HTTP authentication check or a callout failed and
// left a response.
if (http_response) {
+ // Avoid to copy extra headers twice even this should not be required.
+ if (!auth_failed && !headers.empty()) {
+ copyHttpHeaders(headers, *http_response);
+ if (http_response->isFinalized()) {
+ // Argh! The response was already finalized.
+ http_response->reset();
+ http_response->finalize();
+ }
+ }
return (http_response);
}
return (createAnswer(CONTROL_RESULT_SUCCESS, arguments));
}
+ /// @brief Convert header vector to header map.
+ static std::map<std::string, std::string>
+ headers2map(std::vector<HttpHeaderContext> headers) {
+ std::map<std::string, std::string> result;
+ for (const auto& header : headers) {
+ result[header.name_] = header.value_;
+ }
+ return (result);
+ }
+
/// @brief HTTP control socket configuration.
HttpCommandConfigPtr http_config_;
testStockResponse(HttpStatusCode::NO_CONTENT, "HTTP/1.1 204 No Content");
}
+// Test that the server responds with extra headers for an error response.
+TEST_F(HttpCommandResponseCreatorTest, createStockHttpResponseHeaders) {
+ // Add a STS header.
+ CfgHttpHeader hsts("Strict-Transport-Security", "max-age=31536000");
+ CfgHttpHeaders headers;
+ headers.push_back(hsts);
+ // Add a random header.
+ CfgHttpHeader foobar("Foo", "bar");
+ headers.push_back(foobar);
+ setHttpConfig();
+ http_config_->setHttpHeaders(headers);
+
+ setHttpCreator();
+
+ // Set request.
+ request_->context()->http_version_major_ = 1;
+ request_->context()->http_version_minor_ = 1;
+ const HttpStatusCode& status_code = HttpStatusCode::NO_CONTENT;
+ HttpResponsePtr response;
+ response = response_creator_->createStockHttpResponse(request_,
+ status_code);
+ ASSERT_TRUE(response);
+
+ // Check that the two extra headers are in the response.
+ auto got = headers2map(response->context()->headers_);
+ EXPECT_EQ("max-age=31536000", got["Strict-Transport-Security"]);
+ EXPECT_EQ("bar", got["Foo"]);
+}
+
// Test successful server response when the client specifies valid command.
TEST_F(HttpCommandResponseCreatorTest, createDynamicHttpResponse) {
setHttpCreator();
string::npos);
}
+// Test that the server responds with extra headers for a command response.
+TEST_F(HttpCommandResponseCreatorTest, createDynamicHttpResponseHeaders) {
+ // Add a STS header.
+ CfgHttpHeader hsts("Strict-Transport-Security", "max-age=31536000");
+ CfgHttpHeaders headers;
+ headers.push_back(hsts);
+ // Add a random header.
+ CfgHttpHeader foobar("Foo", "bar");
+ headers.push_back(foobar);
+ setHttpConfig();
+ http_config_->setHttpHeaders(headers);
+
+ setHttpCreator();
+
+ setBasicContext(request_);
+
+ // Body: "foo" command has been registered in the test fixture constructor.
+ request_->context()->body_ = "{ \"command\": \"foo\" }";
+
+ // All requests must be finalized before they can be processed.
+ ASSERT_NO_THROW(request_->finalize());
+
+ // Create response from the request.
+ HttpResponsePtr response;
+ ASSERT_NO_THROW(response = response_creator_->createHttpResponse(request_));
+ ASSERT_TRUE(response);
+
+ // Check that the two extra headers are in the response.
+ auto got = headers2map(response->context()->headers_);
+ EXPECT_EQ("max-age=31536000", got["Strict-Transport-Security"]);
+ EXPECT_EQ("bar", got["Foo"]);
+}
+
// Test successful server response without emulating agent response.
TEST_F(HttpCommandResponseCreatorTest, createDynamicHttpResponseNoEmulation) {
// Create the response creator setting emulate_agent_response to false;
EXPECT_EQ("HTTP/1.1 401 Unauthorized", response->toBriefString());
}
+// Test that the server responds with extra headers for auth reject response.
+TEST_F(HttpCommandResponseCreatorTest, basicAuthRejectHeaders) {
+ // Create basic HTTP authentication configuration.
+ BasicHttpAuthConfigPtr basic(new BasicHttpAuthConfig());
+ EXPECT_NO_THROW(basic->add("test", "", "123\xa3", ""));
+ setHttpConfig(false, basic);
+
+ // Add a STS header.
+ CfgHttpHeader hsts("Strict-Transport-Security", "max-age=31536000");
+ CfgHttpHeaders headers;
+ headers.push_back(hsts);
+ // Add a random header.
+ CfgHttpHeader foobar("Foo", "bar");
+ headers.push_back(foobar);
+ http_config_->setHttpHeaders(headers);
+
+ setHttpCreator(false);
+
+ setBasicContext(request_);
+
+ // Body: "foo" command has been registered in the test fixture constructor.
+ request_->context()->body_ = "{ \"command\": \"foo\" }";
+
+ // Add no basic HTTP authentication.
+
+ // All requests must be finalized before they can be processed.
+ ASSERT_NO_THROW(request_->finalize());
+
+ // Create response from the request.
+ HttpResponsePtr response;
+ ASSERT_NO_THROW(response = response_creator_->createHttpResponse(request_));
+ ASSERT_TRUE(response);
+
+ // Check that the two extra headers are in the response.
+ auto got = headers2map(response->context()->headers_);
+ EXPECT_EQ("max-age=31536000", got["Strict-Transport-Security"]);
+ EXPECT_EQ("bar", got["Foo"]);
+}
+
// This test verifies basic HTTP authentication - accept case.
// Empty case was handled in createDynamicHttpResponseNoEmulation.
TEST_F(HttpCommandResponseCreatorTest, basicAuthAccept) {