]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3848] Detect authentication risks
authorThomas Markwalder <tmark@isc.org>
Wed, 11 Jun 2025 18:30:15 +0000 (14:30 -0400)
committerThomas Markwalder <tmark@isc.org>
Mon, 30 Jun 2025 11:49:59 +0000 (11:49 +0000)
Throw or Warn if API end points do not use some form
of authentication

Throw or Warn if 'user', 'password' - API end points
Throw or Warn if 'secret' is used  - TSIG

Disable/enable security for UTs as needed

modified:   src/bin/agent/tests/ca_cfg_mgr_unittests.cc
modified:   src/bin/agent/tests/ca_response_creator_unittests.cc
modified:   src/bin/agent/tests/get_config_unittest.cc
modified:   src/bin/d2/tests/d2_cfg_mgr_unittests.cc
modified:   src/bin/d2/tests/d2_command_unittest.cc
modified:   src/bin/d2/tests/d2_controller_unittests.cc
modified:   src/bin/d2/tests/d2_http_command_unittest.cc
modified:   src/bin/d2/tests/d2_process_unittests.cc
modified:   src/bin/d2/tests/d2_simple_parser_unittest.cc
modified:   src/bin/d2/tests/get_config_unittest.cc
modified:   src/bin/dhcp4/tests/config_parser_unittest.cc
modified:   src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
modified:   src/bin/dhcp4/tests/dhcp4_test_utils.cc
modified:   src/bin/dhcp4/tests/get_config_unittest.cc
modified:   src/bin/dhcp4/tests/get_config_unittest.cc.skel
modified:   src/bin/dhcp4/tests/http_control_socket_unittest.cc
modified:   src/bin/dhcp6/tests/config_parser_unittest.cc
modified:   src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
modified:   src/bin/dhcp6/tests/dhcp6_test_utils.cc
modified:   src/bin/dhcp6/tests/get_config_unittest.cc
modified:   src/bin/dhcp6/tests/get_config_unittest.cc.skel
modified:   src/bin/dhcp6/tests/http_control_socket_unittest.cc
modified:   src/lib/config/tests/http_command_config_unittests.cc
modified:   src/lib/d2srv/d2_config.cc
modified:   src/lib/d2srv/d2_messages.cc
modified:   src/lib/d2srv/d2_messages.h
modified:   src/lib/d2srv/d2_messages.mes
modified:   src/lib/http/auth_messages.cc
modified:   src/lib/http/auth_messages.h
modified:   src/lib/http/auth_messages.mes
modified:   src/lib/http/basic_auth_config.cc
modified:   src/lib/http/tests/basic_auth_config_unittests.cc
modified:   src/lib/testutils/dhcp_test_lib.sh.in

33 files changed:
src/bin/agent/tests/ca_cfg_mgr_unittests.cc
src/bin/agent/tests/ca_response_creator_unittests.cc
src/bin/agent/tests/get_config_unittest.cc
src/bin/d2/tests/d2_cfg_mgr_unittests.cc
src/bin/d2/tests/d2_command_unittest.cc
src/bin/d2/tests/d2_controller_unittests.cc
src/bin/d2/tests/d2_http_command_unittest.cc
src/bin/d2/tests/d2_process_unittests.cc
src/bin/d2/tests/d2_simple_parser_unittest.cc
src/bin/d2/tests/get_config_unittest.cc
src/bin/dhcp4/tests/config_parser_unittest.cc
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
src/bin/dhcp4/tests/dhcp4_test_utils.cc
src/bin/dhcp4/tests/get_config_unittest.cc
src/bin/dhcp4/tests/get_config_unittest.cc.skel
src/bin/dhcp4/tests/http_control_socket_unittest.cc
src/bin/dhcp6/tests/config_parser_unittest.cc
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
src/bin/dhcp6/tests/dhcp6_test_utils.cc
src/bin/dhcp6/tests/get_config_unittest.cc
src/bin/dhcp6/tests/get_config_unittest.cc.skel
src/bin/dhcp6/tests/http_control_socket_unittest.cc
src/lib/config/tests/http_command_config_unittests.cc
src/lib/d2srv/d2_config.cc
src/lib/d2srv/d2_messages.cc
src/lib/d2srv/d2_messages.h
src/lib/d2srv/d2_messages.mes
src/lib/http/auth_messages.cc
src/lib/http/auth_messages.h
src/lib/http/auth_messages.mes
src/lib/http/basic_auth_config.cc
src/lib/http/tests/basic_auth_config_unittests.cc
src/lib/testutils/dhcp_test_lib.sh.in

index edd8ec716be6438769b771e13835bf07224d16f6..9e99ed6d8b1d9a36723ce9f5e564055c13b5dd84 100644 (file)
@@ -436,11 +436,13 @@ public:
     virtual void SetUp() {
         resetHooksPath();
         setSocketTestPath();
+        file::PathChecker::enableEnforcement(false);
     }
 
     virtual void TearDown() {
         resetHooksPath();
         resetSocketPath();
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Sets the Hooks path from which hooks can be loaded.
index e45c2f363b1b1e3c4631576fdfde7a4942035c61..19cf3339c2107a2225f7ec6fa1624c846a1aedf1 100644 (file)
@@ -16,6 +16,7 @@
 #include <http/post_request.h>
 #include <http/post_request_json.h>
 #include <http/response_json.h>
+#include <util/filesystem.h>
 #include <process/testutils/d_test_stubs.h>
 #include <agent/tests/test_basic_auth_libraries.h>
 #include <gtest/gtest.h>
@@ -29,6 +30,7 @@ using namespace isc::data;
 using namespace isc::hooks;
 using namespace isc::http;
 using namespace isc::process;
+using namespace isc::util;
 namespace ph = std::placeholders;
 
 namespace {
@@ -46,6 +48,7 @@ public:
         : DControllerTest(CtrlAgentController::instance),
           response_creator_(),
           request_(response_creator_.createNewHttpRequest()) {
+        file::PathChecker::enableEnforcement(true);
         // Deregisters commands.
         CtrlAgentCommandMgr::instance().deregisterAll();
         CtrlAgentCommandMgr::instance().
@@ -76,6 +79,7 @@ public:
         CtrlAgentCommandMgr::instance().deregisterAll();
         HooksManager::prepareUnloadLibraries();
         static_cast<void>(HooksManager::unloadLibraries());
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Fills request context with required data to create new request.
@@ -435,6 +439,7 @@ TEST_F(CtrlAgentResponseCreatorTest, basicAuth) {
 // required but not provided by request using the hook.
 TEST_F(CtrlAgentResponseCreatorTest, hookNoAuth) {
     setBasicContext(request_);
+    file::PathChecker::enableEnforcement(false);
 
     // Body: "list-commands" is natively supported by the command manager.
     // We add a random value in the extra entry: see next unit test
@@ -493,6 +498,7 @@ TEST_F(CtrlAgentResponseCreatorTest, hookNoAuth) {
 // auth response provided by the hool.
 TEST_F(CtrlAgentResponseCreatorTest, hookNoAuthHeaders) {
     setBasicContext(request_);
+    file::PathChecker::enableEnforcement(false);
 
     // Body: "list-commands" is natively supported by the command manager.
     // We add a random value in the extra entry: see next unit test
@@ -548,6 +554,7 @@ TEST_F(CtrlAgentResponseCreatorTest, hookNoAuthHeaders) {
 // Test successful server response when the client is authenticated.
 TEST_F(CtrlAgentResponseCreatorTest, hookBasicAuth) {
     setBasicContext(request_);
+    file::PathChecker::enableEnforcement(false);
 
     // Body: "list-commands" is natively supported by the command manager.
     // We add a random value in the extra entry:
index eac18255a108be913f94690c0dfc2e2db5a0dd3a..d799d1427c48ab29a494b16af87f95f353d78d49 100644 (file)
@@ -146,12 +146,14 @@ public:
         // Create fresh context.
         resetConfiguration();
         setSocketTestPath();
+        file::PathChecker::enableEnforcement(true);
     }
 
     ~CtrlAgentGetCfgTest() {
         resetConfiguration();
         resetHooksPath();
         resetSocketPath();
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Sets the Hooks path from which hooks can be loaded.
@@ -287,6 +289,7 @@ public:
 /// Test a configuration
 TEST_F(CtrlAgentGetCfgTest, simple) {
     setHooksTestPath();
+    file::PathChecker::enableEnforcement(false);
 
     // get the simple configuration
     std::string simple_file = string(CFG_EXAMPLES) + "/" + "simple.json";
index 384190dde19fb04fcc37f24122e96b7c17550772..051388895f8923249715cdf153258be181151326 100644 (file)
@@ -55,12 +55,14 @@ public:
     D2CfgMgrTest():cfg_mgr_(new D2CfgMgr()), d2_params_() {
         resetHooksPath();
         resetSocketPath();
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Destructor
     ~D2CfgMgrTest() {
         resetHooksPath();
         resetSocketPath();
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Sets the Hooks path from which hooks can be loaded.
@@ -501,6 +503,7 @@ TEST(D2CfgMgr, construction) {
 TEST_F(D2CfgMgrTest, fullConfig) {
     setHooksTestPath();
     setSocketTestPath();
+    file::PathChecker::enableEnforcement(false);
 
     // Create a configuration with all of application level parameters, plus
     // both the forward and reverse ddns managers.  Both managers have two
@@ -958,6 +961,7 @@ TEST_F(D2CfgMgrTest, matchReverse) {
 TEST_F(D2CfgMgrTest, configPermutations) {
     std::string test_file = testDataFile("d2_cfg_tests.json");
     isc::data::ConstElementPtr tests;
+    file::PathChecker::enableEnforcement(false);
 
     // Read contents of the file and parse it as JSON. Note it must contain
     // all valid JSON, we aren't testing JSON parsing.
@@ -1013,6 +1017,7 @@ TEST_F(D2CfgMgrTest, configPermutations) {
 /// @brief Tests comments.
 TEST_F(D2CfgMgrTest, comments) {
     setSocketTestPath();
+    file::PathChecker::enableEnforcement(false);
     std::string config = "{ "
                         "\"comment\": \"D2 config\" , "
                         "\"ip-address\" : \"192.168.1.33\" , "
index 52360a22cbd27ec2c991b76d69e76650594d60d0..53a997d27e93d1e040650b463c42213f09a814ea 100644 (file)
@@ -129,6 +129,7 @@ public:
         : server_(NakedD2Controller::instance()) {
         setSocketTestPath();
         ::remove(socket_path_.c_str());
+        file::PathChecker::enableEnforcement(false);
     }
 
     /// @brief Destructor.
@@ -144,6 +145,7 @@ public:
         CommandMgr::instance().deregisterAll();
         UnixCommandMgr::instance().setConnectionTimeout(TIMEOUT_DHCP_SERVER_RECEIVE_COMMAND);
         resetSocketPath();
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Returns pointer to the server's IO service.
index 243e830ab4134c4abaf58f2b007a28dea7811651..600dc8d580effbc703ee0d5184620518c1181d56 100644 (file)
@@ -11,6 +11,7 @@
 #include <d2srv/testutils/nc_test_utils.h>
 #include <d2/d2_controller.h>
 #include <d2/d2_process.h>
+#include <util/filesystem.h>
 #include <process/testutils/d_test_stubs.h>
 #include <testutils/gtest_utils.h>
 
@@ -22,6 +23,7 @@
 
 using namespace isc::asiolink::test;
 using namespace isc::process;
+using namespace isc::util;
 using namespace boost::posix_time;
 
 namespace isc {
@@ -45,6 +47,12 @@ public:
     /// Note the constructor passes in the static D2Controller instance
     /// method.
     D2ControllerTest() : DControllerTest(D2Controller::instance) {
+        file::PathChecker::enableEnforcement(false);
+    }
+
+    /// @brief Destructor
+    virtual ~D2ControllerTest() {
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Fetches the D2Controller's D2Process
index ed243b15db160cce1a72bb1efefc8166b952a375..47b738ae831421a9a71636cafe2345509f783169 100644 (file)
@@ -19,6 +19,7 @@
 #include <http/response.h>
 #include <http/response_parser.h>
 #include <http/testutils/test_http_client.h>
+#include <util/filesystem.h>
 #include <gtest/gtest.h>
 #include <boost/pointer_cast.hpp>
 #include <atomic>
@@ -36,6 +37,7 @@ using namespace isc::d2;
 using namespace isc::data;
 using namespace isc::http;
 using namespace isc::process;
+using namespace isc::util;
 namespace ph = std::placeholders;
 
 namespace isc {
@@ -105,6 +107,7 @@ public:
     /// Sets socket path to its default value.
     BaseCtrlChannelD2Test()
         : server_(NakedD2Controller::instance()) {
+        file::PathChecker::enableEnforcement(false);
     }
 
     /// @brief Destructor.
@@ -118,6 +121,7 @@ public:
         // Reset command manager.
         CommandMgr::instance().deregisterAll();
         HttpCommandMgr::instance().setConnectionTimeout(TIMEOUT_AGENT_RECEIVE_COMMAND);
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Returns pointer to the server's IO service.
index 315d68d8fdd794acb80529228cdc531408c7004b..e82f3eae08da130d01b1008c650f896aa4044096 100644 (file)
@@ -15,6 +15,7 @@
 #include <dhcp_ddns/ncr_io.h>
 #include <hooks/hooks_manager.h>
 #include <hooks/hooks_parser.h>
+#include <util/filesystem.h>
 #include <process/testutils/d_test_stubs.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
@@ -29,6 +30,7 @@ using namespace isc::d2;
 using namespace isc::data;
 using namespace isc::hooks;
 using namespace isc::process;
+using namespace isc::util;
 using namespace boost::posix_time;
 
 namespace {
@@ -71,12 +73,14 @@ public:
         HooksManager::setTestMode(false);
         D2Controller::instance();
         init();
+        file::PathChecker::enableEnforcement(false);
     }
 
     /// @brief Destructor
     virtual ~D2ProcessTest() {
         D2Controller::instance().reset();
         resetHooksPath();
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Sets the Hooks path from which hooks can be loaded.
index 51728cbfdcaee090c2c929d2d904b43ac10f80fc..0a6111a0b2791619c79c1ca8537635c4d93ff33a 100644 (file)
@@ -10,6 +10,7 @@
 #include <d2/tests/parser_unittest.h>
 #include <d2srv/d2_simple_parser.h>
 #include <testutils/test_to_element.h>
+#include <util/filesystem.h>
 
 #include <boost/lexical_cast.hpp>
 #include <fstream>
@@ -18,6 +19,7 @@ using namespace isc;
 using namespace isc::data;
 using namespace isc::d2;
 using namespace isc::test;
+using namespace isc::util;
 
 namespace {
 
@@ -163,11 +165,13 @@ public:
                        parser_type = D2ParserContext::PARSER_JSON)
         : parser_type_(parser_type) {
         reset();
+        file::PathChecker::enableEnforcement(false);
     }
 
     /// @brief Destructor
     virtual ~D2SimpleParserTest() {
         reset();
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Parses JSON text and compares the results against an expected
index c94589adea23c1484267aebf94a6bc3649148be9..f53f688a0d8d969d734f76de4ef31b4c86537315 100644 (file)
@@ -153,6 +153,7 @@ public:
         resetConfiguration();
         // Fill test secret file.
         fillSecretFile();
+        file::PathChecker::enableEnforcement(false);
     }
 
     ~D2GetConfigTest() {
@@ -160,6 +161,7 @@ public:
         resetConfiguration();
         resetHooksPath();
         resetSocketPath();
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Sets the Hooks path from which hooks can be loaded.
index 51d66ec35ecdcd533961475f9e4b2466b0a40c1a..3c21bfb07ac97901e62c23880d93106ff656c7c2 100644 (file)
@@ -340,6 +340,7 @@ public:
 
         resetHooksPath();
         Dhcpv4SrvTest::resetSocketPath();
+        file::PathChecker::enableEnforcement(true);
     }
 
     ~Dhcp4ParserTest() {
@@ -352,6 +353,7 @@ public:
 
         resetHooksPath();
         Dhcpv4SrvTest::resetSocketPath();
+        file::PathChecker::enableEnforcement(true);
     };
 
     /// @brief Sets the Hooks path from which hooks can be loaded.
@@ -6924,6 +6926,7 @@ TEST_F(Dhcp4ParserTest, hostsDatabases) {
 // This test checks comments. Please keep it last.
 TEST_F(Dhcp4ParserTest, comments) {
     Dhcpv4SrvTest::setSocketTestPath();
+    file::PathChecker::enableEnforcement(false);
 
     string config = PARSER_CONFIGS[6];
     extractConfig(config);
index 43bd2aa9473ad15e44122dc9673209c970bfd5ec..722cf3a7ee0afed558dadfa0ad6adc2a5ca21288 100644 (file)
@@ -2965,6 +2965,7 @@ class DBInitializer {
 void
 Dhcpv4SrvTest::checkConfigFiles() {
     setSocketTestPath();
+    file::PathChecker::enableEnforcement(false);
 #if defined (HAVE_MYSQL)
     MySqlHostDataSourceInit mysql_init;
 #endif
index 6c6dd1836b1325f8e9fda1dd728fb11bc9bbf649..d098994d228a6ebe2a6e5cc1045f07ff3bd92ac1 100644 (file)
@@ -61,6 +61,7 @@ BaseServerTest::~BaseServerTest() {
 
 Dhcpv4SrvTest::Dhcpv4SrvTest()
     : rcode_(-1), srv_(new NakedDhcpv4Srv(0)), multi_threading_(false), start_time_(PktEvent::now()) {
+    file::PathChecker::enableEnforcement(true);
 
     // Wipe any existing statistics
     isc::stats::StatsMgr::instance().removeAll();
@@ -92,6 +93,7 @@ Dhcpv4SrvTest::Dhcpv4SrvTest()
 
 Dhcpv4SrvTest::~Dhcpv4SrvTest() {
     resetSocketPath();
+    file::PathChecker::enableEnforcement(true);
     // Make sure that we revert to default value
     CfgMgr::instance().clear();
 
index f93a1cf290daeb922c559d8c56dac9ce18b7b736..a1bba1580205e13b5ffa04429ee3475291f3794e 100644 (file)
@@ -16,6 +16,7 @@
 #include <dhcp4/tests/dhcp4_test_utils.h>
 #include <dhcp4/tests/get_config_unittest.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <util/filesystem.h>
 #include <testutils/gtest_utils.h>
 #include <testutils/user_context_utils.h>
 
@@ -33,6 +34,7 @@ using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
 using namespace isc::test;
+using namespace isc::util;
 
 namespace {
 
@@ -14575,12 +14577,14 @@ public:
         // Create fresh context.
         resetConfiguration();
         Dhcpv4SrvTest::setSocketTestPath();
+        file::PathChecker::enableEnforcement(false);
     }
 
     ~Dhcp4GetConfigTest() {
         resetConfiguration();
         Dhcpv4SrvTest::resetSocketPath();
-    };
+        file::PathChecker::enableEnforcement(true);
+    }
 
     /// @brief Parse and Execute configuration
     ///
index 5bcfae32fc55c50b9d951ca5abf8397763755ca1..6db931d256d65a52d09411389643d19c935e62b0 100644 (file)
@@ -16,6 +16,7 @@
 #include <dhcp4/tests/dhcp4_test_utils.h>
 #include <dhcp4/tests/get_config_unittest.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <util/filesystem.h>
 #include <testutils/gtest_utils.h>
 #include <testutils/user_context_utils.h>
 
@@ -33,6 +34,7 @@ using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
 using namespace isc::test;
+using namespace isc::util;
 
 namespace {
 
@@ -172,11 +174,15 @@ public:
         srv_.reset(new ControlledDhcpv4Srv(0));
         // Create fresh context.
         resetConfiguration();
+        Dhcpv4SrvTest::setSocketTestPath();
+        file::PathChecker::enableEnforcement(false);
     }
 
     ~Dhcp4GetConfigTest() {
         resetConfiguration();
-    };
+        Dhcpv4SrvTest::resetSocketPath();
+        file::PathChecker::enableEnforcement(true);
+    }
 
     /// @brief Parse and Execute configuration
     ///
index 8c3fb1c2d2fccd353b92ffa9f2c3e1a66aa1ef4f..67126f872699b784d97a7e9354777d4b55b46d55 100644 (file)
@@ -30,6 +30,7 @@
 #include <process/log_parser.h>
 #include <stats/stats_mgr.h>
 #include <util/chrono_time_utils.h>
+#include <util/filesystem.h>
 
 #include "marker_file.h"
 
@@ -102,6 +103,7 @@ public:
         IfaceMgr::instance().setDetectCallback(std::bind(&IfaceMgr::checkDetectIfaces,
                                                IfaceMgr::instancePtr().get(), ph::_1));
         setLogTestPath("/dev");
+        file::PathChecker::enableEnforcement(false);
     }
 
     /// @brief Destructor
@@ -121,6 +123,7 @@ public:
         IfaceMgr::instance().closeSockets();
         IfaceMgr::instance().detectIfaces();
         resetLogPath();
+        file::PathChecker::enableEnforcement(true);
     }
 
     /// @brief Sets the log path where log output may be written.
index a531afd668d8cadc1537922ba63abae0caf5fcc0..548c63fe92638b26be170acec0eb6ca0702b7c4f 100644 (file)
@@ -38,6 +38,7 @@
 #include <testutils/log_utils.h>
 #include <testutils/test_to_element.h>
 #include <util/chrono_time_utils.h>
+#include <util/filesystem.h>
 #include <util/doubles.h>
 
 #include <boost/foreach.hpp>
@@ -64,6 +65,7 @@ using namespace isc::dhcp;
 using namespace isc::dhcp::test;
 using namespace isc::hooks;
 using namespace isc::test;
+using namespace isc::util;
 using namespace std;
 
 namespace {
@@ -425,6 +427,7 @@ public:
         resetConfiguration();
 
         resetHooksPath();
+        file::PathChecker::enableEnforcement(true);
     }
 
     ~Dhcp6ParserTest() {
@@ -436,6 +439,7 @@ public:
         static_cast<void>(remove(UNLOAD_MARKER_FILE));
 
         resetHooksPath();
+        file::PathChecker::enableEnforcement(true);
     };
 
     /// @brief Sets the Hooks path from which hooks can be loaded.
@@ -7700,6 +7704,7 @@ TEST_F(Dhcp6ParserTest, hostsDatabases) {
 // This test checks comments. Please keep it last.
 TEST_F(Dhcp6ParserTest, comments) {
     setSocketTestPath();
+    file::PathChecker::enableEnforcement(false);
 
     string config = PARSER_CONFIGS[9];
     extractConfig(config);
index a4f7159b9b36a62d4a173b85459d5fe206d05ecd..5a367b8b8c5f5ec78c5514a6b667bc5da4a196a0 100644 (file)
@@ -386,6 +386,7 @@ class DBInitializer {
 void
 Dhcpv6SrvTest::checkConfigFiles() {
     setSocketTestPath();
+    file::PathChecker::enableEnforcement(false);
 #if defined (HAVE_MYSQL)
     MySqlHostDataSourceInit mysql_init;
 #endif
index 38da0847c30a717eba3bd0abd3be95adc7d4a2ff..7ea1fea27fc5ee62a0957d8866e616c958c39431 100644 (file)
@@ -17,6 +17,7 @@
 #include <log/logger_support.h>
 #include <process/log_parser.h>
 #include <stats/stats_mgr.h>
+#include <util/filesystem.h>
 #include <util/pointer_util.h>
 #include <cstdio>
 #include <sstream>
@@ -44,6 +45,7 @@ BaseServerTest::BaseServerTest() {
     CfgMgr::instance().getDataDir(true, TEST_DATA_BUILDDIR);
     resetLogPath();
     resetSocketPath();
+    file::PathChecker::enableEnforcement(true);
 }
 
 BaseServerTest::~BaseServerTest() {
@@ -64,6 +66,7 @@ BaseServerTest::~BaseServerTest() {
     isc::log::initLogger();
     resetLogPath();
     resetSocketPath();
+    file::PathChecker::enableEnforcement(true);
 }
 
 void
index b502e210ecb60d58f9e67429c5fc0e0e184eb405..c3dfa1fb328ed4e82b2587c4d3a2558cfc0f0e1e 100644 (file)
@@ -9,7 +9,6 @@
 #include <cc/command_interpreter.h>
 #include <cc/data.h>
 #include <cc/simple_parser.h>
-#include <config/unix_command_config.h>
 #include <dhcp/testutils/iface_mgr_test_config.h>
 #include <dhcp6/ctrl_dhcp6_srv.h>
 #include <dhcp6/dhcp6_srv.h>
@@ -14809,12 +14808,14 @@ public:
         // Reset configuration for each test.
         resetConfiguration();
         BaseServerTest::setSocketTestPath();
+        file::PathChecker::enableEnforcement(false);
     }
 
     ~Dhcp6GetConfigTest() {
         // Reset configuration database after each test.
         resetConfiguration();
         BaseServerTest::resetSocketPath();
+        file::PathChecker::enableEnforcement(true);
     };
 
     /// @brief Parse and Execute configuration
index a05a157eb151445d1c3d839245758edbc0a7aec6..ac7fd8182ba7c1ded9c50bc7165dfa741eec8664 100644 (file)
@@ -16,6 +16,7 @@
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <dhcp6/tests/get_config_unittest.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <util/filesystem.h>
 #include <testutils/gtest_utils.h>
 #include <testutils/user_context_utils.h>
 
@@ -33,6 +34,7 @@ using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
 using namespace isc::test;
+using namespace isc::util;
 
 namespace {
 
@@ -171,11 +173,15 @@ public:
 
         // Reset configuration for each test.
         resetConfiguration();
+        BaseServerTest::setSocketTestPath();
+        file::PathChecker::enableEnforcement(false);
     }
 
     ~Dhcp6GetConfigTest() {
         // Reset configuration database after each test.
         resetConfiguration();
+        BaseServerTest::resetSocketPath();
+        file::PathChecker::enableEnforcement(true);
     };
 
     /// @brief Parse and Execute configuration
index 8bf8994dd0f1870542794203d6dcf9693ac86c96..b13634ca3cb2372427c75a987c509ebedb2ba95e 100644 (file)
@@ -92,6 +92,7 @@ public:
         : BaseServerTest() {
         reset();
         setLogTestPath("/dev");
+        file::PathChecker::enableEnforcement(false);
     }
 
     virtual ~HttpCtrlDhcpv6Test() {
index 0e17e9dad2f03370f9a76f51e12dc903b8b310e8..82d092a23009f5d1499ed9e89baec8e12ec429cf 100644 (file)
@@ -298,6 +298,7 @@ TEST_F(HttpCommandConfigTest, headers) {
 // This test verifies a HTTP control socket configuration with authentication
 // can be parsed and unparsed.
 TEST_F(HttpCommandConfigTest, authentication) {
+    file::PathChecker::enableEnforcement(false);
     // Configure with authentication.
     string config = R"(
     {
index 1a1726b8713d58b61a636da47eed9cc4db298776..1400dc3e058e688634a78bde85cdaaa95202e9d2 100644 (file)
@@ -21,6 +21,7 @@
 
 using namespace isc::data;
 using namespace isc::process;
+using namespace isc::util;
 
 namespace isc {
 namespace d2 {
@@ -423,7 +424,16 @@ TSIGKeyInfoParser::parse(ConstElementPtr key_config) {
         }
     } else {
         secret = getString(key_config, "secret");
+        if (file::PathChecker::shouldEnforceSecurity()) {
+            isc_throw(D2CfgError, "use of clear text TSIG 'secret' is NOT SECURE ("
+                      << " (" << getPosition("secret", key_config)
+                      << ")");
+        } else {
+            LOG_WARN(dhcp_to_d2_logger, DHCP_DDNS_TSIG_SECRET_SECURITY_WARN)
+                     .arg(getPosition("secret", key_config).str());
+        }
     }
+
     ConstElementPtr user_context = key_config->get("user-context");
 
     // Algorithm must be valid.
index 18892f39b7ec0e41009aa6aa44f0133dd8cfd3ed..16a34c1d8ff202090fe73da7d27b58890a4f1d28 100644 (file)
@@ -86,6 +86,7 @@ extern const isc::log::MessageID DHCP_DDNS_STARTED = "DHCP_DDNS_STARTED";
 extern const isc::log::MessageID DHCP_DDNS_STARTING_TRANSACTION = "DHCP_DDNS_STARTING_TRANSACTION";
 extern const isc::log::MessageID DHCP_DDNS_STATE_MODEL_UNEXPECTED_ERROR = "DHCP_DDNS_STATE_MODEL_UNEXPECTED_ERROR";
 extern const isc::log::MessageID DHCP_DDNS_TRANS_SEND_ERROR = "DHCP_DDNS_TRANS_SEND_ERROR";
+extern const isc::log::MessageID DHCP_DDNS_TSIG_SECRET_SECURITY_WARN = "DHCP_DDNS_TSIG_SECRET_SECURITY_WARN";
 extern const isc::log::MessageID DHCP_DDNS_UPDATE_REQUEST_SENT = "DHCP_DDNS_UPDATE_REQUEST_SENT";
 extern const isc::log::MessageID DHCP_DDNS_UPDATE_RESPONSE_RECEIVED = "DHCP_DDNS_UPDATE_RESPONSE_RECEIVED";
 
@@ -174,6 +175,7 @@ const char* values[] = {
     "DHCP_DDNS_STARTING_TRANSACTION", "Request ID %1:",
     "DHCP_DDNS_STATE_MODEL_UNEXPECTED_ERROR", "Request ID %1: application encountered an unexpected error while carrying out a NameChangeRequest: %2",
     "DHCP_DDNS_TRANS_SEND_ERROR", "Request ID %1: application encountered an unexpected error while attempting to send a DNS update: %2",
+    "DHCP_DDNS_TSIG_SECRET_SECURITY_WARN", "use of clear text TSIG 'secret' is NOT SECURE: %1",
     "DHCP_DDNS_UPDATE_REQUEST_SENT", "Request ID %1: %2 to server: %3",
     "DHCP_DDNS_UPDATE_RESPONSE_RECEIVED", "Request ID %1: to server: %2 status: %3",
     NULL
index b6a2b3f659aa0bf130a164543bf9b71896ba5bb5..09434dc532487e77bc33ba1bdaaa48c37d9a152c 100644 (file)
@@ -87,6 +87,7 @@ extern const isc::log::MessageID DHCP_DDNS_STARTED;
 extern const isc::log::MessageID DHCP_DDNS_STARTING_TRANSACTION;
 extern const isc::log::MessageID DHCP_DDNS_STATE_MODEL_UNEXPECTED_ERROR;
 extern const isc::log::MessageID DHCP_DDNS_TRANS_SEND_ERROR;
+extern const isc::log::MessageID DHCP_DDNS_TSIG_SECRET_SECURITY_WARN;
 extern const isc::log::MessageID DHCP_DDNS_UPDATE_REQUEST_SENT;
 extern const isc::log::MessageID DHCP_DDNS_UPDATE_RESPONSE_RECEIVED;
 
index 455fcdaa5b5563afef52a5f1d283fccfb68a2618..2167064fd8654b8b630871c0ea6d4c9a4e0b7752 100644 (file)
@@ -455,3 +455,17 @@ server.
 Logged at debug log level 50.
 This is a debug message issued when DHCP_DDNS receives sends a DNS update
 response from a DNS server.
+
+% DHCP_DDNS_SECURITY_CHECKS_DISABLED Invoked with command line option -X, Security checks are disabled!!
+This warning is emitted when internal security checks normally
+performed by kea-dhcp-ddns have been disabled via command line option '-X'.
+This means the server is not enforcing restrictions on resource
+paths or permissions.  This mode of operation may expose your
+environment to security vulnerabilities and should only be used
+after consideration.
+
+% DHCP_DDNS_TSIG_SECRET_SECURITY_WARN use of clear text TSIG 'secret' is NOT SECURE: %1 
+This warning message is issued when security enforcement is disabled
+and TSIG key configuration uses clear text 'secret' rather
+than 'secret-file'. The server will still use the key as configured
+but is warning that doing so may pose a security risk.
index 993ba8f9987106cb9b6e0c9b520d2a1163477993..bc85af848749bbc763a64934cd0654013a1149cb 100644 (file)
@@ -7,10 +7,12 @@
 namespace isc {
 namespace http {
 
+extern const isc::log::MessageID HTTP_CLIENT_PASSWORD_SECURITY_WARN = "HTTP_CLIENT_PASSWORD_SECURITY_WARN";
 extern const isc::log::MessageID HTTP_CLIENT_REQUEST_AUTHORIZED = "HTTP_CLIENT_REQUEST_AUTHORIZED";
 extern const isc::log::MessageID HTTP_CLIENT_REQUEST_BAD_AUTH_HEADER = "HTTP_CLIENT_REQUEST_BAD_AUTH_HEADER";
 extern const isc::log::MessageID HTTP_CLIENT_REQUEST_NOT_AUTHORIZED = "HTTP_CLIENT_REQUEST_NOT_AUTHORIZED";
 extern const isc::log::MessageID HTTP_CLIENT_REQUEST_NO_AUTH_HEADER = "HTTP_CLIENT_REQUEST_NO_AUTH_HEADER";
+extern const isc::log::MessageID HTTP_CLIENT_USER_SECURITY_WARN = "HTTP_CLIENT_USER_SECURITY_WARN";
 
 } // namespace http
 } // namespace isc
@@ -18,10 +20,12 @@ extern const isc::log::MessageID HTTP_CLIENT_REQUEST_NO_AUTH_HEADER = "HTTP_CLIE
 namespace {
 
 const char* values[] = {
+    "HTTP_CLIENT_PASSWORD_SECURITY_WARN", "use of clear text 'password' is NOT SECURE: %1",
     "HTTP_CLIENT_REQUEST_AUTHORIZED", "received HTTP request authorized for '%1'",
     "HTTP_CLIENT_REQUEST_BAD_AUTH_HEADER", "received HTTP request with malformed authentication header: %1",
     "HTTP_CLIENT_REQUEST_NOT_AUTHORIZED", "received HTTP request with not matching authentication header",
     "HTTP_CLIENT_REQUEST_NO_AUTH_HEADER", "received HTTP request without required authentication header",
+    "HTTP_CLIENT_USER_SECURITY_WARN", "use of clear text 'user' is NOT SECURE: %1",
     NULL
 };
 
index 96dde53e06caca8a9744a68c00ed9adfd5306f9f..c12fb918cd2e66b8929bd64925eb0e187898f7ef 100644 (file)
@@ -8,10 +8,12 @@
 namespace isc {
 namespace http {
 
+extern const isc::log::MessageID HTTP_CLIENT_PASSWORD_SECURITY_WARN;
 extern const isc::log::MessageID HTTP_CLIENT_REQUEST_AUTHORIZED;
 extern const isc::log::MessageID HTTP_CLIENT_REQUEST_BAD_AUTH_HEADER;
 extern const isc::log::MessageID HTTP_CLIENT_REQUEST_NOT_AUTHORIZED;
 extern const isc::log::MessageID HTTP_CLIENT_REQUEST_NO_AUTH_HEADER;
+extern const isc::log::MessageID HTTP_CLIENT_USER_SECURITY_WARN;
 
 } // namespace http
 } // namespace isc
index 685bdb3596cc0672699943d11dbd74b1cfdfddb9..2e44e1e01aa6a0b37265a7dd13c7a0ffe31b91ff 100644 (file)
@@ -22,3 +22,15 @@ provided incorrect user id and/or password.
 % HTTP_CLIENT_REQUEST_NO_AUTH_HEADER received HTTP request without required authentication header
 This information message is issued when the server receives a request without
 a required authentication header.
+
+% HTTP_CLIENT_PASSWORD_SECURITY_WARN use of clear text 'password' is NOT SECURE: %1
+This warning message is issued when security enforcement is disabled
+and command socket configuration uses clear text 'password' rather
+than 'password-file'. The server will still use the socket as configured
+but is warning that doing so may pose a security risk.
+
+% HTTP_CLIENT_USER_SECURITY_WARN use of clear text 'user' is NOT SECURE: %1
+This warning message is issued when security enforcement is disabled
+and command socket configuration uses clear text 'user' rather
+than 'user-file'. The server will still use the socket as configured
+but is warning that doing so may pose a security risk.
index 6f6ff8864949f0796fb4529c91cd1b27d6e9a0f4..0336b16d8c2a1f891f6480809d0eda47828faadb 100644 (file)
@@ -232,6 +232,14 @@ BasicHttpAuthConfig::parse(const ConstElementPtr& config) {
                           "password must not be a default one ("
                           << password_cfg->getPosition() << ")");
             }
+
+            if (file::PathChecker::shouldEnforceSecurity()) {
+                isc_throw(DhcpConfigError, "use of clear text 'password' is NOT SECURE ("
+                                           << password_cfg->getPosition() << ")");
+            } else {
+                LOG_INFO(auth_logger, HTTP_CLIENT_PASSWORD_SECURITY_WARN)
+                        .arg(password_cfg->getPosition().str());
+            }
         }
 
         // password file.
@@ -286,6 +294,14 @@ BasicHttpAuthConfig::parse(const ConstElementPtr& config) {
                 isc_throw(DhcpConfigError, "user must not contain a ':': '"
                           << user << "' (" << user_cfg->getPosition() << ")");
             }
+
+            if (file::PathChecker::shouldEnforceSecurity()) {
+                isc_throw(DhcpConfigError, "use of clear text 'user' is NOT SECURE ("
+                                           << user_cfg->getPosition() << ")");
+            } else {
+                LOG_INFO(auth_logger, HTTP_CLIENT_USER_SECURITY_WARN)
+                        .arg(user_cfg->getPosition().str());
+            }
         }
 
         // user file.
index f53eac6de8db347dd09002f59d1171b4acc97789..b13cc1ee5b01706b926200c05db28ca1a00dcf25 100644 (file)
@@ -8,6 +8,8 @@
 #include <http/basic_auth_config.h>
 #include <testutils/gtest_utils.h>
 #include <testutils/test_to_element.h>
+#include <testutils/log_utils.h>
+#include <util/filesystem.h>
 #include <gtest/gtest.h>
 
 using namespace isc;
@@ -15,6 +17,8 @@ using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::http;
 using namespace isc::test;
+using namespace isc::util;
+using namespace isc::dhcp::test;
 using namespace std;
 
 namespace {
@@ -86,8 +90,24 @@ TEST(BasicHttpAuthClientTest, basicOneFile) {
     runToElementTest<BasicHttpAuthClient>(expected, client);
 }
 
+
+/// @brief Test fixture for testing BasicHttpAuthConfig.
+class BasicHttpAuthConfigTest : public LogContentTest {
+public:
+
+    /// @brief Constructor.
+    BasicHttpAuthConfigTest() {
+        file::PathChecker::enableEnforcement(true);
+    }
+
+    /// @brief Desstructor.
+    virtual ~BasicHttpAuthConfigTest() {
+        file::PathChecker::enableEnforcement(true);
+    }
+};
+
 // Test that basic auth configuration works as expected.
-TEST(BasicHttpAuthConfigTest, basic) {
+TEST_F(BasicHttpAuthConfigTest, basic) {
     // Create a configuration.
     BasicHttpAuthConfig config;
 
@@ -173,7 +193,7 @@ TEST(BasicHttpAuthConfigTest, basic) {
 }
 
 // Test that basic auth configuration with files works as expected.
-TEST(BasicHttpAuthConfigTest, basicFiles) {
+TEST_F(BasicHttpAuthConfigTest, basicFiles) {
     // Create a configuration.
     BasicHttpAuthConfig config;
 
@@ -247,7 +267,8 @@ TEST(BasicHttpAuthConfigTest, basicFiles) {
 }
 
 // Test that basic auth configuration parses.
-TEST(BasicHttpAuthConfigTest, parse) {
+TEST_F(BasicHttpAuthConfigTest, parse) {
+    file::PathChecker::enableEnforcement(false);
     BasicHttpAuthConfig config;
     ElementPtr cfg;
 
@@ -535,6 +556,7 @@ TEST(BasicHttpAuthConfigTest, parse) {
     cfg->set("clients", clients_cfg);
     EXPECT_NO_THROW(config.parse(cfg));
     runToElementTest<BasicHttpAuthConfig>(cfg, config);
+    std::cout << "TKM config: " << prettyPrint(config.toElement()) << std::endl;
 
     // Check a working not empty config with files.
     config.clear();
@@ -547,6 +569,66 @@ TEST(BasicHttpAuthConfigTest, parse) {
     cfg->set("clients", clients_cfg);
     EXPECT_NO_THROW(config.parse(cfg));
     runToElementTest<BasicHttpAuthConfig>(cfg, config);
+
+    EXPECT_EQ(4, countFile("HTTP_CLIENT_PASSWORD_SECURITY_WARN"
+                           " use of clear text 'password' is NOT SECURE: :0:0"));
+}
+
+// Test that basic auth configuration catches use of 'user'
+// and warns if security is disabled or throws if enabled.
+TEST_F(BasicHttpAuthConfigTest, clearUser) {
+    BasicHttpAuthConfig auth;
+
+    std::string json = R"(
+    {
+        "type": "basic",
+        "clients": [
+        {
+            "user": "foo"
+        }]
+    }
+    )";
+
+    ConstElementPtr config;
+    ASSERT_NO_THROW_LOG(config = Element::fromJSON(json));
+    ASSERT_THROW_MSG(auth.parse(config), DhcpConfigError,
+                     "use of clear text 'user' is NOT SECURE (<string>:6:21)");
+
+    // Disable security.
+    file::PathChecker::enableEnforcement(false);
+    ASSERT_NO_THROW_LOG(auth.parse(config));
+    EXPECT_EQ(1, countFile("HTTP_CLIENT_USER_SECURITY_WARN "
+                           "use of clear text 'user' is NOT SECURE: <string>:6:21"));
+}
+
+// Test that basic auth configuration catches use of 'password'
+// and warns if security is disabled or throws if enabled.
+TEST_F(BasicHttpAuthConfigTest, clearPassword) {
+    BasicHttpAuthConfig auth;
+
+    std::string json = R"(
+    {
+        "type": "basic",
+        "clients": [
+        {
+            "user": "foo",
+            "password": "bar"
+        }]
+    }
+    )";
+
+    ConstElementPtr config;
+    ASSERT_NO_THROW_LOG(config = Element::fromJSON(json));
+    ASSERT_THROW_MSG(auth.parse(config), DhcpConfigError,
+                     "use of clear text 'password' is NOT SECURE (<string>:7:25)");
+
+    // Disable security.
+    file::PathChecker::enableEnforcement(false);
+    ASSERT_NO_THROW_LOG(auth.parse(config));
+    EXPECT_EQ(1, countFile("HTTP_CLIENT_PASSWORD_SECURITY_WARN "
+                           "use of clear text 'password' is NOT SECURE: <string>:7:25"));
+    EXPECT_EQ(1, countFile("HTTP_CLIENT_USER_SECURITY_WARN "
+                           "use of clear text 'user' is NOT SECURE: <string>:6:21"));
 }
 
 } // end of anonymous namespace
index b4f479d7d53af39a5476b83fad781772c77d5010..13565bd03fdc1971201f82121d6e29012870e03a 100755 (executable)
@@ -701,8 +701,8 @@ start_kea() {
         test_lib_error "binary name must be specified for start_kea"
         clean_exit 1
     fi
-    printf "Running command %s.\n" "\"${bin} -c ${CFG_FILE}\""
-    "${bin}" -c "${CFG_FILE}" &
+    printf "Running command %s.\n" "\"${bin} -X -c ${CFG_FILE}\""
+    "${bin}" -X -c "${CFG_FILE}" &
 }
 
 # Waits with timeout for Kea to start.
@@ -1096,9 +1096,9 @@ password_redact_test() {
     # Instruct Control Agent to log to the specific file.
     set_logger
     # Check it
-    printf "Running command %s.\n" "\"${bin_path}/${bin} -d -t ${CFG_FILE}\""
+    printf "Running command %s.\n" "\"${bin_path}/${bin} -X -d -t ${CFG_FILE}\""
     run_command \
-        "${bin_path}/${bin}" -d -t "${CFG_FILE}"
+        "${bin_path}/${bin}" -X -d -t "${CFG_FILE}"
     if [ "${EXIT_CODE}" -ne "${expected_code}" ]; then
         printf 'ERROR: expected exit code %s, got %s\n' "${expected_code}" "${EXIT_CODE}"
         clean_exit 1