Kea 2.7.6
ca_response_creator.cc
Go to the documentation of this file.
1// Copyright (C) 2017-2024 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
9#include <agent/ca_cfg_mgr.h>
11#include <agent/ca_controller.h>
12#include <agent/ca_process.h>
14#include <cc/data.h>
16#include <hooks/hooks_log.h>
17#include <hooks/hooks_manager.h>
19#include <http/response_json.h>
20#include <boost/pointer_cast.hpp>
21#include <iostream>
22
23using namespace isc::data;
24using namespace isc::hooks;
25using namespace isc::http;
26
27namespace {
28
30struct CtrlAgentHooks {
31 int hook_index_http_auth_;
32 int hook_index_http_response_;
33
35 CtrlAgentHooks() {
36 hook_index_http_auth_ = HooksManager::registerHook("http_auth");
37 hook_index_http_response_ = HooksManager::registerHook("http_response");
38 }
39};
40
41} // end of anonymous namespace.
42
43// Declare a Hooks object. As this is outside any function or method, it
44// will be instantiated (and the constructor run) when the module is loaded.
45// As a result, the hook indexes will be defined before any method in this
46// module is called.
47CtrlAgentHooks Hooks;
48
49namespace isc {
50namespace agent {
51
56
60 const HttpStatusCode& status_code) const {
61 HttpResponsePtr response = createStockHttpResponseInternal(request, status_code);
62 response->finalize();
63 return (response);
64}
65
66namespace {
67
69CtrlAgentCfgContextPtr getCtrlAgentCfgContext() {
70 // There is a hierarchy of the objects through which we need to pass to get
71 // the configuration context. We may simplify this at some point but since
72 // we're in the singleton we want to make sure that we're using most current
73 // configuration.
75 boost::shared_ptr<CtrlAgentController> controller =
76 boost::dynamic_pointer_cast<CtrlAgentController>(CtrlAgentController::instance());
77 if (controller) {
78 CtrlAgentProcessPtr process = controller->getCtrlAgentProcess();
79 if (process) {
80 CtrlAgentCfgMgrPtr cfgmgr = process->getCtrlAgentCfgMgr();
81 if (cfgmgr) {
82 ctx = cfgmgr->getCtrlAgentCfgContext();
83 }
84 }
85 }
86 return (ctx);
87}
88
89} // end of anonymous namespace.
90
92CtrlAgentResponseCreator::
93createStockHttpResponseInternal(const HttpRequestPtr& request,
94 const HttpStatusCode& status_code) const {
95 // The request hasn't been finalized so the request object
96 // doesn't contain any information about the HTTP version number
97 // used. But, the context should have this data (assuming the
98 // HTTP version is parsed ok).
99 HttpVersion http_version(request->context()->http_version_major_,
100 request->context()->http_version_minor_);
101 // We only accept HTTP version 1.0 or 1.1. If other version number is found
102 // we fall back to HTTP/1.0.
103 if ((http_version < HttpVersion(1, 0)) || (HttpVersion(1, 1) < http_version)) {
104 http_version.major_ = 1;
105 http_version.minor_ = 0;
106 }
107 // This will generate the response holding JSON content.
108 HttpResponsePtr response(new HttpResponseJson(http_version, status_code));
109 CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
110 if (ctx) {
111 copyHttpHeaders(ctx->getHttpHeaders(), *response);
112 }
113 return (response);
114}
115
117CtrlAgentResponseCreator::
118createDynamicHttpResponse(HttpRequestPtr request) {
119 // Extra headers.
120 CfgHttpHeaders headers;
121
122 // First check authentication.
123 HttpResponseJsonPtr http_response;
124
125 // Context will hold the server configuration.
126 CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
127 if (ctx) {
128 headers = ctx->getHttpHeaders();
129 const HttpAuthConfigPtr& auth = ctx->getAuthConfig();
130 if (auth) {
131 // Check authentication.
132 http_response = auth->checkAuth(*this, request);
133 }
134 }
135
136 // Pass extra headers to the hook.
137 bool auth_failed = false;
138 if (http_response) {
139 auth_failed = true;
140 copyHttpHeaders(headers, *http_response);
141 }
142
143 // Callout point for "http_auth".
144 bool reset_handle = false;
145 if (HooksManager::calloutsPresent(Hooks.hook_index_http_auth_)) {
146 // Get callout handle.
147 CalloutHandlePtr callout_handle = request->getCalloutHandle();
148 ScopedCalloutHandleState callout_handle_state(callout_handle);
149
150 // Pass arguments.
151 callout_handle->setArgument("request", request);
152 callout_handle->setArgument("response", http_response);
153
154 // Call callouts.
155 HooksManager::callCallouts(Hooks.hook_index_http_auth_,
156 *callout_handle);
157 callout_handle->getArgument("request", request);
158 callout_handle->getArgument("response", http_response);
159
160 // Status other than continue means 'please reset the handle'.
161 if (callout_handle->getStatus() != CalloutHandle::NEXT_STEP_CONTINUE) {
162 reset_handle = true;
163 }
164 }
165
166 // The basic HTTP authentication check or a callout failed and
167 // left a response.
168 if (http_response) {
169 // Avoid to copy extra headers twice even this should not be required.
170 if (!auth_failed && !headers.empty()) {
171 copyHttpHeaders(headers, *http_response);
172 if (http_response->isFinalized()) {
173 // Argh! The response was already finalized.
174 http_response->reset();
175 http_response->finalize();
176 }
177 }
178 return (http_response);
179 }
180
181 // Reset the handle when a hook asks for.
182 if (reset_handle) {
183 request->resetCalloutHandle();
184 }
185
186 // The request is always non-null, because this is verified by the
187 // createHttpResponse method. Let's try to convert it to the
188 // PostHttpRequestJson type as this is the type generated by the
189 // createNewHttpRequest. If the conversion result is null it means that
190 // the caller did not use createNewHttpRequest method to create this
191 // instance. This is considered an error in the server logic.
192 PostHttpRequestJsonPtr request_json =
193 boost::dynamic_pointer_cast<PostHttpRequestJson>(request);
194 if (!request_json) {
195 // Notify the client that we have a problem with our server.
196 return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
197 }
198
199 // We have already checked that the request is finalized so the call
200 // to getBodyAsJson must not trigger an exception.
201 ConstElementPtr command = request_json->getBodyAsJson();
202
203 // Process command doesn't generate exceptions but can possibly return
204 // null response, if the handler is not implemented properly. This is
205 // again an internal server issue.
207 if (!response) {
208 // Notify the client that we have a problem with our server.
209 return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
210 }
211 // The response is ok, so let's create new HTTP response with the status OK.
212 http_response = boost::dynamic_pointer_cast<
213 HttpResponseJson>(createStockHttpResponseInternal(request, HttpStatusCode::OK));
214 http_response->setBodyAsJson(response);
215 http_response->finalize();
216
217 // Callout point for "http_response".
218 if (HooksManager::calloutsPresent(Hooks.hook_index_http_response_)) {
219 // Get callout handle.
220 CalloutHandlePtr callout_handle = request->getCalloutHandle();
221 ScopedCalloutHandleState callout_handle_state(callout_handle);
222
223 // Pass arguments.
224 callout_handle->setArgument("request", request);
225 callout_handle->setArgument("response", http_response);
226
227 // Call callouts.
228 HooksManager::callCallouts(Hooks.hook_index_http_response_,
229 *callout_handle);
230 callout_handle->getArgument("response", http_response);
231
232 // Ignore status as the HTTP response is used instead.
233 }
234
235 return (http_response);
236}
237
238} // end of namespace isc::agent
239} // end of namespace isc
CtrlAgentHooks Hooks
static CtrlAgentCommandMgr & instance()
Returns sole instance of the Command Manager.
virtual isc::data::ConstElementPtr processCommand(const isc::data::ConstElementPtr &cmd)
Triggers command processing.
static process::DControllerBasePtr & instance()
Static singleton instance method.
virtual http::HttpResponsePtr createStockHttpResponse(const http::HttpRequestPtr &request, const http::HttpStatusCode &status_code) const
Creates stock HTTP response.
virtual http::HttpRequestPtr createNewHttpRequest() const
Create a new request.
@ NEXT_STEP_CONTINUE
continue normally
static int registerHook(const std::string &name)
Register Hook.
static bool calloutsPresent(int index)
Are callouts present?
static void callCallouts(int index, CalloutHandle &handle)
Calls the callouts for a given hook.
Wrapper class around callout handle which automatically resets handle's state.
Represents HTTP response with JSON content.
void setBodyAsJson(const data::ConstElementPtr &json_body)
Generates JSON content from the data structures represented as data::ConstElementPtr.
Represents HTTP POST request with JSON body.
boost::shared_ptr< CtrlAgentCfgContext > CtrlAgentCfgContextPtr
Pointer to a configuration context.
Definition ca_cfg_mgr.h:24
boost::shared_ptr< CtrlAgentProcess > CtrlAgentProcessPtr
Defines a shared pointer to CtrlAgentProcess.
Definition ca_process.h:150
boost::shared_ptr< CtrlAgentCfgMgr > CtrlAgentCfgMgrPtr
Defines a shared pointer to CtrlAgentCfgMgr.
Definition ca_cfg_mgr.h:329
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
HttpStatusCode
HTTP status codes (cf RFC 2068)
Definition response.h:30
void copyHttpHeaders(const CfgHttpHeaders &headers, const HTTP_MSG &message)
Copy config HTTP headers to message.
boost::shared_ptr< PostHttpRequestJson > PostHttpRequestJsonPtr
Pointer to PostHttpRequestJson.
boost::shared_ptr< HttpAuthConfig > HttpAuthConfigPtr
Type of shared pointers to HTTP authentication configuration.
Definition auth_config.h:97
boost::shared_ptr< HttpResponseJson > HttpResponseJsonPtr
Pointer to the HttpResponseJson object.
boost::shared_ptr< HttpResponse > HttpResponsePtr
Pointer to the HttpResponse object.
Definition response.h:81
boost::shared_ptr< HttpRequest > HttpRequestPtr
Pointer to the HttpRequest object.
Definition request.h:30
std::vector< CfgHttpHeader > CfgHttpHeaders
Collection of config HTTP headers.
Defines the logger used by the top-level component of kea-lfc.
HTTP protocol version.
Definition http_types.h:14