]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#396,!205] Implemented audit for the subnets.
authorMarcin Siodelski <marcin@isc.org>
Mon, 21 Jan 2019 10:34:55 +0000 (11:34 +0100)
committerMarcin Siodelski <marcin@isc.org>
Wed, 30 Jan 2019 09:18:59 +0000 (10:18 +0100)
src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc
src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc
src/share/database/scripts/mysql/dhcpdb_create.mysql
src/share/database/scripts/mysql/dhcpdb_drop.mysql

index 10fe1c99bdf243cfc0fc18ff286132598e1f5f5c..ae3180d38af5db60f0aee8ed3c9d6663072f13a3 100644 (file)
@@ -215,6 +215,7 @@ public:
 
         MySqlTransaction transaction(conn_);
 
+        // Set log message to be used to create the audit revision.
         conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::SET_AUDIT_LOG_MESSAGE,
                           { MySqlBinding::createString("this is a log message") });
 
@@ -748,6 +749,10 @@ public:
         MySqlTransaction transaction(conn_);
 
         try {
+            // Set log message to be used to create the audit revision.
+            conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::SET_AUDIT_LOG_MESSAGE,
+                              { MySqlBinding::createString("this is a log message") });
+
             // Try to insert subnet. If this duplicates primary key, i.e. this
             // subnet already exists it will throw DuplicateEntry exception in
             // which case we'll try an update.
index adf9b24587aea89f401470caa6cb569d36e4f95b..915d1014d8d1e8f56b5879840d0de2c336cd6439 100644 (file)
@@ -45,7 +45,7 @@ public:
 
     /// @brief Constructor.
     MySqlConfigBackendDHCPv4Test()
-        : test_subnets_(), test_networks_(), timestamps_() {
+        : test_subnets_(), test_networks_(), timestamps_(), audit_entries_() {
         // Recreate database schema.
         destroyMySQLSchema();
         createMySQLSchema();
@@ -295,6 +295,31 @@ public:
         timestamps_["tomorrow"] = timestamps_["today"] + boost::posix_time::hours(24);
     }
 
+    /// @brief Tests that the new audit entry is added.
+    ///
+    /// This method retrieves a collection of the existing audit entries and
+    /// checks that the new one has been added at the end of this collection.
+    /// It then verifies the values of the audit entry against the values
+    /// specified by the caller.
+    ///
+    /// @param exp_object_type Expected object type.
+    /// @param exp_modification_time Expected modification time.
+    /// @param exp_log_message Expected log message.
+    void testNewAuditEntry(const std::string& exp_object_type,
+                           const AuditEntry::ModificationType& exp_modification_type,
+                           const std::string& exp_log_message) {
+        auto audit_entries_size_save = audit_entries_.size();
+        audit_entries_ = cbptr_->getRecentAuditEntries4(ServerSelector::ALL(),
+                                                        timestamps_["two days ago"]);
+        ASSERT_EQ(audit_entries_size_save + 1, audit_entries_.size());
+
+        auto& mod_time_idx = audit_entries_.get<AuditEntryModificationTimeTag>();
+        auto audit_entry = *mod_time_idx.rbegin();
+        EXPECT_EQ(exp_object_type, audit_entry->getObjectType());
+        EXPECT_EQ(exp_modification_type, audit_entry->getModificationType());
+        EXPECT_EQ(exp_log_message, audit_entry->getLogMessage());
+    }
+
     /// @brief Holds pointers to subnets used in tests.
     std::vector<Subnet4Ptr> test_subnets_;
 
@@ -312,6 +337,9 @@ public:
 
     /// @brief Holds pointer to the backend.
     boost::shared_ptr<ConfigBackendDHCPv4> cbptr_;
+
+    /// @brief Holds the most recent audit entries.
+    AuditEntryCollection audit_entries_;
 };
 
 // This test verifies that the expected backend type is returned.
@@ -357,16 +385,12 @@ TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4) {
     cbptr_->createUpdateGlobalParameter4(ServerSelector::ALL(),
                                          global_parameter);
 
-    AuditEntryCollection audit_entries =
-        cbptr_->getRecentAuditEntries4(ServerSelector::ALL(),
-                                       timestamps_["two days ago"]);
-    ASSERT_EQ(1, audit_entries.size());
-
-    auto& mod_time_idx = audit_entries.get<AuditEntryModificationTimeTag>();
-    auto audit_entry = mod_time_idx.begin();
-    EXPECT_EQ("dhcp4_global_parameter", (*audit_entry)->getObjectType());
-    EXPECT_EQ(AuditEntry::ModificationType::CREATE, (*audit_entry)->getModificationType());
-    EXPECT_EQ("this is a log message", (*audit_entry)->getLogMessage());
+    {
+        SCOPED_TRACE("CREATE audit entry for global parameter");
+        testNewAuditEntry("dhcp4_global_parameter",
+                          AuditEntry::ModificationType::CREATE,
+                          "this is a log message");
+    }
 
     // Verify returned parameter and the modification time.
     StampedValuePtr returned_global_parameter =
@@ -399,21 +423,12 @@ TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4) {
     EXPECT_TRUE(returned_global_parameter->getModificationTime() ==
                 global_parameter->getModificationTime());
 
-    // There should now be two audit entries.
-    audit_entries = cbptr_->getRecentAuditEntries4(ServerSelector::ALL(),
-                                       timestamps_["two days ago"]);
-    ASSERT_EQ(2, audit_entries.size());
-
-    mod_time_idx = audit_entries.get<AuditEntryModificationTimeTag>();
-    audit_entry = mod_time_idx.begin();
-    EXPECT_EQ("dhcp4_global_parameter", (*audit_entry)->getObjectType());
-    EXPECT_EQ(AuditEntry::ModificationType::CREATE, (*audit_entry)->getModificationType());
-    EXPECT_EQ("this is a log message", (*audit_entry)->getLogMessage());
-
-    ++audit_entry;
-    EXPECT_EQ("dhcp4_global_parameter", (*audit_entry)->getObjectType());
-    EXPECT_EQ(AuditEntry::ModificationType::UPDATE, (*audit_entry)->getModificationType());
-    EXPECT_EQ("this is a log message", (*audit_entry)->getLogMessage());
+    {
+        SCOPED_TRACE("UPDATE audit entry for the global parameter");
+        testNewAuditEntry("dhcp4_global_parameter",
+                          AuditEntry::ModificationType::UPDATE,
+                          "this is a log message");
+    }
 
     // Should not delete parameter specified for all servers if explicit
     // server name is provided.
@@ -426,26 +441,12 @@ TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteGlobalParameter4) {
                                                             "global");
     EXPECT_FALSE(returned_global_parameter);
 
-    // There should now be three audit entries.
-    audit_entries = cbptr_->getRecentAuditEntries4(ServerSelector::ALL(),
-                                       timestamps_["two days ago"]);
-    ASSERT_EQ(3, audit_entries.size());
-
-    mod_time_idx = audit_entries.get<AuditEntryModificationTimeTag>();
-    audit_entry = mod_time_idx.begin();
-    EXPECT_EQ("dhcp4_global_parameter", (*audit_entry)->getObjectType());
-    EXPECT_EQ(AuditEntry::ModificationType::CREATE, (*audit_entry)->getModificationType());
-    EXPECT_EQ("this is a log message", (*audit_entry)->getLogMessage());
-
-    ++audit_entry;
-    EXPECT_EQ("dhcp4_global_parameter", (*audit_entry)->getObjectType());
-    EXPECT_EQ(AuditEntry::ModificationType::UPDATE, (*audit_entry)->getModificationType());
-    EXPECT_EQ("this is a log message", (*audit_entry)->getLogMessage());
-
-    ++audit_entry;
-    EXPECT_EQ("dhcp4_global_parameter", (*audit_entry)->getObjectType());
-    EXPECT_EQ(AuditEntry::ModificationType::DELETE, (*audit_entry)->getModificationType());
-    EXPECT_EQ("this is a log message", (*audit_entry)->getLogMessage());
+    {
+        SCOPED_TRACE("DELETE audit entry for the global parameter");
+        testNewAuditEntry("dhcp4_global_parameter",
+                          AuditEntry::ModificationType::DELETE,
+                          "this is a log message");
+    }
 }
 
 // This test verifies that all global parameters can be retrieved and deleted.
@@ -540,6 +541,13 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4) {
     // subnet is to convert both to text.
     EXPECT_EQ(subnet->toElement()->str(), returned_subnet->toElement()->str());
 
+    {
+        SCOPED_TRACE("CREATE audit entry for the subnet");
+        testNewAuditEntry("dhcp4_subnet",
+                          AuditEntry::ModificationType::CREATE,
+                          "this is a log message");
+    }
+
     // Update the subnet in the database (both use the same ID).
     Subnet4Ptr subnet2 = test_subnets_[1];
     cbptr_->createUpdateSubnet4(ServerSelector::ALL(), subnet2);
@@ -554,6 +562,13 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4) {
     returned_subnet = cbptr_->getSubnet4(ServerSelector::ONE("server1"),
                                          SubnetID(1024));
     EXPECT_EQ(subnet2->toElement()->str(), returned_subnet->toElement()->str());
+
+    {
+        SCOPED_TRACE("UPDATE audit entry for the subnet");
+        testNewAuditEntry("dhcp4_subnet",
+                          AuditEntry::ModificationType::UPDATE,
+                          "this is a log message");
+    }
 }
 
 // Test that subnet can be associated with a shared network.
@@ -612,6 +627,21 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getAllSubnets4) {
     // overwrite the first subnet as they use the same ID.
     for (auto subnet : test_subnets_) {
         cbptr_->createUpdateSubnet4(ServerSelector::ALL(), subnet);
+
+        // That subnet overrides the first subnet so the audit entry should
+        // indicate an update.
+        if (subnet->toText() == "10.0.0.0/8") {
+            SCOPED_TRACE("UPDATE audit entry for the subnet " + subnet->toText());
+            testNewAuditEntry("dhcp4_subnet",
+                              AuditEntry::ModificationType::UPDATE,
+                              "this is a log message");
+
+        } else {
+            SCOPED_TRACE("CREATE audit entry for the subnet " + subnet->toText());
+            testNewAuditEntry("dhcp4_subnet",
+                              AuditEntry::ModificationType::CREATE,
+                              "this is a log message");
+        }
     }
 
     // Fetch all subnets.
@@ -650,6 +680,14 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getAllSubnets4) {
     // Delete first subnet by id and verify that it is gone.
     EXPECT_EQ(1, cbptr_->deleteSubnet4(ServerSelector::ALL(),
                                        test_subnets_[1]->getID()));
+
+    {
+        SCOPED_TRACE("DELETE first subnet audit entry");
+        testNewAuditEntry("dhcp4_subnet",
+                          AuditEntry::ModificationType::DELETE,
+                          "this is a log message");
+    }
+
     subnets = cbptr_->getAllSubnets4(ServerSelector::ALL());
     ASSERT_EQ(test_subnets_.size() - 2, subnets.size());
 
@@ -659,10 +697,24 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getAllSubnets4) {
     subnets = cbptr_->getAllSubnets4(ServerSelector::ALL());
     ASSERT_EQ(test_subnets_.size() - 3, subnets.size());
 
+    {
+        SCOPED_TRACE("DELETE second subnet audit entry");
+        testNewAuditEntry("dhcp4_subnet",
+                          AuditEntry::ModificationType::DELETE,
+                          "this is a log message");
+    }
+
     // Delete all.
     EXPECT_EQ(1, cbptr_->deleteAllSubnets4(ServerSelector::ALL()));
     subnets = cbptr_->getAllSubnets4(ServerSelector::ALL());
     ASSERT_TRUE(subnets.empty());
+
+    {
+        SCOPED_TRACE("DELETE all subnets audit entry");
+        testNewAuditEntry("dhcp4_subnet",
+                          AuditEntry::ModificationType::DELETE,
+                          "this is a log message");
+    }
 }
 
 // Test that subnets modified after given time can be fetched.
index f5b1111da181cbfeb141db8e75dd85e43ab8bd45..2c39e2e135cdefe754983eadd623e79b27858812 100644 (file)
@@ -1439,6 +1439,37 @@ CREATE TRIGGER dhcp4_global_parameter_ADEL AFTER DELETE ON dhcp4_global_paramete
     END $$
 DELIMITER ;
 
+# Create dhcp4_subnet insert trigger
+DELIMITER $$
+CREATE TRIGGER dhcp4_subnet_AINS AFTER INSERT ON dhcp4_subnet
+    FOR EACH ROW
+    BEGIN
+        CALL createAuditRevisionDHCP4();
+        CALL createAuditEntryDHCP4('dhcp4_subnet', NEW.subnet_id, 0);
+    END $$
+DELIMITER ;
+
+# Create dhcp4_subnet update trigger
+DELIMITER $$
+CREATE TRIGGER dhcp4_subnet_AUPD AFTER UPDATE ON dhcp4_subnet
+    FOR EACH ROW
+    BEGIN
+        CALL createAuditRevisionDHCP4();
+        CALL createAuditEntryDHCP4('dhcp4_subnet', NEW.subnet_id, 1);
+    END $$
+DELIMITER ;
+
+# Create dhcp4_subnet delete trigger
+DELIMITER $$
+CREATE TRIGGER dhcp4_subnet_ADEL AFTER DELETE ON dhcp4_subnet
+    FOR EACH ROW
+    BEGIN
+        CALL createAuditRevisionDHCP4();
+        CALL createAuditEntryDHCP4('dhcp4_subnet', OLD.subnet_id, 2);
+    END $$
+DELIMITER ;
+
+
 # Update the schema version number
 UPDATE schema_version
 SET version = '8', minor = '0';
index 890e3a124c2812efd799c3f8438a81a343cdec89..db87584f1277ee5e695f762ebeb32e56acd42c1d 100644 (file)
@@ -64,3 +64,6 @@ DROP PROCEDURE IF EXISTS createAuditEntryDHCP4;
 DROP TRIGGER IF EXISTS dhcp4_global_parameter_AINS;
 DROP TRIGGER IF EXISTS dhcp4_global_parameter_AUPD;
 DROP TRIGGER IF EXISTS dhcp4_global_parameter_ADEL;
+DROP TRIGGER IF EXISTS dhcp4_subnet_AINS;
+DROP TRIGGER IF EXISTS dhcp4_subnet_AUPD;
+DROP TRIGGER IF EXISTS dhcp4_subnet_ADEL;