1 #include "mock_user_mgr.hpp" 2 #include "user_mgr.hpp" 3 4 #include <unistd.h> 5 6 #include <sdbusplus/test/sdbus_mock.hpp> 7 #include <xyz/openbmc_project/Common/error.hpp> 8 #include <xyz/openbmc_project/User/Common/error.hpp> 9 10 #include <chrono> 11 #include <exception> 12 #include <filesystem> 13 #include <fstream> 14 #include <vector> 15 16 #include <gmock/gmock.h> 17 #include <gtest/gtest.h> 18 19 namespace phosphor 20 { 21 namespace user 22 { 23 24 using ::testing::_; 25 using ::testing::Invoke; 26 using ::testing::Return; 27 using ::testing::Throw; 28 29 using InternalFailure = 30 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 31 using UserNameDoesNotExist = 32 sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameDoesNotExist; 33 34 namespace 35 { 36 inline static constexpr auto secondsPerDay = 37 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::days{1}) 38 .count(); 39 40 uint64_t getEpochTimeNow() 41 { 42 using namespace std::chrono; 43 44 return duration_cast<seconds>(system_clock::now().time_since_epoch()) 45 .count(); 46 } 47 48 std::string getNextUserName() 49 { 50 static std::string userName{"testUserName"}; 51 static int id{0}; 52 53 return userName + std::to_string(id++); 54 } 55 56 struct PasswordInfo 57 { 58 long lastChangeDate; 59 long maxAge; 60 }; 61 62 struct PasswordExpirationInfo 63 { 64 long lastChangeDate; 65 long oldmaxAge; 66 long newMaxAge; 67 uint64_t passwordExpiration; 68 }; 69 70 void fillPasswordExpiration( 71 const long lastChangeDaysAgo, const long oldPasswordAge, 72 const long nextPasswordChangeInDays, PasswordExpirationInfo& info) 73 { 74 using namespace std::chrono; 75 76 info.lastChangeDate = 77 duration_cast<days>(seconds{getEpochTimeNow()}).count() - 78 lastChangeDaysAgo; 79 80 info.oldmaxAge = oldPasswordAge; 81 info.newMaxAge = nextPasswordChangeInDays + lastChangeDaysAgo; 82 83 info.passwordExpiration = 84 getEpochTimeNow() + nextPasswordChangeInDays * secondsPerDay; 85 } 86 87 } // namespace 88 89 class TestUserMgr : public testing::Test 90 { 91 public: 92 testing::NiceMock<sdbusplus::SdBusMock> sdBusMock; 93 sdbusplus::bus_t bus; 94 MockManager mockManager; 95 96 TestUserMgr() : 97 bus(sdbusplus::get_mocked_new(&sdBusMock)), mockManager(bus, objpath) 98 {} 99 100 void createLocalUser(const std::string& userName, 101 std::vector<std::string> groupNames, 102 const std::string& priv, bool enabled) 103 { 104 sdbusplus::message::object_path tempObjPath(usersObjPath); 105 tempObjPath /= userName; 106 std::string userObj(tempObjPath); 107 if (enabled) 108 { 109 ON_CALL(mockManager, isUserEnabled) 110 .WillByDefault(testing::Return(true)); 111 } 112 else 113 { 114 ON_CALL(mockManager, isUserEnabled) 115 .WillByDefault(testing::Return(false)); 116 } 117 mockManager.usersList.emplace( 118 userName, std::make_unique<phosphor::user::Users>( 119 mockManager.bus, userObj.c_str(), groupNames, priv, 120 enabled, std::nullopt, mockManager)); 121 } 122 123 DbusUserObj createPrivilegeMapperDbusObject(void) 124 { 125 DbusUserObj object; 126 DbusUserObjValue objValue; 127 128 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap"); 129 DbusUserPropVariant enabled(true); 130 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)}; 131 std::string intf = "xyz.openbmc_project.Object.Enable"; 132 objValue.emplace(intf, property); 133 object.emplace(objPath, objValue); 134 135 DbusUserObjPath objectPath( 136 "/xyz/openbmc_project/user/ldap/openldap/role_map/1"); 137 std::string group = "ldapGroup"; 138 std::string priv = "priv-admin"; 139 DbusUserObjProperties properties = {std::make_pair("GroupName", group), 140 std::make_pair("Privilege", priv)}; 141 std::string interface = "xyz.openbmc_project.User.PrivilegeMapperEntry"; 142 143 objValue.emplace(interface, properties); 144 object.emplace(objectPath, objValue); 145 146 return object; 147 } 148 149 DbusUserObj createLdapConfigObjectWithoutPrivilegeMapper(void) 150 { 151 DbusUserObj object; 152 DbusUserObjValue objValue; 153 154 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap"); 155 DbusUserPropVariant enabled(true); 156 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)}; 157 std::string intf = "xyz.openbmc_project.Object.Enable"; 158 objValue.emplace(intf, property); 159 object.emplace(objPath, objValue); 160 return object; 161 } 162 163 auto& getUser(const std::string& userName) 164 { 165 return *mockManager.usersList[userName].get(); 166 } 167 168 void testPasswordExpirationSet(const std::string& userName, 169 const PasswordInfo& oldInfo, 170 const PasswordInfo& newInfo) 171 { 172 EXPECT_CALL(mockManager, getShadowData(testing::StrEq(userName), _)) 173 .WillOnce(Invoke([&oldInfo](auto, struct spwd& spwd) { 174 spwd.sp_lstchg = oldInfo.lastChangeDate; 175 spwd.sp_max = oldInfo.maxAge; 176 })); 177 178 EXPECT_CALL(mockManager, executeUserPasswordExpiration( 179 testing::StrEq(userName), 180 newInfo.lastChangeDate, newInfo.maxAge)) 181 .Times(1); 182 183 createLocalUser(userName, {"ssh"}, "priv-admin", true); 184 185 const auto expirationTime = 186 (newInfo.lastChangeDate + newInfo.maxAge) * secondsPerDay; 187 188 auto& user = getUser(userName); 189 EXPECT_EQ(expirationTime, user.passwordExpiration(expirationTime)); 190 EXPECT_EQ(expirationTime, user.passwordExpiration()); 191 } 192 193 void testPasswordExpirationReset(const std::string& userName, 194 const PasswordInfo& info) 195 { 196 EXPECT_CALL(mockManager, getShadowData(testing::StrEq(userName), _)) 197 .WillOnce(Invoke([&info](auto, struct spwd& spwd) { 198 spwd.sp_lstchg = info.lastChangeDate; 199 spwd.sp_max = info.maxAge; 200 })); 201 202 EXPECT_CALL(mockManager, 203 executeUserPasswordExpiration( 204 testing::StrEq(userName), info.lastChangeDate, 205 mockManager.getUnexpiringPasswordAge())) 206 .Times(1); 207 208 createLocalUser(userName, {"ssh"}, "priv-admin", true); 209 210 const auto expirationTime = UserMgr::getUnexpiringPasswordTime(); 211 212 auto& user = getUser(userName); 213 EXPECT_EQ(expirationTime, user.passwordExpiration(expirationTime)); 214 EXPECT_EQ(expirationTime, user.passwordExpiration()); 215 } 216 217 void testPasswordExpirationGet(const std::string& userName, 218 const PasswordInfo& info, 219 const uint64_t expectedPasswordExpiration) 220 { 221 EXPECT_CALL(mockManager, getShadowData(testing::StrEq(userName), _)) 222 .WillOnce(Invoke([&info](auto, struct spwd& spwd) { 223 spwd.sp_lstchg = info.lastChangeDate; 224 spwd.sp_max = info.maxAge; 225 })); 226 227 createLocalUser(userName, {"ssh"}, "priv-admin", true); 228 229 EXPECT_EQ(mockManager.getPasswordExpiration(userName), 230 expectedPasswordExpiration); 231 } 232 }; 233 234 TEST_F(TestUserMgr, ldapEntryDoesNotExist) 235 { 236 std::string userName = "user"; 237 UserInfoMap userInfo; 238 239 EXPECT_CALL(mockManager, getPrimaryGroup(userName)) 240 .WillRepeatedly(Throw(UserNameDoesNotExist())); 241 EXPECT_THROW(userInfo = mockManager.getUserInfo(userName), 242 UserNameDoesNotExist); 243 } 244 245 TEST_F(TestUserMgr, localUser) 246 { 247 UserInfoMap userInfo; 248 std::string userName = "testUser"; 249 std::string privilege = "priv-admin"; 250 std::vector<std::string> groups{"testGroup"}; 251 // Create local user 252 createLocalUser(userName, groups, privilege, true); 253 EXPECT_CALL(mockManager, userLockedForFailedAttempt(userName)).Times(1); 254 userInfo = mockManager.getUserInfo(userName); 255 256 EXPECT_EQ(privilege, std::get<std::string>(userInfo["UserPrivilege"])); 257 EXPECT_EQ(groups, 258 std::get<std::vector<std::string>>(userInfo["UserGroups"])); 259 EXPECT_EQ(true, std::get<bool>(userInfo["UserEnabled"])); 260 EXPECT_EQ(false, std::get<bool>(userInfo["UserLockedForFailedAttempt"])); 261 EXPECT_EQ(false, std::get<bool>(userInfo["UserPasswordExpired"])); 262 // check password expiration against default value 263 EXPECT_EQ(std::numeric_limits<uint64_t>::max(), 264 std::get<PasswordExpiration>(userInfo["PasswordExpiration"])); 265 EXPECT_EQ(false, std::get<bool>(userInfo["RemoteUser"])); 266 } 267 268 TEST_F(TestUserMgr, ldapUserWithPrivMapper) 269 { 270 UserInfoMap userInfo; 271 std::string userName = "ldapUser"; 272 std::string ldapGroup = "ldapGroup"; 273 gid_t primaryGid = 1000; 274 275 EXPECT_CALL(mockManager, getPrimaryGroup(userName)) 276 .WillRepeatedly(Return(primaryGid)); 277 // Create privilege mapper dbus object 278 DbusUserObj object = createPrivilegeMapperDbusObject(); 279 EXPECT_CALL(mockManager, getPrivilegeMapperObject()) 280 .WillRepeatedly(Return(object)); 281 EXPECT_CALL(mockManager, isGroupMember(userName, primaryGid, ldapGroup)) 282 .WillRepeatedly(Return(true)); 283 userInfo = mockManager.getUserInfo(userName); 284 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"])); 285 EXPECT_EQ("priv-admin", std::get<std::string>(userInfo["UserPrivilege"])); 286 } 287 288 TEST_F(TestUserMgr, ldapUserWithoutPrivMapper) 289 { 290 using ::testing::_; 291 292 UserInfoMap userInfo; 293 std::string userName = "ldapUser"; 294 std::string ldapGroup = "ldapGroup"; 295 gid_t primaryGid = 1000; 296 297 EXPECT_CALL(mockManager, getPrimaryGroup(userName)) 298 .WillRepeatedly(Return(primaryGid)); 299 // Create LDAP config object without privilege mapper 300 DbusUserObj object = createLdapConfigObjectWithoutPrivilegeMapper(); 301 EXPECT_CALL(mockManager, getPrivilegeMapperObject()) 302 .WillRepeatedly(Return(object)); 303 EXPECT_CALL(mockManager, isGroupMember(_, _, _)).Times(0); 304 userInfo = mockManager.getUserInfo(userName); 305 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"])); 306 EXPECT_EQ("", std::get<std::string>(userInfo["UserPrivilege"])); 307 } 308 309 TEST_F(TestUserMgr, PasswordExpiration) 310 { 311 testPasswordExpirationSet(getNextUserName(), {2, 10}, {2, 3}); 312 } 313 314 TEST_F(TestUserMgr, PasswordExpirationLastChangeNegative) 315 { 316 using namespace std::chrono; 317 318 const long lastChangeDate = 319 duration_cast<days>(seconds{getEpochTimeNow()}).count(); 320 321 testPasswordExpirationSet(getNextUserName(), {-2, 15}, {lastChangeDate, 3}); 322 } 323 324 TEST_F(TestUserMgr, PasswordExpirationLastChangeZero) 325 { 326 using namespace std::chrono; 327 328 const long lastChangeDate = 329 duration_cast<days>(seconds{getEpochTimeNow()}).count(); 330 331 testPasswordExpirationSet(getNextUserName(), {0, 7}, {lastChangeDate, 6}); 332 } 333 334 TEST_F(TestUserMgr, PasswordExpirationLastMaxAgeNegative) 335 { 336 testPasswordExpirationSet(getNextUserName(), {10, -5}, {10, 6}); 337 } 338 339 TEST_F(TestUserMgr, PasswordExpirationReset) 340 { 341 testPasswordExpirationReset(getNextUserName(), {2, 10}); 342 } 343 344 TEST_F(TestUserMgr, PasswordExpirationResetLastChangeNegative) 345 { 346 testPasswordExpirationReset(getNextUserName(), {-5, 8}); 347 } 348 349 TEST_F(TestUserMgr, PasswordExpirationResetLastChangeZero) 350 { 351 testPasswordExpirationReset(getNextUserName(), {0, 13}); 352 } 353 354 TEST_F(TestUserMgr, PasswordExpirationResetMaxAgeNegative) 355 { 356 testPasswordExpirationReset(getNextUserName(), {2, -2}); 357 } 358 359 TEST_F(TestUserMgr, PasswordExpirationGet) 360 { 361 constexpr long lastChangeDate = 7; 362 constexpr long passwordAge = 4; 363 constexpr uint64_t expirationTime = 364 (lastChangeDate + passwordAge) * secondsPerDay; 365 366 testPasswordExpirationGet(getNextUserName(), {lastChangeDate, passwordAge}, 367 expirationTime); 368 } 369 370 TEST_F(TestUserMgr, PasswordExpirationSetDefault) 371 { 372 const std::string userName = getNextUserName(); 373 374 createLocalUser(userName, {"ssh"}, "priv-admin", true); 375 376 auto& user = getUser(userName); 377 378 EXPECT_EQ(user.passwordExpiration(UserMgr::getUnexpiringPasswordTime()), 379 UserMgr::getUnexpiringPasswordTime()); 380 381 EXPECT_EQ(user.passwordExpiration(UserMgr::getDefaultPasswordExpiration()), 382 UserMgr::getDefaultPasswordExpiration()); 383 } 384 385 TEST_F(TestUserMgr, PasswordExpirationGetDefault) 386 { 387 const std::string userName = getNextUserName(); 388 389 createLocalUser(userName, {"ssh"}, "priv-admin", true); 390 391 auto& user = getUser(userName); 392 393 EXPECT_EQ(user.passwordExpiration(), 394 UserMgr::getDefaultPasswordExpiration()); 395 } 396 397 TEST_F(TestUserMgr, PasswordExpirationGetLastChangeNegative) 398 { 399 testPasswordExpirationGet(getNextUserName(), {-5, 8}, 400 UserMgr::getUnexpiringPasswordTime()); 401 } 402 403 TEST_F(TestUserMgr, PasswordExpirationGetLastChangeZero) 404 { 405 using namespace std::chrono; 406 407 const std::string userName = getNextUserName(); 408 constexpr long lastChangeDate = 0; 409 constexpr long passwordAge = 4; 410 411 EXPECT_CALL(mockManager, getShadowData(testing::StrEq(userName), _)) 412 .WillOnce(Invoke([](auto, struct spwd& spwd) { 413 spwd.sp_lstchg = lastChangeDate; 414 spwd.sp_max = passwordAge; 415 })); 416 417 createLocalUser(userName, {"ssh"}, "priv-admin", true); 418 419 auto expirationTime = 420 duration_cast<minutes>(seconds{getEpochTimeNow()}).count(); 421 auto time = duration_cast<minutes>( 422 seconds{mockManager.getPasswordExpiration(userName)}) 423 .count(); 424 425 // compare expiration time in minutes to avoid situation where times 426 // measured in second can be different 427 EXPECT_EQ(time, expirationTime); 428 } 429 430 TEST_F(TestUserMgr, PasswordExpirationGetMaxAgeNegative) 431 { 432 testPasswordExpirationGet(getNextUserName(), {12, -2}, 433 UserMgr::getUnexpiringPasswordTime()); 434 } 435 436 TEST_F(TestUserMgr, PasswordExpirationShadowFail) 437 { 438 const std::string userName = getNextUserName(); 439 440 EXPECT_CALL(mockManager, getShadowData(testing::StrEq(userName), _)) 441 .WillOnce([]() { 442 throw sdbusplus::xyz::openbmc_project::Common::Error:: 443 InternalFailure(); 444 }); 445 446 EXPECT_CALL(mockManager, executeUserPasswordExpiration(_, _, _)).Times(0); 447 448 createLocalUser(userName, {"ssh"}, "priv-admin", true); 449 auto& user = getUser(userName); 450 451 const auto oldTime = user.passwordExpiration(); 452 453 EXPECT_THROW( 454 user.passwordExpiration(0), 455 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 456 EXPECT_EQ(oldTime, user.passwordExpiration()); 457 } 458 459 TEST_F(TestUserMgr, PasswordExpirationInvalidDate) 460 { 461 const std::string userName = getNextUserName(); 462 463 EXPECT_CALL(mockManager, getShadowData(testing::StrEq(userName), _)) 464 .WillOnce(Invoke([](auto, struct spwd& spwd) { 465 spwd.sp_lstchg = 2; 466 spwd.sp_max = 2; 467 })); 468 469 EXPECT_CALL(mockManager, executeUserPasswordExpiration(_, _, _)).Times(0); 470 471 createLocalUser(userName, {"ssh"}, "priv-admin", true); 472 auto& user = getUser(userName); 473 474 const auto oldTime = user.passwordExpiration(); 475 476 EXPECT_THROW( 477 user.passwordExpiration(1), 478 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 479 EXPECT_EQ(oldTime, user.passwordExpiration()); 480 } 481 482 TEST_F(TestUserMgr, PasswordExpirationExecFail) 483 { 484 const std::string userName = getNextUserName(); 485 486 constexpr long lastChangeDate = 3; 487 EXPECT_CALL(mockManager, getShadowData(testing::StrEq(userName), _)) 488 .WillOnce(Invoke([](auto, struct spwd& spwd) { 489 spwd.sp_lstchg = lastChangeDate; 490 spwd.sp_max = 5; 491 })); 492 493 constexpr long passwordAge = 11; 494 EXPECT_CALL(mockManager, 495 executeUserPasswordExpiration(testing::StrEq(userName), 496 lastChangeDate, passwordAge)) 497 .WillOnce([]() { throw std::exception(); }); 498 499 createLocalUser(userName, {"ssh"}, "priv-admin", true); 500 auto& user = getUser(userName); 501 502 const auto oldTime = user.passwordExpiration(); 503 const auto expirationTime = (lastChangeDate + passwordAge) * secondsPerDay; 504 505 EXPECT_THROW( 506 user.passwordExpiration(expirationTime), 507 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 508 EXPECT_EQ(oldTime, user.passwordExpiration()); 509 } 510 511 TEST(GetCSVFromVector, EmptyVectorReturnsEmptyString) 512 { 513 EXPECT_EQ(getCSVFromVector({}), ""); 514 } 515 516 TEST(GetCSVFromVector, ElementsAreJoinedByComma) 517 { 518 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123"}), "123"); 519 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123", "456"}), 520 "123,456"); 521 } 522 523 TEST(RemoveStringFromCSV, WithoutDeleteStringReturnsFalse) 524 { 525 std::string expected = "whatever,https"; 526 std::string str = expected; 527 EXPECT_FALSE(removeStringFromCSV(str, "ssh")); 528 EXPECT_EQ(str, expected); 529 530 std::string empty; 531 EXPECT_FALSE(removeStringFromCSV(empty, "ssh")); 532 } 533 534 TEST(RemoveStringFromCSV, WithDeleteStringReturnsTrue) 535 { 536 std::string expected = "whatever"; 537 std::string str = "whatever,https"; 538 EXPECT_TRUE(removeStringFromCSV(str, "https")); 539 EXPECT_EQ(str, expected); 540 541 str = "https"; 542 EXPECT_TRUE(removeStringFromCSV(str, "https")); 543 EXPECT_EQ(str, ""); 544 } 545 546 namespace 547 { 548 inline constexpr const char* objectRootInTest = "/xyz/openbmc_project/user"; 549 550 // Fake configs; referenced configs on real BMC 551 inline constexpr const char* rawFailLockConfig = R"( 552 deny=2 553 unlock_time=3 554 )"; 555 inline constexpr const char* rawPWHistoryConfig = R"( 556 enforce_for_root 557 remember=0 558 )"; 559 inline constexpr const char* rawPWQualityConfig = R"( 560 enforce_for_root 561 minlen=8 562 difok=0 563 lcredit=0 564 ocredit=0 565 dcredit=0 566 ucredit=0 567 )"; 568 } // namespace 569 570 void dumpStringToFile(const std::string& str, const std::string& filePath) 571 { 572 std::ofstream outputFileStream; 573 574 outputFileStream.exceptions( 575 std::ofstream::failbit | std::ofstream::badbit | std::ofstream::eofbit); 576 577 outputFileStream.open(filePath, std::ios::out); 578 outputFileStream << str << "\n" << std::flush; 579 outputFileStream.close(); 580 } 581 582 void removeFile(const std::string& filePath) 583 { 584 std::filesystem::remove(filePath); 585 } 586 587 class UserMgrInTest : public testing::Test, public UserMgr 588 { 589 public: 590 UserMgrInTest() : UserMgr(busInTest, objectRootInTest) 591 { 592 { 593 tempFaillockConfigFile = tempFilePath; 594 int fd = mkstemp(tempFaillockConfigFile.data()); 595 EXPECT_NE(-1, fd); 596 EXPECT_NO_THROW( 597 dumpStringToFile(rawFailLockConfig, tempFaillockConfigFile)); 598 if (fd != -1) 599 { 600 close(fd); 601 } 602 } 603 604 { 605 tempPWHistoryConfigFile = tempFilePath; 606 int fd = mkstemp(tempPWHistoryConfigFile.data()); 607 EXPECT_NE(-1, fd); 608 EXPECT_NO_THROW( 609 dumpStringToFile(rawPWHistoryConfig, tempPWHistoryConfigFile)); 610 if (fd != -1) 611 { 612 close(fd); 613 } 614 } 615 616 { 617 tempPWQualityConfigFile = tempFilePath; 618 int fd = mkstemp(tempPWQualityConfigFile.data()); 619 EXPECT_NE(-1, fd); 620 EXPECT_NO_THROW( 621 dumpStringToFile(rawPWQualityConfig, tempPWQualityConfigFile)); 622 if (fd != -1) 623 { 624 close(fd); 625 } 626 } 627 628 // Set config files to test files 629 faillockConfigFile = tempFaillockConfigFile; 630 pwHistoryConfigFile = tempPWHistoryConfigFile; 631 pwQualityConfigFile = tempPWQualityConfigFile; 632 633 ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_, 634 testing::Eq(true))) 635 .WillByDefault([this]() { 636 ON_CALL(*this, isUserEnabled) 637 .WillByDefault(testing::Return(true)); 638 testing::Return(); 639 }); 640 641 ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_, 642 testing::Eq(false))) 643 .WillByDefault([this]() { 644 ON_CALL(*this, isUserEnabled) 645 .WillByDefault(testing::Return(false)); 646 testing::Return(); 647 }); 648 649 ON_CALL(*this, executeUserDelete).WillByDefault(testing::Return()); 650 651 ON_CALL(*this, executeUserClearFailRecords) 652 .WillByDefault(testing::Return()); 653 654 ON_CALL(*this, getIpmiUsersCount).WillByDefault(testing::Return(0)); 655 656 ON_CALL(*this, executeUserRename).WillByDefault(testing::Return()); 657 658 ON_CALL(*this, executeUserModify(testing::_, testing::_, testing::_)) 659 .WillByDefault(testing::Return()); 660 661 ON_CALL(*this, 662 executeUserModifyUserEnable(testing::_, testing::Eq(true))) 663 .WillByDefault([this]() { 664 ON_CALL(*this, isUserEnabled) 665 .WillByDefault(testing::Return(true)); 666 testing::Return(); 667 }); 668 669 ON_CALL(*this, 670 executeUserModifyUserEnable(testing::_, testing::Eq(false))) 671 .WillByDefault([this]() { 672 ON_CALL(*this, isUserEnabled) 673 .WillByDefault(testing::Return(false)); 674 testing::Return(); 675 }); 676 677 ON_CALL(*this, executeGroupCreation(testing::_)) 678 .WillByDefault(testing::Return()); 679 680 ON_CALL(*this, executeGroupDeletion(testing::_)) 681 .WillByDefault(testing::Return()); 682 683 ON_CALL(*this, executeGroupCreation).WillByDefault(testing::Return()); 684 685 ON_CALL(*this, executeGroupDeletion).WillByDefault(testing::Return()); 686 } 687 688 ~UserMgrInTest() override 689 { 690 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile)); 691 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile)); 692 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile)); 693 } 694 695 MOCK_METHOD(void, executeUserAdd, (const char*, const char*, bool, bool), 696 (override)); 697 698 MOCK_METHOD(void, executeUserDelete, (const char*), (override)); 699 700 MOCK_METHOD(void, executeUserClearFailRecords, (const char*), (override)); 701 702 MOCK_METHOD(size_t, getIpmiUsersCount, (), (override)); 703 704 MOCK_METHOD(void, executeUserRename, (const char*, const char*), 705 (override)); 706 707 MOCK_METHOD(void, executeUserModify, (const char*, const char*, bool), 708 (override)); 709 710 MOCK_METHOD(void, executeUserModifyUserEnable, (const char*, bool), 711 (override)); 712 713 MOCK_METHOD(std::vector<std::string>, getFailedAttempt, (const char*), 714 (override)); 715 716 MOCK_METHOD(void, executeGroupCreation, (const char*), (override)); 717 718 MOCK_METHOD(void, executeGroupDeletion, (const char*), (override)); 719 720 MOCK_METHOD(bool, isUserEnabled, (const std::string& userName), (override)); 721 722 MOCK_METHOD(void, getShadowData, (const std::string&, struct spwd& spwd), 723 (const, override)); 724 725 MOCK_METHOD(void, executeUserPasswordExpiration, 726 (const char*, const long int, const long int), 727 (const, override)); 728 729 protected: 730 static constexpr auto tempFilePath = "/tmp/test-data-XXXXXX"; 731 732 static sdbusplus::bus_t busInTest; 733 std::string tempFaillockConfigFile; 734 std::string tempPWHistoryConfigFile; 735 std::string tempPWQualityConfigFile; 736 737 void setUpCreateUser(const std::string& userName, bool enabled) 738 { 739 EXPECT_CALL(*this, getIpmiUsersCount).WillOnce(testing::Return(0)); 740 741 EXPECT_CALL(*this, 742 executeUserAdd(testing::StrEq(userName), _, _, enabled)) 743 .Times(1); 744 } 745 746 void setUpGetUserInfo(const std::string& userName, bool enabled) 747 { 748 EXPECT_CALL(*this, isUserEnabled(userName)) 749 .WillOnce(testing::Return(enabled)); 750 } 751 752 void setUpSetPasswordExpiration(const std::string& userName, 753 const PasswordExpirationInfo& info) 754 { 755 EXPECT_CALL(*this, getShadowData(testing::StrEq(userName), _)) 756 .WillOnce(Invoke([&info](auto, struct spwd& spwd) { 757 spwd.sp_lstchg = info.lastChangeDate; 758 spwd.sp_max = info.oldmaxAge; 759 })); 760 761 EXPECT_CALL(*this, executeUserPasswordExpiration( 762 testing::StrEq(userName), info.lastChangeDate, 763 info.newMaxAge)) 764 .Times(1); 765 } 766 767 void setUpDeleteUser(const std::string& userName) 768 { 769 EXPECT_CALL(*this, 770 executeUserClearFailRecords(testing::StrEq(userName))) 771 .Times(1); 772 773 EXPECT_CALL(*this, executeUserDelete(testing::StrEq(userName))) 774 .Times(1); 775 } 776 }; 777 778 sdbusplus::bus_t UserMgrInTest::busInTest = sdbusplus::bus::new_default(); 779 780 TEST_F(UserMgrInTest, GetPamModuleConfValueOnSuccess) 781 { 782 std::string minlen; 783 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen), 784 0); 785 EXPECT_EQ(minlen, "8"); 786 std::string deny; 787 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0); 788 EXPECT_EQ(deny, "2"); 789 std::string remember; 790 EXPECT_EQ( 791 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember), 792 0); 793 EXPECT_EQ(remember, "0"); 794 } 795 796 TEST_F(UserMgrInTest, SetPamModuleConfValueOnSuccess) 797 { 798 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"), 799 0); 800 std::string minlen; 801 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen), 802 0); 803 EXPECT_EQ(minlen, "16"); 804 805 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0); 806 std::string deny; 807 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0); 808 EXPECT_EQ(deny, "3"); 809 810 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"), 811 0); 812 std::string remember; 813 EXPECT_EQ( 814 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember), 815 0); 816 EXPECT_EQ(remember, "1"); 817 } 818 819 TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnSuccess) 820 { 821 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"), 822 0); 823 824 std::string tmpFile = tempPWQualityConfigFile + "_tmp"; 825 EXPECT_FALSE(std::filesystem::exists(tmpFile)); 826 827 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0); 828 829 tmpFile = tempFaillockConfigFile + "_tmp"; 830 EXPECT_FALSE(std::filesystem::exists(tmpFile)); 831 832 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"), 833 0); 834 835 tmpFile = tempPWHistoryConfigFile + "_tmp"; 836 EXPECT_FALSE(std::filesystem::exists(tmpFile)); 837 } 838 839 TEST_F(UserMgrInTest, GetPamModuleConfValueOnFailure) 840 { 841 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile)); 842 std::string minlen; 843 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen), 844 -1); 845 846 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile)); 847 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen), 848 -1); 849 850 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile)); 851 std::string deny; 852 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1); 853 854 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile)); 855 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1); 856 857 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile)); 858 std::string remember; 859 EXPECT_EQ( 860 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember), 861 -1); 862 863 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile)); 864 EXPECT_EQ( 865 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember), 866 -1); 867 } 868 869 TEST_F(UserMgrInTest, SetPamModuleConfValueOnFailure) 870 { 871 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile)); 872 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"), 873 -1); 874 875 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile)); 876 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"), 877 -1); 878 879 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile)); 880 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1); 881 882 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile)); 883 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1); 884 885 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile)); 886 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"), 887 -1); 888 889 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile)); 890 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"), 891 -1); 892 } 893 894 TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnFailure) 895 { 896 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile)); 897 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"), 898 -1); 899 900 std::string tmpFile = tempPWQualityConfigFile + "_tmp"; 901 EXPECT_FALSE(std::filesystem::exists(tmpFile)); 902 903 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile)); 904 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"), 905 -1); 906 907 EXPECT_FALSE(std::filesystem::exists(tmpFile)); 908 909 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile)); 910 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1); 911 912 tmpFile = tempFaillockConfigFile + "_tmp"; 913 EXPECT_FALSE(std::filesystem::exists(tmpFile)); 914 915 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile)); 916 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1); 917 918 EXPECT_FALSE(std::filesystem::exists(tmpFile)); 919 920 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile)); 921 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"), 922 -1); 923 924 tmpFile = tempPWHistoryConfigFile + "_tmp"; 925 EXPECT_FALSE(std::filesystem::exists(tmpFile)); 926 927 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile)); 928 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"), 929 -1); 930 931 EXPECT_FALSE(std::filesystem::exists(tmpFile)); 932 } 933 934 TEST_F(UserMgrInTest, IsUserExistEmptyInputThrowsError) 935 { 936 EXPECT_THROW( 937 isUserExist(""), 938 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 939 } 940 941 TEST_F(UserMgrInTest, ThrowForUserDoesNotExistThrowsError) 942 { 943 EXPECT_THROW(throwForUserDoesNotExist("whatever"), 944 sdbusplus::xyz::openbmc_project::User::Common::Error:: 945 UserNameDoesNotExist); 946 } 947 948 TEST_F(UserMgrInTest, ThrowForUserExistsThrowsError) 949 { 950 EXPECT_THROW( 951 throwForUserExists("root"), 952 sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameExists); 953 } 954 955 TEST_F( 956 UserMgrInTest, 957 ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail) 958 { 959 std::string strWith17Chars(17, 'A'); 960 EXPECT_THROW(throwForUserNameConstraints(strWith17Chars, {"ipmi"}), 961 sdbusplus::xyz::openbmc_project::User::Common::Error:: 962 UserNameGroupFail); 963 } 964 965 TEST_F( 966 UserMgrInTest, 967 ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument) 968 { 969 std::string strWith31Chars(101, 'A'); 970 EXPECT_THROW( 971 throwForUserNameConstraints(strWith31Chars, {}), 972 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 973 } 974 975 TEST_F(UserMgrInTest, 976 ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument) 977 { 978 std::string startWithNumber = "0ABC"; 979 std::string startWithDisallowedCharacter = "[test"; 980 EXPECT_THROW( 981 throwForUserNameConstraints(startWithNumber, {"ipmi"}), 982 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 983 EXPECT_THROW( 984 throwForUserNameConstraints(startWithDisallowedCharacter, {"ipmi"}), 985 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 986 } 987 988 TEST_F(UserMgrInTest, UserAddNotRootFailedWithInternalFailure) 989 { 990 EXPECT_THROW( 991 UserMgr::executeUserAdd("user0", "ipmi,ssh", true, true), 992 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 993 } 994 995 TEST_F(UserMgrInTest, UserDeleteNotRootFailedWithInternalFailure) 996 { 997 EXPECT_THROW( 998 UserMgr::executeUserDelete("user0"), 999 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1000 } 1001 1002 TEST_F(UserMgrInTest, 1003 ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit) 1004 { 1005 EXPECT_CALL(*this, getIpmiUsersCount()).WillOnce(Return(ipmiMaxUsers)); 1006 EXPECT_THROW( 1007 throwForMaxGrpUserCount({"ipmi"}), 1008 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource); 1009 } 1010 1011 TEST_F(UserMgrInTest, CreateUserThrowsInternalFailureWhenExecuteUserAddFails) 1012 { 1013 EXPECT_CALL(*this, executeUserAdd) 1014 .WillOnce(testing::Throw( 1015 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())); 1016 EXPECT_THROW( 1017 createUser("whatever", {"redfish"}, "", true), 1018 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1019 } 1020 1021 TEST_F(UserMgrInTest, DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails) 1022 { 1023 std::string username = "user"; 1024 EXPECT_NO_THROW( 1025 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 1026 EXPECT_CALL(*this, executeUserDelete(testing::StrEq(username))) 1027 .WillOnce(testing::Throw( 1028 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())) 1029 .WillOnce(testing::DoDefault()); 1030 1031 EXPECT_THROW( 1032 deleteUser(username), 1033 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1034 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 1035 } 1036 1037 TEST_F(UserMgrInTest, 1038 DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords) 1039 { 1040 const char* username = "user"; 1041 EXPECT_NO_THROW( 1042 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 1043 EXPECT_CALL(*this, executeUserClearFailRecords(testing::StrEq(username))) 1044 .WillOnce(testing::Throw( 1045 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())) 1046 .WillOnce(testing::DoDefault()); 1047 1048 EXPECT_THROW( 1049 deleteUser(username), 1050 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1051 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 1052 } 1053 1054 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid) 1055 { 1056 EXPECT_THROW( 1057 throwForInvalidPrivilege("whatever"), 1058 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1059 } 1060 1061 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid) 1062 { 1063 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-admin")); 1064 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-operator")); 1065 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-user")); 1066 } 1067 1068 TEST_F(UserMgrInTest, ThrowForInvalidGroupsThrowsWhenGroupIsInvalid) 1069 { 1070 EXPECT_THROW( 1071 throwForInvalidGroups({"whatever"}), 1072 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1073 EXPECT_THROW( 1074 throwForInvalidGroups({"web"}), 1075 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1076 } 1077 1078 TEST_F(UserMgrInTest, ThrowForInvalidGroupsNoThrowWhenGroupIsValid) 1079 { 1080 EXPECT_NO_THROW(throwForInvalidGroups({"ipmi"})); 1081 EXPECT_NO_THROW(throwForInvalidGroups({"ssh"})); 1082 EXPECT_NO_THROW(throwForInvalidGroups({"redfish"})); 1083 EXPECT_NO_THROW(throwForInvalidGroups({"hostconsole"})); 1084 } 1085 1086 TEST_F(UserMgrInTest, RenameUserOnSuccess) 1087 { 1088 std::string username = "user001"; 1089 EXPECT_NO_THROW( 1090 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 1091 std::string newUsername = "user002"; 1092 1093 EXPECT_NO_THROW(UserMgr::renameUser(username, newUsername)); 1094 1095 // old username doesn't exist 1096 EXPECT_THROW(getUserInfo(username), 1097 sdbusplus::xyz::openbmc_project::User::Common::Error:: 1098 UserNameDoesNotExist); 1099 1100 UserInfoMap userInfo = getUserInfo(newUsername); 1101 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user"); 1102 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]), 1103 testing::UnorderedElementsAre("redfish", "ssh")); 1104 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 1105 1106 EXPECT_NO_THROW(UserMgr::deleteUser(newUsername)); 1107 } 1108 1109 TEST_F(UserMgrInTest, RenameUserThrowsInternalFailureIfExecuteUserModifyFails) 1110 { 1111 std::string username = "user001"; 1112 EXPECT_NO_THROW( 1113 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 1114 std::string newUsername = "user002"; 1115 1116 EXPECT_CALL(*this, executeUserRename(testing::StrEq(username), 1117 testing::StrEq(newUsername))) 1118 .WillOnce(testing::Throw( 1119 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())); 1120 EXPECT_THROW( 1121 UserMgr::renameUser(username, newUsername), 1122 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1123 1124 // The original user is unchanged 1125 UserInfoMap userInfo = getUserInfo(username); 1126 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user"); 1127 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]), 1128 testing::UnorderedElementsAre("redfish", "ssh")); 1129 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 1130 1131 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 1132 } 1133 1134 TEST_F(UserMgrInTest, DefaultUserModifyFailedWithInternalFailure) 1135 { 1136 EXPECT_THROW( 1137 UserMgr::executeUserRename("user0", "user1"), 1138 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1139 EXPECT_THROW( 1140 UserMgr::executeUserModify("user0", "ssh", true), 1141 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1142 } 1143 1144 TEST_F(UserMgrInTest, UpdateGroupsAndPrivOnSuccess) 1145 { 1146 std::string username = "user001"; 1147 EXPECT_NO_THROW( 1148 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 1149 EXPECT_NO_THROW( 1150 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin")); 1151 UserInfoMap userInfo = getUserInfo(username); 1152 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-admin"); 1153 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]), 1154 testing::UnorderedElementsAre("ipmi", "ssh")); 1155 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 1156 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 1157 } 1158 1159 TEST_F(UserMgrInTest, 1160 UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail) 1161 { 1162 std::string username = "user001"; 1163 EXPECT_NO_THROW( 1164 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 1165 EXPECT_CALL(*this, executeUserModify(testing::StrEq(username), testing::_, 1166 testing::_)) 1167 .WillOnce(testing::Throw( 1168 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())); 1169 EXPECT_THROW( 1170 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"), 1171 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1172 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 1173 } 1174 1175 TEST_F(UserMgrInTest, MinPasswordLengthReturnsIfValueIsTheSame) 1176 { 1177 initializeAccountPolicy(); 1178 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 1179 UserMgr::minPasswordLength(8); 1180 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 1181 } 1182 1183 TEST_F(UserMgrInTest, 1184 MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument) 1185 { 1186 initializeAccountPolicy(); 1187 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 1188 EXPECT_THROW( 1189 UserMgr::minPasswordLength(minPasswdLength - 1), 1190 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1191 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 1192 } 1193 1194 TEST_F(UserMgrInTest, MinPasswordLengthOnSuccess) 1195 { 1196 initializeAccountPolicy(); 1197 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 1198 UserMgr::minPasswordLength(16); 1199 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 16); 1200 } 1201 1202 TEST_F(UserMgrInTest, MinPasswordLengthOnFailure) 1203 { 1204 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile)); 1205 initializeAccountPolicy(); 1206 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 1207 EXPECT_THROW( 1208 UserMgr::minPasswordLength(16), 1209 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1210 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 1211 } 1212 1213 TEST_F(UserMgrInTest, MinPasswordLengthGreaterThanMaxPasswordLength) 1214 { 1215 initializeAccountPolicy(); 1216 1217 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 1218 EXPECT_THROW( 1219 UserMgr::minPasswordLength(maxPasswdLength + 1), 1220 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1221 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 1222 } 1223 1224 TEST_F(UserMgrInTest, RememberOldPasswordTimesReturnsIfValueIsTheSame) 1225 { 1226 initializeAccountPolicy(); 1227 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0); 1228 UserMgr::rememberOldPasswordTimes(8); 1229 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8); 1230 UserMgr::rememberOldPasswordTimes(8); 1231 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8); 1232 } 1233 1234 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnSuccess) 1235 { 1236 initializeAccountPolicy(); 1237 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0); 1238 UserMgr::rememberOldPasswordTimes(16); 1239 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 16); 1240 } 1241 1242 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnFailure) 1243 { 1244 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile)); 1245 initializeAccountPolicy(); 1246 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0); 1247 EXPECT_THROW( 1248 UserMgr::rememberOldPasswordTimes(16), 1249 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1250 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0); 1251 } 1252 1253 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame) 1254 { 1255 initializeAccountPolicy(); 1256 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2); 1257 UserMgr::maxLoginAttemptBeforeLockout(2); 1258 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2); 1259 } 1260 1261 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnSuccess) 1262 { 1263 initializeAccountPolicy(); 1264 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2); 1265 UserMgr::maxLoginAttemptBeforeLockout(16); 1266 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 16); 1267 } 1268 1269 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnFailure) 1270 { 1271 initializeAccountPolicy(); 1272 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile)); 1273 EXPECT_THROW( 1274 UserMgr::maxLoginAttemptBeforeLockout(16), 1275 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1276 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2); 1277 } 1278 1279 TEST_F(UserMgrInTest, AccountUnlockTimeoutReturnsIfValueIsTheSame) 1280 { 1281 initializeAccountPolicy(); 1282 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3); 1283 UserMgr::accountUnlockTimeout(3); 1284 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3); 1285 } 1286 1287 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnSuccess) 1288 { 1289 initializeAccountPolicy(); 1290 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3); 1291 UserMgr::accountUnlockTimeout(16); 1292 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 16); 1293 } 1294 1295 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnFailure) 1296 { 1297 initializeAccountPolicy(); 1298 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile)); 1299 EXPECT_THROW( 1300 UserMgr::accountUnlockTimeout(16), 1301 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1302 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3); 1303 } 1304 1305 TEST_F(UserMgrInTest, UserEnableOnSuccess) 1306 { 1307 std::string username = "user001"; 1308 EXPECT_NO_THROW( 1309 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 1310 UserInfoMap userInfo = getUserInfo(username); 1311 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 1312 1313 EXPECT_NO_THROW(userEnable(username, false)); 1314 1315 userInfo = getUserInfo(username); 1316 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), false); 1317 1318 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 1319 } 1320 1321 TEST_F(UserMgrInTest, CreateDeleteUserSuccessForHostConsole) 1322 { 1323 std::string username = "user001"; 1324 EXPECT_NO_THROW( 1325 UserMgr::createUser(username, {"hostconsole"}, "priv-user", true)); 1326 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 1327 EXPECT_NO_THROW( 1328 UserMgr::createUser(username, {"hostconsole"}, "priv-admin", true)); 1329 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 1330 EXPECT_NO_THROW( 1331 UserMgr::createUser(username, {"hostconsole"}, "priv-operator", true)); 1332 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 1333 } 1334 1335 TEST_F(UserMgrInTest, UserEnableThrowsInternalFailureIfExecuteUserModifyFail) 1336 { 1337 std::string username = "user001"; 1338 EXPECT_NO_THROW( 1339 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 1340 UserInfoMap userInfo = getUserInfo(username); 1341 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 1342 1343 EXPECT_CALL(*this, executeUserModifyUserEnable(testing::StrEq(username), 1344 testing::Eq(false))) 1345 .WillOnce(testing::Throw( 1346 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())); 1347 EXPECT_THROW( 1348 userEnable(username, false), 1349 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1350 1351 userInfo = getUserInfo(username); 1352 // Stay unchanged 1353 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 1354 1355 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 1356 } 1357 1358 TEST_F( 1359 UserMgrInTest, 1360 UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero) 1361 { 1362 EXPECT_FALSE(userLockedForFailedAttempt("whatever")); 1363 } 1364 1365 TEST_F(UserMgrInTest, UserLockedForFailedAttemptZeroFailuresReturnsFalse) 1366 { 1367 std::string username = "user001"; 1368 initializeAccountPolicy(); 1369 // Example output from BMC 1370 // root:~# faillock --user root 1371 // root: 1372 // When Type Source Valid 1373 std::vector<std::string> output = {"whatever", 1374 "When Type Source Valid"}; 1375 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str()))) 1376 .WillOnce(testing::Return(output)); 1377 1378 EXPECT_FALSE(userLockedForFailedAttempt(username)); 1379 } 1380 1381 TEST_F(UserMgrInTest, UserLockedForFailedAttemptFailIfGetFailedAttemptFail) 1382 { 1383 std::string username = "user001"; 1384 initializeAccountPolicy(); 1385 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str()))) 1386 .WillOnce(testing::Throw( 1387 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())); 1388 1389 EXPECT_THROW( 1390 userLockedForFailedAttempt(username), 1391 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1392 } 1393 1394 TEST_F(UserMgrInTest, 1395 UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat) 1396 { 1397 std::string username = "user001"; 1398 initializeAccountPolicy(); 1399 1400 // Choose a date in the past. 1401 std::vector<std::string> output = {"whatever", 1402 "10/24/2002 00:00:00 type source V"}; 1403 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str()))) 1404 .WillOnce(testing::Return(output)); 1405 1406 EXPECT_THROW( 1407 userLockedForFailedAttempt(username), 1408 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1409 } 1410 1411 TEST_F(UserMgrInTest, 1412 UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut) 1413 { 1414 std::string username = "user001"; 1415 initializeAccountPolicy(); 1416 1417 // Choose a date in the past. 1418 std::vector<std::string> output = {"whatever", 1419 "2002-10-24 00:00:00 type source V"}; 1420 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str()))) 1421 .WillOnce(testing::Return(output)); 1422 1423 EXPECT_EQ(userLockedForFailedAttempt(username), false); 1424 } 1425 1426 TEST_F(UserMgrInTest, CheckAndThrowForDisallowedGroupCreationOnSuccess) 1427 { 1428 // Base Redfish Roles 1429 EXPECT_NO_THROW( 1430 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Administrator")); 1431 EXPECT_NO_THROW( 1432 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Operator")); 1433 EXPECT_NO_THROW( 1434 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_ReadOnly")); 1435 // Base Redfish Privileges 1436 EXPECT_NO_THROW( 1437 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_Login")); 1438 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation( 1439 "openbmc_rfp_ConfigureManager")); 1440 EXPECT_NO_THROW( 1441 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureUsers")); 1442 EXPECT_NO_THROW( 1443 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureSelf")); 1444 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation( 1445 "openbmc_rfp_ConfigureComponents")); 1446 // OEM Redfish Roles 1447 EXPECT_NO_THROW( 1448 checkAndThrowForDisallowedGroupCreation("openbmc_orfr_PowerService")); 1449 // OEM Redfish Privileges 1450 EXPECT_NO_THROW( 1451 checkAndThrowForDisallowedGroupCreation("openbmc_orfp_PowerService")); 1452 } 1453 1454 TEST_F(UserMgrInTest, 1455 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong) 1456 { 1457 std::string groupName(maxSystemGroupNameLength + 1, 'A'); 1458 EXPECT_THROW( 1459 checkAndThrowForDisallowedGroupCreation(groupName), 1460 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1461 } 1462 1463 TEST_F( 1464 UserMgrInTest, 1465 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters) 1466 { 1467 EXPECT_THROW( 1468 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_?owerService"), 1469 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1470 EXPECT_THROW( 1471 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_-owerService"), 1472 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1473 } 1474 1475 TEST_F( 1476 UserMgrInTest, 1477 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix) 1478 { 1479 EXPECT_THROW( 1480 checkAndThrowForDisallowedGroupCreation("google_rfp_"), 1481 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1482 EXPECT_THROW( 1483 checkAndThrowForDisallowedGroupCreation("com_rfp_"), 1484 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1485 } 1486 1487 TEST_F(UserMgrInTest, CheckAndThrowForMaxGroupCountOnSuccess) 1488 { 1489 constexpr size_t predefGroupCount = 4; 1490 1491 EXPECT_THAT(allGroups().size(), predefGroupCount); 1492 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i) 1493 { 1494 std::string groupName = "openbmc_rfr_role"; 1495 groupName += std::to_string(i); 1496 EXPECT_NO_THROW(createGroup(groupName)); 1497 } 1498 EXPECT_THROW( 1499 createGroup("openbmc_rfr_AnotherRole"), 1500 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource); 1501 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i) 1502 { 1503 std::string groupName = "openbmc_rfr_role"; 1504 groupName += std::to_string(i); 1505 EXPECT_NO_THROW(deleteGroup(groupName)); 1506 } 1507 } 1508 1509 TEST_F(UserMgrInTest, CheckAndThrowForGroupExist) 1510 { 1511 std::string groupName = "openbmc_rfr_role"; 1512 EXPECT_NO_THROW(createGroup(groupName)); 1513 EXPECT_THROW( 1514 createGroup(groupName), 1515 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists); 1516 EXPECT_NO_THROW(deleteGroup(groupName)); 1517 } 1518 1519 TEST_F(UserMgrInTest, ByDefaultAllGroupsArePredefinedGroups) 1520 { 1521 EXPECT_THAT(allGroups(), testing::UnorderedElementsAre( 1522 "redfish", "ipmi", "ssh", "hostconsole")); 1523 } 1524 1525 TEST_F(UserMgrInTest, AddGroupThrowsIfPreDefinedGroupAdd) 1526 { 1527 EXPECT_THROW( 1528 createGroup("ipmi"), 1529 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists); 1530 EXPECT_THROW( 1531 createGroup("redfish"), 1532 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists); 1533 EXPECT_THROW( 1534 createGroup("ssh"), 1535 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists); 1536 EXPECT_THROW( 1537 createGroup("hostconsole"), 1538 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists); 1539 } 1540 1541 TEST_F(UserMgrInTest, DeleteGroupThrowsIfGroupIsNotAllowedToChange) 1542 { 1543 EXPECT_THROW( 1544 deleteGroup("ipmi"), 1545 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1546 EXPECT_THROW( 1547 deleteGroup("redfish"), 1548 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1549 EXPECT_THROW( 1550 deleteGroup("ssh"), 1551 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1552 EXPECT_THROW( 1553 deleteGroup("hostconsole"), 1554 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 1555 } 1556 1557 TEST_F(UserMgrInTest, 1558 CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails) 1559 { 1560 EXPECT_CALL(*this, executeGroupCreation) 1561 .WillOnce(testing::Throw( 1562 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())); 1563 EXPECT_THROW( 1564 createGroup("openbmc_rfr_role1"), 1565 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1566 } 1567 1568 TEST_F(UserMgrInTest, 1569 DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails) 1570 { 1571 std::string groupName = "openbmc_rfr_role1"; 1572 EXPECT_NO_THROW(UserMgr::createGroup(groupName)); 1573 EXPECT_CALL(*this, executeGroupDeletion(testing::StrEq(groupName))) 1574 .WillOnce(testing::Throw( 1575 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())) 1576 .WillOnce(testing::DoDefault()); 1577 1578 EXPECT_THROW( 1579 deleteGroup(groupName), 1580 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1581 EXPECT_NO_THROW(UserMgr::deleteGroup(groupName)); 1582 } 1583 1584 TEST_F(UserMgrInTest, CheckAndThrowForGroupNotExist) 1585 { 1586 EXPECT_THROW(deleteGroup("whatever"), 1587 sdbusplus::xyz::openbmc_project::User::Common::Error:: 1588 GroupNameDoesNotExist); 1589 } 1590 1591 TEST(ReadAllGroupsOnSystemTest, OnlyReturnsPredefinedGroups) 1592 { 1593 EXPECT_THAT( 1594 UserMgr::readAllGroupsOnSystem(), 1595 testing::UnorderedElementsAre("redfish", "ipmi", "ssh", "hostconsole")); 1596 } 1597 1598 TEST_F(UserMgrInTest, CreateUser2) 1599 { 1600 const std::string userName = getNextUserName(); 1601 const bool enabled = true; 1602 1603 // last password change date is today 1604 // old maximum password age is 5000 1605 // set password expiration in 3 days 1606 PasswordExpirationInfo info; 1607 fillPasswordExpiration(0, 5000, 3, info); 1608 1609 setUpCreateUser(userName, enabled); 1610 setUpSetPasswordExpiration(userName, info); 1611 setUpGetUserInfo(userName, enabled); 1612 setUpDeleteUser(userName); 1613 1614 std::vector<std::string> groups = {"redfish", "ssh"}; 1615 1616 UserCreateMap props; 1617 props[UserProperty::GroupNames] = std::move(groups); 1618 props[UserProperty::Privilege] = "priv-user"; 1619 props[UserProperty::Enabled] = enabled; 1620 props[UserProperty::PasswordExpiration] = info.passwordExpiration; 1621 1622 EXPECT_NO_THROW(UserMgr::createUser2(userName, props)); 1623 1624 UserInfoMap userInfo = getUserInfo(userName); 1625 EXPECT_EQ(std::get<PasswordExpiration>(userInfo["PasswordExpiration"]), 1626 info.passwordExpiration); 1627 1628 EXPECT_NO_THROW(UserMgr::deleteUser(userName)); 1629 } 1630 1631 TEST_F(UserMgrInTest, CreateUser2WithoutPasswordExpiration) 1632 { 1633 const std::string userName = getNextUserName(); 1634 const bool enabled = true; 1635 1636 setUpCreateUser(userName, enabled); 1637 setUpGetUserInfo(userName, enabled); 1638 setUpDeleteUser(userName); 1639 1640 std::vector<std::string> groups = {"redfish", "ssh"}; 1641 1642 UserCreateMap props; 1643 props[UserProperty::GroupNames] = std::move(groups); 1644 props[UserProperty::Privilege] = "priv-user"; 1645 props[UserProperty::Enabled] = enabled; 1646 1647 EXPECT_NO_THROW(UserMgr::createUser2(userName, props)); 1648 1649 UserInfoMap userInfo = getUserInfo(userName); 1650 EXPECT_EQ(std::get<PasswordExpiration>(userInfo["PasswordExpiration"]), 1651 getDefaultPasswordExpiration()); 1652 1653 EXPECT_NO_THROW(UserMgr::deleteUser(userName)); 1654 } 1655 1656 TEST_F(UserMgrInTest, CreateUser2PasswordExpirationNotSet) 1657 { 1658 using namespace std::chrono; 1659 1660 const std::string userName = getNextUserName(); 1661 const bool enabled = true; 1662 1663 setUpCreateUser(userName, enabled); 1664 1665 EXPECT_CALL(*this, getShadowData(testing::StrEq(userName), _)).Times(0); 1666 1667 EXPECT_CALL(*this, 1668 executeUserPasswordExpiration(testing::StrEq(userName), _, _)) 1669 .Times(0); 1670 1671 setUpGetUserInfo(userName, enabled); 1672 setUpDeleteUser(userName); 1673 1674 constexpr auto passwordExpiration = getDefaultPasswordExpiration(); 1675 1676 std::vector<std::string> groups = {"redfish", "ssh"}; 1677 1678 UserCreateMap props; 1679 props[UserProperty::GroupNames] = std::move(groups); 1680 props[UserProperty::Privilege] = "priv-user"; 1681 props[UserProperty::Enabled] = enabled; 1682 props[UserProperty::PasswordExpiration] = passwordExpiration; 1683 1684 EXPECT_NO_THROW(UserMgr::createUser2(userName, props)); 1685 1686 UserInfoMap userInfo = getUserInfo(userName); 1687 EXPECT_EQ(std::get<PasswordExpiration>(userInfo["PasswordExpiration"]), 1688 passwordExpiration); 1689 1690 EXPECT_NO_THROW(UserMgr::deleteUser(userName)); 1691 } 1692 1693 TEST_F(UserMgrInTest, CreateUser2UnexpiringPassword) 1694 { 1695 using namespace std::chrono; 1696 1697 const std::string userName = getNextUserName(); 1698 const bool enabled = true; 1699 1700 // last password change date is today 1701 const long lastChangeDate = 1702 duration_cast<days>(seconds{getEpochTimeNow()}).count(); 1703 1704 // password age is 1705 constexpr long passwordAge = 99999; 1706 1707 // make password not to expire 1708 const uint64_t passwordExpiration = getUnexpiringPasswordTime(); 1709 1710 setUpCreateUser(userName, enabled); 1711 1712 EXPECT_CALL(*this, getShadowData(testing::StrEq(userName), _)) 1713 .WillOnce(Invoke([&lastChangeDate](auto, struct spwd& spwd) { 1714 spwd.sp_lstchg = lastChangeDate; 1715 spwd.sp_max = passwordAge; 1716 })); 1717 1718 EXPECT_CALL(*this, executeUserPasswordExpiration( 1719 testing::StrEq(userName), lastChangeDate, 1720 getUnexpiringPasswordAge())) 1721 .Times(1); 1722 1723 setUpGetUserInfo(userName, enabled); 1724 setUpDeleteUser(userName); 1725 1726 std::vector<std::string> groups = {"redfish", "ssh"}; 1727 1728 UserCreateMap props; 1729 props[UserProperty::GroupNames] = std::move(groups); 1730 props[UserProperty::Privilege] = "priv-user"; 1731 props[UserProperty::Enabled] = enabled; 1732 props[UserProperty::PasswordExpiration] = passwordExpiration; 1733 1734 EXPECT_NO_THROW(UserMgr::createUser2(userName, props)); 1735 1736 UserInfoMap userInfo = getUserInfo(userName); 1737 EXPECT_EQ(std::get<PasswordExpiration>(userInfo["PasswordExpiration"]), 1738 passwordExpiration); 1739 1740 EXPECT_NO_THROW(UserMgr::deleteUser(userName)); 1741 } 1742 1743 TEST_F(UserMgrInTest, CreateUser2Rename) 1744 { 1745 const std::string userName = getNextUserName(); 1746 const std::string newUserName = getNextUserName(); 1747 const bool enabled = true; 1748 1749 // last password change date is 7 days ago 1750 // old maximum password age is 15 1751 // set password expiration in 5 days 1752 PasswordExpirationInfo info; 1753 fillPasswordExpiration(7, 15, 5, info); 1754 1755 setUpCreateUser(userName, enabled); 1756 setUpSetPasswordExpiration(userName, info); 1757 setUpGetUserInfo(newUserName, enabled); 1758 setUpDeleteUser(newUserName); 1759 1760 EXPECT_CALL(*this, isUserEnabled(userName)) 1761 .WillOnce(testing::Return(enabled)); 1762 1763 EXPECT_CALL(*this, executeUserRename(testing::StrEq(userName), 1764 testing::StrEq(newUserName))) 1765 .Times(1); 1766 1767 std::vector<std::string> groups = {"redfish", "ssh"}; 1768 1769 UserCreateMap props; 1770 props[UserProperty::GroupNames] = std::move(groups); 1771 props[UserProperty::Privilege] = "priv-user"; 1772 props[UserProperty::Enabled] = enabled; 1773 props[UserProperty::PasswordExpiration] = info.passwordExpiration; 1774 1775 EXPECT_NO_THROW(UserMgr::createUser2(userName, props)); 1776 1777 EXPECT_NO_THROW(UserMgr::renameUser(userName, newUserName)); 1778 1779 UserInfoMap userInfo = getUserInfo(newUserName); 1780 EXPECT_EQ(std::get<PasswordExpiration>(userInfo["PasswordExpiration"]), 1781 info.passwordExpiration); 1782 1783 EXPECT_NO_THROW(UserMgr::deleteUser(newUserName)); 1784 } 1785 1786 TEST_F(UserMgrInTest, CreateUser2PasswordExpirationFail) 1787 { 1788 using namespace std::chrono; 1789 1790 const std::string userName = getNextUserName(); 1791 const bool enabled = true; 1792 1793 setUpCreateUser(userName, enabled); 1794 1795 EXPECT_CALL(*this, getShadowData(testing::StrEq(userName), _)) 1796 .WillOnce([]() { 1797 throw sdbusplus::xyz::openbmc_project::Common::Error:: 1798 InternalFailure(); 1799 }); 1800 1801 setUpDeleteUser(userName); 1802 1803 std::vector<std::string> groups = {"redfish", "ssh"}; 1804 1805 UserCreateMap props; 1806 props[UserProperty::GroupNames] = std::move(groups); 1807 props[UserProperty::Privilege] = "priv-user"; 1808 props[UserProperty::Enabled] = enabled; 1809 props[UserProperty::PasswordExpiration] = (uint64_t)1; 1810 1811 EXPECT_THROW( 1812 UserMgr::createUser2(userName, props), 1813 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 1814 1815 EXPECT_THROW(getUserInfo(userName), 1816 sdbusplus::xyz::openbmc_project::User::Common::Error:: 1817 UserNameDoesNotExist); 1818 } 1819 1820 } // namespace user 1821 } // namespace phosphor 1822