Kea  1.9.9-git
ca_response_creator.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-2020 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  if (HooksManager::calloutsPresent(Hooks.hook_index_auth_)) {
121  // Get callout handle.
122  CalloutHandlePtr callout_handle = request->getCalloutHandle();
123  ScopedCalloutHandleState callout_handle_state(callout_handle);
124 
125  // Pass arguments.
126  callout_handle->setArgument("request", request);
127  callout_handle->setArgument("response", http_response);
128 
129  // Call callouts.
130  HooksManager::callCallouts(Hooks.hook_index_auth_, *callout_handle);
131  callout_handle->getArgument("request", request);
132  callout_handle->getArgument("response", http_response);
133 
134  // Ignore status as the HTTP response is used instead.
135  }
136 
137  // The basic HTTP authentication check or a callout failed and
138  // left a response.
139  if (http_response) {
140  return (http_response);
141  }
142 
143  // The request is always non-null, because this is verified by the
144  // createHttpResponse method. Let's try to convert it to the
145  // PostHttpRequestJson type as this is the type generated by the
146  // createNewHttpRequest. If the conversion result is null it means that
147  // the caller did not use createNewHttpRequest method to create this
148  // instance. This is considered an error in the server logic.
149  PostHttpRequestJsonPtr request_json =
150  boost::dynamic_pointer_cast<PostHttpRequestJson>(request);
151  if (!request_json) {
152  // Notify the client that we have a problem with our server.
153  return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
154  }
155 
156  // We have already checked that the request is finalized so the call
157  // to getBodyAsJson must not trigger an exception.
158  ConstElementPtr command = request_json->getBodyAsJson();
159 
160  // Process command doesn't generate exceptions but can possibly return
161  // null response, if the handler is not implemented properly. This is
162  // again an internal server issue.
163  ConstElementPtr response = CtrlAgentCommandMgr::instance().processCommand(command);
164  if (!response) {
165  // Notify the client that we have a problem with our server.
166  return (createStockHttpResponse(request, HttpStatusCode::INTERNAL_SERVER_ERROR));
167  }
168  // The response is ok, so let's create new HTTP response with the status OK.
169  http_response = boost::dynamic_pointer_cast<
170  HttpResponseJson>(createStockHttpResponseInternal(request, HttpStatusCode::OK));
171  http_response->setBodyAsJson(response);
172  http_response->finalize();
173 
174  // Callout point for "response".
175  if (HooksManager::calloutsPresent(Hooks.hook_index_response_)) {
176  // Get callout handle.
177  CalloutHandlePtr callout_handle = request->getCalloutHandle();
178  ScopedCalloutHandleState callout_handle_state(callout_handle);
179 
180  // Pass arguments.
181  callout_handle->setArgument("request", request);
182  callout_handle->setArgument("response", http_response);
183 
184  // Call callouts.
185  HooksManager::callCallouts(Hooks.hook_index_response_,
186  *callout_handle);
187  callout_handle->getArgument("response", http_response);
188 
189  // Ignore status as the HTTP response is used instead.
190  }
191 
192  return (http_response);
193 }
194 
195 } // end of namespace isc::agent
196 } // 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
data::ConstElementPtr getBodyAsJson() const
Retrieves JSON body.
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
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's state.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
Represents HTTP response with JSON content.
Definition: response_json.h:34
Defines the logger used by the top-level component of kea-dhcp-ddns.
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:79
HttpStatusCode
HTTP status codes (cf RFC 2068)
Definition: response.h:30