2929#include < cstdio>
3030#include < cstdlib>
3131#include < sstream>
32+ #include < stdexcept>
3233
3334namespace ros2_medkit_gateway {
3435
@@ -48,6 +49,44 @@ inline bool plugin_debug_enabled() {
4849 return rcutils_logging_logger_is_enabled_for (" opcua.plugin" , RCUTILS_LOG_SEVERITY_DEBUG );
4950}
5051
52+ // Security-config parse wrappers. An unrecognized value must NOT silently fall
53+ // back to the insecure default (SecurityPolicy::None / SecurityMode::None /
54+ // anonymous auth): a typo would quietly downgrade a hardened link. Fail loud and
55+ // refuse - the thrown exception disables the plugin in PluginManager::configure_plugins.
56+ SecurityPolicy require_security_policy (const std::string & value) {
57+ bool ok = true ;
58+ const auto parsed = OpcuaClient::parse_security_policy (value, &ok);
59+ if (!ok) {
60+ RCLCPP_ERROR (opcua_plugin_logger (),
61+ " Unrecognized OPC-UA security_policy '%s'; refusing to start with an insecure fallback" ,
62+ value.c_str ());
63+ throw std::invalid_argument (" opcua: unrecognized security_policy '" + value + " '" );
64+ }
65+ return parsed;
66+ }
67+
68+ SecurityMode require_security_mode (const std::string & value) {
69+ bool ok = true ;
70+ const auto parsed = OpcuaClient::parse_security_mode (value, &ok);
71+ if (!ok) {
72+ RCLCPP_ERROR (opcua_plugin_logger (),
73+ " Unrecognized OPC-UA security_mode '%s'; refusing to start with an insecure fallback" , value.c_str ());
74+ throw std::invalid_argument (" opcua: unrecognized security_mode '" + value + " '" );
75+ }
76+ return parsed;
77+ }
78+
79+ UserAuthMode require_user_auth_mode (const std::string & value) {
80+ bool ok = true ;
81+ const auto parsed = OpcuaClient::parse_user_auth_mode (value, &ok);
82+ if (!ok) {
83+ RCLCPP_ERROR (opcua_plugin_logger (),
84+ " Unrecognized OPC-UA user_auth_mode '%s'; refusing to start with an insecure fallback" , value.c_str ());
85+ throw std::invalid_argument (" opcua: unrecognized user_auth_mode '" + value + " '" );
86+ }
87+ return parsed;
88+ }
89+
5190// / Parse a JSON "value" field, coerce to the node's declared data_type, and
5291// / validate against the optional min/max range. Shared by handle_plc_operations,
5392// / DataProvider::write_data, and OperationProvider::execute_operation to keep
@@ -119,12 +158,12 @@ void OpcuaPlugin::configure(const nlohmann::json & config) {
119158 // OPC-UA SecureChannel security + user identity. All opt-in; defaults keep
120159 // the legacy anonymous + SecurityPolicy=None behaviour.
121160 if (config.contains (" security_policy" )) {
122- client_config_.security_policy = OpcuaClient::parse_security_policy (config[" security_policy" ].get <std::string>());
161+ client_config_.security_policy = require_security_policy (config[" security_policy" ].get <std::string>());
123162 }
124163 if (config.contains (" security_mode" ) || config.contains (" message_security_mode" )) {
125164 const std::string mode_str = config.contains (" security_mode" ) ? config[" security_mode" ].get <std::string>()
126165 : config[" message_security_mode" ].get <std::string>();
127- client_config_.security_mode = OpcuaClient::parse_security_mode (mode_str);
166+ client_config_.security_mode = require_security_mode (mode_str);
128167 }
129168 if (config.contains (" client_cert_path" )) {
130169 client_config_.client_cert_path = config[" client_cert_path" ].get <std::string>();
@@ -147,7 +186,7 @@ void OpcuaPlugin::configure(const nlohmann::json & config) {
147186 client_config_.reject_untrusted = config[" reject_untrusted" ].get <bool >();
148187 }
149188 if (config.contains (" user_auth_mode" )) {
150- client_config_.user_auth_mode = OpcuaClient::parse_user_auth_mode (config[" user_auth_mode" ].get <std::string>());
189+ client_config_.user_auth_mode = require_user_auth_mode (config[" user_auth_mode" ].get <std::string>());
151190 }
152191 if (config.contains (" username" )) {
153192 client_config_.username = config[" username" ].get <std::string>();
@@ -190,10 +229,10 @@ void OpcuaPlugin::configure(const nlohmann::json & config) {
190229 }
191230 // Security env overrides (for Docker / appliance deployments).
192231 if (auto * env = std::getenv (" OPCUA_SECURITY_POLICY" )) {
193- client_config_.security_policy = OpcuaClient::parse_security_policy (env);
232+ client_config_.security_policy = require_security_policy (env);
194233 }
195234 if (auto * env = std::getenv (" OPCUA_SECURITY_MODE" )) {
196- client_config_.security_mode = OpcuaClient::parse_security_mode (env);
235+ client_config_.security_mode = require_security_mode (env);
197236 }
198237 if (auto * env = std::getenv (" OPCUA_CLIENT_CERT" )) {
199238 client_config_.client_cert_path = env;
@@ -229,7 +268,7 @@ void OpcuaPlugin::configure(const nlohmann::json & config) {
229268 client_config_.reject_untrusted = !(v == " 0" || v == " false" || v == " no" );
230269 }
231270 if (auto * env = std::getenv (" OPCUA_USER_AUTH" )) {
232- client_config_.user_auth_mode = OpcuaClient::parse_user_auth_mode (env);
271+ client_config_.user_auth_mode = require_user_auth_mode (env);
233272 }
234273 if (auto * env = std::getenv (" OPCUA_USERNAME" )) {
235274 client_config_.username = env;
0 commit comments