Kea 3.1.9
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
38
40 : socket_type_("http"), socket_address_(DEFAULT_SOCKET_ADDRESS),
41 socket_port_(DEFAULT_SOCKET_PORT), http_headers_(), auth_config_(),
42 trust_anchor_(""), cert_file_(""), key_file_(""), cert_required_(true) {
43 if (config->getType() != Element::map) {
44 isc_throw(DhcpConfigError, "expected map type ("
45 << config->getPosition() << ")");
46 }
47 // Get socket type.
48 ConstElementPtr socket_type = config->get("socket-type");
49 if (socket_type) {
50 if (socket_type->getType() != Element::string) {
52 "invalid type specified for parameter 'socket-type' ("
53 << socket_type->getPosition() << ")");
54 }
55 socket_type_ = socket_type->stringValue();
56 if ((socket_type_ != "http") && (socket_type_ != "https")) {
57 isc_throw(DhcpConfigError, "unsupported 'socket-type' '"
58 << socket_type_ << "' not 'http' or 'https'");
59 }
60 }
61 // Reject UNIX only socket-name.
62 if (config->contains("socket-name")) {
63 isc_throw(DhcpConfigError,
64 "parameter 'socket-name' is not supported by "
65 << (socket_type_ == string("http") ? string("HTTP") : string("HTTPS"))
66 << " control sockets");
67 }
68 // Get socket address.
69 ConstElementPtr socket_address = config->get("socket-address");
70 if (socket_address) {
71 if (socket_address->getType() != Element::string) {
73 "invalid type specified for parameter 'socket-address' ("
74 << socket_address->getPosition() << ")");
75 }
76 try {
77 socket_address_ = IOAddress(socket_address->stringValue());
78 } catch (const std::exception& ex) {
79 isc_throw(DhcpConfigError, "failed to convert '"
80 << socket_address->stringValue()
81 << "' to address: " << ex.what()
82 << " (" << socket_address->getPosition() << ")");
83 }
84 }
85
86 // Get socket port.
87 ConstElementPtr socket_port = config->get("socket-port");
88 if (socket_port) {
89 if (socket_port->getType() != Element::integer) {
91 "invalid type specified for parameter 'socket-port' ("
92 << socket_port->getPosition() << ")");
93 }
94 int64_t value = socket_port->intValue();
95 if ((value < numeric_limits<uint16_t>::min()) ||
96 (value > numeric_limits<uint16_t>::max())) {
98 "out of range value " << value
99 << " specified for parameter 'socket-port' ("
100 << socket_port->getPosition() << ")");
101 }
102 socket_port_ = static_cast<uint16_t>(value);
103 }
104
105 // Get HTTP headers.
106 ConstElementPtr headers = config->get("http-headers");
107 if (headers) {
108 http_headers_ = parseCfgHttpHeaders(headers);
109 }
110
111 // Get HTTP authentication.
112 ConstElementPtr auth_config = config->get("authentication");
113 if (auth_config) {
114 ElementPtr mutable_auth_config =
115 boost::const_pointer_cast<Element>(auth_config);
116 if (auth_config->getType() != Element::map) {
118 "invalid type specified for parameter 'authentication' ("
119 << auth_config->getPosition() << ")");
120 }
121 // Default type is basic.
122 ConstElementPtr type = auth_config->get("type");
123 if (!type) {
124 mutable_auth_config->set("type", Element::create(string("basic")));
125 }
126 // Set default realm when not present.
127 ConstElementPtr realm = auth_config->get("realm");
128 if (!realm) {
129 mutable_auth_config->set("realm",
131 }
132
134 auth->parse(auth_config);
135 auth_config_ = auth;
136 }
137
138 // Get trust anchor.
139 ConstElementPtr trust_anchor = config->get("trust-anchor");
140 if (trust_anchor) {
141 if (trust_anchor->getType() != Element::string) {
143 "invalid type specified for parameter 'trust-anchor' ("
144 << trust_anchor->getPosition() << ")");
145 }
146 trust_anchor_ = trust_anchor->stringValue();
147 }
148
149 // Get cert file.
150 ConstElementPtr cert_file = config->get("cert-file");
151 if (cert_file) {
152 if (cert_file->getType() != Element::string) {
154 "invalid type specified for parameter 'cert-file' ("
155 << cert_file->getPosition() << ")");
156 }
157 cert_file_ = cert_file->stringValue();
158 }
159
160 // Get key file.
161 ConstElementPtr key_file = config->get("key-file");
162 if (key_file) {
163 if (key_file->getType() != Element::string) {
165 "invalid type specified for parameter 'key-file' ("
166 << key_file->getPosition() << ")");
167 }
168 key_file_ = key_file->stringValue();
169 }
170
171 // Get cert required.
172 ConstElementPtr cert_required = config->get("cert-required");
173 if (cert_required) {
174 if (cert_required->getType() != Element::boolean) {
176 "invalid type specified for parameter 'cert-required' ("
177 << cert_required->getPosition() << ")");
178 }
179 cert_required_ = cert_required->boolValue();
180 }
181
182 // Check the TLS setup.
183 bool has_tls = checkTlsSetup(socket_type_ == "https");
184 if (!auth_config_ && !has_tls) {
186 isc_throw(DhcpConfigError, "Unsecured HTTP control channel ("
187 << config->getPosition() << ")");
188
189 }
190
191 std::ostringstream oss;
192 config->toJSON(oss);
194 .arg(oss.str());
195 }
196
197 // Get user context.
198 ConstElementPtr user_context = config->get("user-context");
199 if (user_context) {
200 setContext(user_context);
201 }
202}
203
204bool
205HttpCommandConfig::checkTlsSetup(bool require_tls) const {
206 bool have_ca = !trust_anchor_.empty();
207 bool have_cert = !cert_file_.empty();
208 bool have_key = !key_file_.empty();
209 if (!have_ca && !have_cert && !have_key) {
210 if (require_tls) {
212 "no TLS setup for a HTTPS control socket");
213 }
214 return (false);
215 }
216 // TLS is used: all 3 parameters are required.
217 if (!have_ca) {
219 "trust-anchor parameter is missing or empty:"
220 " all or none of TLS parameters must be set");
221 }
222 if (!have_cert) {
223 isc_throw(DhcpConfigError, "cert-file parameter is missing or empty:"
224 " all or none of TLS parameters must be set");
225 }
226 if (!have_key) {
227 isc_throw(DhcpConfigError, "key-file parameter is missing or empty:"
228 " all or none of TLS parameters must be set");
229 }
230
231 return (true);
232}
233
237 // Set user-context.
238 contextToElement(result);
239 // Set socket type.
240 result->set("socket-type", Element::create(socket_type_));
241 // Set socket address.
242 result->set("socket-address", Element::create(socket_address_.toText()));
243 // Set http-headers.
244 if (!http_headers_.empty()) {
245 result->set("http-headers", CfgHttpHeaderstoElement(http_headers_));
246 }
247 // Set socket port.
248 result->set("socket-port",
249 Element::create(static_cast<uint32_t>(socket_port_)));
251 if (auth_config_) {
252 result->set("authentication", auth_config_->toElement());
253 }
254 // Set TLS setup when enabled.
255 if (!trust_anchor_.empty()) {
256 result->set("trust-anchor", Element::create(trust_anchor_));
257 result->set("cert-file", Element::create(cert_file_));
258 result->set("key-file", Element::create(key_file_));
259 result->set("cert-required", Element::create(cert_required_));
260 }
261 return (result);
262}
263
264} // end of isc::config
265} // end of isc
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:299
@ map
Definition data.h:160
@ integer
Definition data.h:153
@ boolean
Definition data.h:155
@ string
Definition data.h:157
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:354
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.
static std::string SUPPORTED_SERVICE
Supported service.
static bool EMULATE_AGENT_RESPONSE
Emulation flag.
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.
if(!(yy_init))
Definition d2_lexer.cc:1502
#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:30
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
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.