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
getEpochTimeNow()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
getNextUserName()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
fillPasswordExpiration(const long lastChangeDaysAgo,const long oldPasswordAge,const long nextPasswordChangeInDays,PasswordExpirationInfo & info)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
TestUserMgr()96 TestUserMgr() :
97 bus(sdbusplus::get_mocked_new(&sdBusMock)), mockManager(bus, objpath)
98 {}
99
createLocalUser(const std::string & userName,std::vector<std::string> groupNames,const std::string & priv,bool enabled)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
createPrivilegeMapperDbusObject(void)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
createLdapConfigObjectWithoutPrivilegeMapper(void)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
getUser(const std::string & userName)163 auto& getUser(const std::string& userName)
164 {
165 return *mockManager.usersList[userName].get();
166 }
167
testPasswordExpirationSet(const std::string & userName,const PasswordInfo & oldInfo,const PasswordInfo & newInfo)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
testPasswordExpirationReset(const std::string & userName,const PasswordInfo & info)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
testPasswordExpirationGet(const std::string & userName,const PasswordInfo & info,const uint64_t expectedPasswordExpiration)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
TEST_F(TestUserMgr,ldapEntryDoesNotExist)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
TEST_F(TestUserMgr,localUser)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
TEST_F(TestUserMgr,ldapUserWithPrivMapper)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
TEST_F(TestUserMgr,ldapUserWithoutPrivMapper)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
TEST_F(TestUserMgr,PasswordExpiration)309 TEST_F(TestUserMgr, PasswordExpiration)
310 {
311 testPasswordExpirationSet(getNextUserName(), {2, 10}, {2, 3});
312 }
313
TEST_F(TestUserMgr,PasswordExpirationLastChangeNegative)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
TEST_F(TestUserMgr,PasswordExpirationLastChangeZero)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
TEST_F(TestUserMgr,PasswordExpirationLastMaxAgeNegative)334 TEST_F(TestUserMgr, PasswordExpirationLastMaxAgeNegative)
335 {
336 testPasswordExpirationSet(getNextUserName(), {10, -5}, {10, 6});
337 }
338
TEST_F(TestUserMgr,PasswordExpirationReset)339 TEST_F(TestUserMgr, PasswordExpirationReset)
340 {
341 testPasswordExpirationReset(getNextUserName(), {2, 10});
342 }
343
TEST_F(TestUserMgr,PasswordExpirationResetLastChangeNegative)344 TEST_F(TestUserMgr, PasswordExpirationResetLastChangeNegative)
345 {
346 testPasswordExpirationReset(getNextUserName(), {-5, 8});
347 }
348
TEST_F(TestUserMgr,PasswordExpirationResetLastChangeZero)349 TEST_F(TestUserMgr, PasswordExpirationResetLastChangeZero)
350 {
351 testPasswordExpirationReset(getNextUserName(), {0, 13});
352 }
353
TEST_F(TestUserMgr,PasswordExpirationResetMaxAgeNegative)354 TEST_F(TestUserMgr, PasswordExpirationResetMaxAgeNegative)
355 {
356 testPasswordExpirationReset(getNextUserName(), {2, -2});
357 }
358
TEST_F(TestUserMgr,PasswordExpirationGet)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
TEST_F(TestUserMgr,PasswordExpirationSetDefault)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
TEST_F(TestUserMgr,PasswordExpirationGetDefault)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
TEST_F(TestUserMgr,PasswordExpirationGetLastChangeNegative)397 TEST_F(TestUserMgr, PasswordExpirationGetLastChangeNegative)
398 {
399 testPasswordExpirationGet(getNextUserName(), {-5, 8},
400 UserMgr::getUnexpiringPasswordTime());
401 }
402
TEST_F(TestUserMgr,PasswordExpirationGetLastChangeZero)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
TEST_F(TestUserMgr,PasswordExpirationGetMaxAgeNegative)430 TEST_F(TestUserMgr, PasswordExpirationGetMaxAgeNegative)
431 {
432 testPasswordExpirationGet(getNextUserName(), {12, -2},
433 UserMgr::getUnexpiringPasswordTime());
434 }
435
TEST_F(TestUserMgr,PasswordExpirationShadowFail)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
TEST_F(TestUserMgr,PasswordExpirationInvalidDate)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
TEST_F(TestUserMgr,PasswordExpirationExecFail)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
TEST(GetCSVFromVector,EmptyVectorReturnsEmptyString)511 TEST(GetCSVFromVector, EmptyVectorReturnsEmptyString)
512 {
513 EXPECT_EQ(getCSVFromVector({}), "");
514 }
515
TEST(GetCSVFromVector,ElementsAreJoinedByComma)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
TEST(RemoveStringFromCSV,WithoutDeleteStringReturnsFalse)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
TEST(RemoveStringFromCSV,WithDeleteStringReturnsTrue)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
dumpStringToFile(const std::string & str,const std::string & filePath)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
removeFile(const std::string & filePath)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:
UserMgrInTest()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
~UserMgrInTest()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 MOCK_METHOD(bool, isUserExistSystem, (const std::string& userName),
730 (override));
731
732 protected:
733 static constexpr auto tempFilePath = "/tmp/test-data-XXXXXX";
734
735 static sdbusplus::bus_t busInTest;
736 std::string tempFaillockConfigFile;
737 std::string tempPWHistoryConfigFile;
738 std::string tempPWQualityConfigFile;
739
setUpCreateUser(const std::string & userName,bool enabled)740 void setUpCreateUser(const std::string& userName, bool enabled)
741 {
742 EXPECT_CALL(*this, getIpmiUsersCount).WillOnce(testing::Return(0));
743
744 EXPECT_CALL(*this,
745 executeUserAdd(testing::StrEq(userName), _, _, enabled))
746 .Times(1);
747 }
748
setUpGetUserInfo(const std::string & userName,bool enabled)749 void setUpGetUserInfo(const std::string& userName, bool enabled)
750 {
751 EXPECT_CALL(*this, isUserEnabled(userName))
752 .WillOnce(testing::Return(enabled));
753 }
754
setUpSetPasswordExpiration(const std::string & userName,const PasswordExpirationInfo & info)755 void setUpSetPasswordExpiration(const std::string& userName,
756 const PasswordExpirationInfo& info)
757 {
758 EXPECT_CALL(*this, getShadowData(testing::StrEq(userName), _))
759 .WillOnce(Invoke([&info](auto, struct spwd& spwd) {
760 spwd.sp_lstchg = info.lastChangeDate;
761 spwd.sp_max = info.oldmaxAge;
762 }));
763
764 EXPECT_CALL(*this, executeUserPasswordExpiration(
765 testing::StrEq(userName), info.lastChangeDate,
766 info.newMaxAge))
767 .Times(1);
768 }
769
setUpDeleteUser(const std::string & userName)770 void setUpDeleteUser(const std::string& userName)
771 {
772 EXPECT_CALL(*this,
773 executeUserClearFailRecords(testing::StrEq(userName)))
774 .Times(1);
775
776 EXPECT_CALL(*this, executeUserDelete(testing::StrEq(userName)))
777 .Times(1);
778 }
779 };
780
781 sdbusplus::bus_t UserMgrInTest::busInTest = sdbusplus::bus::new_default();
782
TEST_F(UserMgrInTest,GetPamModuleConfValueOnSuccess)783 TEST_F(UserMgrInTest, GetPamModuleConfValueOnSuccess)
784 {
785 std::string minlen;
786 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
787 0);
788 EXPECT_EQ(minlen, "8");
789 std::string deny;
790 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
791 EXPECT_EQ(deny, "2");
792 std::string remember;
793 EXPECT_EQ(
794 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
795 0);
796 EXPECT_EQ(remember, "0");
797 }
798
TEST_F(UserMgrInTest,SetPamModuleConfValueOnSuccess)799 TEST_F(UserMgrInTest, SetPamModuleConfValueOnSuccess)
800 {
801 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
802 0);
803 std::string minlen;
804 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
805 0);
806 EXPECT_EQ(minlen, "16");
807
808 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
809 std::string deny;
810 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
811 EXPECT_EQ(deny, "3");
812
813 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
814 0);
815 std::string remember;
816 EXPECT_EQ(
817 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
818 0);
819 EXPECT_EQ(remember, "1");
820 }
821
TEST_F(UserMgrInTest,SetPamModuleConfValueTempFileOnSuccess)822 TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnSuccess)
823 {
824 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
825 0);
826
827 std::string tmpFile = tempPWQualityConfigFile + "_tmp";
828 EXPECT_FALSE(std::filesystem::exists(tmpFile));
829
830 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
831
832 tmpFile = tempFaillockConfigFile + "_tmp";
833 EXPECT_FALSE(std::filesystem::exists(tmpFile));
834
835 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
836 0);
837
838 tmpFile = tempPWHistoryConfigFile + "_tmp";
839 EXPECT_FALSE(std::filesystem::exists(tmpFile));
840 }
841
TEST_F(UserMgrInTest,GetPamModuleConfValueOnFailure)842 TEST_F(UserMgrInTest, GetPamModuleConfValueOnFailure)
843 {
844 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
845 std::string minlen;
846 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
847 -1);
848
849 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
850 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
851 -1);
852
853 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
854 std::string deny;
855 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
856
857 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
858 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
859
860 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
861 std::string remember;
862 EXPECT_EQ(
863 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
864 -1);
865
866 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
867 EXPECT_EQ(
868 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
869 -1);
870 }
871
TEST_F(UserMgrInTest,SetPamModuleConfValueOnFailure)872 TEST_F(UserMgrInTest, SetPamModuleConfValueOnFailure)
873 {
874 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
875 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
876 -1);
877
878 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
879 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
880 -1);
881
882 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
883 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
884
885 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
886 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
887
888 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
889 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
890 -1);
891
892 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
893 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
894 -1);
895 }
896
TEST_F(UserMgrInTest,SetPamModuleConfValueTempFileOnFailure)897 TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnFailure)
898 {
899 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
900 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
901 -1);
902
903 std::string tmpFile = tempPWQualityConfigFile + "_tmp";
904 EXPECT_FALSE(std::filesystem::exists(tmpFile));
905
906 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
907 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
908 -1);
909
910 EXPECT_FALSE(std::filesystem::exists(tmpFile));
911
912 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
913 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
914
915 tmpFile = tempFaillockConfigFile + "_tmp";
916 EXPECT_FALSE(std::filesystem::exists(tmpFile));
917
918 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
919 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
920
921 EXPECT_FALSE(std::filesystem::exists(tmpFile));
922
923 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
924 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
925 -1);
926
927 tmpFile = tempPWHistoryConfigFile + "_tmp";
928 EXPECT_FALSE(std::filesystem::exists(tmpFile));
929
930 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
931 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
932 -1);
933
934 EXPECT_FALSE(std::filesystem::exists(tmpFile));
935 }
936
TEST_F(UserMgrInTest,IsUserExistEmptyInputThrowsError)937 TEST_F(UserMgrInTest, IsUserExistEmptyInputThrowsError)
938 {
939 EXPECT_THROW(
940 isUserExist(""),
941 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
942 }
943
TEST_F(UserMgrInTest,ThrowForUserDoesNotExistThrowsError)944 TEST_F(UserMgrInTest, ThrowForUserDoesNotExistThrowsError)
945 {
946 EXPECT_THROW(throwForUserDoesNotExist("whatever"),
947 sdbusplus::xyz::openbmc_project::User::Common::Error::
948 UserNameDoesNotExist);
949 }
950
TEST_F(UserMgrInTest,ThrowForUserExistsThrowsError)951 TEST_F(UserMgrInTest, ThrowForUserExistsThrowsError)
952 {
953 EXPECT_THROW(
954 throwForUserExists("root"),
955 sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameExists);
956 }
957
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)958 TEST_F(
959 UserMgrInTest,
960 ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)
961 {
962 std::string strWith17Chars(17, 'A');
963 EXPECT_THROW(throwForUserNameConstraints(strWith17Chars, {"ipmi"}),
964 sdbusplus::xyz::openbmc_project::User::Common::Error::
965 UserNameGroupFail);
966 }
967
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)968 TEST_F(
969 UserMgrInTest,
970 ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)
971 {
972 std::string strWith31Chars(101, 'A');
973 EXPECT_THROW(
974 throwForUserNameConstraints(strWith31Chars, {}),
975 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
976 }
977
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)978 TEST_F(UserMgrInTest,
979 ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)
980 {
981 std::string startWithNumber = "0ABC";
982 std::string startWithDisallowedCharacter = "[test";
983 EXPECT_THROW(
984 throwForUserNameConstraints(startWithNumber, {"ipmi"}),
985 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
986 EXPECT_THROW(
987 throwForUserNameConstraints(startWithDisallowedCharacter, {"ipmi"}),
988 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
989 }
990
TEST_F(UserMgrInTest,UserAddNotRootFailedWithInternalFailure)991 TEST_F(UserMgrInTest, UserAddNotRootFailedWithInternalFailure)
992 {
993 EXPECT_THROW(
994 UserMgr::executeUserAdd("user0", "ipmi,ssh", true, true),
995 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
996 }
997
TEST_F(UserMgrInTest,UserDeleteNotRootFailedWithInternalFailure)998 TEST_F(UserMgrInTest, UserDeleteNotRootFailedWithInternalFailure)
999 {
1000 EXPECT_THROW(
1001 UserMgr::executeUserDelete("user0"),
1002 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1003 }
1004
TEST_F(UserMgrInTest,ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)1005 TEST_F(UserMgrInTest,
1006 ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)
1007 {
1008 EXPECT_CALL(*this, getIpmiUsersCount()).WillOnce(Return(ipmiMaxUsers));
1009 EXPECT_THROW(
1010 throwForMaxGrpUserCount({"ipmi"}),
1011 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
1012 }
1013
TEST_F(UserMgrInTest,CreateUserThrowsInternalFailureWhenExecuteUserAddFails)1014 TEST_F(UserMgrInTest, CreateUserThrowsInternalFailureWhenExecuteUserAddFails)
1015 {
1016 std::string username = "whatever";
1017 EXPECT_CALL(*this, executeUserAdd)
1018 .WillOnce(testing::Throw(
1019 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1020 EXPECT_CALL(*this, isUserExistSystem(testing::StrEq(username)))
1021 .WillOnce(Return(false));
1022 EXPECT_THROW(
1023 createUser(username, {"redfish"}, "", true),
1024 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1025 EXPECT_FALSE(isUserExist(username));
1026 }
1027
TEST_F(UserMgrInTest,CreateUserThrowsInternalFailureWhenExecuteUserAddPartiallyFails)1028 TEST_F(UserMgrInTest,
1029 CreateUserThrowsInternalFailureWhenExecuteUserAddPartiallyFails)
1030 {
1031 std::string username = "whatever";
1032 EXPECT_CALL(*this, executeUserAdd)
1033 .WillOnce(testing::Throw(
1034 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1035 EXPECT_CALL(*this, isUserExistSystem(testing::StrEq(username)))
1036 .WillOnce(Return(true));
1037 EXPECT_CALL(*this, executeUserDelete(testing::StrEq(username)))
1038 .WillOnce(testing::DoDefault());
1039 EXPECT_THROW(
1040 createUser(username, {"redfish"}, "", true),
1041 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1042 EXPECT_FALSE(isUserExist(username));
1043 }
1044
TEST_F(UserMgrInTest,DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)1045 TEST_F(UserMgrInTest, DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)
1046 {
1047 std::string username = "user";
1048 EXPECT_NO_THROW(
1049 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
1050 EXPECT_CALL(*this, executeUserDelete(testing::StrEq(username)))
1051 .WillOnce(testing::Throw(
1052 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
1053 .WillOnce(testing::DoDefault());
1054 EXPECT_CALL(*this, isUserExistSystem(testing::StrEq(username)))
1055 .WillOnce(Return(true)); // delete legitimately failed
1056
1057 EXPECT_THROW(
1058 deleteUser(username),
1059 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1060 EXPECT_TRUE(isUserExist(username));
1061 EXPECT_NO_THROW(UserMgr::deleteUser(username));
1062 }
1063
TEST_F(UserMgrInTest,DeleteUserSuccessWhenExecuteUserSucceedsWithError)1064 TEST_F(UserMgrInTest, DeleteUserSuccessWhenExecuteUserSucceedsWithError)
1065 {
1066 std::string username = "user";
1067 EXPECT_NO_THROW(
1068 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
1069 EXPECT_CALL(*this, executeUserDelete(testing::StrEq(username)))
1070 .WillOnce(testing::Throw(
1071 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1072 EXPECT_CALL(*this, isUserExistSystem(testing::StrEq(username)))
1073 .WillOnce(Return(false)); // delete partly failed
1074
1075 EXPECT_NO_THROW(deleteUser(username));
1076 EXPECT_FALSE(isUserExist(username));
1077 }
1078
TEST_F(UserMgrInTest,DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)1079 TEST_F(UserMgrInTest,
1080 DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)
1081 {
1082 const char* username = "user";
1083 EXPECT_NO_THROW(
1084 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
1085 EXPECT_CALL(*this, executeUserClearFailRecords(testing::StrEq(username)))
1086 .WillOnce(testing::Throw(
1087 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
1088 .WillOnce(testing::DoDefault());
1089 EXPECT_CALL(*this, isUserExistSystem(testing::StrEq(username)))
1090 .WillOnce(Return(true));
1091
1092 EXPECT_THROW(
1093 deleteUser(username),
1094 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1095 EXPECT_TRUE(isUserExist(username));
1096 EXPECT_NO_THROW(UserMgr::deleteUser(username));
1097 }
1098
TEST_F(UserMgrInTest,ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)1099 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)
1100 {
1101 EXPECT_THROW(
1102 throwForInvalidPrivilege("whatever"),
1103 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1104 }
1105
TEST_F(UserMgrInTest,ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)1106 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)
1107 {
1108 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-admin"));
1109 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-operator"));
1110 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-user"));
1111 }
1112
TEST_F(UserMgrInTest,ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)1113 TEST_F(UserMgrInTest, ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)
1114 {
1115 EXPECT_THROW(
1116 throwForInvalidGroups({"whatever"}),
1117 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1118 EXPECT_THROW(
1119 throwForInvalidGroups({"web"}),
1120 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1121 }
1122
TEST_F(UserMgrInTest,ThrowForInvalidGroupsNoThrowWhenGroupIsValid)1123 TEST_F(UserMgrInTest, ThrowForInvalidGroupsNoThrowWhenGroupIsValid)
1124 {
1125 EXPECT_NO_THROW(throwForInvalidGroups({"ipmi"}));
1126 EXPECT_NO_THROW(throwForInvalidGroups({"ssh"}));
1127 EXPECT_NO_THROW(throwForInvalidGroups({"redfish"}));
1128 EXPECT_NO_THROW(throwForInvalidGroups({"hostconsole"}));
1129 }
1130
TEST_F(UserMgrInTest,RenameUserOnSuccess)1131 TEST_F(UserMgrInTest, RenameUserOnSuccess)
1132 {
1133 std::string username = "user001";
1134 EXPECT_NO_THROW(
1135 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
1136 std::string newUsername = "user002";
1137
1138 EXPECT_NO_THROW(UserMgr::renameUser(username, newUsername));
1139
1140 // old username doesn't exist
1141 EXPECT_THROW(getUserInfo(username),
1142 sdbusplus::xyz::openbmc_project::User::Common::Error::
1143 UserNameDoesNotExist);
1144
1145 UserInfoMap userInfo = getUserInfo(newUsername);
1146 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
1147 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
1148 testing::UnorderedElementsAre("redfish", "ssh"));
1149 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
1150
1151 EXPECT_NO_THROW(UserMgr::deleteUser(newUsername));
1152 }
1153
TEST_F(UserMgrInTest,RenameUserThrowsInternalFailureIfExecuteUserModifyFails)1154 TEST_F(UserMgrInTest, RenameUserThrowsInternalFailureIfExecuteUserModifyFails)
1155 {
1156 std::string username = "user001";
1157 EXPECT_NO_THROW(
1158 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
1159 std::string newUsername = "user002";
1160
1161 EXPECT_CALL(*this, executeUserRename(testing::StrEq(username),
1162 testing::StrEq(newUsername)))
1163 .WillOnce(testing::Throw(
1164 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1165 EXPECT_CALL(*this, isUserExistSystem(testing::StrEq(newUsername)))
1166 .WillOnce(Return(false));
1167 EXPECT_THROW(
1168 UserMgr::renameUser(username, newUsername),
1169 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1170
1171 // The original user is unchanged
1172 UserInfoMap userInfo = getUserInfo(username);
1173 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
1174 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
1175 testing::UnorderedElementsAre("redfish", "ssh"));
1176 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
1177
1178 EXPECT_NO_THROW(UserMgr::deleteUser(username));
1179 }
1180
TEST_F(UserMgrInTest,RenameUserThrowsInternalFailureIfExecuteUserModifyPartiallyFails)1181 TEST_F(UserMgrInTest,
1182 RenameUserThrowsInternalFailureIfExecuteUserModifyPartiallyFails)
1183 {
1184 std::string username = "user001";
1185 EXPECT_NO_THROW(
1186 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
1187 std::string newUsername = "user002";
1188
1189 EXPECT_CALL(*this, executeUserRename(testing::StrEq(username),
1190 testing::StrEq(newUsername)))
1191 .WillOnce(testing::Throw(
1192 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1193 EXPECT_CALL(*this, isUserExistSystem(testing::StrEq(newUsername)))
1194 .WillOnce(Return(true));
1195 EXPECT_THROW(
1196 UserMgr::renameUser(username, newUsername),
1197 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1198
1199 // The original user is updated
1200 UserInfoMap userInfo = getUserInfo(newUsername);
1201 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
1202 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
1203 testing::UnorderedElementsAre("redfish", "ssh"));
1204 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
1205
1206 EXPECT_NO_THROW(UserMgr::deleteUser(newUsername));
1207 }
1208
TEST_F(UserMgrInTest,DefaultUserModifyFailedWithInternalFailure)1209 TEST_F(UserMgrInTest, DefaultUserModifyFailedWithInternalFailure)
1210 {
1211 EXPECT_THROW(
1212 UserMgr::executeUserRename("user0", "user1"),
1213 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1214 EXPECT_THROW(
1215 UserMgr::executeUserModify("user0", "ssh", true),
1216 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1217 }
1218
TEST_F(UserMgrInTest,UpdateGroupsAndPrivOnSuccess)1219 TEST_F(UserMgrInTest, UpdateGroupsAndPrivOnSuccess)
1220 {
1221 std::string username = "user001";
1222 EXPECT_NO_THROW(
1223 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
1224 EXPECT_NO_THROW(
1225 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"));
1226 UserInfoMap userInfo = getUserInfo(username);
1227 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-admin");
1228 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
1229 testing::UnorderedElementsAre("ipmi", "ssh"));
1230 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
1231 EXPECT_NO_THROW(UserMgr::deleteUser(username));
1232 }
1233
TEST_F(UserMgrInTest,UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)1234 TEST_F(UserMgrInTest,
1235 UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)
1236 {
1237 std::string username = "user001";
1238 EXPECT_NO_THROW(
1239 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
1240 EXPECT_CALL(*this, executeUserModify(testing::StrEq(username), testing::_,
1241 testing::_))
1242 .WillOnce(testing::Throw(
1243 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1244 EXPECT_THROW(
1245 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"),
1246 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1247 EXPECT_NO_THROW(UserMgr::deleteUser(username));
1248 }
1249
TEST_F(UserMgrInTest,MinPasswordLengthReturnsIfValueIsTheSame)1250 TEST_F(UserMgrInTest, MinPasswordLengthReturnsIfValueIsTheSame)
1251 {
1252 initializeAccountPolicy();
1253 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
1254 UserMgr::minPasswordLength(8);
1255 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
1256 }
1257
TEST_F(UserMgrInTest,MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)1258 TEST_F(UserMgrInTest,
1259 MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)
1260 {
1261 initializeAccountPolicy();
1262 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
1263 EXPECT_THROW(
1264 UserMgr::minPasswordLength(minPasswdLength - 1),
1265 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1266 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
1267 }
1268
TEST_F(UserMgrInTest,MinPasswordLengthOnSuccess)1269 TEST_F(UserMgrInTest, MinPasswordLengthOnSuccess)
1270 {
1271 initializeAccountPolicy();
1272 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
1273 UserMgr::minPasswordLength(16);
1274 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 16);
1275 }
1276
TEST_F(UserMgrInTest,MinPasswordLengthOnFailure)1277 TEST_F(UserMgrInTest, MinPasswordLengthOnFailure)
1278 {
1279 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
1280 initializeAccountPolicy();
1281 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
1282 EXPECT_THROW(
1283 UserMgr::minPasswordLength(16),
1284 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1285 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
1286 }
1287
TEST_F(UserMgrInTest,MinPasswordLengthGreaterThanMaxPasswordLength)1288 TEST_F(UserMgrInTest, MinPasswordLengthGreaterThanMaxPasswordLength)
1289 {
1290 initializeAccountPolicy();
1291
1292 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
1293 EXPECT_THROW(
1294 UserMgr::minPasswordLength(maxPasswdLength + 1),
1295 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1296 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
1297 }
1298
TEST_F(UserMgrInTest,RememberOldPasswordTimesReturnsIfValueIsTheSame)1299 TEST_F(UserMgrInTest, RememberOldPasswordTimesReturnsIfValueIsTheSame)
1300 {
1301 initializeAccountPolicy();
1302 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
1303 UserMgr::rememberOldPasswordTimes(8);
1304 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
1305 UserMgr::rememberOldPasswordTimes(8);
1306 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
1307 }
1308
TEST_F(UserMgrInTest,RememberOldPasswordTimesOnSuccess)1309 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnSuccess)
1310 {
1311 initializeAccountPolicy();
1312 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
1313 UserMgr::rememberOldPasswordTimes(16);
1314 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 16);
1315 }
1316
TEST_F(UserMgrInTest,RememberOldPasswordTimesOnFailure)1317 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnFailure)
1318 {
1319 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
1320 initializeAccountPolicy();
1321 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
1322 EXPECT_THROW(
1323 UserMgr::rememberOldPasswordTimes(16),
1324 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1325 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
1326 }
1327
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)1328 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)
1329 {
1330 initializeAccountPolicy();
1331 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
1332 UserMgr::maxLoginAttemptBeforeLockout(2);
1333 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
1334 }
1335
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutOnSuccess)1336 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnSuccess)
1337 {
1338 initializeAccountPolicy();
1339 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
1340 UserMgr::maxLoginAttemptBeforeLockout(16);
1341 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 16);
1342 }
1343
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutOnFailure)1344 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnFailure)
1345 {
1346 initializeAccountPolicy();
1347 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
1348 EXPECT_THROW(
1349 UserMgr::maxLoginAttemptBeforeLockout(16),
1350 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1351 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
1352 }
1353
TEST_F(UserMgrInTest,AccountUnlockTimeoutReturnsIfValueIsTheSame)1354 TEST_F(UserMgrInTest, AccountUnlockTimeoutReturnsIfValueIsTheSame)
1355 {
1356 initializeAccountPolicy();
1357 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
1358 UserMgr::accountUnlockTimeout(3);
1359 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
1360 }
1361
TEST_F(UserMgrInTest,AccountUnlockTimeoutOnSuccess)1362 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnSuccess)
1363 {
1364 initializeAccountPolicy();
1365 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
1366 UserMgr::accountUnlockTimeout(16);
1367 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 16);
1368 }
1369
TEST_F(UserMgrInTest,AccountUnlockTimeoutOnFailure)1370 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnFailure)
1371 {
1372 initializeAccountPolicy();
1373 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
1374 EXPECT_THROW(
1375 UserMgr::accountUnlockTimeout(16),
1376 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1377 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
1378 }
1379
TEST_F(UserMgrInTest,UserEnableOnSuccess)1380 TEST_F(UserMgrInTest, UserEnableOnSuccess)
1381 {
1382 std::string username = "user001";
1383 EXPECT_NO_THROW(
1384 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
1385 UserInfoMap userInfo = getUserInfo(username);
1386 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
1387
1388 EXPECT_NO_THROW(userEnable(username, false));
1389
1390 userInfo = getUserInfo(username);
1391 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), false);
1392
1393 EXPECT_NO_THROW(UserMgr::deleteUser(username));
1394 }
1395
TEST_F(UserMgrInTest,CreateDeleteUserSuccessForHostConsole)1396 TEST_F(UserMgrInTest, CreateDeleteUserSuccessForHostConsole)
1397 {
1398 std::string username = "user001";
1399 EXPECT_NO_THROW(
1400 UserMgr::createUser(username, {"hostconsole"}, "priv-user", true));
1401 EXPECT_NO_THROW(UserMgr::deleteUser(username));
1402 EXPECT_NO_THROW(
1403 UserMgr::createUser(username, {"hostconsole"}, "priv-admin", true));
1404 EXPECT_NO_THROW(UserMgr::deleteUser(username));
1405 EXPECT_NO_THROW(
1406 UserMgr::createUser(username, {"hostconsole"}, "priv-operator", true));
1407 EXPECT_NO_THROW(UserMgr::deleteUser(username));
1408 }
1409
TEST_F(UserMgrInTest,UserEnableThrowsInternalFailureIfExecuteUserModifyFail)1410 TEST_F(UserMgrInTest, UserEnableThrowsInternalFailureIfExecuteUserModifyFail)
1411 {
1412 std::string username = "user001";
1413 EXPECT_NO_THROW(
1414 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
1415 UserInfoMap userInfo = getUserInfo(username);
1416 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
1417
1418 EXPECT_CALL(*this, executeUserModifyUserEnable(testing::StrEq(username),
1419 testing::Eq(false)))
1420 .WillOnce(testing::Throw(
1421 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1422 EXPECT_THROW(
1423 userEnable(username, false),
1424 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1425
1426 userInfo = getUserInfo(username);
1427 // Stay unchanged
1428 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
1429
1430 EXPECT_NO_THROW(UserMgr::deleteUser(username));
1431 }
1432
TEST_F(UserMgrInTest,UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)1433 TEST_F(
1434 UserMgrInTest,
1435 UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)
1436 {
1437 EXPECT_FALSE(userLockedForFailedAttempt("whatever"));
1438 }
1439
TEST_F(UserMgrInTest,UserLockedForFailedAttemptZeroFailuresReturnsFalse)1440 TEST_F(UserMgrInTest, UserLockedForFailedAttemptZeroFailuresReturnsFalse)
1441 {
1442 std::string username = "user001";
1443 initializeAccountPolicy();
1444 // Example output from BMC
1445 // root:~# faillock --user root
1446 // root:
1447 // When Type Source Valid
1448 std::vector<std::string> output = {"whatever",
1449 "When Type Source Valid"};
1450 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1451 .WillOnce(testing::Return(output));
1452
1453 EXPECT_FALSE(userLockedForFailedAttempt(username));
1454 }
1455
TEST_F(UserMgrInTest,UserLockedForFailedAttemptFailIfGetFailedAttemptFail)1456 TEST_F(UserMgrInTest, UserLockedForFailedAttemptFailIfGetFailedAttemptFail)
1457 {
1458 std::string username = "user001";
1459 initializeAccountPolicy();
1460 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1461 .WillOnce(testing::Throw(
1462 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1463
1464 EXPECT_THROW(
1465 userLockedForFailedAttempt(username),
1466 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1467 }
1468
TEST_F(UserMgrInTest,UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)1469 TEST_F(UserMgrInTest,
1470 UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)
1471 {
1472 std::string username = "user001";
1473 initializeAccountPolicy();
1474
1475 // Choose a date in the past.
1476 std::vector<std::string> output = {"whatever",
1477 "10/24/2002 00:00:00 type source V"};
1478 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1479 .WillOnce(testing::Return(output));
1480
1481 EXPECT_THROW(
1482 userLockedForFailedAttempt(username),
1483 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1484 }
1485
TEST_F(UserMgrInTest,UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)1486 TEST_F(UserMgrInTest,
1487 UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)
1488 {
1489 std::string username = "user001";
1490 initializeAccountPolicy();
1491
1492 // Choose a date in the past.
1493 std::vector<std::string> output = {"whatever",
1494 "2002-10-24 00:00:00 type source V"};
1495 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1496 .WillOnce(testing::Return(output));
1497
1498 EXPECT_EQ(userLockedForFailedAttempt(username), false);
1499 }
1500
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationOnSuccess)1501 TEST_F(UserMgrInTest, CheckAndThrowForDisallowedGroupCreationOnSuccess)
1502 {
1503 // Base Redfish Roles
1504 EXPECT_NO_THROW(
1505 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Administrator"));
1506 EXPECT_NO_THROW(
1507 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Operator"));
1508 EXPECT_NO_THROW(
1509 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_ReadOnly"));
1510 // Base Redfish Privileges
1511 EXPECT_NO_THROW(
1512 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_Login"));
1513 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1514 "openbmc_rfp_ConfigureManager"));
1515 EXPECT_NO_THROW(
1516 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureUsers"));
1517 EXPECT_NO_THROW(
1518 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureSelf"));
1519 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1520 "openbmc_rfp_ConfigureComponents"));
1521 // OEM Redfish Roles
1522 EXPECT_NO_THROW(
1523 checkAndThrowForDisallowedGroupCreation("openbmc_orfr_PowerService"));
1524 // OEM Redfish Privileges
1525 EXPECT_NO_THROW(
1526 checkAndThrowForDisallowedGroupCreation("openbmc_orfp_PowerService"));
1527 }
1528
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)1529 TEST_F(UserMgrInTest,
1530 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)
1531 {
1532 std::string groupName(maxSystemGroupNameLength + 1, 'A');
1533 EXPECT_THROW(
1534 checkAndThrowForDisallowedGroupCreation(groupName),
1535 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1536 }
1537
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)1538 TEST_F(
1539 UserMgrInTest,
1540 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)
1541 {
1542 EXPECT_THROW(
1543 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_?owerService"),
1544 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1545 EXPECT_THROW(
1546 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_-owerService"),
1547 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1548 }
1549
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)1550 TEST_F(
1551 UserMgrInTest,
1552 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)
1553 {
1554 EXPECT_THROW(
1555 checkAndThrowForDisallowedGroupCreation("google_rfp_"),
1556 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1557 EXPECT_THROW(
1558 checkAndThrowForDisallowedGroupCreation("com_rfp_"),
1559 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1560 }
1561
TEST_F(UserMgrInTest,CheckAndThrowForMaxGroupCountOnSuccess)1562 TEST_F(UserMgrInTest, CheckAndThrowForMaxGroupCountOnSuccess)
1563 {
1564 constexpr size_t predefGroupCount = 4;
1565
1566 EXPECT_THAT(allGroups().size(), predefGroupCount);
1567 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
1568 {
1569 std::string groupName = "openbmc_rfr_role";
1570 groupName += std::to_string(i);
1571 EXPECT_NO_THROW(createGroup(groupName));
1572 }
1573 EXPECT_THROW(
1574 createGroup("openbmc_rfr_AnotherRole"),
1575 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
1576 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
1577 {
1578 std::string groupName = "openbmc_rfr_role";
1579 groupName += std::to_string(i);
1580 EXPECT_NO_THROW(deleteGroup(groupName));
1581 }
1582 }
1583
TEST_F(UserMgrInTest,CheckAndThrowForGroupExist)1584 TEST_F(UserMgrInTest, CheckAndThrowForGroupExist)
1585 {
1586 std::string groupName = "openbmc_rfr_role";
1587 EXPECT_NO_THROW(createGroup(groupName));
1588 EXPECT_THROW(
1589 createGroup(groupName),
1590 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1591 EXPECT_NO_THROW(deleteGroup(groupName));
1592 }
1593
TEST_F(UserMgrInTest,ByDefaultAllGroupsArePredefinedGroups)1594 TEST_F(UserMgrInTest, ByDefaultAllGroupsArePredefinedGroups)
1595 {
1596 EXPECT_THAT(allGroups(), testing::UnorderedElementsAre(
1597 "redfish", "ipmi", "ssh", "hostconsole"));
1598 }
1599
TEST_F(UserMgrInTest,AddGroupThrowsIfPreDefinedGroupAdd)1600 TEST_F(UserMgrInTest, AddGroupThrowsIfPreDefinedGroupAdd)
1601 {
1602 EXPECT_THROW(
1603 createGroup("ipmi"),
1604 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1605 EXPECT_THROW(
1606 createGroup("redfish"),
1607 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1608 EXPECT_THROW(
1609 createGroup("ssh"),
1610 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1611 EXPECT_THROW(
1612 createGroup("hostconsole"),
1613 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1614 }
1615
TEST_F(UserMgrInTest,DeleteGroupThrowsIfGroupIsNotAllowedToChange)1616 TEST_F(UserMgrInTest, DeleteGroupThrowsIfGroupIsNotAllowedToChange)
1617 {
1618 EXPECT_THROW(
1619 deleteGroup("ipmi"),
1620 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1621 EXPECT_THROW(
1622 deleteGroup("redfish"),
1623 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1624 EXPECT_THROW(
1625 deleteGroup("ssh"),
1626 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1627 EXPECT_THROW(
1628 deleteGroup("hostconsole"),
1629 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1630 }
1631
TEST_F(UserMgrInTest,CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)1632 TEST_F(UserMgrInTest,
1633 CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)
1634 {
1635 EXPECT_CALL(*this, executeGroupCreation)
1636 .WillOnce(testing::Throw(
1637 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1638 EXPECT_THROW(
1639 createGroup("openbmc_rfr_role1"),
1640 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1641 }
1642
TEST_F(UserMgrInTest,DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)1643 TEST_F(UserMgrInTest,
1644 DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)
1645 {
1646 std::string groupName = "openbmc_rfr_role1";
1647 EXPECT_NO_THROW(UserMgr::createGroup(groupName));
1648 EXPECT_CALL(*this, executeGroupDeletion(testing::StrEq(groupName)))
1649 .WillOnce(testing::Throw(
1650 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
1651 .WillOnce(testing::DoDefault());
1652
1653 EXPECT_THROW(
1654 deleteGroup(groupName),
1655 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1656 EXPECT_NO_THROW(UserMgr::deleteGroup(groupName));
1657 }
1658
TEST_F(UserMgrInTest,CheckAndThrowForGroupNotExist)1659 TEST_F(UserMgrInTest, CheckAndThrowForGroupNotExist)
1660 {
1661 EXPECT_THROW(deleteGroup("whatever"),
1662 sdbusplus::xyz::openbmc_project::User::Common::Error::
1663 GroupNameDoesNotExist);
1664 }
1665
TEST(ReadAllGroupsOnSystemTest,OnlyReturnsPredefinedGroups)1666 TEST(ReadAllGroupsOnSystemTest, OnlyReturnsPredefinedGroups)
1667 {
1668 EXPECT_THAT(
1669 UserMgr::readAllGroupsOnSystem(),
1670 testing::UnorderedElementsAre("redfish", "ipmi", "ssh", "hostconsole"));
1671 }
1672
TEST_F(UserMgrInTest,CreateUser2)1673 TEST_F(UserMgrInTest, CreateUser2)
1674 {
1675 const std::string userName = getNextUserName();
1676 const bool enabled = true;
1677
1678 // last password change date is today
1679 // old maximum password age is 5000
1680 // set password expiration in 3 days
1681 PasswordExpirationInfo info;
1682 fillPasswordExpiration(0, 5000, 3, info);
1683
1684 setUpCreateUser(userName, enabled);
1685 setUpSetPasswordExpiration(userName, info);
1686 setUpGetUserInfo(userName, enabled);
1687 setUpDeleteUser(userName);
1688
1689 std::vector<std::string> groups = {"redfish", "ssh"};
1690
1691 UserCreateMap props;
1692 props[UserProperty::GroupNames] = std::move(groups);
1693 props[UserProperty::Privilege] = "priv-user";
1694 props[UserProperty::Enabled] = enabled;
1695 props[UserProperty::PasswordExpiration] = info.passwordExpiration;
1696
1697 EXPECT_NO_THROW(UserMgr::createUser2(userName, props));
1698
1699 UserInfoMap userInfo = getUserInfo(userName);
1700 EXPECT_EQ(std::get<PasswordExpiration>(userInfo["PasswordExpiration"]),
1701 info.passwordExpiration);
1702
1703 EXPECT_NO_THROW(UserMgr::deleteUser(userName));
1704 }
1705
TEST_F(UserMgrInTest,CreateUser2WithoutPasswordExpiration)1706 TEST_F(UserMgrInTest, CreateUser2WithoutPasswordExpiration)
1707 {
1708 const std::string userName = getNextUserName();
1709 const bool enabled = true;
1710
1711 setUpCreateUser(userName, enabled);
1712 setUpGetUserInfo(userName, enabled);
1713 setUpDeleteUser(userName);
1714
1715 std::vector<std::string> groups = {"redfish", "ssh"};
1716
1717 UserCreateMap props;
1718 props[UserProperty::GroupNames] = std::move(groups);
1719 props[UserProperty::Privilege] = "priv-user";
1720 props[UserProperty::Enabled] = enabled;
1721
1722 EXPECT_NO_THROW(UserMgr::createUser2(userName, props));
1723
1724 UserInfoMap userInfo = getUserInfo(userName);
1725 EXPECT_EQ(std::get<PasswordExpiration>(userInfo["PasswordExpiration"]),
1726 getDefaultPasswordExpiration());
1727
1728 EXPECT_NO_THROW(UserMgr::deleteUser(userName));
1729 }
1730
TEST_F(UserMgrInTest,CreateUser2PasswordExpirationNotSet)1731 TEST_F(UserMgrInTest, CreateUser2PasswordExpirationNotSet)
1732 {
1733 using namespace std::chrono;
1734
1735 const std::string userName = getNextUserName();
1736 const bool enabled = true;
1737
1738 setUpCreateUser(userName, enabled);
1739
1740 EXPECT_CALL(*this, getShadowData(testing::StrEq(userName), _)).Times(0);
1741
1742 EXPECT_CALL(*this,
1743 executeUserPasswordExpiration(testing::StrEq(userName), _, _))
1744 .Times(0);
1745
1746 setUpGetUserInfo(userName, enabled);
1747 setUpDeleteUser(userName);
1748
1749 constexpr auto passwordExpiration = getDefaultPasswordExpiration();
1750
1751 std::vector<std::string> groups = {"redfish", "ssh"};
1752
1753 UserCreateMap props;
1754 props[UserProperty::GroupNames] = std::move(groups);
1755 props[UserProperty::Privilege] = "priv-user";
1756 props[UserProperty::Enabled] = enabled;
1757 props[UserProperty::PasswordExpiration] = passwordExpiration;
1758
1759 EXPECT_NO_THROW(UserMgr::createUser2(userName, props));
1760
1761 UserInfoMap userInfo = getUserInfo(userName);
1762 EXPECT_EQ(std::get<PasswordExpiration>(userInfo["PasswordExpiration"]),
1763 passwordExpiration);
1764
1765 EXPECT_NO_THROW(UserMgr::deleteUser(userName));
1766 }
1767
TEST_F(UserMgrInTest,CreateUser2UnexpiringPassword)1768 TEST_F(UserMgrInTest, CreateUser2UnexpiringPassword)
1769 {
1770 using namespace std::chrono;
1771
1772 const std::string userName = getNextUserName();
1773 const bool enabled = true;
1774
1775 // last password change date is today
1776 const long lastChangeDate =
1777 duration_cast<days>(seconds{getEpochTimeNow()}).count();
1778
1779 // password age is
1780 constexpr long passwordAge = 99999;
1781
1782 // make password not to expire
1783 const uint64_t passwordExpiration = getUnexpiringPasswordTime();
1784
1785 setUpCreateUser(userName, enabled);
1786
1787 EXPECT_CALL(*this, getShadowData(testing::StrEq(userName), _))
1788 .WillOnce(Invoke([&lastChangeDate](auto, struct spwd& spwd) {
1789 spwd.sp_lstchg = lastChangeDate;
1790 spwd.sp_max = passwordAge;
1791 }));
1792
1793 EXPECT_CALL(*this, executeUserPasswordExpiration(
1794 testing::StrEq(userName), lastChangeDate,
1795 getUnexpiringPasswordAge()))
1796 .Times(1);
1797
1798 setUpGetUserInfo(userName, enabled);
1799 setUpDeleteUser(userName);
1800
1801 std::vector<std::string> groups = {"redfish", "ssh"};
1802
1803 UserCreateMap props;
1804 props[UserProperty::GroupNames] = std::move(groups);
1805 props[UserProperty::Privilege] = "priv-user";
1806 props[UserProperty::Enabled] = enabled;
1807 props[UserProperty::PasswordExpiration] = passwordExpiration;
1808
1809 EXPECT_NO_THROW(UserMgr::createUser2(userName, props));
1810
1811 UserInfoMap userInfo = getUserInfo(userName);
1812 EXPECT_EQ(std::get<PasswordExpiration>(userInfo["PasswordExpiration"]),
1813 passwordExpiration);
1814
1815 EXPECT_NO_THROW(UserMgr::deleteUser(userName));
1816 }
1817
TEST_F(UserMgrInTest,CreateUser2Rename)1818 TEST_F(UserMgrInTest, CreateUser2Rename)
1819 {
1820 const std::string userName = getNextUserName();
1821 const std::string newUserName = getNextUserName();
1822 const bool enabled = true;
1823
1824 // last password change date is 7 days ago
1825 // old maximum password age is 15
1826 // set password expiration in 5 days
1827 PasswordExpirationInfo info;
1828 fillPasswordExpiration(7, 15, 5, info);
1829
1830 setUpCreateUser(userName, enabled);
1831 setUpSetPasswordExpiration(userName, info);
1832 setUpGetUserInfo(newUserName, enabled);
1833 setUpDeleteUser(newUserName);
1834
1835 EXPECT_CALL(*this, isUserEnabled(userName))
1836 .WillOnce(testing::Return(enabled));
1837
1838 EXPECT_CALL(*this, executeUserRename(testing::StrEq(userName),
1839 testing::StrEq(newUserName)))
1840 .Times(1);
1841
1842 std::vector<std::string> groups = {"redfish", "ssh"};
1843
1844 UserCreateMap props;
1845 props[UserProperty::GroupNames] = std::move(groups);
1846 props[UserProperty::Privilege] = "priv-user";
1847 props[UserProperty::Enabled] = enabled;
1848 props[UserProperty::PasswordExpiration] = info.passwordExpiration;
1849
1850 EXPECT_NO_THROW(UserMgr::createUser2(userName, props));
1851
1852 EXPECT_NO_THROW(UserMgr::renameUser(userName, newUserName));
1853
1854 UserInfoMap userInfo = getUserInfo(newUserName);
1855 EXPECT_EQ(std::get<PasswordExpiration>(userInfo["PasswordExpiration"]),
1856 info.passwordExpiration);
1857
1858 EXPECT_NO_THROW(UserMgr::deleteUser(newUserName));
1859 }
1860
TEST_F(UserMgrInTest,CreateUser2PasswordExpirationFail)1861 TEST_F(UserMgrInTest, CreateUser2PasswordExpirationFail)
1862 {
1863 using namespace std::chrono;
1864
1865 const std::string userName = getNextUserName();
1866 const bool enabled = true;
1867
1868 setUpCreateUser(userName, enabled);
1869
1870 EXPECT_CALL(*this, getShadowData(testing::StrEq(userName), _))
1871 .WillOnce([]() {
1872 throw sdbusplus::xyz::openbmc_project::Common::Error::
1873 InternalFailure();
1874 });
1875
1876 setUpDeleteUser(userName);
1877
1878 std::vector<std::string> groups = {"redfish", "ssh"};
1879
1880 UserCreateMap props;
1881 props[UserProperty::GroupNames] = std::move(groups);
1882 props[UserProperty::Privilege] = "priv-user";
1883 props[UserProperty::Enabled] = enabled;
1884 props[UserProperty::PasswordExpiration] = (uint64_t)1;
1885
1886 EXPECT_THROW(
1887 UserMgr::createUser2(userName, props),
1888 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1889
1890 EXPECT_THROW(getUserInfo(userName),
1891 sdbusplus::xyz::openbmc_project::User::Common::Error::
1892 UserNameDoesNotExist);
1893 }
1894
1895 } // namespace user
1896 } // namespace phosphor
1897