Kea  2.3.3-git
ca_response_creator.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-2022 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>
10 #include <agent/ca_command_mgr.h>
11 #include <agent/ca_controller.h>
12 #include <agent/ca_process.h>
14 #include <cc/data.h>
15 #include <hooks/callout_handle.h>
16 #include <hooks/hooks_log.h>
17 #include <hooks/hooks_manager.h>
18 #include <http/post_request_json.h>
19 #include <http/response_json.h>
20 #include <boost/pointer_cast.hpp>
21 #include <iostream>
22 
23 using namespace isc::data;
24 using namespace isc::hooks;
25 using namespace isc::http;
26 
27 namespace {
28 
30 struct CtrlAgentHooks {
31  int hook_index_auth_;
32  int hook_index_response_;
33 
35  CtrlAgentHooks() {
36  hook_index_auth_ = HooksManager::registerHook("auth");
37  hook_index_response_ = HooksManager::registerHook("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.
47 CtrlAgentHooks Hooks;
48 
49 namespace isc {
50 namespace agent {
51 
53 CtrlAgentResponseCreator::createNewHttpRequest() const {
54  return (HttpRequestPtr(new PostHttpRequestJson()));
55 }
56 
58 CtrlAgentResponseCreator::
59 createStockHttpResponse(const HttpRequestPtr& request,
60  const HttpStatusCode& status_code) const {
61  HttpResponsePtr response = createStockHttpResponseInternal(request, status_code);
62  response->finalize();
63  return (response);
64 }
65 
67 CtrlAgentResponseCreator::
68 createStockHttpResponseInternal(const HttpRequestPtr& request,
69  const HttpStatusCode& status_code) const {
70  // The request hasn't been finalized so the request object
71  // doesn't contain any information about the HTTP version number
72  // used. But, the context should have this data (assuming the
73  // HTTP version is parsed ok).
74  HttpVersion http_version(request->context()->http_version_major_,
75  request->context()->http_version_minor_);
76  // We only accept HTTP version 1.0 or 1.1. If other version number is found
77  // we fall back to HTTP/1.0.
78  if ((http_version < HttpVersion(1, 0)) || (HttpVersion(1, 1) < http_version)) {
79  http_version.major_ = 1;
80  http_version.minor_ = 0;
81  }
82  // This will generate the response holding JSON content.
83  HttpResponsePtr response(new HttpResponseJson(http_version, status_code));
84  return (response);
85 }
86 
88 CtrlAgentResponseCreator::
89 createDynamicHttpResponse(HttpRequestPtr request) {
90  // First check authentication.
91  HttpResponseJsonPtr http_response;
92 
93  // Context will hold the server configuration.
95 
96  // There is a hierarchy of the objects through which we need to pass to get
97  // the configuration context. We may simplify this at some point but since
98  // we're in the singleton we want to make sure that we're using most current
99  // configuration.
100  boost::shared_ptr<CtrlAgentController> controller =
101  boost::dynamic_pointer_cast<CtrlAgentController>(CtrlAgentController::instance());
102  if (controller) {
103  CtrlAgentProcessPtr process = controller->getCtrlAgentProcess();
104  if (process) {
105  CtrlAgentCfgMgrPtr cfgmgr = process->getCtrlAgentCfgMgr();
106  if (cfgmgr) {
107  ctx = cfgmgr->getCtrlAgentCfgContext();
108  if (ctx) {
109  const HttpAuthConfigPtr& auth = ctx->getAuthConfig();
110  if (auth) {
111  // Check authentication.
112  http_response = auth->checkAuth(*this, request);
113  }
114  }
115  }
116  }
117  }
118 
119  // Callout point for "auth".
120  bool reset_handle = false;
121  if (HooksManager::calloutsPresent(Hooks.hook_index_auth_)) {
122  // Get callout handle.
123  CalloutHandlePtr callout_handle = request->getCalloutHandle();
124  ScopedCalloutHandleState callout_handle_state(callout_handle);
125 
126  // Pass arguments.
127  callout_handle->setArgument("request", request);
128  callout_handle->setArgument("response", http_response);
129 
130  // Call callouts.
131  HooksManager::callCallouts(Hooks.hook_index_auth_, *callout_handle);
132  callout_handle->getArgument("request", request);
133  callout_handle->getArgument("response", http_response);
134 
135  // Status other than continue means 'please reset the handle'.
136  if (callout_handle->getStatus() != CalloutHandle::NEXT_STEP_CONTINUE) {
137  reset_handle = true;
138  }
139  }
140 
141  // The basic HTTP authentication check or a callout failed and
142  // left a response.
143  if (http_response) {
144  return (http_response);
145  }
146 
147  // Reset the handle when a hook asks for.
148  if (reset_handle) {
149  request->resetCalloutHandle();
150  }
151 
152  // The request is always non-null, because this is verified by the
153  // createHttpResponse method. Let's try to convert it to the
154  // PostHttpRequestJson type as this is the type generated by the
155  // createNewHttpRequest. If the conversion result is null it means that
156  // the caller did not use createNewHttpRequest method to create this
157  // instance. This is considered an error in the server logic.
158  PostHttpRequestJsonPtr request_json =
159  boost::dynamic_pointer_cast<PostHttpRequestJson>(request);
160  if (!request_json) {
161  // Notify the client that we have a problem with our server.
162  return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
163  }
164 
165  // We have already checked that the request is finalized so the call
166  // to getBodyAsJson must not trigger an exception.
167  ConstElementPtr command = request_json->getBodyAsJson();
168 
169  // Process command doesn't generate exceptions but can possibly return
170  // null response, if the handler is not implemented properly. This is
171  // again an internal server issue.
172  ConstElementPtr response = CtrlAgentCommandMgr::instance().processCommand(command);
173  if (!response) {
174  // Notify the client that we have a problem with our server.
175  return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
176  }
177  // The response is ok, so let's create new HTTP response with the status OK.
178  http_response = boost::dynamic_pointer_cast<
179  HttpResponseJson>(createStockHttpResponseInternal(request, HttpStatusCode::OK));
180  http_response->setBodyAsJson(response);
181  http_response->finalize();
182 
183  // Callout point for "response".
184  if (HooksManager::calloutsPresent(Hooks.hook_index_response_)) {
185  // Get callout handle.
186  CalloutHandlePtr callout_handle = request->getCalloutHandle();
187  ScopedCalloutHandleState callout_handle_state(callout_handle);
188 
189  // Pass arguments.
190  callout_handle->setArgument("request", request);
191  callout_handle->setArgument("response", http_response);
192 
193  // Call callouts.
194  HooksManager::callCallouts(Hooks.hook_index_response_,
195  *callout_handle);
196  callout_handle->getArgument("response", http_response);
197 
198  // Ignore status as the HTTP response is used instead.
199  }
200 
201  return (http_response);
202 }
203 
204 } // end of namespace isc::agent
205 } // end of namespace isc
Represents HTTP POST request with JSON body.
boost::shared_ptr< HttpResponseJson > HttpResponseJsonPtr
Pointer to the HttpResponseJson object.
Definition: response_json.h:24
HTTP protocol version.
Definition: http_types.h:14
boost::shared_ptr< CtrlAgentCfgMgr > CtrlAgentCfgMgrPtr
Defines a shared pointer to CtrlAgentCfgMgr.
Definition: ca_cfg_mgr.h:311
unsigned major_
Major HTTP version.
Definition: http_types.h:15
boost::shared_ptr< CtrlAgentProcess > CtrlAgentProcessPtr
Defines a shared pointer to CtrlAgentProcess.
Definition: ca_process.h:150
data::ConstElementPtr getBodyAsJson() const
Retrieves JSON body.
CtrlAgentProcessPtr getCtrlAgentProcess()
Returns pointer to an instance of the underlying process object.
boost::shared_ptr< PostHttpRequestJson > PostHttpRequestJsonPtr
Pointer to PostHttpRequestJson.
boost::shared_ptr< HttpResponse > HttpResponsePtr
Pointer to the HttpResponse object.
Definition: response.h:78
Wrapper class around callout handle which automatically resets handle&#39;s state.
Process Controller for Control Agent Process.
Definition: ca_controller.h:21
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
Represents HTTP response with JSON content.
Definition: response_json.h:34
Defines the logger used by the top-level component of kea-lfc.
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
CtrlAgentHooks Hooks
boost::shared_ptr< HttpRequest > HttpRequestPtr
Pointer to the HttpRequest object.
Definition: request.h:27
boost::shared_ptr< CtrlAgentCfgContext > CtrlAgentCfgContextPtr
Pointer to a configuration context.
Definition: ca_cfg_mgr.h:21
void setBodyAsJson(const data::ConstElementPtr &json_body)
Generates JSON content from the data structures represented as data::ConstElementPtr.
boost::shared_ptr< HttpAuthConfig > HttpAuthConfigPtr
Type of shared pointers to HTTP authentication configuration.
Definition: auth_config.h:97
HttpStatusCode
HTTP status codes (cf RFC 2068)
Definition: response.h:30