From 7fa3cb9eedad389ba89978e31889b61fd651ecf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= <37657534+Pietfried@users.noreply.github.com> Date: Thu, 18 Jan 2024 17:30:48 +0100 Subject: [PATCH] Added option for writing SecurityEvents to a security log file for ocpp1.6 and ocpp2.0.1 (#407) Signed-off-by: pietfried --- .gitignore | 1 + config/v16/config-docker.json | 3 ++- config/v16/profile_schemas/Internal.json | 5 +++-- .../standardized/InternalCtrlr.json | 6 +++--- config/v201/config.json | 2 +- include/ocpp/common/ocpp_logging.hpp | 6 +++++- lib/ocpp/common/ocpp_logging.cpp | 18 ++++++++++++++++-- lib/ocpp/v16/charge_point_impl.cpp | 5 ++++- lib/ocpp/v201/charge_point.cpp | 17 +++++++++-------- 9 files changed, 44 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 8e78b9cb2..fa2c74069 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ .cache/ workspace.yaml CMakeLists.txt.user +__pycache__ !doc/build-with-fetchcontent /dist diff --git a/config/v16/config-docker.json b/config/v16/config-docker.json index 3260133d9..534bfd94e 100644 --- a/config/v16/config-docker.json +++ b/config/v16/config-docker.json @@ -7,7 +7,8 @@ "ChargePointVendor": "Pionix", "FirmwareVersion": "0.1", "AllowChargingProfileWithoutStartSchedule": true, - "UseTPM" : false + "UseTPM" : false, + "LogMessagesFormat": ["html","security"] }, "Core": { "AuthorizeRemoteTxRequests": false, diff --git a/config/v16/profile_schemas/Internal.json b/config/v16/profile_schemas/Internal.json index d431ecaf1..af2c3da63 100644 --- a/config/v16/profile_schemas/Internal.json +++ b/config/v16/profile_schemas/Internal.json @@ -140,7 +140,7 @@ "default": true }, "LogMessagesFormat": { - "$comment": "Supported log formats are console, log, html, console_detailed and session_logging", + "$comment": "Supported log formats are console, log, html, console_detailed, session_logging, callback and security. \"security\" logs security events into a seperate logfile", "type": "array", "items": { "type": "string" @@ -149,7 +149,8 @@ "default": [ "log", "html", - "session_logging" + "session_logging", + "security" ] }, "SupportedChargingProfilePurposeTypes": { diff --git a/config/v201/component_schemas/standardized/InternalCtrlr.json b/config/v201/component_schemas/standardized/InternalCtrlr.json index 982129e27..fa0cb2723 100644 --- a/config/v201/component_schemas/standardized/InternalCtrlr.json +++ b/config/v201/component_schemas/standardized/InternalCtrlr.json @@ -261,7 +261,7 @@ "LogMessagesFormat": { "variable_name": "LogMessagesFormat", "characteristics": { - "valuesList": "log,html,console,console_detailed", + "valuesList": "log,html,console,console_detailed,security", "supportsMonitoring": true, "dataType": "MemberList" }, @@ -271,8 +271,8 @@ "mutability": "ReadOnly" } ], - "description": "Supported log formats are console, log, html, console_detailed and callback", - "default": "log,html", + "description": "Supported log formats are console, log, html, console_detailed, callback and security. \"security\" logs security events into a seperate logfile", + "default": "log,html,security", "type": "string" }, "SupportedChargingProfilePurposeTypes": { diff --git a/config/v201/config.json b/config/v201/config.json index 13aa92dd4..8fdd3d4e0 100644 --- a/config/v201/config.json +++ b/config/v201/config.json @@ -257,7 +257,7 @@ "LogMessagesFormat": { "variable_name": "LogMessagesFormat", "attributes": { - "Actual": "log,html" + "Actual": "log,html,security" } }, "SupportedCriteria": { diff --git a/include/ocpp/common/ocpp_logging.hpp b/include/ocpp/common/ocpp_logging.hpp index c757146d8..a250d0e01 100644 --- a/include/ocpp/common/ocpp_logging.hpp +++ b/include/ocpp/common/ocpp_logging.hpp @@ -30,9 +30,11 @@ class MessageLogging { bool detailed_log_to_console; bool log_to_file; bool log_to_html; + bool log_security; bool session_logging; std::ofstream output_file; std::ofstream html_log_file; + std::ofstream security_log_file; std::mutex output_file_mutex; std::function message_callback; std::map lookup_map; @@ -47,13 +49,15 @@ class MessageLogging { /// \brief Creates a new Websocket object with the providede \p configuration explicit MessageLogging( bool log_messages, const std::string& message_log_path, const std::string& output_file_name, - bool log_to_console, bool detailed_log_to_console, bool log_to_file, bool log_to_html, bool session_logging, + bool log_to_console, bool detailed_log_to_console, bool log_to_file, bool log_to_html, bool log_security, + bool session_logging, std::function message_callback); ~MessageLogging(); void charge_point(const std::string& message_type, const std::string& json_str); void central_system(const std::string& message_type, const std::string& json_str); void sys(const std::string& msg); + void security(const std::string& msg); void start_session_logging(const std::string& session_id, const std::string& log_path); void stop_session_logging(const std::string& session_id); std::string get_message_log_path(); diff --git a/lib/ocpp/common/ocpp_logging.cpp b/lib/ocpp/common/ocpp_logging.cpp index 3b8ef0ca1..60f0730a0 100644 --- a/lib/ocpp/common/ocpp_logging.cpp +++ b/lib/ocpp/common/ocpp_logging.cpp @@ -14,7 +14,7 @@ namespace ocpp { MessageLogging::MessageLogging( bool log_messages, const std::string& message_log_path, const std::string& output_file_name, bool log_to_console, - bool detailed_log_to_console, bool log_to_file, bool log_to_html, bool session_logging, + bool detailed_log_to_console, bool log_to_file, bool log_to_html, bool log_security, bool session_logging, std::function message_callback) : log_messages(log_messages), message_log_path(message_log_path), @@ -23,6 +23,7 @@ MessageLogging::MessageLogging( detailed_log_to_console(detailed_log_to_console), log_to_file(log_to_file), log_to_html(log_to_html), + log_security(log_security), session_logging(session_logging), message_callback(message_callback) { @@ -69,6 +70,10 @@ MessageLogging::MessageLogging( ""; this->html_log_file << "\n"; } + if (this->log_security) { + EVLOG_info << "Logging SecurityEvents to file"; + this->security_log_file.open(message_log_path + "/" + output_file_name + ".security.log"); + } sys("Session logging started."); } } @@ -83,6 +88,10 @@ MessageLogging::~MessageLogging() { this->html_log_file << "
\n"; this->html_log_file.close(); } + + if (this->log_security) { + this->security_log_file.close(); + } } } @@ -124,6 +133,11 @@ void MessageLogging::sys(const std::string& msg) { } } +void MessageLogging::security(const std::string& msg) { + this->security_log_file << msg << "\n"; + this->security_log_file.flush(); +} + void MessageLogging::log_output(unsigned int typ, const std::string& message_type, const std::string& json_str) { if (this->log_messages) { std::lock_guard lock(this->output_file_mutex); @@ -206,7 +220,7 @@ FormattedMessageWithType MessageLogging::format_message(const std::string& messa void MessageLogging::start_session_logging(const std::string& session_id, const std::string& log_path) { std::scoped_lock lock(this->session_id_logging_mutex); this->session_id_logging[session_id] = std::make_shared( - true, log_path, "incomplete-ocpp", false, false, false, true, false, nullptr); + true, log_path, "incomplete-ocpp", false, false, false, true, false, false, nullptr); } void MessageLogging::stop_session_logging(const std::string& session_id) { diff --git a/lib/ocpp/v16/charge_point_impl.cpp b/lib/ocpp/v16/charge_point_impl.cpp index 4c89746c6..f4794003d 100644 --- a/lib/ocpp/v16/charge_point_impl.cpp +++ b/lib/ocpp/v16/charge_point_impl.cpp @@ -50,11 +50,12 @@ ChargePointImpl::ChargePointImpl(const std::string& config, const fs::path& shar std::find(log_formats.begin(), log_formats.end(), "console_detailed") != log_formats.end(); bool log_to_file = std::find(log_formats.begin(), log_formats.end(), "log") != log_formats.end(); bool log_to_html = std::find(log_formats.begin(), log_formats.end(), "html") != log_formats.end(); + bool log_security = std::find(log_formats.begin(), log_formats.end(), "security") != log_formats.end(); bool session_logging = std::find(log_formats.begin(), log_formats.end(), "session_logging") != log_formats.end(); this->logging = std::make_shared( this->configuration->getLogMessages(), this->message_log_path, DateTime().to_rfc3339(), log_to_console, - detailed_log_to_console, log_to_file, log_to_html, session_logging, nullptr); + detailed_log_to_console, log_to_file, log_to_html, log_security, session_logging, nullptr); this->boot_notification_timer = std::make_unique(&this->io_service, [this]() { this->boot_notification(); }); @@ -2359,6 +2360,8 @@ void ChargePointImpl::securityEventNotification(const std::string& type, const s req.techInfo.emplace(tech_info); req.timestamp = ocpp::DateTime(); + this->logging->security(json(req).dump()); + ocpp::Call call(req, this->message_queue->createMessageId()); this->send(call); diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 7e022f12d..043a4b1a6 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -465,6 +465,7 @@ void ChargePoint::configure_message_logging_format(const std::string& message_lo bool detailed_log_to_console = log_formats.find("console_detailed") != log_formats.npos; bool log_to_file = log_formats.find("log") != log_formats.npos; bool log_to_html = log_formats.find("html") != log_formats.npos; + bool log_security = log_formats.find("security") != log_formats.npos; bool session_logging = log_formats.find("session_logging") != log_formats.npos; bool message_callback = log_formats.find("callback") != log_formats.npos; std::function logging_callback = nullptr; @@ -475,7 +476,7 @@ void ChargePoint::configure_message_logging_format(const std::string& message_lo this->logging = std::make_shared( !log_formats.empty(), message_log_path, DateTime().to_rfc3339(), log_to_console, detailed_log_to_console, - log_to_file, log_to_html, session_logging, logging_callback); + log_to_file, log_to_html, log_security, session_logging, logging_callback); } void ChargePoint::on_unavailable(const int32_t evse_id, const int32_t connector_id) { this->evses.at(evse_id)->submit_event(connector_id, ConnectorEvent::Unavailable); @@ -1518,14 +1519,14 @@ bool ChargePoint::is_offline() { void ChargePoint::security_event_notification_req(const CiString<50>& event_type, const std::optional>& tech_info, const bool triggered_internally, const bool critical) { - if (critical) { - EVLOG_debug << "Sending SecurityEventNotification"; - SecurityEventNotificationRequest req; - - req.type = event_type; - req.timestamp = DateTime().to_rfc3339(); - req.techInfo = tech_info; + EVLOG_debug << "Sending SecurityEventNotification"; + SecurityEventNotificationRequest req; + req.type = event_type; + req.timestamp = DateTime().to_rfc3339(); + req.techInfo = tech_info; + this->logging->security(json(req).dump()); + if (critical) { ocpp::Call call(req, this->message_queue->createMessageId()); this->send(call); }