diff --git a/doxygen/microservices.cpp b/doxygen/microservices.cpp index bfb9d7d9be..dc12ebd5f9 100644 --- a/doxygen/microservices.cpp +++ b/doxygen/microservices.cpp @@ -113,7 +113,7 @@ - #msiSubstr - Returns a substring of the given string \subsection msiemail Email Microservices - - #msiSendMail - (Deprecated) Sends email + - #msiSendMail - (Deprecated) Sends email \subsection msikv Key-Value (Attr-Value) Microservices - #writeKeyValPairs - Writes key-value pairs to stdout or stderr and with given separator diff --git a/scripts/irods/test/test_all_rules.py b/scripts/irods/test/test_all_rules.py index ae74b93a3d..5d30a013a8 100644 --- a/scripts/irods/test/test_all_rules.py +++ b/scripts/irods/test/test_all_rules.py @@ -265,6 +265,10 @@ def filter_rulefiles(rulefile): # print("skipping " + rulefile + " ----- tested separately") return False + # msiSendMail is deprecated and disabled by default as of 4.3.2. + if "rulemsiSendMail" in rulefile: + return False + return True for rulefile in filter(filter_rulefiles, sorted(os.listdir(rulesdir))): @@ -275,6 +279,26 @@ def test(self): ,'STDOUT_SINGLELINE', "completed successfully") return test + # Returns a test with the following name: + # + # test__r + # + # Dots (.) are replaced with underscores (_). + # + # The rule files which are used to generate the tests normally follow + # the naming scheme below (following the scheme is not required): + # + # rule.r. + # + # So, given a file named rulemsiSendMail.r, the line below will + # generate the following test name: + # + # test_rulemsiSendMail_r + # + # Individual tests can be run using the generated name like so: + # + # test_all_rules.Test_AllRules.test__r + # yield 'test_' + rulefile.replace('.', '_'), make_test(rulefile) def test_rulemsiDataObjRsync(self): diff --git a/scripts/irods/test/test_misc.py b/scripts/irods/test/test_misc.py index 5139409e9b..59c489d9e4 100644 --- a/scripts/irods/test/test_misc.py +++ b/scripts/irods/test/test_misc.py @@ -16,13 +16,14 @@ from ..controller import IrodsController from ..core_file import temporary_core_file -class Test_Misc(session.make_sessions_mixin([('otherrods', 'rods')], []), unittest.TestCase): +class Test_Misc(session.make_sessions_mixin([('otherrods', 'rods')], [('alice', 'apass')]), unittest.TestCase): plugin_name = IrodsConfig().default_rule_engine_plugin def setUp(self): super(Test_Misc, self).setUp() self.admin = self.admin_sessions[0] + self.user = self.user_sessions[0] def tearDown(self): super(Test_Misc, self).tearDown() @@ -471,3 +472,39 @@ def test_tcp_keepalive_probes__issue_2533_3824(self): # Check for SOCKET_ERROR (-179000) with an errno of 22 (Invalid argument). self.env['IRODS_TCP_KEEPALIVE_PROBES'] = str(2147483647) self.admin.assert_icommand('ils', 'STDERR', '-179022 SOCKET_ERROR, Invalid argument', env=self.env) + + + @unittest.skipUnless(plugin_name == 'irods_rule_engine_plugin-irods_rule_language', "Designed for the NREP") + @unittest.skipIf(test.settings.RUN_IN_TOPOLOGY, "Skip for Topology Testing") + def test_enabling_and_disabling_of_msiSendMail__issue_7651(self): + config = IrodsConfig() + rep_name = f'{self.plugin_name}-instance' + rule = 'msiSendMail("x", "y", "z")' + + # Show use of msiSendMail is blocked when the configuration option is not defined. + self.assertNotIn('enable_deprecated_msiSendMail', config.server_config['advanced_settings']) + self.user.assert_icommand(['irule', '-r', rep_name, rule, 'null', 'ruleExecOut'], 'STDERR', ['-169000 SYS_NOT_ALLOWED']) + + # Show use of msiSendMail is blocked when the configuration option is set to false. + with lib.file_backed_up(config.server_config_path): + config.server_config['advanced_settings']['enable_deprecated_msiSendMail'] = False + lib.update_json_file_from_dict(config.server_config_path, config.server_config) + self.assertIn('enable_deprecated_msiSendMail', config.server_config['advanced_settings']) + self.user.assert_icommand(['irule', '-r', rep_name, rule, 'null', 'ruleExecOut'], 'STDERR', ['-169000 SYS_NOT_ALLOWED']) + + # Show use of msiSendMail is blocked when the configuration option is set to something + # other than a boolean. + with lib.file_backed_up(config.server_config_path): + config.server_config['advanced_settings']['enable_deprecated_msiSendMail'] = 'not_a_boolean' + lib.update_json_file_from_dict(config.server_config_path, config.server_config) + self.assertIn('enable_deprecated_msiSendMail', config.server_config['advanced_settings']) + self.user.assert_icommand(['irule', '-r', rep_name, rule, 'null', 'ruleExecOut'], 'STDERR', ['-169000 SYS_NOT_ALLOWED']) + + # Show use of msiSendMail is allowed when the configuration option is set to true. + with lib.file_backed_up(config.server_config_path): + config.server_config['advanced_settings']['enable_deprecated_msiSendMail'] = True + lib.update_json_file_from_dict(config.server_config_path, config.server_config) + self.assertIn('enable_deprecated_msiSendMail', config.server_config['advanced_settings']) + # irule will not report an error even if the underlying mail command isn't installed. + # This behavior is expected. + self.user.assert_icommand(['irule', '-r', rep_name, rule, 'null', 'ruleExecOut']) diff --git a/server/re/src/mailMS.cpp b/server/re/src/mailMS.cpp index d63b103cd2..99cc1e21c5 100644 --- a/server/re/src/mailMS.cpp +++ b/server/re/src/mailMS.cpp @@ -3,12 +3,20 @@ #include "irods/icatHighLevelRoutines.hpp" #include "irods/irods_log.hpp" +#include "irods/irods_logger.hpp" #include "irods/irods_re_structs.hpp" +#include "irods/irods_server_properties.hpp" +#include "irods/rodsErrorTable.h" #include #include #include +namespace +{ + using log_msi = irods::experimental::log::microservice; +} // anonymous namespace + /** * \fn msiSendMail(msParam_t* xtoAddr, msParam_t* xsubjectLine, msParam_t* xbody, ruleExecInfo_t *) * @@ -20,10 +28,12 @@ * * \since pre-2.1 * - * * \note This microservice sends e-mail using the mail command in the unix system. No attachments are supported. The * sender of the e-mail is the unix user-id running the irodsServer. * + * \warning This microservice will fail unless /advanced_settings/enable_deprecated_msiSendMail is set to true in + * server_config.json. + * * \usage See clients/icommands/test/rules/ * * \param[in] xtoAddr - a msParam of type STR_MS_T which is an address of the receiver. @@ -46,6 +56,25 @@ * \sa none **/ int msiSendMail( msParam_t* xtoAddr, msParam_t* xsubjectLine, msParam_t* xbody, ruleExecInfo_t* ) { + const auto enabled = [] { + try { + return irods::get_advanced_setting("enable_deprecated_msiSendMail"); + } + catch (...) { + log_msi::trace( + "msiSendMail: [/advanced_settings/enable_deprecated_msiSendMail] is not defined in server_config.json. " + "Defaulting to false."); + return false; + } + }(); + + // Do not allow this MSI to proceed unless the local administrator has approved it for use. + if (!enabled) { + log_msi::error( + "{}: Use of this microservice is not allowed. Blocked by the local administrator. See server_config.json.", + __func__); + return SYS_NOT_ALLOWED; + } const char * toAddr = ( char * ) xtoAddr->inOutStruct; const char * subjectLine = xsubjectLine->inOutStruct ? ( char * ) xsubjectLine->inOutStruct : "";