1 #include "mock_user_mgr.hpp" 2 #include "user_mgr.hpp" 3 4 #include <sdbusplus/test/sdbus_mock.hpp> 5 #include <xyz/openbmc_project/Common/error.hpp> 6 #include <xyz/openbmc_project/User/Common/error.hpp> 7 8 #include <exception> 9 #include <filesystem> 10 #include <fstream> 11 12 #include <gtest/gtest.h> 13 14 namespace phosphor 15 { 16 namespace user 17 { 18 19 using ::testing::Return; 20 21 using InternalFailure = 22 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 23 24 class TestUserMgr : public testing::Test 25 { 26 public: 27 sdbusplus::SdBusMock sdBusMock; 28 sdbusplus::bus_t bus; 29 MockManager mockManager; 30 31 TestUserMgr() : 32 bus(sdbusplus::get_mocked_new(&sdBusMock)), mockManager(bus, objpath) 33 {} 34 35 void createLocalUser(const std::string& userName, 36 std::vector<std::string> groupNames, 37 const std::string& priv, bool enabled) 38 { 39 sdbusplus::message::object_path tempObjPath(usersObjPath); 40 tempObjPath /= userName; 41 std::string userObj(tempObjPath); 42 mockManager.usersList.emplace( 43 userName, std::make_unique<phosphor::user::Users>( 44 mockManager.bus, userObj.c_str(), groupNames, priv, 45 enabled, mockManager)); 46 } 47 48 DbusUserObj createPrivilegeMapperDbusObject(void) 49 { 50 DbusUserObj object; 51 DbusUserObjValue objValue; 52 53 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap"); 54 DbusUserPropVariant enabled(true); 55 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)}; 56 std::string intf = "xyz.openbmc_project.Object.Enable"; 57 objValue.emplace(intf, property); 58 object.emplace(objPath, objValue); 59 60 DbusUserObjPath objectPath( 61 "/xyz/openbmc_project/user/ldap/openldap/role_map/1"); 62 std::string group = "ldapGroup"; 63 std::string priv = "priv-admin"; 64 DbusUserObjProperties properties = {std::make_pair("GroupName", group), 65 std::make_pair("Privilege", priv)}; 66 std::string interface = "xyz.openbmc_project.User.PrivilegeMapperEntry"; 67 68 objValue.emplace(interface, properties); 69 object.emplace(objectPath, objValue); 70 71 return object; 72 } 73 74 DbusUserObj createLdapConfigObjectWithoutPrivilegeMapper(void) 75 { 76 DbusUserObj object; 77 DbusUserObjValue objValue; 78 79 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap"); 80 DbusUserPropVariant enabled(true); 81 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)}; 82 std::string intf = "xyz.openbmc_project.Object.Enable"; 83 objValue.emplace(intf, property); 84 object.emplace(objPath, objValue); 85 return object; 86 } 87 }; 88 89 TEST_F(TestUserMgr, ldapEntryDoesNotExist) 90 { 91 std::string userName = "user"; 92 UserInfoMap userInfo; 93 94 EXPECT_CALL(mockManager, getLdapGroupName(userName)) 95 .WillRepeatedly(Return("")); 96 EXPECT_THROW(userInfo = mockManager.getUserInfo(userName), InternalFailure); 97 } 98 99 TEST_F(TestUserMgr, localUser) 100 { 101 UserInfoMap userInfo; 102 std::string userName = "testUser"; 103 std::string privilege = "priv-admin"; 104 std::vector<std::string> groups{"testGroup"}; 105 // Create local user 106 createLocalUser(userName, groups, privilege, true); 107 EXPECT_CALL(mockManager, userLockedForFailedAttempt(userName)).Times(1); 108 userInfo = mockManager.getUserInfo(userName); 109 110 EXPECT_EQ(privilege, std::get<std::string>(userInfo["UserPrivilege"])); 111 EXPECT_EQ(groups, 112 std::get<std::vector<std::string>>(userInfo["UserGroups"])); 113 EXPECT_EQ(true, std::get<bool>(userInfo["UserEnabled"])); 114 EXPECT_EQ(false, std::get<bool>(userInfo["UserLockedForFailedAttempt"])); 115 EXPECT_EQ(false, std::get<bool>(userInfo["UserPasswordExpired"])); 116 EXPECT_EQ(false, std::get<bool>(userInfo["RemoteUser"])); 117 } 118 119 TEST_F(TestUserMgr, ldapUserWithPrivMapper) 120 { 121 UserInfoMap userInfo; 122 std::string userName = "ldapUser"; 123 std::string ldapGroup = "ldapGroup"; 124 125 EXPECT_CALL(mockManager, getLdapGroupName(userName)) 126 .WillRepeatedly(Return(ldapGroup)); 127 // Create privilege mapper dbus object 128 DbusUserObj object = createPrivilegeMapperDbusObject(); 129 EXPECT_CALL(mockManager, getPrivilegeMapperObject()) 130 .WillRepeatedly(Return(object)); 131 userInfo = mockManager.getUserInfo(userName); 132 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"])); 133 EXPECT_EQ("priv-admin", std::get<std::string>(userInfo["UserPrivilege"])); 134 } 135 136 TEST_F(TestUserMgr, ldapUserWithoutPrivMapper) 137 { 138 UserInfoMap userInfo; 139 std::string userName = "ldapUser"; 140 std::string ldapGroup = "ldapGroup"; 141 142 EXPECT_CALL(mockManager, getLdapGroupName(userName)) 143 .WillRepeatedly(Return(ldapGroup)); 144 // Create LDAP config object without privilege mapper 145 DbusUserObj object = createLdapConfigObjectWithoutPrivilegeMapper(); 146 EXPECT_CALL(mockManager, getPrivilegeMapperObject()) 147 .WillRepeatedly(Return(object)); 148 userInfo = mockManager.getUserInfo(userName); 149 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"])); 150 EXPECT_EQ("", std::get<std::string>(userInfo["UserPrivilege"])); 151 } 152 153 TEST(GetCSVFromVector, EmptyVectorReturnsEmptyString) 154 { 155 EXPECT_EQ(getCSVFromVector({}), ""); 156 } 157 158 TEST(GetCSVFromVector, ElementsAreJoinedByComma) 159 { 160 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123"}), "123"); 161 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123", "456"}), 162 "123,456"); 163 } 164 165 TEST(RemoveStringFromCSV, WithoutDeleteStringReturnsFalse) 166 { 167 std::string expected = "whatever,https"; 168 std::string str = expected; 169 EXPECT_FALSE(removeStringFromCSV(str, "ssh")); 170 EXPECT_EQ(str, expected); 171 172 std::string empty; 173 EXPECT_FALSE(removeStringFromCSV(empty, "ssh")); 174 } 175 176 TEST(RemoveStringFromCSV, WithDeleteStringReturnsTrue) 177 { 178 std::string expected = "whatever"; 179 std::string str = "whatever,https"; 180 EXPECT_TRUE(removeStringFromCSV(str, "https")); 181 EXPECT_EQ(str, expected); 182 183 str = "https"; 184 EXPECT_TRUE(removeStringFromCSV(str, "https")); 185 EXPECT_EQ(str, ""); 186 } 187 188 namespace 189 { 190 inline constexpr const char* objectRootInTest = "/xyz/openbmc_project/user"; 191 192 // Fake config; referenced config on real BMC 193 inline constexpr const char* rawConfig = R"( 194 # 195 # /etc/pam.d/common-password - password-related modules common to all services 196 # 197 # This file is included from other service-specific PAM config files, 198 # and should contain a list of modules that define the services to be 199 # used to change user passwords. The default is pam_unix. 200 201 # Explanation of pam_unix options: 202 # 203 # The "sha512" option enables salted SHA512 passwords. Without this option, 204 # the default is Unix crypt. Prior releases used the option "md5". 205 # 206 # The "obscure" option replaces the old `OBSCURE_CHECKS_ENAB' option in 207 # login.defs. 208 # 209 # See the pam_unix manpage for other options. 210 211 # here are the per-package modules (the "Primary" block) 212 password [success=ok default=die] pam_tally2.so debug enforce_for_root reject_username minlen=8 difok=0 lcredit=0 ocredit=0 dcredit=0 ucredit=0 deny=2 unlock_time=3 #some comments 213 password [success=ok default=die] pam_cracklib.so debug enforce_for_root reject_username minlen=8 difok=0 lcredit=0 ocredit=0 dcredit=0 ucredit=0 #some comments 214 password [success=ok default=die] pam_ipmicheck.so spec_grp_name=ipmi use_authtok 215 password [success=ok ignore=ignore default=die] pam_pwhistory.so debug enforce_for_root remember=0 use_authtok 216 password [success=ok default=die] pam_unix.so sha512 use_authtok 217 password [success=1 default=die] pam_ipmisave.so spec_grp_name=ipmi spec_pass_file=/etc/ipmi_pass key_file=/etc/key_file 218 # here's the fallback if no module succeeds 219 password requisite pam_deny.so 220 # prime the stack with a positive return value if there isn't one already; 221 # this avoids us returning an error just because nothing sets a success code 222 # since the modules above will each just jump around 223 password required pam_permit.so 224 # and here are more per-package modules (the "Additional" block) 225 )"; 226 } // namespace 227 228 void dumpStringToFile(const std::string& str, const std::string& filePath) 229 { 230 std::ofstream outputFileStream; 231 232 outputFileStream.exceptions(std::ofstream::failbit | std::ofstream::badbit | 233 std::ofstream::eofbit); 234 235 outputFileStream.open(filePath, std::ios::out); 236 outputFileStream << str << "\n" << std::flush; 237 outputFileStream.close(); 238 } 239 240 void removeFile(const std::string& filePath) 241 { 242 std::filesystem::remove(filePath); 243 } 244 245 class UserMgrInTest : public testing::Test, public UserMgr 246 { 247 public: 248 UserMgrInTest() : UserMgr(busInTest, objectRootInTest) 249 { 250 tempPamConfigFile = "/tmp/test-data-XXXXXX"; 251 mktemp(tempPamConfigFile.data()); 252 EXPECT_NO_THROW(dumpStringToFile(rawConfig, tempPamConfigFile)); 253 // Set config files to test files 254 pamPasswdConfigFile = tempPamConfigFile; 255 pamAuthConfigFile = tempPamConfigFile; 256 257 ON_CALL(*this, executeUserAdd).WillByDefault(testing::Return()); 258 259 ON_CALL(*this, executeUserDelete).WillByDefault(testing::Return()); 260 261 ON_CALL(*this, getIpmiUsersCount).WillByDefault(testing::Return(0)); 262 263 ON_CALL(*this, executeUserRename).WillByDefault(testing::Return()); 264 265 ON_CALL(*this, executeUserModify(testing::_, testing::_, testing::_)) 266 .WillByDefault(testing::Return()); 267 268 ON_CALL(*this, executeUserModifyUserEnable) 269 .WillByDefault(testing::Return()); 270 } 271 272 ~UserMgrInTest() override 273 { 274 EXPECT_NO_THROW(removeFile(tempPamConfigFile)); 275 } 276 277 MOCK_METHOD(void, executeUserAdd, (const char*, const char*, bool, bool), 278 (override)); 279 280 MOCK_METHOD(void, executeUserDelete, (const char*), (override)); 281 282 MOCK_METHOD(size_t, getIpmiUsersCount, (), (override)); 283 284 MOCK_METHOD(void, executeUserRename, (const char*, const char*), 285 (override)); 286 287 MOCK_METHOD(void, executeUserModify, (const char*, const char*, bool), 288 (override)); 289 290 MOCK_METHOD(void, executeUserModifyUserEnable, (const char*, bool), 291 (override)); 292 293 MOCK_METHOD(std::vector<std::string>, getFailedAttempt, (const char*), 294 (override)); 295 296 protected: 297 static sdbusplus::bus_t busInTest; 298 std::string tempPamConfigFile; 299 }; 300 301 sdbusplus::bus_t UserMgrInTest::busInTest = sdbusplus::bus::new_default(); 302 303 TEST_F(UserMgrInTest, GetPamModuleArgValueOnSuccess) 304 { 305 std::string minLen; 306 EXPECT_EQ(getPamModuleArgValue("pam_tally2.so", "minlen", minLen), 0); 307 EXPECT_EQ(minLen, "8"); 308 EXPECT_EQ(getPamModuleArgValue("pam_cracklib.so", "minlen", minLen), 0); 309 EXPECT_EQ(minLen, "8"); 310 } 311 312 TEST_F(UserMgrInTest, SetPamModuleArgValueOnSuccess) 313 { 314 EXPECT_EQ(setPamModuleArgValue("pam_cracklib.so", "minlen", "16"), 0); 315 EXPECT_EQ(setPamModuleArgValue("pam_tally2.so", "minlen", "16"), 0); 316 std::string minLen; 317 EXPECT_EQ(getPamModuleArgValue("pam_tally2.so", "minlen", minLen), 0); 318 EXPECT_EQ(minLen, "16"); 319 EXPECT_EQ(getPamModuleArgValue("pam_cracklib.so", "minlen", minLen), 0); 320 EXPECT_EQ(minLen, "16"); 321 } 322 323 TEST_F(UserMgrInTest, GetPamModuleArgValueOnFailure) 324 { 325 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile)); 326 std::string minLen; 327 EXPECT_EQ(getPamModuleArgValue("pam_tally2.so", "minlen", minLen), -1); 328 EXPECT_EQ(getPamModuleArgValue("pam_cracklib.so", "minlen", minLen), -1); 329 330 EXPECT_NO_THROW(removeFile(tempPamConfigFile)); 331 EXPECT_EQ(getPamModuleArgValue("pam_tally2.so", "minlen", minLen), -1); 332 EXPECT_EQ(getPamModuleArgValue("pam_cracklib.so", "minlen", minLen), -1); 333 } 334 335 TEST_F(UserMgrInTest, SetPamModuleArgValueOnFailure) 336 { 337 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile)); 338 EXPECT_EQ(setPamModuleArgValue("pam_cracklib.so", "minlen", "16"), -1); 339 EXPECT_EQ(setPamModuleArgValue("pam_tally2.so", "minlen", "16"), -1); 340 341 EXPECT_NO_THROW(removeFile(tempPamConfigFile)); 342 EXPECT_EQ(setPamModuleArgValue("pam_cracklib.so", "minlen", "16"), -1); 343 EXPECT_EQ(setPamModuleArgValue("pam_tally2.so", "minlen", "16"), -1); 344 } 345 346 TEST_F(UserMgrInTest, IsUserExistEmptyInputThrowsError) 347 { 348 EXPECT_THROW( 349 isUserExist(""), 350 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 351 } 352 353 TEST_F(UserMgrInTest, ThrowForUserDoesNotExistThrowsError) 354 { 355 EXPECT_THROW(throwForUserDoesNotExist("whatever"), 356 sdbusplus::xyz::openbmc_project::User::Common::Error:: 357 UserNameDoesNotExist); 358 } 359 360 TEST_F(UserMgrInTest, ThrowForUserExistsThrowsError) 361 { 362 EXPECT_THROW( 363 throwForUserExists("root"), 364 sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameExists); 365 } 366 367 TEST_F( 368 UserMgrInTest, 369 ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail) 370 { 371 std::string strWith17Chars(17, 'A'); 372 EXPECT_THROW(throwForUserNameConstraints(strWith17Chars, {"ipmi"}), 373 sdbusplus::xyz::openbmc_project::User::Common::Error:: 374 UserNameGroupFail); 375 } 376 377 TEST_F( 378 UserMgrInTest, 379 ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument) 380 { 381 std::string strWith31Chars(31, 'A'); 382 EXPECT_THROW( 383 throwForUserNameConstraints(strWith31Chars, {}), 384 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 385 } 386 387 TEST_F(UserMgrInTest, 388 ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument) 389 { 390 std::string startWithNumber = "0ABC"; 391 EXPECT_THROW( 392 throwForUserNameConstraints(startWithNumber, {"ipmi"}), 393 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 394 } 395 396 TEST_F(UserMgrInTest, UserAddNotRootFailedWithInternalFailure) 397 { 398 EXPECT_THROW( 399 UserMgr::executeUserAdd("user0", "ipmi,ssh", true, true), 400 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 401 } 402 403 TEST_F(UserMgrInTest, UserDeleteNotRootFailedWithInternalFailure) 404 { 405 EXPECT_THROW( 406 UserMgr::executeUserDelete("user0"), 407 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 408 } 409 410 TEST_F(UserMgrInTest, 411 ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit) 412 { 413 EXPECT_CALL(*this, getIpmiUsersCount()).WillOnce(Return(ipmiMaxUsers)); 414 EXPECT_THROW( 415 throwForMaxGrpUserCount({"ipmi"}), 416 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource); 417 } 418 419 TEST_F(UserMgrInTest, CreateUserThrowsInternalFailureWhenExecuteUserAddFails) 420 { 421 EXPECT_CALL(*this, executeUserAdd) 422 .WillOnce(testing::Throw( 423 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())); 424 EXPECT_THROW( 425 createUser("whatever", {"redfish"}, "", true), 426 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 427 } 428 429 TEST_F(UserMgrInTest, DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails) 430 { 431 std::string username = "user"; 432 EXPECT_NO_THROW( 433 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 434 EXPECT_CALL(*this, executeUserDelete(testing::StrEq(username))) 435 .WillOnce(testing::Throw( 436 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())) 437 .WillOnce(testing::DoDefault()); 438 439 EXPECT_THROW( 440 deleteUser(username), 441 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 442 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 443 } 444 445 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid) 446 { 447 EXPECT_THROW( 448 throwForInvalidPrivilege("whatever"), 449 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 450 } 451 452 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid) 453 { 454 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-admin")); 455 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-operator")); 456 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-user")); 457 } 458 459 TEST_F(UserMgrInTest, ThrowForInvalidGroupsThrowsWhenGroupIsInvalid) 460 { 461 EXPECT_THROW( 462 throwForInvalidGroups({"whatever"}), 463 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 464 } 465 466 TEST_F(UserMgrInTest, ThrowForInvalidGroupsNoThrowWhenGroupIsValid) 467 { 468 EXPECT_NO_THROW(throwForInvalidGroups({"ipmi"})); 469 EXPECT_NO_THROW(throwForInvalidGroups({"ssh"})); 470 EXPECT_NO_THROW(throwForInvalidGroups({"redfish"})); 471 EXPECT_NO_THROW(throwForInvalidGroups({"web"})); 472 } 473 474 TEST_F(UserMgrInTest, RenameUserOnSuccess) 475 { 476 std::string username = "user001"; 477 EXPECT_NO_THROW( 478 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 479 std::string newUsername = "user002"; 480 481 EXPECT_NO_THROW(UserMgr::renameUser(username, newUsername)); 482 483 // old username doesn't exist 484 EXPECT_THROW(getUserInfo(username), 485 sdbusplus::xyz::openbmc_project::User::Common::Error:: 486 UserNameDoesNotExist); 487 488 UserInfoMap userInfo = getUserInfo(newUsername); 489 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user"); 490 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]), 491 testing::UnorderedElementsAre("redfish", "ssh")); 492 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 493 494 EXPECT_NO_THROW(UserMgr::deleteUser(newUsername)); 495 } 496 497 TEST_F(UserMgrInTest, RenameUserThrowsInternalFailureIfExecuteUserModifyFails) 498 { 499 std::string username = "user001"; 500 EXPECT_NO_THROW( 501 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 502 std::string newUsername = "user002"; 503 504 EXPECT_CALL(*this, executeUserRename(testing::StrEq(username), 505 testing::StrEq(newUsername))) 506 .WillOnce(testing::Throw( 507 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())); 508 EXPECT_THROW( 509 UserMgr::renameUser(username, newUsername), 510 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 511 512 // The original user is unchanged 513 UserInfoMap userInfo = getUserInfo(username); 514 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user"); 515 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]), 516 testing::UnorderedElementsAre("redfish", "ssh")); 517 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 518 519 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 520 } 521 522 TEST_F(UserMgrInTest, DefaultUserModifyFailedWithInternalFailure) 523 { 524 EXPECT_THROW( 525 UserMgr::executeUserRename("user0", "user1"), 526 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 527 EXPECT_THROW( 528 UserMgr::executeUserModify("user0", "ssh", true), 529 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 530 } 531 532 TEST_F(UserMgrInTest, UpdateGroupsAndPrivOnSuccess) 533 { 534 std::string username = "user001"; 535 EXPECT_NO_THROW( 536 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 537 EXPECT_NO_THROW( 538 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin")); 539 UserInfoMap userInfo = getUserInfo(username); 540 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-admin"); 541 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]), 542 testing::UnorderedElementsAre("ipmi", "ssh")); 543 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 544 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 545 } 546 547 TEST_F(UserMgrInTest, 548 UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail) 549 { 550 std::string username = "user001"; 551 EXPECT_NO_THROW( 552 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 553 EXPECT_CALL(*this, executeUserModify(testing::StrEq(username), testing::_, 554 testing::_)) 555 .WillOnce(testing::Throw( 556 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())); 557 EXPECT_THROW( 558 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"), 559 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 560 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 561 } 562 563 TEST_F(UserMgrInTest, MinPasswordLengthReturnsIfValueIsTheSame) 564 { 565 initializeAccountPolicy(); 566 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 567 UserMgr::minPasswordLength(8); 568 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 569 } 570 571 TEST_F(UserMgrInTest, 572 MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument) 573 { 574 initializeAccountPolicy(); 575 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 576 EXPECT_THROW( 577 UserMgr::minPasswordLength(minPasswdLength - 1), 578 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 579 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 580 } 581 582 TEST_F(UserMgrInTest, MinPasswordLengthOnSuccess) 583 { 584 initializeAccountPolicy(); 585 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 586 UserMgr::minPasswordLength(16); 587 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 16); 588 } 589 590 TEST_F(UserMgrInTest, MinPasswordLengthOnFailure) 591 { 592 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile)); 593 initializeAccountPolicy(); 594 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 595 EXPECT_THROW( 596 UserMgr::minPasswordLength(16), 597 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 598 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8); 599 } 600 601 TEST_F(UserMgrInTest, RememberOldPasswordTimesReturnsIfValueIsTheSame) 602 { 603 initializeAccountPolicy(); 604 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0); 605 UserMgr::rememberOldPasswordTimes(8); 606 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8); 607 UserMgr::rememberOldPasswordTimes(8); 608 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8); 609 } 610 611 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnSuccess) 612 { 613 initializeAccountPolicy(); 614 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0); 615 UserMgr::rememberOldPasswordTimes(16); 616 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 16); 617 } 618 619 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnFailure) 620 { 621 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile)); 622 initializeAccountPolicy(); 623 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0); 624 EXPECT_THROW( 625 UserMgr::rememberOldPasswordTimes(16), 626 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 627 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0); 628 } 629 630 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame) 631 { 632 initializeAccountPolicy(); 633 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2); 634 UserMgr::maxLoginAttemptBeforeLockout(2); 635 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2); 636 } 637 638 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnSuccess) 639 { 640 initializeAccountPolicy(); 641 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2); 642 UserMgr::maxLoginAttemptBeforeLockout(16); 643 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 16); 644 } 645 646 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnFailure) 647 { 648 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile)); 649 initializeAccountPolicy(); 650 EXPECT_THROW( 651 UserMgr::maxLoginAttemptBeforeLockout(16), 652 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 653 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0); 654 } 655 656 TEST_F(UserMgrInTest, AccountUnlockTimeoutReturnsIfValueIsTheSame) 657 { 658 initializeAccountPolicy(); 659 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3); 660 UserMgr::accountUnlockTimeout(3); 661 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3); 662 } 663 664 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnSuccess) 665 { 666 initializeAccountPolicy(); 667 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3); 668 UserMgr::accountUnlockTimeout(16); 669 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 16); 670 } 671 672 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnFailure) 673 { 674 initializeAccountPolicy(); 675 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile)); 676 EXPECT_THROW( 677 UserMgr::accountUnlockTimeout(16), 678 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 679 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3); 680 } 681 682 TEST_F(UserMgrInTest, UserEnableOnSuccess) 683 { 684 std::string username = "user001"; 685 EXPECT_NO_THROW( 686 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 687 UserInfoMap userInfo = getUserInfo(username); 688 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 689 690 EXPECT_NO_THROW(userEnable(username, false)); 691 692 userInfo = getUserInfo(username); 693 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), false); 694 695 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 696 } 697 698 TEST_F(UserMgrInTest, UserEnableThrowsInternalFailureIfExecuteUserModifyFail) 699 { 700 std::string username = "user001"; 701 EXPECT_NO_THROW( 702 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true)); 703 UserInfoMap userInfo = getUserInfo(username); 704 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 705 706 EXPECT_CALL(*this, executeUserModifyUserEnable(testing::StrEq(username), 707 testing::Eq(false))) 708 .WillOnce(testing::Throw( 709 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())); 710 EXPECT_THROW( 711 userEnable(username, false), 712 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 713 714 userInfo = getUserInfo(username); 715 // Stay unchanged 716 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true); 717 718 EXPECT_NO_THROW(UserMgr::deleteUser(username)); 719 } 720 721 TEST_F( 722 UserMgrInTest, 723 UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero) 724 { 725 EXPECT_FALSE(userLockedForFailedAttempt("whatever")); 726 } 727 728 TEST_F(UserMgrInTest, UserLockedForFailedAttemptZeroFailuresReturnsFalse) 729 { 730 std::string username = "user001"; 731 initializeAccountPolicy(); 732 // Example output from BMC 733 // root@s7106:~# pam_tally2 -u root 734 // Login Failures Latest failure From 735 // root 0 736 std::vector<std::string> output = {"whatever", "root\t0"}; 737 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str()))) 738 .WillOnce(testing::Return(output)); 739 740 EXPECT_FALSE(userLockedForFailedAttempt(username)); 741 } 742 743 TEST_F(UserMgrInTest, UserLockedForFailedAttemptFailIfGetFailedAttemptFail) 744 { 745 std::string username = "user001"; 746 initializeAccountPolicy(); 747 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str()))) 748 .WillOnce(testing::Throw( 749 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure())); 750 751 EXPECT_THROW( 752 userLockedForFailedAttempt(username), 753 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 754 } 755 756 TEST_F(UserMgrInTest, 757 UserLockedForFailedAttemptThrowsInternalFailureIfFailAttemptsOutOfRange) 758 { 759 std::string username = "user001"; 760 initializeAccountPolicy(); 761 std::vector<std::string> output = {"whatever", "root\t1000000"}; 762 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str()))) 763 .WillOnce(testing::Return(output)); 764 765 EXPECT_THROW( 766 userLockedForFailedAttempt(username), 767 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 768 } 769 770 TEST_F(UserMgrInTest, 771 UserLockedForFailedAttemptThrowsInternalFailureIfNoFailDateTime) 772 { 773 std::string username = "user001"; 774 initializeAccountPolicy(); 775 std::vector<std::string> output = {"whatever", "root\t2"}; 776 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str()))) 777 .WillOnce(testing::Return(output)); 778 779 EXPECT_THROW( 780 userLockedForFailedAttempt(username), 781 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 782 } 783 784 TEST_F(UserMgrInTest, 785 UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat) 786 { 787 std::string username = "user001"; 788 initializeAccountPolicy(); 789 790 // Choose a date in the past. 791 std::vector<std::string> output = {"whatever", 792 "root\t2\t10/24/2002\t00:00:00"}; 793 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str()))) 794 .WillOnce(testing::Return(output)); 795 796 EXPECT_THROW( 797 userLockedForFailedAttempt(username), 798 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure); 799 } 800 801 TEST_F(UserMgrInTest, 802 UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut) 803 { 804 std::string username = "user001"; 805 initializeAccountPolicy(); 806 807 // Choose a date in the past. 808 std::vector<std::string> output = {"whatever", 809 "root\t2\t10/24/02\t00:00:00"}; 810 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str()))) 811 .WillOnce(testing::Return(output)); 812 813 EXPECT_EQ(userLockedForFailedAttempt(username), false); 814 } 815 816 } // namespace user 817 } // namespace phosphor 818