1 #include "config.h" 2 #include "phosphor-ldap-config/ldap_config.hpp" 3 #include "phosphor-ldap-config/ldap_config_mgr.hpp" 4 5 #include <phosphor-logging/log.hpp> 6 #include <phosphor-logging/elog-errors.hpp> 7 #include <sdbusplus/bus.hpp> 8 #include <xyz/openbmc_project/Common/error.hpp> 9 #include <sdbusplus/bus.hpp> 10 #include <gmock/gmock.h> 11 #include <gtest/gtest.h> 12 13 #include <filesystem> 14 #include <fstream> 15 #include <string> 16 #include <sys/types.h> 17 18 namespace phosphor 19 { 20 namespace ldap 21 { 22 namespace fs = std::filesystem; 23 namespace ldap_base = sdbusplus::xyz::openbmc_project::User::Ldap::server; 24 using Config = phosphor::ldap::Config; 25 static constexpr const char* dbusPersistFile = "Config"; 26 27 class TestLDAPConfig : public testing::Test 28 { 29 public: 30 TestLDAPConfig() : bus(sdbusplus::bus::new_default()) 31 { 32 } 33 void SetUp() override 34 { 35 using namespace phosphor::ldap; 36 char tmpldap[] = "/tmp/ldap_test.XXXXXX"; 37 dir = fs::path(mkdtemp(tmpldap)); 38 fs::path tslCacertFilePath{TLS_CACERT_FILE}; 39 tslCacertFile = tslCacertFilePath.filename().c_str(); 40 fs::path confFilePath{LDAP_CONFIG_FILE}; 41 ldapconfFile = confFilePath.filename().c_str(); 42 std::fstream fs; 43 fs.open(dir / defaultNslcdFile, std::fstream::out); 44 fs.close(); 45 fs.open(dir / nsSwitchFile, std::fstream::out); 46 fs.close(); 47 } 48 49 void TearDown() override 50 { 51 fs::remove_all(dir); 52 } 53 54 protected: 55 fs::path dir; 56 std::string tslCacertFile; 57 std::string ldapconfFile; 58 sdbusplus::bus::bus bus; 59 }; 60 61 class MockConfigMgr : public phosphor::ldap::ConfigMgr 62 { 63 public: 64 MockConfigMgr(sdbusplus::bus::bus& bus, const char* path, 65 const char* filePath, const char* dbusPersistentFile, 66 const char* caCertFile) : 67 phosphor::ldap::ConfigMgr(bus, path, filePath, dbusPersistentFile, 68 caCertFile) 69 { 70 } 71 MOCK_METHOD1(restartService, void(const std::string& service)); 72 MOCK_METHOD1(stopService, void(const std::string& service)); 73 std::unique_ptr<Config>& getOpenLdapConfigPtr() 74 { 75 return openLDAPConfigPtr; 76 } 77 78 std::string configBindPassword() 79 { 80 return getADConfigPtr()->lDAPBindPassword; 81 } 82 83 std::unique_ptr<Config>& getADConfigPtr() 84 { 85 return ADConfigPtr; 86 } 87 void restore() 88 { 89 phosphor::ldap::ConfigMgr::restore(); 90 return; 91 } 92 93 void createDefaultObjects() 94 { 95 phosphor::ldap::ConfigMgr::createDefaultObjects(); 96 } 97 98 friend class TestLDAPConfig; 99 }; 100 101 TEST_F(TestLDAPConfig, testCreate) 102 { 103 auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; 104 auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; 105 auto dbusPersistentFilePath = std::string(dir.c_str()); 106 107 if (fs::exists(configFilePath)) 108 { 109 fs::remove(configFilePath); 110 } 111 EXPECT_FALSE(fs::exists(configFilePath)); 112 MockConfigMgr manager(bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), 113 dbusPersistentFilePath.c_str(), 114 tlsCacertfile.c_str()); 115 116 EXPECT_CALL(manager, stopService("nslcd.service")).Times(2); 117 EXPECT_CALL(manager, restartService("nslcd.service")).Times(2); 118 EXPECT_CALL(manager, restartService("nscd.service")).Times(2); 119 120 manager.createConfig( 121 "ldap://9.194.251.136/", "cn=Users,dc=com", "cn=Users,dc=corp", 122 "MyLdap12", ldap_base::Create::SearchScope::sub, 123 ldap_base::Create::Type::ActiveDirectory, "uid", "gid"); 124 manager.getADConfigPtr()->enabled(true); 125 126 manager.createConfig("ldap://9.194.251.137/", "cn=Users", 127 "cn=Users,dc=test", "MyLdap123", 128 ldap_base::Create::SearchScope::sub, 129 ldap_base::Create::Type::OpenLdap, "uid", "gid"); 130 manager.getOpenLdapConfigPtr()->enabled(false); 131 132 // Below setting of username/groupname attr is to make sure 133 // that in-active config should not call the start/stop service. 134 manager.getOpenLdapConfigPtr()->userNameAttribute("abc"); 135 EXPECT_EQ(manager.getOpenLdapConfigPtr()->userNameAttribute(), "abc"); 136 137 manager.getOpenLdapConfigPtr()->groupNameAttribute("def"); 138 EXPECT_EQ(manager.getOpenLdapConfigPtr()->groupNameAttribute(), "def"); 139 140 EXPECT_TRUE(fs::exists(configFilePath)); 141 EXPECT_EQ(manager.getADConfigPtr()->lDAPServerURI(), 142 "ldap://9.194.251.136/"); 143 EXPECT_EQ(manager.getADConfigPtr()->lDAPBindDN(), "cn=Users,dc=com"); 144 EXPECT_EQ(manager.getADConfigPtr()->lDAPBaseDN(), "cn=Users,dc=corp"); 145 EXPECT_EQ(manager.getADConfigPtr()->lDAPSearchScope(), 146 ldap_base::Config::SearchScope::sub); 147 EXPECT_EQ(manager.getADConfigPtr()->lDAPType(), 148 ldap_base::Config::Type::ActiveDirectory); 149 150 EXPECT_EQ(manager.getADConfigPtr()->userNameAttribute(), "uid"); 151 EXPECT_EQ(manager.getADConfigPtr()->groupNameAttribute(), "gid"); 152 EXPECT_EQ(manager.getADConfigPtr()->lDAPBindDNPassword(), ""); 153 EXPECT_EQ(manager.configBindPassword(), "MyLdap12"); 154 // change the password 155 manager.getADConfigPtr()->lDAPBindDNPassword("MyLdap14"); 156 EXPECT_EQ(manager.getADConfigPtr()->lDAPBindDNPassword(), ""); 157 EXPECT_EQ(manager.configBindPassword(), "MyLdap14"); 158 } 159 160 TEST_F(TestLDAPConfig, testDefaultObject) 161 { 162 auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; 163 auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; 164 auto dbusPersistentFilePath = std::string(dir.c_str()); 165 166 if (fs::exists(configFilePath)) 167 { 168 fs::remove(configFilePath); 169 } 170 EXPECT_FALSE(fs::exists(configFilePath)); 171 172 MockConfigMgr manager(bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), 173 dbusPersistentFilePath.c_str(), 174 tlsCacertfile.c_str()); 175 176 manager.createDefaultObjects(); 177 178 EXPECT_NE(nullptr, manager.getADConfigPtr()); 179 EXPECT_NE(nullptr, manager.getOpenLdapConfigPtr()); 180 EXPECT_EQ(manager.getADConfigPtr()->lDAPType(), 181 ldap_base::Config::Type::ActiveDirectory); 182 EXPECT_EQ(manager.getOpenLdapConfigPtr()->lDAPType(), 183 ldap_base::Config::Type::OpenLdap); 184 } 185 186 TEST_F(TestLDAPConfig, testRestores) 187 { 188 auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; 189 auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; 190 auto dbusPersistentFilePath = std::string(dir.c_str()); 191 192 if (fs::exists(configFilePath)) 193 { 194 fs::remove(configFilePath); 195 } 196 EXPECT_FALSE(fs::exists(configFilePath)); 197 MockConfigMgr* managerPtr = new MockConfigMgr( 198 bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), 199 dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); 200 EXPECT_CALL(*managerPtr, stopService("nslcd.service")).Times(1); 201 EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(1); 202 EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(1); 203 managerPtr->createConfig( 204 "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", 205 "MyLdap12", ldap_base::Create::SearchScope::sub, 206 ldap_base::Create::Type::ActiveDirectory, "uid", "gid"); 207 managerPtr->getADConfigPtr()->enabled(false); 208 EXPECT_FALSE(fs::exists(configFilePath)); 209 EXPECT_FALSE(managerPtr->getADConfigPtr()->enabled()); 210 managerPtr->getADConfigPtr()->enabled(true); 211 212 EXPECT_TRUE(fs::exists(configFilePath)); 213 // Restore from configFilePath 214 managerPtr->restore(); 215 // validate restored properties 216 EXPECT_TRUE(managerPtr->getADConfigPtr()->enabled()); 217 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPServerURI(), 218 "ldap://9.194.251.138/"); 219 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPBindDN(), "cn=Users,dc=com"); 220 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPBaseDN(), "cn=Users,dc=corp"); 221 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPSearchScope(), 222 ldap_base::Config::SearchScope::sub); 223 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPType(), 224 ldap_base::Config::Type::ActiveDirectory); 225 EXPECT_EQ(managerPtr->getADConfigPtr()->userNameAttribute(), "uid"); 226 EXPECT_EQ(managerPtr->getADConfigPtr()->groupNameAttribute(), "gid"); 227 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPBindDNPassword(), ""); 228 EXPECT_EQ(managerPtr->configBindPassword(), "MyLdap12"); 229 delete managerPtr; 230 } 231 232 TEST_F(TestLDAPConfig, testLDAPServerURI) 233 { 234 auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; 235 auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; 236 auto dbusPersistentFilePath = std::string(dir.c_str()); 237 238 if (fs::exists(configFilePath)) 239 { 240 fs::remove(configFilePath); 241 } 242 EXPECT_FALSE(fs::exists(configFilePath)); 243 MockConfigMgr* managerPtr = new MockConfigMgr( 244 bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), 245 dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); 246 247 EXPECT_CALL(*managerPtr, stopService("nslcd.service")).Times(1); 248 EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); 249 EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(1); 250 251 managerPtr->createConfig( 252 "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", 253 "MyLdap12", ldap_base::Create::SearchScope::sub, 254 ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); 255 managerPtr->getADConfigPtr()->enabled(true); 256 257 // Change LDAP Server URI 258 managerPtr->getADConfigPtr()->lDAPServerURI("ldap://9.194.251.139/"); 259 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPServerURI(), 260 "ldap://9.194.251.139/"); 261 262 // Change LDAP Server URI to make it secure 263 EXPECT_THROW( 264 managerPtr->getADConfigPtr()->lDAPServerURI("ldaps://9.194.251.139/"), 265 NoCACertificate); 266 267 // check once again 268 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPServerURI(), 269 "ldap://9.194.251.139/"); 270 271 managerPtr->restore(); 272 // Check LDAP Server URI 273 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPServerURI(), 274 "ldap://9.194.251.139/"); 275 delete managerPtr; 276 } 277 278 TEST_F(TestLDAPConfig, testLDAPBindDN) 279 { 280 auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; 281 auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; 282 auto dbusPersistentFilePath = std::string(dir.c_str()); 283 284 if (fs::exists(configFilePath)) 285 { 286 fs::remove(configFilePath); 287 } 288 EXPECT_FALSE(fs::exists(configFilePath)); 289 MockConfigMgr* managerPtr = new MockConfigMgr( 290 bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), 291 dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); 292 293 EXPECT_CALL(*managerPtr, stopService("nslcd.service")).Times(1); 294 EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); 295 EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(1); 296 297 managerPtr->createConfig( 298 "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", 299 "MyLdap12", ldap_base::Create::SearchScope::sub, 300 ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); 301 managerPtr->getADConfigPtr()->enabled(true); 302 303 // Change LDAP BindDN 304 managerPtr->getADConfigPtr()->lDAPBindDN( 305 "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com"); 306 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPBindDN(), 307 "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com"); 308 // Change LDAP BindDN 309 EXPECT_THROW( 310 { 311 try 312 { 313 managerPtr->getADConfigPtr()->lDAPBindDN(""); 314 } 315 catch (const InvalidArgument& e) 316 { 317 throw; 318 } 319 }, 320 InvalidArgument); 321 322 managerPtr->restore(); 323 // Check LDAP BindDN after restoring 324 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPBindDN(), 325 "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com"); 326 delete managerPtr; 327 } 328 329 TEST_F(TestLDAPConfig, testLDAPBaseDN) 330 { 331 auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; 332 auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; 333 auto dbusPersistentFilePath = std::string(dir.c_str()); 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, stopService("nslcd.service")).Times(1); 344 EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); 345 EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(1); 346 managerPtr->createConfig( 347 "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", 348 "MyLdap12", ldap_base::Create::SearchScope::sub, 349 ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); 350 managerPtr->getADConfigPtr()->enabled(true); 351 // Change LDAP BaseDN 352 managerPtr->getADConfigPtr()->lDAPBaseDN( 353 "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com"); 354 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPBaseDN(), 355 "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com"); 356 // Change LDAP BaseDN 357 EXPECT_THROW( 358 { 359 try 360 { 361 managerPtr->getADConfigPtr()->lDAPBaseDN(""); 362 } 363 catch (const InvalidArgument& e) 364 { 365 throw; 366 } 367 }, 368 InvalidArgument); 369 370 managerPtr->restore(); 371 // Check LDAP BaseDN after restoring 372 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPBaseDN(), 373 "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com"); 374 delete managerPtr; 375 } 376 377 TEST_F(TestLDAPConfig, testSearchScope) 378 { 379 auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; 380 auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; 381 auto dbusPersistentFilePath = std::string(dir.c_str()); 382 383 if (fs::exists(configFilePath)) 384 { 385 fs::remove(configFilePath); 386 } 387 EXPECT_FALSE(fs::exists(configFilePath)); 388 MockConfigMgr* managerPtr = new MockConfigMgr( 389 bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), 390 dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); 391 EXPECT_CALL(*managerPtr, stopService("nslcd.service")).Times(1); 392 EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); 393 EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(1); 394 managerPtr->createConfig( 395 "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", 396 "MyLdap12", ldap_base::Create::SearchScope::sub, 397 ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); 398 managerPtr->getADConfigPtr()->enabled(true); 399 400 // Change LDAP SearchScope 401 managerPtr->getADConfigPtr()->lDAPSearchScope( 402 ldap_base::Config::SearchScope::one); 403 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPSearchScope(), 404 ldap_base::Config::SearchScope::one); 405 406 managerPtr->restore(); 407 // Check LDAP SearchScope after restoring 408 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPSearchScope(), 409 ldap_base::Config::SearchScope::one); 410 delete managerPtr; 411 } 412 413 TEST_F(TestLDAPConfig, testLDAPType) 414 { 415 auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; 416 auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; 417 auto dbusPersistentFilePath = std::string(dir.c_str()); 418 419 if (fs::exists(configFilePath)) 420 { 421 fs::remove(configFilePath); 422 } 423 EXPECT_FALSE(fs::exists(configFilePath)); 424 MockConfigMgr* managerPtr = new MockConfigMgr( 425 bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), 426 dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); 427 EXPECT_CALL(*managerPtr, stopService("nslcd.service")).Times(1); 428 EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(1); 429 EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(1); 430 managerPtr->createConfig( 431 "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", 432 "MyLdap12", ldap_base::Create::SearchScope::sub, 433 ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); 434 managerPtr->getADConfigPtr()->enabled(true); 435 436 // Change LDAP type 437 // will not be changed 438 EXPECT_THROW(managerPtr->getADConfigPtr()->lDAPType( 439 ldap_base::Config::Type::OpenLdap), 440 NotAllowed); 441 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPType(), 442 ldap_base::Config::Type::ActiveDirectory); 443 444 managerPtr->restore(); 445 // Check LDAP type after restoring 446 EXPECT_EQ(managerPtr->getADConfigPtr()->lDAPType(), 447 ldap_base::Config::Type::ActiveDirectory); 448 delete managerPtr; 449 } 450 451 TEST_F(TestLDAPConfig, filePermission) 452 { 453 auto configFilePath = std::string(dir.c_str()) + "/" + ldapconfFile; 454 auto tlsCacertfile = std::string(dir.c_str()) + "/" + tslCacertFile; 455 auto dbusPersistentFilePath = std::string(dir.c_str()); 456 457 if (fs::exists(configFilePath)) 458 { 459 fs::remove(configFilePath); 460 } 461 EXPECT_FALSE(fs::exists(configFilePath)); 462 MockConfigMgr* managerPtr = new MockConfigMgr( 463 bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), 464 dbusPersistentFilePath.c_str(), tlsCacertfile.c_str()); 465 EXPECT_CALL(*managerPtr, stopService("nslcd.service")).Times(1); 466 EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(1); 467 EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(1); 468 managerPtr->createConfig( 469 "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", 470 "MyLdap12", ldap_base::Create::SearchScope::sub, 471 ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); 472 managerPtr->getADConfigPtr()->enabled(true); 473 474 // Permission of the persistent file should be 640 475 // Others should not be allowed to read. 476 auto permission = 477 fs::perms::owner_read | fs::perms::owner_write | fs::perms::group_read; 478 auto persistFilepath = std::string(dir.c_str()); 479 persistFilepath += ADDbusObjectPath; 480 persistFilepath += "/config"; 481 482 EXPECT_EQ(fs::status(persistFilepath).permissions(), permission); 483 delete managerPtr; 484 } 485 486 } // namespace ldap 487 } // namespace phosphor 488