1 #include "config.h"
2 #include "phosphor-ldap-config/ldap_configuration.hpp"
3 #include "phosphor-ldap-config/ldap_config_mgr.hpp"
4 #include "phosphor-ldap-config/ldap_serialize.hpp"
5 
6 #include <phosphor-logging/log.hpp>
7 #include <phosphor-logging/elog-errors.hpp>
8 #include <sdbusplus/bus.hpp>
9 #include <xyz/openbmc_project/Common/error.hpp>
10 #include <sdbusplus/bus.hpp>
11 #include <gmock/gmock.h>
12 #include <gtest/gtest.h>
13 
14 #include <filesystem>
15 #include <fstream>
16 #include <string>
17 #include <sys/types.h>
18 
19 namespace phosphor
20 {
21 namespace ldap
22 {
23 namespace fs = std::filesystem;
24 namespace ldap_base = sdbusplus::xyz::openbmc_project::User::Ldap::server;
25 using Config = phosphor::ldap::Config;
26 static constexpr const char* dbusPersistFile = "Config";
27 
28 class TestLDAPConfig : public testing::Test
29 {
30   public:
31     TestLDAPConfig() : bus(sdbusplus::bus::new_default())
32     {
33     }
34     void SetUp() override
35     {
36         using namespace phosphor::ldap;
37         char tmpldap[] = "/tmp/ldap_test.XXXXXX";
38         dir = fs::path(mkdtemp(tmpldap));
39         fs::path tslCacertFilePath{TLS_CACERT_FILE};
40         tslCacertFile = tslCacertFilePath.filename().c_str();
41         fs::path confFilePath{LDAP_CONFIG_FILE};
42         ldapconfFile = confFilePath.filename().c_str();
43         std::fstream fs;
44         fs.open(dir / defaultNslcdFile, std::fstream::out);
45         fs.close();
46         fs.open(dir / nsSwitchFile, std::fstream::out);
47         fs.close();
48     }
49 
50     void TearDown() override
51     {
52         fs::remove_all(dir);
53     }
54 
55   protected:
56     fs::path dir;
57     std::string tslCacertFile;
58     std::string ldapconfFile;
59     sdbusplus::bus::bus bus;
60 };
61 
62 class MockConfigMgr : public phosphor::ldap::ConfigMgr
63 {
64   public:
65     MockConfigMgr(sdbusplus::bus::bus& bus, const char* path,
66                   const char* filePath, const char* dbusPersistentFile,
67                   const char* caCertFile) :
68         phosphor::ldap::ConfigMgr(bus, path, filePath, dbusPersistentFile,
69                                   caCertFile)
70     {
71     }
72     MOCK_METHOD1(restartService, void(const std::string& service));
73     MOCK_METHOD1(stopService, void(const std::string& service));
74     std::unique_ptr<Config>& getConfigPtr()
75     {
76         return configPtr;
77     }
78 
79     std::string configBindPassword()
80     {
81         return getConfigPtr()->lDAPBindPassword;
82     }
83 
84     void restore(const char* filePath)
85     {
86         phosphor::ldap::ConfigMgr::restore(filePath);
87         return;
88     }
89 
90     friend class TestLDAPConfig;
91 };
92 
93 TEST_F(TestLDAPConfig, testCreate)
94 {
95     auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile;
96     auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile;
97     auto dbusPersistentFilePath =
98         std::string(dir.c_str()) + "/" + dbusPersistFile;
99 
100     if (fs::exists(configFilePath))
101     {
102         fs::remove(configFilePath);
103     }
104     EXPECT_FALSE(fs::exists(configFilePath));
105     MockConfigMgr manager(bus, LDAP_CONFIG_ROOT, configFilePath.c_str(),
106                           dbusPersistentFilePath.c_str(),
107                           tlsCacertfile.c_str());
108     EXPECT_CALL(manager, restartService("nslcd.service")).Times(2);
109     EXPECT_CALL(manager, restartService("nscd.service")).Times(1);
110     manager.createConfig(
111         "ldap://9.194.251.136/", "cn=Users,dc=com", "cn=Users,dc=corp",
112         "MyLdap12", ldap_base::Create::SearchScope::sub,
113         ldap_base::Create::Type::ActiveDirectory, "uid", "gid");
114     manager.getConfigPtr()->enabled(true);
115 
116     EXPECT_TRUE(fs::exists(configFilePath));
117     EXPECT_EQ(manager.getConfigPtr()->lDAPServerURI(), "ldap://9.194.251.136/");
118     EXPECT_EQ(manager.getConfigPtr()->lDAPBindDN(), "cn=Users,dc=com");
119     EXPECT_EQ(manager.getConfigPtr()->lDAPBaseDN(), "cn=Users,dc=corp");
120     EXPECT_EQ(manager.getConfigPtr()->lDAPSearchScope(),
121               ldap_base::Config::SearchScope::sub);
122     EXPECT_EQ(manager.getConfigPtr()->lDAPType(),
123               ldap_base::Config::Type::ActiveDirectory);
124     EXPECT_EQ(manager.getConfigPtr()->userNameAttribute(), "uid");
125     EXPECT_EQ(manager.getConfigPtr()->groupNameAttribute(), "gid");
126     EXPECT_EQ(manager.getConfigPtr()->lDAPBindDNPassword(), "");
127     EXPECT_EQ(manager.configBindPassword(), "MyLdap12");
128     // change the password
129     manager.getConfigPtr()->lDAPBindDNPassword("MyLdap14");
130     EXPECT_EQ(manager.getConfigPtr()->lDAPBindDNPassword(), "");
131     EXPECT_EQ(manager.configBindPassword(), "MyLdap14");
132 }
133 
134 TEST_F(TestLDAPConfig, testRestores)
135 {
136     auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile;
137     auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile;
138     auto dbusPersistentFilePath =
139         std::string(dir.c_str()) + "/" + dbusPersistFile;
140 
141     if (fs::exists(configFilePath))
142     {
143         fs::remove(configFilePath);
144     }
145     EXPECT_FALSE(fs::exists(configFilePath));
146     MockConfigMgr* managerPtr = new MockConfigMgr(
147         bus, LDAP_CONFIG_ROOT, configFilePath.c_str(),
148         dbusPersistentFilePath.c_str(), tlsCacertfile.c_str());
149     EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2);
150     EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2);
151     managerPtr->createConfig(
152         "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp",
153         "MyLdap12", ldap_base::Create::SearchScope::sub,
154         ldap_base::Create::Type::ActiveDirectory, "uid", "gid");
155     managerPtr->getConfigPtr()->enabled(false);
156 
157     EXPECT_TRUE(fs::exists(configFilePath));
158     EXPECT_FALSE(managerPtr->getConfigPtr()->enabled());
159     managerPtr->getConfigPtr()->enabled(true);
160     // Delete LDAP configuration
161     managerPtr->deleteObject();
162     EXPECT_TRUE(fs::exists(configFilePath));
163     // Restore from configFilePath
164     managerPtr->restore(configFilePath.c_str());
165     // validate restored properties
166     EXPECT_TRUE(managerPtr->getConfigPtr()->enabled());
167     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPServerURI(),
168               "ldap://9.194.251.138/");
169     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPBindDN(), "cn=Users,dc=com");
170     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPBaseDN(), "cn=Users,dc=corp");
171     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPSearchScope(),
172               ldap_base::Config::SearchScope::sub);
173     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPType(),
174               ldap_base::Config::Type::ActiveDirectory);
175     EXPECT_EQ(managerPtr->getConfigPtr()->userNameAttribute(), "uid");
176     EXPECT_EQ(managerPtr->getConfigPtr()->groupNameAttribute(), "gid");
177     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPBindDNPassword(), "");
178     EXPECT_EQ(managerPtr->configBindPassword(), "MyLdap12");
179     delete managerPtr;
180 }
181 
182 TEST_F(TestLDAPConfig, testLDAPServerURI)
183 {
184     auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile;
185     auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile;
186     auto dbusPersistentFilePath =
187         std::string(dir.c_str()) + "/" + dbusPersistFile;
188 
189     if (fs::exists(configFilePath))
190     {
191         fs::remove(configFilePath);
192     }
193     EXPECT_FALSE(fs::exists(configFilePath));
194     MockConfigMgr* managerPtr = new MockConfigMgr(
195         bus, LDAP_CONFIG_ROOT, configFilePath.c_str(),
196         dbusPersistentFilePath.c_str(), tlsCacertfile.c_str());
197     EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3);
198     EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2);
199 
200     managerPtr->createConfig(
201         "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp",
202         "MyLdap12", ldap_base::Create::SearchScope::sub,
203         ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2");
204     managerPtr->getConfigPtr()->enabled(true);
205 
206     // Change LDAP Server URI
207     managerPtr->getConfigPtr()->lDAPServerURI("ldap://9.194.251.139/");
208     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPServerURI(),
209               "ldap://9.194.251.139/");
210     // Change LDAP Server URI
211     EXPECT_THROW(
212         managerPtr->getConfigPtr()->lDAPServerURI("ldaps://9.194.251.139/"),
213         NoCACertificate);
214     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPServerURI(),
215               "ldap://9.194.251.139/");
216     // Delete LDAP configuration
217     managerPtr->deleteObject();
218 
219     managerPtr->restore(configFilePath.c_str());
220     // Check LDAP Server URI
221     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPServerURI(),
222               "ldap://9.194.251.139/");
223     delete managerPtr;
224 }
225 
226 TEST_F(TestLDAPConfig, testLDAPBindDN)
227 {
228     auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile;
229     auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile;
230     auto dbusPersistentFilePath =
231         std::string(dir.c_str()) + "/" + dbusPersistFile;
232 
233     if (fs::exists(configFilePath))
234     {
235         fs::remove(configFilePath);
236     }
237     EXPECT_FALSE(fs::exists(configFilePath));
238     MockConfigMgr* managerPtr = new MockConfigMgr(
239         bus, LDAP_CONFIG_ROOT, configFilePath.c_str(),
240         dbusPersistentFilePath.c_str(), tlsCacertfile.c_str());
241     EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3);
242     EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2);
243 
244     managerPtr->createConfig(
245         "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp",
246         "MyLdap12", ldap_base::Create::SearchScope::sub,
247         ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2");
248     managerPtr->getConfigPtr()->enabled(true);
249 
250     // Change LDAP BindDN
251     managerPtr->getConfigPtr()->lDAPBindDN(
252         "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com");
253     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPBindDN(),
254               "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com");
255     // Change LDAP BindDN
256     EXPECT_THROW(
257         {
258             try
259             {
260                 managerPtr->getConfigPtr()->lDAPBindDN("");
261             }
262             catch (const InvalidArgument& e)
263             {
264                 throw;
265             }
266         },
267         InvalidArgument);
268     // Delete LDAP configuration
269     managerPtr->deleteObject();
270 
271     managerPtr->restore(configFilePath.c_str());
272     // Check LDAP BindDN after restoring
273     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPBindDN(),
274               "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com");
275     delete managerPtr;
276 }
277 
278 TEST_F(TestLDAPConfig, testLDAPBaseDN)
279 {
280     auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile;
281     auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile;
282     auto dbusPersistentFilePath =
283         std::string(dir.c_str()) + "/" + dbusPersistFile;
284 
285     if (fs::exists(configFilePath))
286     {
287         fs::remove(configFilePath);
288     }
289     EXPECT_FALSE(fs::exists(configFilePath));
290     MockConfigMgr* managerPtr = new MockConfigMgr(
291         bus, LDAP_CONFIG_ROOT, configFilePath.c_str(),
292         dbusPersistentFilePath.c_str(), tlsCacertfile.c_str());
293     EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3);
294     EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2);
295     managerPtr->createConfig(
296         "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp",
297         "MyLdap12", ldap_base::Create::SearchScope::sub,
298         ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2");
299     managerPtr->getConfigPtr()->enabled(true);
300     // Change LDAP BaseDN
301     managerPtr->getConfigPtr()->lDAPBaseDN(
302         "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com");
303     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPBaseDN(),
304               "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com");
305     // Change LDAP BaseDN
306     EXPECT_THROW(
307         {
308             try
309             {
310                 managerPtr->getConfigPtr()->lDAPBaseDN("");
311             }
312             catch (const InvalidArgument& e)
313             {
314                 throw;
315             }
316         },
317         InvalidArgument);
318     // Delete LDAP configuration
319     managerPtr->deleteObject();
320 
321     managerPtr->restore(configFilePath.c_str());
322     // Check LDAP BaseDN after restoring
323     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPBaseDN(),
324               "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com");
325     delete managerPtr;
326 }
327 
328 TEST_F(TestLDAPConfig, testSearchScope)
329 {
330     auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile;
331     auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile;
332     auto dbusPersistentFilePath =
333         std::string(dir.c_str()) + "/" + dbusPersistFile;
334 
335     if (fs::exists(configFilePath))
336     {
337         fs::remove(configFilePath);
338     }
339     EXPECT_FALSE(fs::exists(configFilePath));
340     MockConfigMgr* managerPtr = new MockConfigMgr(
341         bus, LDAP_CONFIG_ROOT, configFilePath.c_str(),
342         dbusPersistentFilePath.c_str(), tlsCacertfile.c_str());
343     EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3);
344     EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2);
345     managerPtr->createConfig(
346         "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp",
347         "MyLdap12", ldap_base::Create::SearchScope::sub,
348         ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2");
349     managerPtr->getConfigPtr()->enabled(true);
350 
351     // Change LDAP SearchScope
352     managerPtr->getConfigPtr()->lDAPSearchScope(
353         ldap_base::Config::SearchScope::one);
354     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPSearchScope(),
355               ldap_base::Config::SearchScope::one);
356     // Delete LDAP configuration
357     managerPtr->deleteObject();
358 
359     managerPtr->restore(configFilePath.c_str());
360     // Check LDAP SearchScope after restoring
361     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPSearchScope(),
362               ldap_base::Config::SearchScope::one);
363     delete managerPtr;
364 }
365 
366 TEST_F(TestLDAPConfig, testLDAPType)
367 {
368     auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile;
369     auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile;
370     auto dbusPersistentFilePath =
371         std::string(dir.c_str()) + "/" + dbusPersistFile;
372 
373     if (fs::exists(configFilePath))
374     {
375         fs::remove(configFilePath);
376     }
377     EXPECT_FALSE(fs::exists(configFilePath));
378     MockConfigMgr* managerPtr = new MockConfigMgr(
379         bus, LDAP_CONFIG_ROOT, configFilePath.c_str(),
380         dbusPersistentFilePath.c_str(), tlsCacertfile.c_str());
381     EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3);
382     EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2);
383     managerPtr->createConfig(
384         "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp",
385         "MyLdap12", ldap_base::Create::SearchScope::sub,
386         ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2");
387     managerPtr->getConfigPtr()->enabled(true);
388 
389     // Change LDAP type
390     managerPtr->getConfigPtr()->lDAPType(ldap_base::Config::Type::OpenLdap);
391     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPType(),
392               ldap_base::Config::Type::OpenLdap);
393     // Delete LDAP configuration
394     managerPtr->deleteObject();
395 
396     managerPtr->restore(configFilePath.c_str());
397     // Check LDAP type after restoring
398     EXPECT_EQ(managerPtr->getConfigPtr()->lDAPType(),
399               ldap_base::Config::Type::OpenLdap);
400     delete managerPtr;
401 }
402 } // namespace ldap
403 } // namespace phosphor
404