Leosac  0.8.0
Open Source Access Control
RemoteControl.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014-2016 Leosac
3 
4  This file is part of Leosac.
5 
6  Leosac is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Affero General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Leosac is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Affero General Public License for more details.
15 
16  You should have received a copy of the GNU Affero General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "RemoteControl.hpp"
21 #include "core/CoreUtils.hpp"
26 #include "kernel.hpp"
28 #include "tools/log.hpp"
29 #include <boost/archive/binary_iarchive.hpp>
30 #include <boost/archive/text_iarchive.hpp>
31 #include <boost/archive/text_oarchive.hpp>
32 #include <boost/property_tree/ptree_serialization.hpp>
33 #include <boost/regex.hpp>
34 #include <cassert>
35 #include <zmqpp/curve.hpp>
36 
37 using namespace Leosac;
38 
39 RemoteControl::RemoteControl(zmqpp::context &ctx, Kernel &kernel,
40  const boost::property_tree::ptree &cfg)
41  : kernel_(kernel)
42  , socket_(ctx, zmqpp::socket_type::router)
43  , auth_(ctx)
44  , context_(ctx)
45  , security_(cfg)
46 {
47  auth_.configure_curve("CURVE_ALLOW_ANY");
48  process_config(cfg);
49 }
50 
51 void RemoteControl::process_config(const boost::property_tree::ptree &cfg)
52 {
53  int port = cfg.get<int>("port");
54 
55  secret_key_ = cfg.get<std::string>("secret_key");
56  public_key_ = cfg.get<std::string>("public_key");
57 
58  INFO("Enabling Remote Control:"
59  << "\n\t "
60  << "Port: " << port << "\n\t "
61  << "Public Key: " << public_key_ << "\n\t "
62  << "Private Key: " << secret_key_);
63 
64  command_handlers_["MODULE_CONFIG"] =
65  std::bind(&RemoteControl::handle_module_config, this, std::placeholders::_1,
66  std::placeholders::_2);
67 
68  command_handlers_["MODULE_LIST"] =
69  std::bind(&RemoteControl::handle_module_list, this, std::placeholders::_1,
70  std::placeholders::_2);
71 
72  command_handlers_["SYNC_FROM"] =
73  std::bind(&RemoteControl::handle_sync_from, this, std::placeholders::_1,
74  std::placeholders::_2);
75 
76  command_handlers_["SAVE"] =
77  std::bind(&RemoteControl::handle_save, this, std::placeholders::_1,
78  std::placeholders::_2);
79 
80  command_handlers_["GENERAL_CONFIG"] =
81  std::bind(&RemoteControl::handle_general_config, this, std::placeholders::_1,
82  std::placeholders::_2);
83 
84  command_handlers_["CONFIG_VERSION"] =
85  std::bind(&RemoteControl::handle_config_version, this, std::placeholders::_1,
86  std::placeholders::_2);
87 
88  socket_.set(zmqpp::socket_option::curve_server, true);
89  socket_.set(zmqpp::socket_option::curve_secret_key, secret_key_);
90  socket_.set(zmqpp::socket_option::curve_public_key, public_key_);
91  socket_.bind("tcp://*:" + std::to_string(port));
92 }
93 
95 {
96  zmqpp::message msg;
97  zmqpp::message rep;
98  std::string frame1;
99  socket_.receive(msg);
100 
101  assert(msg.parts() > 1);
102  msg >> current_client_idt_;
103  rep << current_client_idt_;
104 
105  msg.pop_front(); // otherwise getting the "User-Id" property
106  msg.reset_read_cursor(); // wont work.
107 
108  msg >> frame1;
109  DEBUG("Remote Control command: " << frame1 << " with " << msg.parts()
110  << " parts");
111 
112  std::string user_pubkey;
113  bool ret = msg.get_property("User-Id", user_pubkey);
114  assert(ret);
115 
116  if (command_handlers_.find(frame1) != command_handlers_.end())
117  {
118 
119  if (security_.allow_request(user_pubkey, frame1))
120  {
121  auto h = command_handlers_[frame1];
122 
123  ret = h(&msg, &rep);
124  if (!ret)
125  {
126  // if the handler fails, that means the source message was incorrect.
127  // therefore, the response shall be empty (except for the zmq id)
128  assert(rep.parts() == 1);
129  rep << "KO"
130  << "Malformed message: " << frame1;
131  WARN("Received malformed message on Remote Control Interface. "
132  "Message type was "
133  << frame1);
134  }
135  }
136  else
137  {
138  WARN("Request denied. Insuficient permission for user "
139  << user_pubkey << ". Command was: " << frame1);
140  rep << "KO"
141  << "Insuficient permission";
142  }
143  }
144  else
145  {
146  rep << "KO"
147  << "UNKOWN MESSAGE";
148  WARN("Unknown message on Remote Control interface");
149  }
150 
151  socket_.send(rep);
152 }
153 
154 void RemoteControl::module_list(zmqpp::message *message_out)
155 {
156  assert(message_out);
157  for (const std::string &s : kernel_.module_manager().modules_names())
158  {
159  *message_out << s;
160  }
161 }
162 
163 void RemoteControl::module_config(const std::string &module,
164  ConfigManager::ConfigFormat cfg_format,
165  zmqpp::message *message_out)
166 {
167  assert(message_out);
168 
169  // we need to make sure the module's name exist.
170  std::vector<std::string> modules_names =
172  if (std::find(modules_names.begin(), modules_names.end(), module) !=
173  modules_names.end())
174  {
175  zmqpp::socket sock(context_, zmqpp::socket_type::req);
176  sock.connect("inproc://module-" + module);
177 
178  bool ret = sock.send(zmqpp::message() << "DUMP_CONFIG" << cfg_format);
179  ASSERT_LOG(ret, "Failed to send");
180 
181  zmqpp::message rep;
182 
183  sock.receive(rep);
184  *message_out << "OK";
185  *message_out << module;
186 
187  // extract data from received configuration
188  // fixme this is poor code and involve lots of copying.
189  while (rep.remaining())
190  {
191  std::string tmp;
192  rep >> tmp;
193  *message_out << tmp;
194  }
195  }
196  else
197  {
198  // if module with this name is not found
199  ERROR("RemoteControl: Cannot retrieve local module configuration for {"
200  << module << "}"
201  << "The module appears to not be loaded.");
202  *message_out << "KO"
203  << "Module not loaded, so config not available";
204  }
205 }
206 
208  zmqpp::message *msg_out)
209 {
210  assert(msg_out);
211 
213 
215  {
216  std::ostringstream oss;
217  boost::archive::text_oarchive archive(oss);
218  boost::property_tree::save(archive, cfg, 1);
219  msg_out->add("OK");
220  msg_out->add(oss.str());
221  }
222  else
223  {
224  msg_out->add("OK");
225  msg_out->add(Tools::propertyTreeToXml(cfg));
226  }
227 }
228 
229 bool RemoteControl::handle_module_config(zmqpp::message *msg_in,
230  zmqpp::message *msg_out)
231 {
232  assert(msg_in);
233  assert(msg_out);
234 
235  if (msg_in->remaining() >= 2)
236  {
237  std::string module_name;
239  *msg_in >> module_name >> format;
240  module_config(module_name, format, msg_out);
241  return true;
242  }
243  return false;
244 }
245 
246 bool RemoteControl::handle_module_list(zmqpp::message *msg_in,
247  zmqpp::message *msg_out)
248 {
249  assert(msg_in);
250  assert(msg_out);
251 
252  if (msg_in->remaining() == 0)
253  {
254  module_list(msg_out);
255  return true;
256  }
257  return false;
258 }
259 
260 bool RemoteControl::handle_sync_from(zmqpp::message *msg_in, zmqpp::message *msg_out)
261 {
262  assert(msg_in);
263  assert(msg_out);
264 
265  uint8_t autocommit;
266 
267  if (msg_in->remaining() == 4)
268  {
269  std::string endpoint;
270  std::string remote_server_pubkey;
271  uint8_t sync_general_config;
272 
273  *msg_in >> endpoint;
274  *msg_in >> autocommit;
275  *msg_in >> remote_server_pubkey;
276  *msg_in >> sync_general_config;
277 
278 
279  auto fetch_task = std::make_shared<Tasks::FetchRemoteConfig>(
280  endpoint, remote_server_pubkey);
281 
282  auto sync_task = std::make_shared<Tasks::SyncConfig>(
283  kernel_, fetch_task, sync_general_config, autocommit);
284  auto *sched = &kernel_.core_utils()->scheduler();
285 
286  auto success_response_task =
287  std::make_shared<Tasks::RemoteControlAsyncResponse>(
289  zmqpp::message() << "Success" << sync_task->get_guid(), socket_);
290 
291  auto failure_response_task =
292  std::make_shared<Tasks::RemoteControlAsyncResponse>(
294  zmqpp::message() << "Failed" << sync_task->get_guid(), socket_);
295 
296  auto abort_response_task =
297  std::make_shared<Tasks::RemoteControlAsyncResponse>(
299  zmqpp::message() << "Aborted" << sync_task->get_guid(), socket_);
300 
301  sync_task->set_on_success([=]() {
302  success_response_task->run();
303  ASSERT_LOG(success_response_task->succeed(), "TASK FAILED");
304  });
305  sync_task->set_on_failure([=]() {
306  failure_response_task->run();
307  ASSERT_LOG(failure_response_task->succeed(), "TASK FAILED");
308  });
309  fetch_task->set_on_failure([=]() {
310  // not run on main thread, need to be queued.
311  sched->enqueue(abort_response_task, TargetThread::MAIN);
312  });
313 
314  fetch_task->set_on_success([=]() {
315  DEBUG("FETCH TASK COMPLETE. WILL QUEUE SYNC_CONFIG");
316  sched->enqueue(sync_task, TargetThread::MAIN);
317  });
318 
319  kernel_.core_utils()->scheduler().enqueue(fetch_task, TargetThread::POOL);
320 
321  *msg_out << "DELAYED" << sync_task->get_guid();
322  return true;
323  }
324  return false;
325 }
326 
327 bool RemoteControl::handle_save(zmqpp::message *msg_in, zmqpp::message *msg_out)
328 {
329  assert(msg_in);
330  assert(msg_out);
331 
332  if (msg_in->remaining() == 0)
333  {
334  if (kernel_.save_config())
335  *msg_out << "OK";
336  else
337  *msg_out << "KO"
338  << "Saving config failed for some unkown reason.";
339 
340  return true;
341  }
342  return false;
343 }
344 
345 bool RemoteControl::handle_general_config(zmqpp::message *msg_in,
346  zmqpp::message *msg_out)
347 {
348  assert(msg_in);
349  assert(msg_out);
350 
351  if (msg_in->remaining() == 1)
352  {
354  *msg_in >> format;
355  general_config(format, msg_out);
356  return true;
357  }
358  return false;
359 }
360 
361 bool RemoteControl::handle_config_version(zmqpp::message *msg_in,
362  zmqpp::message *msg_out)
363 {
364  assert(msg_in);
365  assert(msg_out);
366 
367  if (msg_in->remaining() == 0)
368  {
369  *msg_out << static_cast<uint64_t>(kernel_.config_manager().config_version());
370  return true;
371  }
372  return false;
373 }
374 
376 {
377 }
RemoteControlAsyncResponse.hpp
Leosac::RemoteControl::context_
zmqpp::context & context_
Definition: RemoteControl.hpp:169
WARN
@ WARN
Definition: log.hpp:33
zmqpp
Definition: CoreUtils.hpp:27
SyncConfig.hpp
Leosac::RemoteControlSecurity::allow_request
bool allow_request(const std::string &user_pubkey, const std::string &req)
Definition: RemoteControlSecurity.cpp:49
ERROR
@ ERROR
Definition: log.hpp:32
DEBUG
@ DEBUG
Definition: log.hpp:35
Leosac::RemoteControl::module_config
void module_config(const std::string &module, ConfigManager::ConfigFormat cfg_format, zmqpp::message *message_out)
Implements the MODULE_CONFIG command.
Definition: RemoteControl.cpp:163
ASSERT_LOG
#define ASSERT_LOG(cond, msg)
Definition: log.hpp:190
Leosac::RemoteControl::process_config
void process_config(const boost::property_tree::ptree &cfg)
Definition: RemoteControl.cpp:51
Leosac::RemoteControl::handle_config_version
bool handle_config_version(zmqpp::message *msg_in, zmqpp::message *msg_out)
Command handler for CONFIG_VERSION command.
Definition: RemoteControl.cpp:361
INFO
@ INFO
Definition: log.hpp:34
Leosac::ConfigManager::ConfigFormat
ConfigFormat
This enum is used internally, when core request module configuration.
Definition: ConfigManager.hpp:118
Leosac::RemoteControl::current_client_idt_
std::string current_client_idt_
Definition: RemoteControl.hpp:183
Leosac::RemoteControl::handle_msg
void handle_msg()
Register by core and called when message arrives.
Definition: RemoteControl.cpp:94
Leosac::RemoteControl::handle_sync_from
bool handle_sync_from(zmqpp::message *msg_in, zmqpp::message *msg_out)
Extract and verify content from message and call sync_from()
Definition: RemoteControl.cpp:260
Leosac::RemoteControl::handle_save
bool handle_save(zmqpp::message *msg_in, zmqpp::message *msg_out)
Save the current configuration to disk.
Definition: RemoteControl.cpp:327
Leosac::RemoteControl::handle_general_config
bool handle_general_config(zmqpp::message *msg_in, zmqpp::message *msg_out)
Command handler for GENERAL_CONFIG.
Definition: RemoteControl.cpp:345
Leosac::RemoteControl::socket_
zmqpp::socket socket_
Public ROUTER.
Definition: RemoteControl.hpp:156
Leosac::ConfigManager::ConfigFormat::BOOST_ARCHIVE
@ BOOST_ARCHIVE
Leosac
This is the header file for a generated source file, GitSHA1.cpp.
Definition: APIStatusCode.hpp:22
RemoteControl.hpp
kernel.hpp
Leosac::RemoteControl::secret_key_
std::string secret_key_
z85 encoded private curve key
Definition: RemoteControl.hpp:166
Leosac::RemoteControl::RemoteControl
RemoteControl(zmqpp::context &ctx, Kernel &kernel, const boost::property_tree::ptree &cfg)
Definition: RemoteControl.cpp:39
ModuleManager::modules_names
std::vector< std::string > modules_names() const
Returns the list of the name of the loaded modules.
Definition: module_manager.cpp:278
Leosac::RemoteControl::module_list
void module_list(zmqpp::message *message_out)
Implements the module list command.
Definition: RemoteControl.cpp:154
Leosac::Kernel::save_config
bool save_config()
Save the current configuration to its original file if autosave is enabled.
Definition: kernel.cpp:415
Leosac::RemoteControl::public_key_
std::string public_key_
z85 encoded public curve key
Definition: RemoteControl.hpp:161
Leosac::RemoteControl::update
void update()
Definition: RemoteControl.cpp:375
Leosac::ConfigManager::get_exportable_general_config
boost::property_tree::ptree get_exportable_general_config() const
Return the property_tree of item inside the <kernel> tag (except <modules>`) that are marked exportab...
Definition: ConfigManager.cpp:76
XmlPropertyTree.hpp
Leosac::ConfigManager::config_version
uint64_t config_version() const
Return the current configuration version.
Definition: ConfigManager.cpp:251
Leosac::Kernel
Core of Leosac.
Definition: kernel.hpp:73
Leosac::RemoteControl::auth_
zmqpp::auth auth_
Definition: RemoteControl.hpp:168
FetchRemoteConfig.hpp
Leosac::TargetThread::MAIN
@ MAIN
Leosac::RemoteControl::command_handlers_
CommandHandlerMap command_handlers_
Definition: RemoteControl.hpp:176
RemoteConfigCollector.hpp
Leosac::Colorize::detail::format
std::string format(const std::string &escape_code, const T &in)
Return a string containing the escape code, a string representation of T and the clear escape string.
Definition: Colorize.hpp:49
log.hpp
CoreUtils.hpp
Leosac::Tools::propertyTreeToXml
std::string propertyTreeToXml(const boost::property_tree::ptree &tree)
Convert a property tree to an xml formatted string.
Definition: XmlPropertyTree.cpp:67
Leosac::RemoteControl::security_
RemoteControlSecurity security_
Object to check remote user permission before processing their request.
Definition: RemoteControl.hpp:181
Leosac::RemoteControl::handle_module_config
bool handle_module_config(zmqpp::message *msg_in, zmqpp::message *msg_out)
Extract and verify content from user-message and call implementation.
Definition: RemoteControl.cpp:229
Leosac::RemoteControl::general_config
void general_config(ConfigManager::ConfigFormat cfg_format, zmqpp::message *msg_out)
Implements GLOBAL_CONFIG API call.
Definition: RemoteControl.cpp:207
Leosac::Kernel::core_utils
CoreUtilsPtr core_utils()
Returns a (smart) pointer to the core utils: some thread-safe utilities.
Definition: kernel.cpp:447
Leosac::Kernel::module_manager
const ModuleManager & module_manager() const
Returns a reference to the module manager object (const version).
Definition: kernel.cpp:405
Leosac::RemoteControl::kernel_
Kernel & kernel_
Definition: RemoteControl.hpp:151
Leosac::RemoteControl::handle_module_list
bool handle_module_list(zmqpp::message *msg_in, zmqpp::message *msg_out)
Extract and verify content from message and call implementation.
Definition: RemoteControl.cpp:246
Leosac::Kernel::config_manager
ConfigManager & config_manager()
Retrieve a reference to the configuration manager object.
Definition: kernel.cpp:436
Leosac::TargetThread::POOL
@ POOL