mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 21:45:37 +00:00
[#3609] Checkpoint: error UT to add
This commit is contained in:
@@ -23,13 +23,14 @@ namespace isc {
|
||||
namespace agent {
|
||||
|
||||
CtrlAgentCfgContext::CtrlAgentCfgContext()
|
||||
: http_host_(""), http_port_(0),
|
||||
: http_host_(""), http_port_(0), http_headers_(),
|
||||
trust_anchor_(""), cert_file_(""), key_file_(""), cert_required_(true) {
|
||||
}
|
||||
|
||||
CtrlAgentCfgContext::CtrlAgentCfgContext(const CtrlAgentCfgContext& orig)
|
||||
: ConfigBase(), ctrl_sockets_(orig.ctrl_sockets_),
|
||||
http_host_(orig.http_host_), http_port_(orig.http_port_),
|
||||
http_headers_(orig.http_headers_),
|
||||
trust_anchor_(orig.trust_anchor_), cert_file_(orig.cert_file_),
|
||||
key_file_(orig.key_file_), cert_required_(orig.cert_required_),
|
||||
hooks_config_(orig.hooks_config_), auth_config_(orig.auth_config_) {
|
||||
@@ -186,6 +187,10 @@ CtrlAgentCfgContext::toElement() const {
|
||||
ca->set("http-host", Element::create(http_host_));
|
||||
// Set http-port
|
||||
ca->set("http-port", Element::create(static_cast<int64_t>(http_port_)));
|
||||
// Set http-headers
|
||||
if (!http_headers_.empty()) {
|
||||
ca->set("http-headers", toElement(http_headers_));
|
||||
}
|
||||
// Set TLS setup when enabled
|
||||
if (!trust_anchor_.empty()) {
|
||||
ca->set("trust-anchor", Element::create(trust_anchor_));
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <cc/data.h>
|
||||
#include <hooks/hooks_config.h>
|
||||
#include <http/auth_config.h>
|
||||
#include <http/cfg_http_header.h>
|
||||
#include <process/d_cfg_mgr.h>
|
||||
#include <boost/pointer_cast.hpp>
|
||||
#include <map>
|
||||
@@ -99,6 +100,20 @@ public:
|
||||
return (http_port_);
|
||||
}
|
||||
|
||||
/// @brief Sets http-headers parameter
|
||||
///
|
||||
/// @param headers Collection of config HTTP headers.
|
||||
void setHttpHeaders(const isc::http::CfgHttpHeaders& headers) {
|
||||
http_headers_ = headers;
|
||||
}
|
||||
|
||||
/// @brief Returns http-headers parameter
|
||||
///
|
||||
/// @return Collection of config HTTP headers.
|
||||
const isc::http::CfgHttpHeaders& getHttpHeaders() const {
|
||||
return (http_headers_);
|
||||
}
|
||||
|
||||
/// @brief Sets HTTP authentication configuration.
|
||||
///
|
||||
/// @note Only the basic HTTP authentication is supported.
|
||||
@@ -225,6 +240,9 @@ private:
|
||||
/// TCP port the CA should listen on.
|
||||
uint16_t http_port_;
|
||||
|
||||
/// Config HTTP headers.
|
||||
isc::http::CfgHttpHeaders http_headers_;
|
||||
|
||||
/// Trust anchor aka Certificate Authority (can be a file name or
|
||||
/// a directory path).
|
||||
std::string trust_anchor_;
|
||||
|
@@ -162,6 +162,13 @@ AgentSimpleParser::parse(const CtrlAgentCfgContextPtr& ctx,
|
||||
ctx->setAuthConfig(auth);
|
||||
}
|
||||
|
||||
// HTTP headers are fifth.
|
||||
ConstElementPtr headers_config = config->get("http-headers");
|
||||
if (headers_config) {
|
||||
using namespace isc::http;
|
||||
ctx->setHttpHeaders(parseCfgHttpHeaders(headers_config));
|
||||
}
|
||||
|
||||
// User context can be done at anytime.
|
||||
ConstElementPtr user_context = config->get("user-context");
|
||||
if (user_context) {
|
||||
|
@@ -43,6 +43,7 @@ libkea_http_la_SOURCES += auth_log.cc auth_log.h
|
||||
libkea_http_la_SOURCES += auth_messages.cc auth_messages.h
|
||||
libkea_http_la_SOURCES += basic_auth_config.cc basic_auth_config.h
|
||||
libkea_http_la_SOURCES += basic_auth.cc basic_auth.h
|
||||
libkea_http_la_SOURCES += cfg_http_header.h cfg_http_header.cc
|
||||
|
||||
libkea_http_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
libkea_http_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
@@ -103,6 +104,7 @@ libkea_http_include_HEADERS = \
|
||||
auth_messages.h \
|
||||
basic_auth.h \
|
||||
basic_auth_config.h \
|
||||
cfg_http_header.h \
|
||||
client.h \
|
||||
connection.h \
|
||||
connection_pool.h \
|
||||
|
95
src/lib/http/cfg_http_header.cc
Normal file
95
src/lib/http/cfg_http_header.cc
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <cc/simple_parser.h>
|
||||
#include <http/cfg_http_header.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::data;
|
||||
using namespace isc::dhcp;
|
||||
using namespace std;
|
||||
|
||||
namespace isc {
|
||||
namespace http {
|
||||
|
||||
ElementPtr
|
||||
CfgHttpHeader::toElement() const {
|
||||
ElementPtr map = isc::data::Element::createMap();
|
||||
contextToElement(map);
|
||||
map->set("name", Element::create(name_));
|
||||
map->set("value", Element::create(value_));
|
||||
return (map);
|
||||
}
|
||||
|
||||
ElementPtr
|
||||
toElement(const CfgHttpHeaders& headers) {
|
||||
ElementPtr list = Element::createList();
|
||||
for (auto const& header : headers) {
|
||||
list->add(header.toElement());
|
||||
}
|
||||
return (list);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const SimpleKeywords HTTP_HEADER_KEYWORDS = {
|
||||
{ "name", Element::string },
|
||||
{ "value", Element::string },
|
||||
{ "user-context", Element::map }
|
||||
};
|
||||
|
||||
const SimpleRequiredKeywords HTTP_HEADER_REQUIRED = { "name", "value" };
|
||||
|
||||
CfgHttpHeader
|
||||
parseCfgHttpHeader(const ConstElementPtr& config) {
|
||||
if (!config) {
|
||||
// Should not happen.
|
||||
isc_throw(DhcpConfigError, "null 'http-headers' item");
|
||||
}
|
||||
if (config->getType() != Element::map) {
|
||||
isc_throw(DhcpConfigError, "invalid type specified for 'http-headers' "
|
||||
"item (" << config->getPosition() << ")");
|
||||
}
|
||||
SimpleParser::checkKeywords(HTTP_HEADER_KEYWORDS, config);
|
||||
SimpleParser::checkRequired(HTTP_HEADER_REQUIRED, config);
|
||||
string name = config->get("name")->stringValue();
|
||||
if (name.empty()) {
|
||||
isc_throw(DhcpConfigError, "empty 'name' ("
|
||||
<< config->get("name")->getPosition() << ")");
|
||||
}
|
||||
string value = config->get("value")->stringValue();
|
||||
if (value.empty()) {
|
||||
isc_throw(DhcpConfigError, "empty 'value' ("
|
||||
<< config->get("value")->getPosition() << ")");
|
||||
}
|
||||
CfgHttpHeader header(name, value);
|
||||
ConstElementPtr user_context = config->get("user-context");
|
||||
if (user_context) {
|
||||
header.setContext(user_context);
|
||||
}
|
||||
return (header);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CfgHttpHeaders
|
||||
parseCfgHttpHeaders(const ConstElementPtr& config) {
|
||||
CfgHttpHeaders headers;
|
||||
if (!config) {
|
||||
return (headers);
|
||||
}
|
||||
if (config->getType() != Element::list) {
|
||||
isc_throw(DhcpConfigError, "invalid type specified for parameter "
|
||||
"'http-headers' (" << config->getPosition() << ")");
|
||||
}
|
||||
for (auto const& item : config->listValue()) {
|
||||
headers.push_back(parseCfgHttpHeader(item));
|
||||
}
|
||||
return (headers);
|
||||
}
|
||||
|
||||
} // namespace http
|
||||
} // namespace isc
|
71
src/lib/http/cfg_http_header.h
Normal file
71
src/lib/http/cfg_http_header.h
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef CFG_HTTP_HEADER_H
|
||||
#define CFG_HTTP_HEADER_H
|
||||
|
||||
#include <cc/cfg_to_element.h>
|
||||
#include <cc/data.h>
|
||||
#include <cc/user_context.h>
|
||||
#include <http/request.h>
|
||||
#include <http/response.h>
|
||||
|
||||
namespace isc {
|
||||
namespace http {
|
||||
|
||||
/// @brief Config HTTP header.
|
||||
class CfgHttpHeader : public isc::data::UserContext, public isc::data::CfgToElement {
|
||||
public:
|
||||
std::string name_;
|
||||
std::string value_;
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// @param name Header name.
|
||||
/// @param value Header value.
|
||||
CfgHttpHeader(const std::string& name, const std::string& value)
|
||||
: name_(name), value_(value) {
|
||||
}
|
||||
|
||||
/// @brief Unparses config HTTP header.
|
||||
///
|
||||
/// @return A pointer to unparsed header configuration.
|
||||
virtual isc::data::ElementPtr toElement() const;
|
||||
};
|
||||
|
||||
/// @brief Collection of config HTTP headers.
|
||||
typedef std::vector<CfgHttpHeader> CfgHttpHeaders;
|
||||
|
||||
/// @brief Copy config HTTP headers to message.
|
||||
///
|
||||
/// @tparam HTTP_MSG Either HttpRequest or HttpResponse.
|
||||
/// @param headers Config HTTP headers.
|
||||
/// @param message HTTP_MSG target object.
|
||||
template<typename HTTP_MSG>
|
||||
void copyHttpHeaders(const CfgHttpHeaders& headers, const HTTP_MSG& message) {
|
||||
for (auto const& header : headers) {
|
||||
message.context()->headers_.
|
||||
push_back(HttpHeaderContext(header.name_, header.value_));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Unparse config HTTP headers.
|
||||
///
|
||||
/// @param headers Config HTTP headers.
|
||||
/// @return A pointer to unparsed headers configuration.
|
||||
isc::data::ElementPtr toElement(const CfgHttpHeaders& headers);
|
||||
|
||||
/// @brief Parse config HTTP headers.
|
||||
///
|
||||
/// @param config Element holding the HTTP headers configuration.
|
||||
/// @return The HTTP headers.
|
||||
/// @throw DhcpConfigError when the configuration is invalid.
|
||||
CfgHttpHeaders parseCfgHttpHeaders(const isc::data::ConstElementPtr& config);
|
||||
|
||||
} // namespace http
|
||||
} // namespace isc
|
||||
|
||||
#endif
|
@@ -29,6 +29,7 @@ TESTS += libhttp_unittests
|
||||
|
||||
libhttp_unittests_SOURCES = basic_auth_unittests.cc
|
||||
libhttp_unittests_SOURCES += basic_auth_config_unittests.cc
|
||||
libhttp_unittests_SOURCES += cfg_http_header_unittests.cc
|
||||
libhttp_unittests_SOURCES += connection_pool_unittests.cc
|
||||
libhttp_unittests_SOURCES += date_time_unittests.cc
|
||||
libhttp_unittests_SOURCES += http_header_unittests.cc
|
||||
|
79
src/lib/http/tests/cfg_http_header_unittests.cc
Normal file
79
src/lib/http/tests/cfg_http_header_unittests.cc
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <http/cfg_http_header.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace isc::data;
|
||||
using namespace isc::http;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
// This test verifies copy to response.
|
||||
TEST(CfgHttpHeaderTest, copy) {
|
||||
// Create a response.
|
||||
HttpResponse response(HttpVersion(1, 0), HttpStatusCode::OK);
|
||||
// Create a HSTS header.
|
||||
CfgHttpHeader hsts("Strict-Transport-Security", "max-age=31536000");
|
||||
// Create a random header.
|
||||
CfgHttpHeader foobar("Foo", "bar");
|
||||
// Add them to a collection.
|
||||
CfgHttpHeaders headers;
|
||||
headers.push_back(hsts);
|
||||
headers.push_back(foobar);
|
||||
// Copy headers to response.
|
||||
EXPECT_NO_THROW(copyHttpHeaders(headers, response));
|
||||
|
||||
// Verify.
|
||||
auto const& got = response.context()->headers_;
|
||||
ASSERT_EQ(2, got.size());
|
||||
EXPECT_EQ("Strict-Transport-Security", got[0].name_);
|
||||
EXPECT_EQ("max-age=31536000", got[0].value_);
|
||||
EXPECT_EQ("Foo", got[1].name_);
|
||||
EXPECT_EQ("bar", got[1].value_);
|
||||
|
||||
// Unparse.
|
||||
string expected = "[ ";
|
||||
expected += "{ \"name\": \"Strict-Transport-Security\", ";
|
||||
expected += "\"value\": \"max-age=31536000\" }, ";
|
||||
expected += "{ \"name\": \"Foo\", \"value\": \"bar\" } ]";
|
||||
EXPECT_EQ(expected, toElement(headers)->str());
|
||||
}
|
||||
|
||||
// This test verifies parse and toElement behavior.
|
||||
TEST(CfgHttpHeaderTest, parse) {
|
||||
// Config.
|
||||
string config = "[\n"
|
||||
" {\n"
|
||||
" \"name\": \"Strict-Transport-Security\",\n"
|
||||
" \"value\": \"max-age=31536000\",\n"
|
||||
" \"user-context\": { \"comment\": \"HSTS header\" }\n"
|
||||
" },{\n"
|
||||
" \"name\": \"Foo\", \"value\": \"bar\"\n"
|
||||
" }\n"
|
||||
" ]\n";
|
||||
ConstElementPtr json;
|
||||
ASSERT_NO_THROW(json = Element::fromJSON(config));
|
||||
CfgHttpHeaders headers;
|
||||
ASSERT_NO_THROW(headers = parseCfgHttpHeaders(json));
|
||||
ASSERT_EQ(2, headers.size());
|
||||
EXPECT_EQ("Strict-Transport-Security", headers[0].name_);
|
||||
EXPECT_EQ("max-age=31536000", headers[0].value_);
|
||||
ConstElementPtr user_context = headers[0].getContext();
|
||||
ASSERT_TRUE(user_context);
|
||||
EXPECT_EQ("{ \"comment\": \"HSTS header\" }", user_context->str());
|
||||
EXPECT_EQ("Foo", headers[1].name_);
|
||||
EXPECT_EQ("bar", headers[1].value_);
|
||||
EXPECT_FALSE(headers[1].getContext());
|
||||
ConstElementPtr unparsed;
|
||||
ASSERT_NO_THROW(unparsed = toElement(headers));
|
||||
EXPECT_TRUE(json->equals(*unparsed));
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user