diff options
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | phosphor-ldap-config/Makefile.am | 3 | ||||
-rw-r--r-- | phosphor-ldap-config/ldap_configuration.cpp | 14 | ||||
-rw-r--r-- | phosphor-ldap-config/ldap_configuration.hpp | 11 | ||||
-rw-r--r-- | phosphor-ldap-config/ldap_serialize.cpp | 88 | ||||
-rw-r--r-- | phosphor-ldap-config/ldap_serialize.hpp | 29 | ||||
-rw-r--r-- | phosphor-ldap-config/main.cpp | 2 | ||||
-rw-r--r-- | test/Makefile.am | 4 | ||||
-rw-r--r-- | test/ldap_config_test.cpp | 69 |
9 files changed, 202 insertions, 24 deletions
diff --git a/configure.ac b/configure.ac index e82dd1c..6813056 100644 --- a/configure.ac +++ b/configure.ac @@ -83,6 +83,12 @@ AC_ARG_VAR(LDAP_CONFIG_BUSNAME, [D-Bus busname of LDAP config service]) AS_IF([test "x$LDAP_CONFIG_BUSNAME" == "x"], [LDAP_CONFIG_BUSNAME="xyz.openbmc_project.Ldap.Config"]) AC_DEFINE_UNQUOTED([LDAP_CONFIG_BUSNAME], ["$LDAP_CONFIG_BUSNAME"], [D-Bus busname of LDAP config service]) +AC_ARG_VAR(LDAP_CONF_PERSIST_PATH, [directory path to persist LDAP enabled property.]) +AS_IF([test "x$LDAP_CONF_PERSIST_PATH" == "x"], \ + [LDAP_CONF_PERSIST_PATH="/var/lib/phosphor-user-manager/ldap/conf"]) +AC_DEFINE_UNQUOTED([LDAP_CONF_PERSIST_PATH], ["$LDAP_CONF_PERSIST_PATH"], \ + [path of directory having persisted LDAP configuration enabled property.]) + AC_DEFINE(SYSTEMD_BUSNAME, "org.freedesktop.systemd1", [systemd busname.]) AC_DEFINE(SYSTEMD_PATH, "/org/freedesktop/systemd1", [systemd path.]) AC_DEFINE(SYSTEMD_INTERFACE, "org.freedesktop.systemd1.Manager", [systemd interface.]) diff --git a/phosphor-ldap-config/Makefile.am b/phosphor-ldap-config/Makefile.am index 907c365..501e577 100644 --- a/phosphor-ldap-config/Makefile.am +++ b/phosphor-ldap-config/Makefile.am @@ -5,7 +5,8 @@ noinst_HEADERS = ldap_configuration.hpp utils.hpp phosphor_ldap_conf_SOURCES = \ main.cpp \ utils.cpp \ - ldap_configuration.cpp + ldap_configuration.cpp \ + ldap_serialize.cpp phosphor_ldap_conf_LDFLAGS = $(SDBUSPLUS_LIBS) \ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \ diff --git a/phosphor-ldap-config/ldap_configuration.cpp b/phosphor-ldap-config/ldap_configuration.cpp index 413998a..4f2f85c 100644 --- a/phosphor-ldap-config/ldap_configuration.cpp +++ b/phosphor-ldap-config/ldap_configuration.cpp @@ -1,6 +1,7 @@ #include "ldap_configuration.hpp" +#include "ldap_serialize.hpp" #include "utils.hpp" -#include <experimental/filesystem> +#include <filesystem> #include <fstream> #include <sstream> @@ -15,7 +16,7 @@ constexpr auto LDAPSscheme = "ldaps"; using namespace phosphor::logging; using namespace sdbusplus::xyz::openbmc_project::Common::Error; -namespace fs = std::experimental::filesystem; +namespace fs = std::filesystem; using Argument = xyz::openbmc_project::Common::InvalidArgument; using Line = std::string; @@ -386,6 +387,8 @@ bool Config::enabled(bool value) return value; } isEnable = EnableIface::enabled(value); + // save the enabled property. + serialize(*this, parent.dbusPersistentPath); parent.startOrStopService(nslcdService, value); } catch (const InternalFailure& e) @@ -691,6 +694,13 @@ void ConfigMgr::restore(const char* filePath) std::move(configValues["bindpw"]), lDAPSearchScope, lDAPType, std::move(configValues["map_passwd_uid"]), std::move(configValues["map_passwd_gidNumber"])); + + // Get the enabled property value from the persistent location + if (!deserialize(dbusPersistentPath, *configPtr)) + { + log<level::INFO>( + "Deserialization Failed, continue with service disable"); + } } catch (const InvalidArgument& e) { diff --git a/phosphor-ldap-config/ldap_configuration.hpp b/phosphor-ldap-config/ldap_configuration.hpp index 0d69f08..976aac6 100644 --- a/phosphor-ldap-config/ldap_configuration.hpp +++ b/phosphor-ldap-config/ldap_configuration.hpp @@ -178,12 +178,14 @@ class ConfigMgr : public CreateIface * @param[in] bus - Bus to attach to. * @param[in] path - Path to attach at. * @param[in] filePath - LDAP configuration file. + * @param[in] dbusPersistentPath - Persistent path for LDAP D-Bus property. * @param[in] caCertFile - LDAP's CA certificate file. */ ConfigMgr(sdbusplus::bus::bus& bus, const char* path, const char* filePath, - const char* caCertFile) : + const char* dbusPersistentPath, const char* caCertFile) : CreateIface(bus, path, true), - configFilePath(filePath), bus(bus) + dbusPersistentPath(dbusPersistentPath), configFilePath(filePath), + bus(bus) { try { @@ -242,6 +244,11 @@ class ConfigMgr : public CreateIface */ void deleteObject(); + /* ldap service enabled property would be saved under + * this path. + */ + std::string dbusPersistentPath; + protected: std::string configFilePath{}; std::string tlsCacertFile{}; diff --git a/phosphor-ldap-config/ldap_serialize.cpp b/phosphor-ldap-config/ldap_serialize.cpp new file mode 100644 index 0000000..510686c --- /dev/null +++ b/phosphor-ldap-config/ldap_serialize.cpp @@ -0,0 +1,88 @@ +#include <cereal/types/string.hpp> +#include <cereal/types/vector.hpp> +#include <cereal/archives/binary.hpp> +#include <fstream> + +#include "ldap_serialize.hpp" +#include "ldap_configuration.hpp" +#include <phosphor-logging/log.hpp> +#include "config.h" + +// Register class version +// From cereal documentation; +// "This macro should be placed at global scope" +CEREAL_CLASS_VERSION(phosphor::ldap::Config, CLASS_VERSION); + +namespace phosphor +{ +namespace ldap +{ + +using namespace phosphor::logging; + +/** @brief Function required by Cereal to perform serialization. + * @tparam Archive - Cereal archive type (binary in our case). + * @param[in] archive - reference to Cereal archive. + * @param[in] config - const reference to ldap config. + * @param[in] version - Class version that enables handling + * a serialized data across code levels + */ +template <class Archive> +void save(Archive& archive, const Config& config, const std::uint32_t version) +{ + archive(config.enabled()); +} + +/** @brief Function required by Cereal to perform deserialization. + * @tparam Archive - Cereal archive type (binary in our case). + * @param[in] archive - reference to Cereal archive. + * @param[in] config - reference of ldap config object. + * @param[in] version - Class version that enables handling + * a serialized data across code levels + */ +template <class Archive> +void load(Archive& archive, Config& config, const std::uint32_t version) +{ + bool enabled = false; + archive(enabled); + config.enabled(enabled); +} + +fs::path serialize(const Config& config, const fs::path& path) +{ + fs::create_directories(path.parent_path()); + + std::ofstream os(path.string(), std::ios::binary); + cereal::BinaryOutputArchive oarchive(os); + oarchive(config); + return path; +} + +bool deserialize(const fs::path& path, Config& config) +{ + try + { + if (fs::exists(path)) + { + std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); + cereal::BinaryInputArchive iarchive(is); + iarchive(config); + return true; + } + return false; + } + catch (cereal::Exception& e) + { + log<level::ERR>(e.what()); + std::error_code ec; + fs::remove(path, ec); + return false; + } + catch (const fs::filesystem_error& e) + { + return false; + } +} + +} // namespace ldap +} // namespace phosphor diff --git a/phosphor-ldap-config/ldap_serialize.hpp b/phosphor-ldap-config/ldap_serialize.hpp new file mode 100644 index 0000000..b784baf --- /dev/null +++ b/phosphor-ldap-config/ldap_serialize.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include <filesystem> +#include "ldap_configuration.hpp" + +namespace phosphor +{ +namespace ldap +{ + +namespace fs = std::filesystem; + +/** @brief Serialize and persist LDAP service status property. + * @param[in] config - const reference to LDAP config object. + * @param[in] path - path of persistent location where D-Bus property would be + * saved. + * @return fs::path - pathname of persisted LDAP Config file. + */ +fs::path serialize(const Config& config, const fs::path& path); + +/** @brief Deserialize LDAP service status into a D-Bus object + * @param[in] path - pathname of persisted LDAP Config file. + * @param[in] config - reference of the object which needs to be deserialized. + * @return bool - true if the deserialization was successful, false otherwise. + */ +bool deserialize(const fs::path& path, Config& config); + +} // namespace ldap +} // namespace phosphor diff --git a/phosphor-ldap-config/main.cpp b/phosphor-ldap-config/main.cpp index 3ecc0ca..2e3bf66 100644 --- a/phosphor-ldap-config/main.cpp +++ b/phosphor-ldap-config/main.cpp @@ -26,7 +26,7 @@ int main(int argc, char* argv[]) sdbusplus::server::manager::manager objManager(bus, LDAP_CONFIG_ROOT); phosphor::ldap::ConfigMgr mgr(bus, LDAP_CONFIG_ROOT, LDAP_CONFIG_FILE, - TLS_CACERT_FILE); + LDAP_CONF_PERSIST_PATH, TLS_CACERT_FILE); bus.request_name(LDAP_CONFIG_BUSNAME); diff --git a/test/Makefile.am b/test/Makefile.am index e3c1366..06b7bb2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -33,7 +33,9 @@ ldap_config_test_LDFLAGS = $(utest_LDFLAGS) \ -lldap \ -lgmock ldap_config_test_SOURCES = ldap_config_test.cpp utils_test.cpp -ldap_config_test_LDADD = $(top_builddir)/phosphor-ldap-config/ldap_configuration.o $(top_builddir)/phosphor-ldap-config/utils.o +ldap_config_test_LDADD = $(top_builddir)/phosphor-ldap-config/ldap_configuration.o \ + $(top_builddir)/phosphor-ldap-config/utils.o \ + $(top_builddir)/phosphor-ldap-config/ldap_serialize.o check_PROGRAMS += ldap_mapper_test ldap_mapper_test_CPPFLAGS = $(utest_CPPFLAGS) diff --git a/test/ldap_config_test.cpp b/test/ldap_config_test.cpp index 0f22b8f..f7962f7 100644 --- a/test/ldap_config_test.cpp +++ b/test/ldap_config_test.cpp @@ -1,7 +1,7 @@ #include "config.h" #include "phosphor-ldap-config/ldap_configuration.hpp" +#include "phosphor-ldap-config/ldap_serialize.hpp" -#include <experimental/filesystem> #include <phosphor-logging/log.hpp> #include <phosphor-logging/elog-errors.hpp> #include <sdbusplus/bus.hpp> @@ -9,6 +9,8 @@ #include <sdbusplus/bus.hpp> #include <gmock/gmock.h> #include <gtest/gtest.h> + +#include <filesystem> #include <fstream> #include <string> #include <sys/types.h> @@ -17,9 +19,10 @@ namespace phosphor { namespace ldap { -namespace fs = std::experimental::filesystem; +namespace fs = std::filesystem; namespace ldap_base = sdbusplus::xyz::openbmc_project::User::Ldap::server; using Config = phosphor::ldap::Config; +static constexpr const char* dbusPersistFile = "Config"; class TestLDAPConfig : public testing::Test { @@ -59,8 +62,10 @@ class MockConfigMgr : public phosphor::ldap::ConfigMgr { public: MockConfigMgr(sdbusplus::bus::bus& bus, const char* path, - const char* filePath, const char* caCertFile) : - phosphor::ldap::ConfigMgr(bus, path, filePath, caCertFile) + const char* filePath, const char* dbusPersistentFile, + const char* caCertFile) : + phosphor::ldap::ConfigMgr(bus, path, filePath, dbusPersistentFile, + caCertFile) { } MOCK_METHOD1(restartService, void(const std::string& service)); @@ -83,6 +88,8 @@ TEST_F(TestLDAPConfig, testCreate) { auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; + auto dbusPersistentFilePath = + std::string(dir.c_str()) + "/" + dbusPersistFile; if (fs::exists(configFilePath)) { @@ -90,6 +97,7 @@ TEST_F(TestLDAPConfig, testCreate) } EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr manager(bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), + dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); EXPECT_CALL(manager, restartService("nslcd.service")).Times(1); EXPECT_CALL(manager, restartService("nscd.service")).Times(1); @@ -98,6 +106,7 @@ TEST_F(TestLDAPConfig, testCreate) "MyLdap12", ldap_base::Create::SearchScope::sub, ldap_base::Create::Type::ActiveDirectory, "uid", "gid"); manager.getConfigPtr()->enabled(true); + EXPECT_TRUE(fs::exists(configFilePath)); EXPECT_EQ(manager.getConfigPtr()->lDAPServerURI(), "ldap://9.194.251.136/"); EXPECT_EQ(manager.getConfigPtr()->lDAPBindDN(), "cn=Users,dc=com"); @@ -114,6 +123,8 @@ TEST_F(TestLDAPConfig, testRestores) { auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; + auto dbusPersistentFilePath = + std::string(dir.c_str()) + "/" + dbusPersistFile; if (fs::exists(configFilePath)) { @@ -121,21 +132,26 @@ TEST_F(TestLDAPConfig, testRestores) } EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( - bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(1); + bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), + dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); managerPtr->createConfig( "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", "MyLdap12", ldap_base::Create::SearchScope::sub, ldap_base::Create::Type::ActiveDirectory, "uid", "gid"); - managerPtr->getConfigPtr()->enabled(true); + managerPtr->getConfigPtr()->enabled(false); + EXPECT_TRUE(fs::exists(configFilePath)); + EXPECT_FALSE(managerPtr->getConfigPtr()->enabled()); + managerPtr->getConfigPtr()->enabled(true); // Delete LDAP configuration managerPtr->deleteObject(); EXPECT_TRUE(fs::exists(configFilePath)); // Restore from configFilePath managerPtr->restore(configFilePath.c_str()); // validate restored properties + EXPECT_TRUE(managerPtr->getConfigPtr()->enabled()); EXPECT_EQ(managerPtr->getConfigPtr()->lDAPServerURI(), "ldap://9.194.251.138/"); EXPECT_EQ(managerPtr->getConfigPtr()->lDAPBindDN(), "cn=Users,dc=com"); @@ -153,6 +169,8 @@ TEST_F(TestLDAPConfig, testLDAPServerURI) { auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; + auto dbusPersistentFilePath = + std::string(dir.c_str()) + "/" + dbusPersistFile; if (fs::exists(configFilePath)) { @@ -160,8 +178,9 @@ TEST_F(TestLDAPConfig, testLDAPServerURI) } EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( - bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); + bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), + dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); managerPtr->createConfig( @@ -169,6 +188,7 @@ TEST_F(TestLDAPConfig, testLDAPServerURI) "MyLdap12", ldap_base::Create::SearchScope::sub, ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); managerPtr->getConfigPtr()->enabled(true); + // Change LDAP Server URI managerPtr->getConfigPtr()->lDAPServerURI("ldap://9.194.251.139/"); EXPECT_EQ(managerPtr->getConfigPtr()->lDAPServerURI(), @@ -193,6 +213,8 @@ TEST_F(TestLDAPConfig, testLDAPBindDN) { auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; + auto dbusPersistentFilePath = + std::string(dir.c_str()) + "/" + dbusPersistFile; if (fs::exists(configFilePath)) { @@ -200,8 +222,9 @@ TEST_F(TestLDAPConfig, testLDAPBindDN) } EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( - bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); + bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), + dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); managerPtr->createConfig( @@ -209,6 +232,7 @@ TEST_F(TestLDAPConfig, testLDAPBindDN) "MyLdap12", ldap_base::Create::SearchScope::sub, ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); managerPtr->getConfigPtr()->enabled(true); + // Change LDAP BindDN managerPtr->getConfigPtr()->lDAPBindDN( "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com"); @@ -241,6 +265,8 @@ TEST_F(TestLDAPConfig, testLDAPBaseDN) { auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; + auto dbusPersistentFilePath = + std::string(dir.c_str()) + "/" + dbusPersistFile; if (fs::exists(configFilePath)) { @@ -248,8 +274,9 @@ TEST_F(TestLDAPConfig, testLDAPBaseDN) } EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( - bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); + bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), + dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); managerPtr->createConfig( "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", @@ -288,6 +315,8 @@ TEST_F(TestLDAPConfig, testSearchScope) { auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; + auto dbusPersistentFilePath = + std::string(dir.c_str()) + "/" + dbusPersistFile; if (fs::exists(configFilePath)) { @@ -295,14 +324,16 @@ TEST_F(TestLDAPConfig, testSearchScope) } EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( - bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); + bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), + dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); managerPtr->createConfig( "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", "MyLdap12", ldap_base::Create::SearchScope::sub, ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); managerPtr->getConfigPtr()->enabled(true); + // Change LDAP SearchScope managerPtr->getConfigPtr()->lDAPSearchScope( ldap_base::Config::SearchScope::one); @@ -322,6 +353,8 @@ TEST_F(TestLDAPConfig, testLDAPType) { auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; + auto dbusPersistentFilePath = + std::string(dir.c_str()) + "/" + dbusPersistFile; if (fs::exists(configFilePath)) { @@ -329,14 +362,16 @@ TEST_F(TestLDAPConfig, testLDAPType) } EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( - bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); + bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), + dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); managerPtr->createConfig( "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", "MyLdap12", ldap_base::Create::SearchScope::sub, ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); managerPtr->getConfigPtr()->enabled(true); + // Change LDAP type managerPtr->getConfigPtr()->lDAPType(ldap_base::Config::Type::OpenLdap); EXPECT_EQ(managerPtr->getConfigPtr()->lDAPType(), |