Kea 3.1.1
http_command_config.cc
Go to the documentation of this file.
1// Copyright (C) 2015-2025 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <config/command_mgr.h>
11#include <config/config_log.h>
14#include <util/filesystem.h>
15#include <limits>
16
17using namespace isc;
18using namespace isc::asiolink;
19using namespace isc::config;
20using namespace isc::data;
21using namespace isc::dhcp;
22using namespace isc::http;
23using namespace isc::util;
24using namespace std;
25
26namespace isc {
27namespace config {
28
29IOAddress HttpCommandConfig::DEFAULT_SOCKET_ADDRESS = IOAddress("127.0.0.1");
30
32
34
36 : socket_type_("http"), socket_address_(DEFAULT_SOCKET_ADDRESS),
37 socket_port_(DEFAULT_SOCKET_PORT), http_headers_(), auth_config_(),
38 trust_anchor_(""), cert_file_(""), key_file_(""), cert_required_(true),
39 emulate_agent_response_(true) {
40 if (config->getType() != Element::map) {
41 isc_throw(DhcpConfigError, "expected map type ("
42 << config->getPosition() << ")");
43 }
44 // Get socket type.
45 ConstElementPtr socket_type = config->get("socket-type");
46 if (socket_type) {
47 if (socket_type->getType() != Element::string) {
49 "invalid type specified for parameter 'socket-type' ("
50 << socket_type->getPosition() << ")");
51 }
52 socket_type_ = socket_type->stringValue();
53 if ((socket_type_ != "http") && (socket_type_ != "https")) {
54 isc_throw(DhcpConfigError, "unsupported 'socket-type' '"
55 << socket_type_ << "' not 'http' or 'https'");
56 }
57 }
58 // Reject UNIX only socket-name.
59 if (config->contains("socket-name")) {
60 isc_throw(DhcpConfigError,
61 "parameter 'socket-name' is not supported by "
62 << (socket_type_ == string("http") ? string("HTTP") : string("HTTPS"))
63 << " control sockets");
64 }
65 // Get socket address.
66 ConstElementPtr socket_address = config->get("socket-address");
67 if (socket_address) {
68 if (socket_address->getType() != Element::string) {
70 "invalid type specified for parameter 'socket-address' ("
71 << socket_address->getPosition() << ")");
72 }
73 try {
74 socket_address_ = IOAddress(socket_address->stringValue());
75 } catch (const std::exception& ex) {
76 isc_throw(DhcpConfigError, "failed to convert '"
77 << socket_address->stringValue()
78 << "' to address: " << ex.what()
79 << " (" << socket_address->getPosition() << ")");
80 }
81 }
82
83 // Get socket port.
84 ConstElementPtr socket_port = config->get("socket-port");
85 if (socket_port) {
86 if (socket_port->getType() != Element::integer) {
88 "invalid type specified for parameter 'socket-port' ("
89 << socket_port->getPosition() << ")");
90 }
91 int64_t value = socket_port->intValue();
92 if ((value < numeric_limits<uint16_t>::min()) ||
93 (value > numeric_limits<uint16_t>::max())) {
95 "out of range value " << value
96 << " specified for parameter 'socket-port' ("
97 << socket_port->getPosition() << ")");
98 }
99 socket_port_ = static_cast<uint16_t>(value);
100 }
101
102 // Get HTTP headers.
103 ConstElementPtr headers = config->get("http-headers");
104 if (headers) {
105 http_headers_ = parseCfgHttpHeaders(headers);
106 }
107
108 // Get HTTP authentication.
109 ConstElementPtr auth_config = config->get("authentication");
110 if (auth_config) {
111 ElementPtr mutable_auth_config =
112 boost::const_pointer_cast<Element>(auth_config);
113 if (auth_config->getType() != Element::map) {
115 "invalid type specified for parameter 'authentication' ("
116 << auth_config->getPosition() << ")");
117 }
118 // Default type is basic.
119 ConstElementPtr type = auth_config->get("type");
120 if (!type) {
121 mutable_auth_config->set("type", Element::create(string("basic")));
122 }
123 // Set default realm when not present.
124 ConstElementPtr realm = auth_config->get("realm");
125 if (!realm) {
126 mutable_auth_config->set("realm",
128 }
129
131 auth->parse(auth_config);
132 auth_config_ = auth;
133 }
134
135 // Get trust anchor.
136 ConstElementPtr trust_anchor = config->get("trust-anchor");
137 if (trust_anchor) {
138 if (trust_anchor->getType() != Element::string) {
140 "invalid type specified for parameter 'trust-anchor' ("
141 << trust_anchor->getPosition() << ")");
142 }
143 trust_anchor_ = trust_anchor->stringValue();
144 }
145
146 // Get cert file.
147 ConstElementPtr cert_file = config->get("cert-file");
148 if (cert_file) {
149 if (cert_file->getType() != Element::string) {
151 "invalid type specified for parameter 'cert-file' ("
152 << cert_file->getPosition() << ")");
153 }
154 cert_file_ = cert_file->stringValue();
155 }
156
157 // Get key file.
158 ConstElementPtr key_file = config->get("key-file");
159 if (key_file) {
160 if (key_file->getType() != Element::string) {
162 "invalid type specified for parameter 'key-file' ("
163 << key_file->getPosition() << ")");
164 }
165 key_file_ = key_file->stringValue();
166 }
167
168 // Get cert required.
169 ConstElementPtr cert_required = config->get("cert-required");
170 if (cert_required) {
171 if (cert_required->getType() != Element::boolean) {
173 "invalid type specified for parameter 'cert-required' ("
174 << cert_required->getPosition() << ")");
175 }
176 cert_required_ = cert_required->boolValue();
177 }
178
179 // Check the TLS setup.
180 bool has_tls = checkTlsSetup(socket_type_ == "https");
181 if (!auth_config_ && !has_tls) {
183 isc_throw(DhcpConfigError, "Unsecured HTTP control channel ("
184 << config->getPosition() << ")");
185
186 }
187
188 std::ostringstream oss;
189 config->toJSON(oss);
191 .arg(oss.str());
192 }
193
194 // Get user context.
195 ConstElementPtr user_context = config->get("user-context");
196 if (user_context) {
197 setContext(user_context);
198 }
199}
200
201bool
202HttpCommandConfig::checkTlsSetup(bool require_tls) const {
203 bool have_ca = !trust_anchor_.empty();
204 bool have_cert = !cert_file_.empty();
205 bool have_key = !key_file_.empty();
206 if (!have_ca && !have_cert && !have_key) {
207 if (require_tls) {
209 "no TLS setup for a HTTPS control socket");
210 }
211 return (false);
212 }
213 // TLS is used: all 3 parameters are required.
214 if (!have_ca) {
216 "trust-anchor parameter is missing or empty:"
217 " all or none of TLS parameters must be set");
218 }
219 if (!have_cert) {
220 isc_throw(DhcpConfigError, "cert-file parameter is missing or empty:"
221 " all or none of TLS parameters must be set");
222 }
223 if (!have_key) {
224 isc_throw(DhcpConfigError, "key-file parameter is missing or empty:"
225 " all or none of TLS parameters must be set");
226 }
227
228 return (true);
229}
230
234 // Set user-context.
235 contextToElement(result);
236 // Set socket type.
237 result->set("socket-type", Element::create(socket_type_));
238 // Set socket address.
239 result->set("socket-address", Element::create(socket_address_.toText()));
240 // Set http-headers.
241 if (!http_headers_.empty()) {
242 result->set("http-headers", CfgHttpHeaderstoElement(http_headers_));
243 }
244 // Set socket port.
245 result->set("socket-port",
246 Element::create(static_cast<uint32_t>(socket_port_)));
248 if (auth_config_) {
249 result->set("authentication", auth_config_->toElement());
250 }
251 // Set TLS setup when enabled.
252 if (!trust_anchor_.empty()) {
253 result->set("trust-anchor", Element::create(trust_anchor_));
254 result->set("cert-file", Element::create(cert_file_));
255 result->set("key-file", Element::create(key_file_));
256 result->set("cert-required", Element::create(cert_required_));
257 }
258 return (result);
259}
260
261} // end of isc::config
262} // end of isc
if(!(yy_init))
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
@ map
Definition data.h:147
@ integer
Definition data.h:140
@ boolean
Definition data.h:142
@ string
Definition data.h:144
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:304
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
static std::string DEFAULT_AUTHENTICATION_REALM
Default HTTP authentication realm.
static isc::asiolink::IOAddress DEFAULT_SOCKET_ADDRESS
Default socket address (127.0.0.1).
static uint16_t DEFAULT_SOCKET_PORT
Default socket port.
HttpCommandConfig(isc::data::ConstElementPtr config)
Constructor.
To be removed. Please use ConfigError instead.
Basic HTTP authentication configuration.
static bool shouldEnforceSecurity()
Indicates security checks should be enforced.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
const isc::log::MessageID COMMAND_HTTP_SOCKET_SECURITY_WARNING
isc::log::Logger command_logger("commands")
Command processing Logger.
Definition config_log.h:21
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
boost::shared_ptr< BasicHttpAuthConfig > BasicHttpAuthConfigPtr
Type of shared pointers to basic HTTP authentication configuration.
ElementPtr CfgHttpHeaderstoElement(const CfgHttpHeaders &headers)
Unparse config HTTP headers.
CfgHttpHeaders parseCfgHttpHeaders(const ConstElementPtr &config)
Parse config HTTP headers.
Defines the logger used by the top-level component of kea-lfc.
void contextToElement(data::ElementPtr map) const
Merge unparse a user_context object.
void setContext(const data::ConstElementPtr &ctx)
Sets user context.