diff --git a/include/ocpp/common/utils.hpp b/include/ocpp/common/utils.hpp index c29b4bdf4..cbeed531b 100644 --- a/include/ocpp/common/utils.hpp +++ b/include/ocpp/common/utils.hpp @@ -12,8 +12,6 @@ namespace ocpp { /// \brief Case insensitive compare for a case insensitive (Ci)String bool iequals(const std::string& lhs, const std::string rhs); -std::vector get_vector_from_csv(const std::string& csv_str); - bool is_integer(const std::string& value); std::tuple is_positive_integer(const std::string& value); bool is_decimal_number(const std::string& value); diff --git a/lib/ocpp/common/utils.cpp b/lib/ocpp/common/utils.cpp index 270cc3252..3f204cf24 100644 --- a/lib/ocpp/common/utils.cpp +++ b/lib/ocpp/common/utils.cpp @@ -14,16 +14,6 @@ bool iequals(const std::string& lhs, const std::string rhs) { return boost::algorithm::iequals(lhs, rhs); } -std::vector get_vector_from_csv(const std::string& csv_str) { - std::vector csv; - std::string str; - std::stringstream ss(csv_str); - while (std::getline(ss, str, ',')) { - csv.push_back(str); - } - return csv; -} - bool is_integer(const std::string& value) { if (value.empty()) { return false; diff --git a/lib/ocpp/v16/charge_point_configuration.cpp b/lib/ocpp/v16/charge_point_configuration.cpp index 8975d42a9..63f2ead75 100644 --- a/lib/ocpp/v16/charge_point_configuration.cpp +++ b/lib/ocpp/v16/charge_point_configuration.cpp @@ -210,7 +210,7 @@ std::string to_csl(const std::vector& vec) { } void ChargePointConfiguration::init_supported_measurands() { - const auto _supported_measurands = ocpp::get_vector_from_csv(this->config["Internal"]["SupportedMeasurands"]); + const auto _supported_measurands = ocpp::split_string(this->config["Internal"]["SupportedMeasurands"], ','); for (const auto& measurand : _supported_measurands) { try { const auto _measurand = conversions::string_to_measurand(measurand); diff --git a/lib/ocpp/v16/charge_point_impl.cpp b/lib/ocpp/v16/charge_point_impl.cpp index 46a9e7f83..1413eca50 100644 --- a/lib/ocpp/v16/charge_point_impl.cpp +++ b/lib/ocpp/v16/charge_point_impl.cpp @@ -4165,7 +4165,7 @@ void ChargePointImpl::stop_transaction(int32_t connector, Reason reason, std::op std::vector ChargePointImpl::get_measurands_vec(const std::string& measurands_csv) { std::vector measurands; - std::vector measurands_strings = ocpp::get_vector_from_csv(measurands_csv); + std::vector measurands_strings = ocpp::split_string(measurands_csv, ','); for (const auto& measurand_string : measurands_strings) { try { diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index a9d49c5fc..dab9f74fd 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -687,6 +687,11 @@ AuthorizeResponse ChargePoint::validate_token(const IdToken id_token, const std: AuthorizeResponse response; + bool is_online = this->connectivity_manager->is_websocket_connected(); + bool local_authorize_offline = + this->device_model->get_optional_value(ControllerComponentVariables::LocalAuthorizeOffline) + .value_or(true); + // C03.FR.01 && C05.FR.01: We SHALL NOT send an authorize reqeust for IdTokenType Central if (id_token.type == IdTokenEnum::Central or !this->device_model->get_optional_value(ControllerComponentVariables::AuthCtrlrEnabled).value_or(true)) { @@ -694,6 +699,10 @@ AuthorizeResponse ChargePoint::validate_token(const IdToken id_token, const std: return response; } + bool disabled_remote_auth = + this->device_model->get_optional_value(ControllerComponentVariables::DisableRemoteAuthorization) + .value_or(false); + // C07: Authorization using contract certificates if (id_token.type == IdTokenEnum::eMAID) { // Temporary variable that is set to true to avoid immediate response to allow the local auth list @@ -702,7 +711,7 @@ AuthorizeResponse ChargePoint::validate_token(const IdToken id_token, const std: bool forwarded_to_csms = false; // If OCSP data is provided as argument, use it - if (this->connectivity_manager->is_websocket_connected() and ocsp_request_data.has_value()) { + if (is_online and ocsp_request_data.has_value() and !disabled_remote_auth) { EVLOG_info << "Online: Pass provided OCSP data to CSMS"; response = this->authorize_req(id_token, std::nullopt, ocsp_request_data); forwarded_to_csms = true; @@ -719,14 +728,11 @@ AuthorizeResponse ChargePoint::validate_token(const IdToken id_token, const std: bool contract_validation_offline = this->device_model->get_optional_value(ControllerComponentVariables::ContractValidationOffline) .value_or(true); - bool local_authorize_offline = - this->device_model->get_optional_value(ControllerComponentVariables::LocalAuthorizeOffline) - .value_or(true); // C07.FR.01: When CS is online, it shall send an AuthorizeRequest // C07.FR.02: The AuthorizeRequest shall at least contain the OCSP data // TODO: local validation results are ignored if response is based only on OCSP data, is that acceptable? - if (this->connectivity_manager->is_websocket_connected()) { + if (is_online and !disabled_remote_auth) { // If no OCSP data was provided, check for a contract root if (local_verify_result == CertificateValidationResult::IssuerNotFound) { // C07.FR.06: Pass contract validation to CSMS when no contract root is found @@ -808,8 +814,12 @@ AuthorizeResponse ChargePoint::validate_token(const IdToken id_token, const std: } } - if (this->device_model->get_optional_value(ControllerComponentVariables::LocalAuthListCtrlrEnabled) - .value_or(false)) { + bool local_pre_authorize = this->device_model->get_value(ControllerComponentVariables::LocalPreAuthorize); + bool local_auth_list_enabled = + this->device_model->get_optional_value(ControllerComponentVariables::LocalAuthListCtrlrEnabled) + .value_or(false); + + if (local_auth_list_enabled and ((is_online and local_pre_authorize) or (!is_online and local_authorize_offline))) { std::optional id_token_info = std::nullopt; try { id_token_info = this->database_handler->get_local_authorization_list_entry(id_token); @@ -820,7 +830,9 @@ AuthorizeResponse ChargePoint::validate_token(const IdToken id_token, const std: } if (id_token_info.has_value()) { - if (id_token_info.value().status == AuthorizationStatusEnum::Accepted) { + if ((is_online and id_token_info.value().status == AuthorizationStatusEnum::Accepted) or + (!is_online and local_authorize_offline and + id_token_info.value().status == AuthorizationStatusEnum::Accepted)) { // C14.FR.02: If found in local list we shall start charging without an AuthorizeRequest EVLOG_info << "Found valid entry in local authorization list"; response.idTokenInfo = id_token_info.value(); @@ -830,7 +842,7 @@ AuthorizeResponse ChargePoint::validate_token(const IdToken id_token, const std: EVLOG_info << "Found invalid entry in local authorization list but not sending Authorize.req because " "RemoteAuthorization is disabled"; response.idTokenInfo.status = AuthorizationStatusEnum::Unknown; - } else if (this->connectivity_manager->is_websocket_connected()) { + } else if (is_online) { // C14.FR.03: If a value found but not valid we shall send an authorize request EVLOG_info << "Found invalid entry in local authorization list: Sending Authorize.req"; response = this->authorize_req(id_token, certificate, ocsp_request_data); @@ -848,7 +860,7 @@ AuthorizeResponse ChargePoint::validate_token(const IdToken id_token, const std: this->device_model->get_optional_value(ControllerComponentVariables::AuthCacheCtrlrEnabled) .value_or(false); - if (auth_cache_enabled) { + if (auth_cache_enabled and ((is_online and local_pre_authorize) or (!is_online and local_authorize_offline))) { try { const auto cache_entry = this->database_handler->authorization_cache_get_entry(hashed_id_token); if (cache_entry.has_value()) { @@ -869,8 +881,7 @@ AuthorizeResponse ChargePoint::validate_token(const IdToken id_token, const std: << ": Removing from cache and sending new request"; this->database_handler->authorization_cache_delete_entry(hashed_id_token); this->update_authorization_cache_size(); - } else if (this->device_model->get_value(ControllerComponentVariables::LocalPreAuthorize) and - id_token_info.status == AuthorizationStatusEnum::Accepted) { + } else if (cache_entry.value().status == AuthorizationStatusEnum::Accepted) { EVLOG_info << "Found valid entry in AuthCache"; this->database_handler->authorization_cache_update_last_used(hashed_id_token); response.idTokenInfo = id_token_info; @@ -895,7 +906,7 @@ AuthorizeResponse ChargePoint::validate_token(const IdToken id_token, const std: } } - if (!this->connectivity_manager->is_websocket_connected() and + if (!is_online and this->device_model->get_optional_value(ControllerComponentVariables::OfflineTxForUnknownIdEnabled) .value_or(false)) { EVLOG_info << "Offline authorization due to OfflineTxForUnknownIdEnabled being enabled"; @@ -905,8 +916,7 @@ AuthorizeResponse ChargePoint::validate_token(const IdToken id_token, const std: // When set to true this instructs the Charging Station to not issue any AuthorizationRequests, but only use // Authorization Cache and Local Authorization List to determine validity of idTokens. - if (!this->device_model->get_optional_value(ControllerComponentVariables::DisableRemoteAuthorization) - .value_or(false)) { + if (disabled_remote_auth) { response = this->authorize_req(id_token, certificate, ocsp_request_data); if (auth_cache_enabled) { @@ -1090,8 +1100,8 @@ void ChargePoint::remove_network_connection_profiles_below_actual_security_profi VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); // Update the NetworkConfigurationPriority so only remaining profiles are in there - const auto network_priority = ocpp::get_vector_from_csv( - this->device_model->get_value(ControllerComponentVariables::NetworkConfigurationPriority)); + const auto network_priority = ocpp::split_string( + this->device_model->get_value(ControllerComponentVariables::NetworkConfigurationPriority), ','); auto in_network_profiles = [&network_connection_profiles](const std::string& item) { auto is_same_slot = [&item](const SetNetworkProfileRequest& profile) { @@ -1691,7 +1701,7 @@ void ChargePoint::handle_variables_changed(const std::mapdevice_model->get_value(ControllerComponentVariables::SecurityProfile); for (const auto configuration_slot : network_configuration_priorities) { diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index 3d9bfdede..d87ba3fa1 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -267,8 +267,8 @@ void ConnectivityManager::cache_network_connection_profiles() { this->network_connection_profiles = json::parse(this->device_model.get_value(ControllerComponentVariables::NetworkConnectionProfiles)); - this->network_connection_priorities = ocpp::get_vector_from_csv( - this->device_model.get_value(ControllerComponentVariables::NetworkConfigurationPriority)); + this->network_connection_priorities = ocpp::split_string( + this->device_model.get_value(ControllerComponentVariables::NetworkConfigurationPriority), ','); if (this->network_connection_priorities.empty()) { EVLOG_AND_THROW(std::runtime_error("NetworkConfigurationPriority must not be empty")); diff --git a/lib/ocpp/v201/device_model.cpp b/lib/ocpp/v201/device_model.cpp index fe56abac2..c9edde94c 100644 --- a/lib/ocpp/v201/device_model.cpp +++ b/lib/ocpp/v201/device_model.cpp @@ -175,7 +175,7 @@ bool validate_value(const VariableCharacteristics& characteristics, const std::s if (!characteristics.valuesList.has_value()) { return true; } - const auto values_list = ocpp::get_vector_from_csv(characteristics.valuesList.value().get()); + const auto values_list = ocpp::split_string(characteristics.valuesList.value().get(), ','); return std::find(values_list.begin(), values_list.end(), value) != values_list.end(); } default: // same validation for MemberList or SequenceList @@ -186,8 +186,8 @@ bool validate_value(const VariableCharacteristics& characteristics, const std::s if (!characteristics.valuesList.has_value()) { return true; } - const auto values_list = ocpp::get_vector_from_csv(characteristics.valuesList.value().get()); - const auto value_csv = get_vector_from_csv(value); + const auto values_list = ocpp::split_string(characteristics.valuesList.value().get(), ','); + const auto value_csv = ocpp::split_string(value, ','); for (const auto& v : value_csv) { if (std::find(values_list.begin(), values_list.end(), v) == values_list.end()) { return false; diff --git a/lib/ocpp/v201/utils.cpp b/lib/ocpp/v201/utils.cpp index da2ae3809..5d8256c2c 100644 --- a/lib/ocpp/v201/utils.cpp +++ b/lib/ocpp/v201/utils.cpp @@ -16,7 +16,7 @@ namespace utils { std::vector get_measurands_vec(const std::string& measurands_csv) { std::vector measurands; - std::vector measurands_strings = ocpp::get_vector_from_csv(measurands_csv); + std::vector measurands_strings = ocpp::split_string(measurands_csv, ','); for (const auto& measurand_string : measurands_strings) { try {