|
Leosac
0.8.0
Open Source Access Control
|
Go to the documentation of this file.
25 #include "core/auth/User_odb.h"
28 #include "core/credentials/RFIDCard_odb.h"
38 #include "tools/ScheduleMapping_odb.h"
39 #include "tools/Schedule_odb.h"
50 #include <boost/algorithm/string/join.hpp>
51 #include <boost/archive/binary_iarchive.hpp>
52 #include <boost/archive/binary_oarchive.hpp>
53 #include <boost/archive/text_oarchive.hpp>
54 #include <boost/property_tree/ptree_serialization.hpp>
56 #include <odb/pgsql/database.hxx>
57 #include <odb/sqlite/database.hxx>
59 using boost::property_tree::ptree;
60 using boost::property_tree::ptree_error;
69 , config_manager_(config)
72 , control_(ctx_,
zmqpp::socket_type::rep)
73 , bus_push_(ctx_,
zmqpp::socket_type::push)
75 , want_restart_(false)
76 , module_manager_(ctx_, *this)
77 , network_config_(nullptr)
78 , remote_controller_(nullptr)
81 , start_time_(std::chrono::steady_clock::now())
82 , xmlnne_(config_file_path())
89 if (config.get_child_optional(
"network"))
100 if (config.get_child_optional(
"remote"))
106 if (
auto child = config.get_child_optional(
"autosave"))
111 control_.bind(
"inproc://leosac-kernel");
112 bus_push_.connect(
"inproc://zmq-bus-pull");
130 boost::property_tree::ptree cfg;
131 std::string filename = opt.
get_param(
"kernel-cfg");
133 if (filename.empty())
134 throw CoreException(
"Invalid command line parameter. No kernel "
135 "configuration file specified.");
141 cfg.get_child(
"kernel").add(
"kernel-cfg", filename);
142 return cfg.get_child(
"kernel");
144 catch (ptree_error &e)
146 std::throw_with_nested(
157 bus_push_.send(zmqpp::message() <<
"KERNEL"
172 bus_push_.send(zmqpp::message() <<
"KERNEL"
178 INFO(
"KERNEL JUST EXITED MAIN LOOP");
193 for (
const auto &plugin_dir : plugin_dirs)
195 std::string pname = plugin_dir.first;
196 std::string pvalue = plugin_dir.second.data();
199 DEBUG(
"Adding {" << pvalue <<
"} in library path");
205 std::string pname = module.first;
208 ptree module_conf = module.second;
209 std::string module_file = module_conf.get_child(
"file").data();
210 std::string module_name = module_conf.get_child(
"name").data();
218 std::string search_path;
220 search_path = boost::algorithm::join(
223 "Cannot load modules. Search path was: \n\t -> " + search_path);
227 catch (ptree_error &e)
229 ERROR(
"Invalid configuration file: " << e.what());
242 INFO(
"Receive request: " << req);
244 if (req ==
"RESTART")
250 else if (req ==
"RESET")
256 else if (req ==
"GET_NETCONFIG")
260 else if (req ==
"SET_NETCONFIG")
264 else if (req ==
"SCRIPTS_DIR")
268 else if (req ==
"FACTORY_CONF_DIR")
283 std::string kernel_config_file =
285 INFO(
"Kernel config file path = " << kernel_config_file);
286 INFO(
"RESTORING FACTORY CONFIG");
288 if (script.
run(UnixShellScript::toCmdLine(
291 ERROR(
"Error restoring factory configuration...");
297 std::ostringstream oss;
298 boost::archive::binary_oarchive archive(oss);
301 zmqpp::message response;
302 boost::property_tree::save(archive, network_config, 1);
303 response << oss.str();
309 std::string serialized_config;
310 *msg >> serialized_config;
311 std::istringstream iss(serialized_config);
312 boost::archive::binary_iarchive archive(iss);
314 boost::property_tree::ptree network_config;
315 boost::property_tree::load(archive, network_config, 1);
321 boost::property_tree::ptree to_save;
325 to_save.get_child(
"kernel").erase(
"kernel-cfg");
331 catch (std::exception &e)
333 ERROR(
"Exception: " << e.what());
342 if (
char *str = getenv(
"LEOSAC_FACTORY_CONFIG_DIR"))
344 INFO(
"Using FACTORY_CONFIG_DIR: " << str);
347 if (
char *str = getenv(
"LEOSAC_SCRIPTS_DIR"))
349 INFO(
"Using SCRIPTS_DIR: " << str);
370 bool use_syslog =
true;
371 bool use_database =
false;
372 std::string syslog_min_level =
"WARNING";
373 std::shared_ptr<spdlog::logger> console;
376 spdlog::drop(
"syslog");
377 spdlog::drop(
"console");
382 use_syslog = log_cfg_node->get<
bool>(
"enable_syslog",
true);
383 use_database = log_cfg_node->get<
bool>(
"enable_database",
false);
384 syslog_min_level = log_cfg_node->get<std::string>(
"min_syslog",
"WARNING");
388 auto syslog = spdlog::create(
389 "syslog", {std::make_shared<spdlog::sinks::syslog_sink>()});
390 syslog->set_level(
static_cast<spdlog::level::level_enum
>(
395 console = spdlog::create(
396 "console", {std::make_shared<spdlog::sinks::stdout_sink_mt>(),
397 std::make_shared<Tools::DatabaseLogSink>(
database_)});
400 console = spdlog::create(
401 "console", {std::make_shared<spdlog::sinks::stdout_sink_mt>()});
402 console->set_level(spdlog::level::debug);
417 INFO(
"Saving current configuration to disk.");
418 std::string full_config =
420 std::string cfg_file_path =
423 DEBUG(
"Will overwrite " << cfg_file_path <<
" in order to save configuration.");
424 std::ofstream cfg_file(cfg_file_path);
426 if (cfg_file << full_config)
462 INFO(
"DONE SOFT STOP");
484 db_cfg_node->get<uint64_t>(
"startup_abort_time", 60 * 5) * 1000)
493 catch (odb::unknown_schema &ex)
495 INFO(
"Database schema unknown: "
496 << ex.what() <<
". Leosac will attempt to create the schema "
497 "and populate the database.");
500 catch (
const odb::exception &e)
504 WARN(
"Cannot connect to or initialize database at this point. "
505 "Leosac will not start until it can reach the database. "
508 INFO(
"Will now wait " << wait_time <<
" seconds.");
509 std::this_thread::sleep_for(std::chrono::seconds(wait_time));
510 wait_time = std::min(wait_time * 2, 60);
514 "connect to / initialize the database");
543 std::make_unique<Audit::Serializer::JSONService>());
550 auto aps = std::make_unique<Auth::AccessPointService>();
559 auto update_srv = std::make_unique<update::UpdateService>();
563 std::move(update_srv));
569 auto hardware_srv = std::make_unique<Hardware::HardwareService>(
585 ASSERT_LOG(ret,
"Failed to unregister AuditSerializerService.");
589 ASSERT_LOG(ret,
"Failed to unregister DBService");
600 ASSERT_LOG(ret,
"Failed to unregister Auth::AccessPointService");
606 ASSERT_LOG(ret,
"Failed to unregister update::UpdateService");
613 ASSERT_LOG(ret,
"Failed to unregister HardwareService");
626 using namespace odb::core;
636 admin = std::make_shared<Auth::User>();
637 admin->firstname(
"Admin");
638 admin->lastname(
"ADMIN");
639 admin->username(
"admin");
640 admin->password(
"admin");
645 demo->firstname(
"Demo");
646 demo->lastname(
"Demo");
647 demo->username(
"demo");
648 demo->password(
"demo");
652 administrators->name(
"Administrator");
653 administrators->member_add(admin);
656 users = std::make_shared<Auth::Group>();
657 users->name(
"Users");
658 users->member_add(demo);
659 users->member_add(admin);
668 card = std::make_shared<Cred::RFIDCard>();
670 card->alias(std::string(
"BestCardEver"));
671 card->card_id(
"00:11:22:33");
676 card2.
alias(std::string(
"Ownerless"));
688 sched->name(
"DummySchedule");
689 sched->description(
"A test schedule, with mapping.");
691 map0->add_user(admin);
692 map0->add_group(users);
693 map0->add_credential(card);
694 map0->alias(
"My first mapping");
696 sched->add_mapping(map0);
705 std::string db_type = db_cfg_node.get<std::string>(
"type",
"");
706 if (db_type ==
"sqlite")
708 std::string db_path = db_cfg_node.get<std::string>(
"path");
709 database_ = std::make_shared<odb::sqlite::database>(
710 db_path, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
712 else if (db_type ==
"pgsql")
714 std::string db_user = db_cfg_node.get<std::string>(
"username");
715 std::string db_pw = db_cfg_node.get<std::string>(
"password");
716 std::string db_dbname = db_cfg_node.get<std::string>(
"dbname");
717 std::string db_host = db_cfg_node.get<std::string>(
"host",
"");
718 uint16_t db_port = db_cfg_node.get<uint16_t>(
"port", 0);
720 INFO(
"Connecting to PGSQL database.");
721 auto pg_db = std::make_shared<odb::pgsql::database>(
722 db_user, db_pw, db_dbname, db_host, db_port);
736 SignalHandler::registerCallback(Signal::SigInt, [
this](
Signal) {
739 std::cerr <<
"SIGINT received a second time. Exiting abruptly."
749 SignalHandler::registerCallback(Signal::SigTerm,
752 SignalHandler::registerCallback(Signal::SigHup,
760 odb::schema_version v =
database_->schema_version(
"core");
761 odb::schema_version cv(odb::schema_catalog::current_version(*
database_,
"core"));
763 DEBUG(
"Database schema version: " << v);
768 odb::schema_catalog::create_schema(*
database_,
"core");
775 INFO(
"Leosac performing database migration. Going from version "
776 << v <<
" to version " << cv);
778 odb::schema_catalog::migrate(*
database_, cv,
"core");
zmqpp::reactor reactor_
Watch for message on the control_ socket.
std::unique_ptr< NetworkConfig > network_config_
Object that handle networking configuration.
std::string factory_config_directory() const
Return the path to factory config directory Uses environment variable if available,...
void restart_later()
Set the running_ and want_restart flag so that leosac will restart in the next main loop iteration.
UnixShellScript class declaration.
Database aware Hardware Service.
~Kernel()
Implemented in .cpp for unique_ptr to work.
That class helps manage the configuration for the application and its module.
Tools::XmlNodeNameEnforcer xmlnne_
virtual int nb_bits() const override
void set_netconfig(zmqpp::message *msg)
Handle SET_NETCONFIG command and update the configuration file directly.
std::shared_ptr< RFIDCard > RFIDCardPtr
signal handler to provide a C++ interface for UNIX sigaction()
#define ASSERT_LOG(cond, msg)
std::shared_ptr< User > UserPtr
ModuleManager module_manager_
Manages the different libraries (.so) we load, path to those libraries, modules instantiation.
bool autosave_
Autosave configuration on shutdown.
bool run()
Main loop of the main thread.
A second module manager that loads "ZMQ aware" module – modules that talks to the application through...
void connect_to_db(const boost::property_tree::ptree &db_cfg_node)
std::shared_ptr< odb::database > DBPtr
std::map< EnvironVar, std::string > environ_
Provide ODB magic to be able to store an Leosac::Audit::EventType (FlagSet) object.
ServiceRegistryUPtr service_registry_
DBPtr database_
A pointer to the database used by Leosac, if any.
void initModules()
Actually call the init_module() function of each library we loaded.
void handle_msg()
Register by core and called when message arrives.
Provides various database-related services to consumer.
std::string underline(const T &in)
const boost::property_tree::ptree & kconfig() const
Return const & on the general config tree.
bool store_config(const std::string &module, const boost::property_tree::ptree &cfg)
Store the configuration tree for a module.
unix filesystem helper functions
void populate_default_db()
This is the header file for a generated source file, GitSHA1.cpp.
Kernel(const boost::property_tree::ptree &config, bool strict_mode=false)
Construct a Kernel object.
This class is here to help check the validity of the configuration.
const std::chrono::steady_clock::time_point start_time() const
Return the time point at which Leosac started.
void unregister_core_services()
Unregister the service that were registered into register_core_services().
void factory_reset()
Reset Leosac configuration.
bool want_restart_
Should leosac restart ?
Class that helps configuring the network.
void get_netconfig()
Handle GET_NETCONFIG command.
This is a scheduler that is used internally to schedule asynchronous / long running tasks.
static json serialize(const Auth::AccessPointUpdate &in, const SecurityContext &sc)
A base class for Leosac specific exception.
zmqpp::context ctx_
The application ZMQ context.
bool save_config()
Save the current configuration to its original file if autosave is enabled.
A class that manages services.
This service lets various AccessPoint backend register and provide implementation to use by the Acces...
std::shared_ptr< Group > GroupPtr
static json serialize(const Auth::IAccessPoint &ap, const SecurityContext &sc)
This class is part of Leosac::Kernel, but it only exposes thread-safe functionalities that may be use...
bool send_sighup_
Should we broadcast "SIGHUP" in the next main loop iteration ?
bool is_running_
Controls core main loop.
zmqpp::context & zmqpp_context()
Returns a reference to the zmqpp context created for the application.
void module_manager_init()
Init the module manager by feeding it paths to library file, loading module, etc.
virtual const std::string & card_id() const override
void configure_signal_handler()
Setup signal handling for the process.
static boost::property_tree::ptree make_config(const Leosac::Tools::RuntimeOptions &opt)
Build a property tree from a runtime object object.
static Kernel * instance_
A global pointer to the Kernel instance.
An implementation of odb::tracer that use the logging infrastructure of Leosac.
void unregister_serializer()
virtual std::string alias() const override
An alias for the credential.
ConfigManager config_manager_
std::string script_directory() const
Return the path to the scripts directory.
void create_update_schema()
Create and/or update the database schema.
@ ADMIN
Site administrator.
LogLevel log_level_from_string(const std::string &level)
void stopModules(bool soft=false)
Opposite of init module.
This service provides various update management utilities.
void handle_control_request()
A request has arrived on the control_ socket.
void addToPath(const std::string &dir)
Add a directory to a path.
std::unique_ptr< RemoteControl > remote_controller_
Object that expose leosac to the world.
void register_core_services()
Register some important services to the service registry.
std::string config_file_path() const
Return the path to the kernel configuration file.
zmqpp::socket control_
A REP socket to send request to the kernel.
bool loadModule(const std::string &module_name)
Search the path and load a module based on a property tree for this module.
ServiceRegistry & service_registry()
Retrieve a reference to the service registry.
void configure_database()
CoreUtilsPtr core_utils()
Returns a (smart) pointer to the core utils: some thread-safe utilities.
std::shared_ptr< CoreUtils > CoreUtilsPtr
const ModuleManager & module_manager() const
Returns a reference to the module manager object (const version).
boost::property_tree::ptree get_application_config()
Retrieve the (current, running) configuration from the application and its modules.
ConfigManager & config_manager()
Retrieve a reference to the configuration manager object.
This service manages runtime registered serializer that target AuditEntry object.
const std::chrono::steady_clock::time_point start_time_
Time-point when Leosac started to run.
This class handle the remote control of leosac.
DBPtr database()
Retrieve a pointer to the database, if any.
zmqpp::socket bus_push_
A PUSH socket to write on the bus.