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 #include <vector>
12
13 #include <gmock/gmock.h>
14 #include <gtest/gtest.h>
15
16 namespace phosphor
17 {
18 namespace user
19 {
20
21 using ::testing::Return;
22 using ::testing::Throw;
23
24 using InternalFailure =
25 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
26 using UserNameDoesNotExist =
27 sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameDoesNotExist;
28
29 class TestUserMgr : public testing::Test
30 {
31 public:
32 sdbusplus::SdBusMock sdBusMock;
33 sdbusplus::bus_t bus;
34 MockManager mockManager;
35
TestUserMgr()36 TestUserMgr() :
37 bus(sdbusplus::get_mocked_new(&sdBusMock)), mockManager(bus, objpath)
38 {}
39
createLocalUser(const std::string & userName,std::vector<std::string> groupNames,const std::string & priv,bool enabled)40 void createLocalUser(const std::string& userName,
41 std::vector<std::string> groupNames,
42 const std::string& priv, bool enabled)
43 {
44 sdbusplus::message::object_path tempObjPath(usersObjPath);
45 tempObjPath /= userName;
46 std::string userObj(tempObjPath);
47 if (enabled)
48 {
49 ON_CALL(mockManager, isUserEnabled)
50 .WillByDefault(testing::Return(true));
51 }
52 else
53 {
54 ON_CALL(mockManager, isUserEnabled)
55 .WillByDefault(testing::Return(false));
56 }
57 mockManager.usersList.emplace(
58 userName,
59 std::make_unique<MockUser>(mockManager.bus, userObj.c_str(),
60 groupNames, priv, enabled, mockManager));
61 }
62
createPrivilegeMapperDbusObject(void)63 DbusUserObj createPrivilegeMapperDbusObject(void)
64 {
65 DbusUserObj object;
66 DbusUserObjValue objValue;
67
68 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
69 DbusUserPropVariant enabled(true);
70 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)};
71 std::string intf = "xyz.openbmc_project.Object.Enable";
72 objValue.emplace(intf, property);
73 object.emplace(objPath, objValue);
74
75 DbusUserObjPath objectPath(
76 "/xyz/openbmc_project/user/ldap/openldap/role_map/1");
77 std::string group = "ldapGroup";
78 std::string priv = "priv-admin";
79 DbusUserObjProperties properties = {std::make_pair("GroupName", group),
80 std::make_pair("Privilege", priv)};
81 std::string interface = "xyz.openbmc_project.User.PrivilegeMapperEntry";
82
83 objValue.emplace(interface, properties);
84 object.emplace(objectPath, objValue);
85
86 return object;
87 }
88
createLdapConfigObjectWithoutPrivilegeMapper(void)89 DbusUserObj createLdapConfigObjectWithoutPrivilegeMapper(void)
90 {
91 DbusUserObj object;
92 DbusUserObjValue objValue;
93
94 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
95 DbusUserPropVariant enabled(true);
96 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)};
97 std::string intf = "xyz.openbmc_project.Object.Enable";
98 objValue.emplace(intf, property);
99 object.emplace(objPath, objValue);
100 return object;
101 }
102 };
103
TEST_F(TestUserMgr,ldapEntryDoesNotExist)104 TEST_F(TestUserMgr, ldapEntryDoesNotExist)
105 {
106 std::string userName = "user";
107 UserInfoMap userInfo;
108
109 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
110 .WillRepeatedly(Throw(UserNameDoesNotExist()));
111 EXPECT_THROW(userInfo = mockManager.getUserInfo(userName),
112 UserNameDoesNotExist);
113 }
114
TEST_F(TestUserMgr,localUser)115 TEST_F(TestUserMgr, localUser)
116 {
117 UserInfoMap userInfo;
118 std::string userName = "testUser";
119 std::string privilege = "priv-admin";
120 std::vector<std::string> groups{"testGroup"};
121 // Create local user
122 createLocalUser(userName, groups, privilege, true);
123 EXPECT_CALL(mockManager, userLockedForFailedAttempt(userName)).Times(1);
124 userInfo = mockManager.getUserInfo(userName);
125
126 EXPECT_EQ(privilege, std::get<std::string>(userInfo["UserPrivilege"]));
127 EXPECT_EQ(groups,
128 std::get<std::vector<std::string>>(userInfo["UserGroups"]));
129 EXPECT_EQ(true, std::get<bool>(userInfo["UserEnabled"]));
130 EXPECT_EQ(false, std::get<bool>(userInfo["UserLockedForFailedAttempt"]));
131 EXPECT_EQ(false, std::get<bool>(userInfo["UserPasswordExpired"]));
132 EXPECT_EQ(false, std::get<bool>(userInfo["RemoteUser"]));
133 }
TEST_F(TestUserMgr,mfaEnabled)134 TEST_F(TestUserMgr, mfaEnabled)
135 {
136 auto ret =
137 mockManager.enabled(MultiFactorAuthType::GoogleAuthenticator, false);
138 EXPECT_EQ(ret, MultiFactorAuthType::GoogleAuthenticator);
139 EXPECT_EQ(ret, mockManager.enabled());
140
141 ret = mockManager.enabled(MultiFactorAuthType::None, false);
142 EXPECT_EQ(ret, MultiFactorAuthType::None);
143 EXPECT_EQ(ret, mockManager.enabled());
144 }
TEST_F(TestUserMgr,mfaDefaultUser)145 TEST_F(TestUserMgr, mfaDefaultUser)
146 {
147 std::string userName = "testUser";
148 std::string privilege = "priv-admin";
149 std::vector<std::string> groups{"testGroup"};
150 // Create local user
151 createLocalUser(userName, groups, privilege, true);
152 auto user = mockManager.getUserObject(userName);
153 EXPECT_EQ(user->secretKeyIsValid(), false);
154 }
TEST_F(TestUserMgr,mfaCreateSecretKeyEnableMFA)155 TEST_F(TestUserMgr, mfaCreateSecretKeyEnableMFA)
156 {
157 std::string userName = "testUser";
158 std::string privilege = "priv-admin";
159 std::vector<std::string> groups{"testGroup"};
160 // Create local user
161 createLocalUser(userName, groups, privilege, true);
162 MockUser* user =
163 static_cast<MockUser*>(mockManager.getUserObject(userName));
164 EXPECT_EQ(user->secretKeyIsValid(), false);
165 auto ret =
166 mockManager.enabled(MultiFactorAuthType::GoogleAuthenticator, true);
167 EXPECT_EQ(ret, MultiFactorAuthType::GoogleAuthenticator);
168 ON_CALL(*user, createSecretKey).WillByDefault(testing::Return("SKJDY&@H"));
169 user->createSecretKey();
170 EXPECT_EQ(user->secretKeyIsValid(), false);
171 }
TEST_F(TestUserMgr,bypassMFA)172 TEST_F(TestUserMgr, bypassMFA)
173 {
174 std::string userName = "testUser";
175 std::string privilege = "priv-admin";
176 std::vector<std::string> groups{"testGroup"};
177 // Create local user
178 createLocalUser(userName, groups, privilege, true);
179 MockUser* user =
180 static_cast<MockUser*>(mockManager.getUserObject(userName));
181 mockManager.enabled(MultiFactorAuthType::GoogleAuthenticator, true);
182 user->bypassedProtocol(MultiFactorAuthType::GoogleAuthenticator, false);
183 EXPECT_EQ(user->secretKeyGenerationRequired(), false);
184 user->bypassedProtocol(MultiFactorAuthType::None, false);
185 EXPECT_EQ(user->secretKeyGenerationRequired(), true);
186 }
187
TEST_F(TestUserMgr,ldapUserWithPrivMapper)188 TEST_F(TestUserMgr, ldapUserWithPrivMapper)
189 {
190 UserInfoMap userInfo;
191 std::string userName = "ldapUser";
192 std::string ldapGroup = "ldapGroup";
193 gid_t primaryGid = 1000;
194
195 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
196 .WillRepeatedly(Return(primaryGid));
197 // Create privilege mapper dbus object
198 DbusUserObj object = createPrivilegeMapperDbusObject();
199 EXPECT_CALL(mockManager, getPrivilegeMapperObject())
200 .WillRepeatedly(Return(object));
201 EXPECT_CALL(mockManager, isGroupMember(userName, primaryGid, ldapGroup))
202 .WillRepeatedly(Return(true));
203 userInfo = mockManager.getUserInfo(userName);
204 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"]));
205 EXPECT_EQ("priv-admin", std::get<std::string>(userInfo["UserPrivilege"]));
206 }
207
TEST_F(TestUserMgr,ldapUserWithoutPrivMapper)208 TEST_F(TestUserMgr, ldapUserWithoutPrivMapper)
209 {
210 using ::testing::_;
211
212 UserInfoMap userInfo;
213 std::string userName = "ldapUser";
214 std::string ldapGroup = "ldapGroup";
215 gid_t primaryGid = 1000;
216
217 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
218 .WillRepeatedly(Return(primaryGid));
219 // Create LDAP config object without privilege mapper
220 DbusUserObj object = createLdapConfigObjectWithoutPrivilegeMapper();
221 EXPECT_CALL(mockManager, getPrivilegeMapperObject())
222 .WillRepeatedly(Return(object));
223 EXPECT_CALL(mockManager, isGroupMember(_, _, _)).Times(0);
224 userInfo = mockManager.getUserInfo(userName);
225 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"]));
226 EXPECT_EQ("priv-user", std::get<std::string>(userInfo["UserPrivilege"]));
227 }
228
TEST(GetCSVFromVector,EmptyVectorReturnsEmptyString)229 TEST(GetCSVFromVector, EmptyVectorReturnsEmptyString)
230 {
231 EXPECT_EQ(getCSVFromVector({}), "");
232 }
233
TEST(GetCSVFromVector,ElementsAreJoinedByComma)234 TEST(GetCSVFromVector, ElementsAreJoinedByComma)
235 {
236 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123"}), "123");
237 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123", "456"}),
238 "123,456");
239 }
240
TEST(RemoveStringFromCSV,WithoutDeleteStringReturnsFalse)241 TEST(RemoveStringFromCSV, WithoutDeleteStringReturnsFalse)
242 {
243 std::string expected = "whatever,https";
244 std::string str = expected;
245 EXPECT_FALSE(removeStringFromCSV(str, "ssh"));
246 EXPECT_EQ(str, expected);
247
248 std::string empty;
249 EXPECT_FALSE(removeStringFromCSV(empty, "ssh"));
250 }
251
TEST(RemoveStringFromCSV,WithDeleteStringReturnsTrue)252 TEST(RemoveStringFromCSV, WithDeleteStringReturnsTrue)
253 {
254 std::string expected = "whatever";
255 std::string str = "whatever,https";
256 EXPECT_TRUE(removeStringFromCSV(str, "https"));
257 EXPECT_EQ(str, expected);
258
259 str = "https";
260 EXPECT_TRUE(removeStringFromCSV(str, "https"));
261 EXPECT_EQ(str, "");
262 }
263
264 namespace
265 {
266 inline constexpr const char* objectRootInTest = "/xyz/openbmc_project/user";
267
268 // Fake configs; referenced configs on real BMC
269 inline constexpr const char* rawFailLockConfig = R"(
270 deny=2
271 unlock_time=3
272 )";
273 inline constexpr const char* rawPWHistoryConfig = R"(
274 enforce_for_root
275 remember=0
276 )";
277 inline constexpr const char* rawPWQualityConfig = R"(
278 enforce_for_root
279 minlen=8
280 difok=0
281 lcredit=0
282 ocredit=0
283 dcredit=0
284 ucredit=0
285 )";
286 } // namespace
287
dumpStringToFile(const std::string & str,const std::string & filePath)288 void dumpStringToFile(const std::string& str, const std::string& filePath)
289 {
290 std::ofstream outputFileStream;
291
292 outputFileStream.exceptions(
293 std::ofstream::failbit | std::ofstream::badbit | std::ofstream::eofbit);
294
295 outputFileStream.open(filePath, std::ios::out);
296 outputFileStream << str << "\n" << std::flush;
297 outputFileStream.close();
298 }
299
removeFile(const std::string & filePath)300 void removeFile(const std::string& filePath)
301 {
302 std::filesystem::remove(filePath);
303 }
304
305 class UserMgrInTest : public testing::Test, public UserMgr
306 {
307 public:
UserMgrInTest()308 UserMgrInTest() : UserMgr(busInTest, objectRootInTest)
309 {
310 tempFaillockConfigFile = "/tmp/test-data-XXXXXX";
311 mktemp(tempFaillockConfigFile.data());
312 EXPECT_NO_THROW(
313 dumpStringToFile(rawFailLockConfig, tempFaillockConfigFile));
314 tempPWHistoryConfigFile = "/tmp/test-data-XXXXXX";
315 mktemp(tempPWHistoryConfigFile.data());
316 EXPECT_NO_THROW(
317 dumpStringToFile(rawPWHistoryConfig, tempPWHistoryConfigFile));
318 tempPWQualityConfigFile = "/tmp/test-data-XXXXXX";
319 mktemp(tempPWQualityConfigFile.data());
320 EXPECT_NO_THROW(
321 dumpStringToFile(rawPWQualityConfig, tempPWQualityConfigFile));
322 // Set config files to test files
323 faillockConfigFile = tempFaillockConfigFile;
324 pwHistoryConfigFile = tempPWHistoryConfigFile;
325 pwQualityConfigFile = tempPWQualityConfigFile;
326
327 ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_,
328 testing::Eq(true)))
329 .WillByDefault([this]() {
330 ON_CALL(*this, isUserEnabled)
331 .WillByDefault(testing::Return(true));
332 testing::Return();
333 });
334
335 ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_,
336 testing::Eq(false)))
337 .WillByDefault([this]() {
338 ON_CALL(*this, isUserEnabled)
339 .WillByDefault(testing::Return(false));
340 testing::Return();
341 });
342
343 ON_CALL(*this, executeUserDelete).WillByDefault(testing::Return());
344
345 ON_CALL(*this, executeUserClearFailRecords)
346 .WillByDefault(testing::Return());
347
348 ON_CALL(*this, getIpmiUsersCount).WillByDefault(testing::Return(0));
349
350 ON_CALL(*this, executeUserRename).WillByDefault(testing::Return());
351
352 ON_CALL(*this, executeUserModify(testing::_, testing::_, testing::_))
353 .WillByDefault(testing::Return());
354
355 ON_CALL(*this,
356 executeUserModifyUserEnable(testing::_, testing::Eq(true)))
357 .WillByDefault([this]() {
358 ON_CALL(*this, isUserEnabled)
359 .WillByDefault(testing::Return(true));
360 testing::Return();
361 });
362
363 ON_CALL(*this,
364 executeUserModifyUserEnable(testing::_, testing::Eq(false)))
365 .WillByDefault([this]() {
366 ON_CALL(*this, isUserEnabled)
367 .WillByDefault(testing::Return(false));
368 testing::Return();
369 });
370
371 ON_CALL(*this, executeGroupCreation(testing::_))
372 .WillByDefault(testing::Return());
373
374 ON_CALL(*this, executeGroupDeletion(testing::_))
375 .WillByDefault(testing::Return());
376
377 ON_CALL(*this, executeGroupCreation).WillByDefault(testing::Return());
378
379 ON_CALL(*this, executeGroupDeletion).WillByDefault(testing::Return());
380 }
381
~UserMgrInTest()382 ~UserMgrInTest() override
383 {
384 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
385 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
386 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
387 }
388
389 MOCK_METHOD(void, executeUserAdd, (const char*, const char*, bool, bool),
390 (override));
391
392 MOCK_METHOD(void, executeUserDelete, (const char*), (override));
393
394 MOCK_METHOD(void, executeUserClearFailRecords, (const char*), (override));
395
396 MOCK_METHOD(size_t, getIpmiUsersCount, (), (override));
397
398 MOCK_METHOD(void, executeUserRename, (const char*, const char*),
399 (override));
400
401 MOCK_METHOD(void, executeUserModify, (const char*, const char*, bool),
402 (override));
403
404 MOCK_METHOD(void, executeUserModifyUserEnable, (const char*, bool),
405 (override));
406
407 MOCK_METHOD(std::vector<std::string>, getFailedAttempt, (const char*),
408 (override));
409
410 MOCK_METHOD(void, executeGroupCreation, (const char*), (override));
411
412 MOCK_METHOD(void, executeGroupDeletion, (const char*), (override));
413
414 MOCK_METHOD(bool, isUserEnabled, (const std::string& userName), (override));
415
416 protected:
417 static sdbusplus::bus_t busInTest;
418 std::string tempFaillockConfigFile;
419 std::string tempPWHistoryConfigFile;
420 std::string tempPWQualityConfigFile;
421 };
422
423 sdbusplus::bus_t UserMgrInTest::busInTest = sdbusplus::bus::new_default();
424
TEST_F(UserMgrInTest,GetPamModuleConfValueOnSuccess)425 TEST_F(UserMgrInTest, GetPamModuleConfValueOnSuccess)
426 {
427 std::string minlen;
428 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
429 0);
430 EXPECT_EQ(minlen, "8");
431 std::string deny;
432 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
433 EXPECT_EQ(deny, "2");
434 std::string remember;
435 EXPECT_EQ(
436 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
437 0);
438 EXPECT_EQ(remember, "0");
439 }
440
TEST_F(UserMgrInTest,SetPamModuleConfValueOnSuccess)441 TEST_F(UserMgrInTest, SetPamModuleConfValueOnSuccess)
442 {
443 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
444 0);
445 std::string minlen;
446 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
447 0);
448 EXPECT_EQ(minlen, "16");
449
450 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
451 std::string deny;
452 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
453 EXPECT_EQ(deny, "3");
454
455 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
456 0);
457 std::string remember;
458 EXPECT_EQ(
459 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
460 0);
461 EXPECT_EQ(remember, "1");
462 }
463
TEST_F(UserMgrInTest,SetPamModuleConfValueTempFileOnSuccess)464 TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnSuccess)
465 {
466 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
467 0);
468
469 std::string tmpFile = tempPWQualityConfigFile + "_tmp";
470 EXPECT_FALSE(std::filesystem::exists(tmpFile));
471
472 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
473
474 tmpFile = tempFaillockConfigFile + "_tmp";
475 EXPECT_FALSE(std::filesystem::exists(tmpFile));
476
477 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
478 0);
479
480 tmpFile = tempPWHistoryConfigFile + "_tmp";
481 EXPECT_FALSE(std::filesystem::exists(tmpFile));
482 }
483
TEST_F(UserMgrInTest,GetPamModuleConfValueOnFailure)484 TEST_F(UserMgrInTest, GetPamModuleConfValueOnFailure)
485 {
486 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
487 std::string minlen;
488 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
489 -1);
490
491 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
492 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
493 -1);
494
495 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
496 std::string deny;
497 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
498
499 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
500 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
501
502 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
503 std::string remember;
504 EXPECT_EQ(
505 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
506 -1);
507
508 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
509 EXPECT_EQ(
510 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
511 -1);
512 }
513
TEST_F(UserMgrInTest,SetPamModuleConfValueOnFailure)514 TEST_F(UserMgrInTest, SetPamModuleConfValueOnFailure)
515 {
516 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
517 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
518 -1);
519
520 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
521 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
522 -1);
523
524 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
525 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
526
527 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
528 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
529
530 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
531 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
532 -1);
533
534 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
535 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
536 -1);
537 }
538
TEST_F(UserMgrInTest,SetPamModuleConfValueTempFileOnFailure)539 TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnFailure)
540 {
541 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
542 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
543 -1);
544
545 std::string tmpFile = tempPWQualityConfigFile + "_tmp";
546 EXPECT_FALSE(std::filesystem::exists(tmpFile));
547
548 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
549 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
550 -1);
551
552 EXPECT_FALSE(std::filesystem::exists(tmpFile));
553
554 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
555 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
556
557 tmpFile = tempFaillockConfigFile + "_tmp";
558 EXPECT_FALSE(std::filesystem::exists(tmpFile));
559
560 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
561 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
562
563 EXPECT_FALSE(std::filesystem::exists(tmpFile));
564
565 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
566 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
567 -1);
568
569 tmpFile = tempPWHistoryConfigFile + "_tmp";
570 EXPECT_FALSE(std::filesystem::exists(tmpFile));
571
572 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
573 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
574 -1);
575
576 EXPECT_FALSE(std::filesystem::exists(tmpFile));
577 }
578
TEST_F(UserMgrInTest,IsUserExistEmptyInputThrowsError)579 TEST_F(UserMgrInTest, IsUserExistEmptyInputThrowsError)
580 {
581 EXPECT_THROW(
582 isUserExist(""),
583 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
584 }
585
TEST_F(UserMgrInTest,ThrowForUserDoesNotExistThrowsError)586 TEST_F(UserMgrInTest, ThrowForUserDoesNotExistThrowsError)
587 {
588 EXPECT_THROW(throwForUserDoesNotExist("whatever"),
589 sdbusplus::xyz::openbmc_project::User::Common::Error::
590 UserNameDoesNotExist);
591 }
592
TEST_F(UserMgrInTest,ThrowForUserExistsThrowsError)593 TEST_F(UserMgrInTest, ThrowForUserExistsThrowsError)
594 {
595 EXPECT_THROW(
596 throwForUserExists("root"),
597 sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameExists);
598 }
599
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)600 TEST_F(
601 UserMgrInTest,
602 ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)
603 {
604 std::string strWith17Chars(17, 'A');
605 EXPECT_THROW(throwForUserNameConstraints(strWith17Chars, {"ipmi"}),
606 sdbusplus::xyz::openbmc_project::User::Common::Error::
607 UserNameGroupFail);
608 }
609
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)610 TEST_F(
611 UserMgrInTest,
612 ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)
613 {
614 std::string strWith31Chars(101, 'A');
615 EXPECT_THROW(
616 throwForUserNameConstraints(strWith31Chars, {}),
617 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
618 }
619
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)620 TEST_F(UserMgrInTest,
621 ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)
622 {
623 std::string startWithNumber = "0ABC";
624 std::string startWithDisallowedCharacter = "[test";
625 EXPECT_THROW(
626 throwForUserNameConstraints(startWithNumber, {"ipmi"}),
627 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
628 EXPECT_THROW(
629 throwForUserNameConstraints(startWithDisallowedCharacter, {"ipmi"}),
630 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
631 }
632
TEST_F(UserMgrInTest,UserAddNotRootFailedWithInternalFailure)633 TEST_F(UserMgrInTest, UserAddNotRootFailedWithInternalFailure)
634 {
635 EXPECT_THROW(
636 UserMgr::executeUserAdd("user0", "ipmi,ssh", true, true),
637 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
638 }
639
TEST_F(UserMgrInTest,UserDeleteNotRootFailedWithInternalFailure)640 TEST_F(UserMgrInTest, UserDeleteNotRootFailedWithInternalFailure)
641 {
642 EXPECT_THROW(
643 UserMgr::executeUserDelete("user0"),
644 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
645 }
646
TEST_F(UserMgrInTest,ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)647 TEST_F(UserMgrInTest,
648 ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)
649 {
650 EXPECT_CALL(*this, getIpmiUsersCount()).WillOnce(Return(ipmiMaxUsers));
651 EXPECT_THROW(
652 throwForMaxGrpUserCount({"ipmi"}),
653 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
654 }
655
TEST_F(UserMgrInTest,CreateUserThrowsInternalFailureWhenExecuteUserAddFails)656 TEST_F(UserMgrInTest, CreateUserThrowsInternalFailureWhenExecuteUserAddFails)
657 {
658 EXPECT_CALL(*this, executeUserAdd)
659 .WillOnce(testing::Throw(
660 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
661 EXPECT_THROW(
662 createUser("whatever", {"redfish"}, "", true),
663 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
664 }
665
TEST_F(UserMgrInTest,DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)666 TEST_F(UserMgrInTest, DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)
667 {
668 std::string username = "user";
669 EXPECT_NO_THROW(
670 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
671 EXPECT_CALL(*this, executeUserDelete(testing::StrEq(username)))
672 .WillOnce(testing::Throw(
673 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
674 .WillOnce(testing::DoDefault());
675
676 EXPECT_THROW(
677 deleteUser(username),
678 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
679 EXPECT_NO_THROW(UserMgr::deleteUser(username));
680 }
681
TEST_F(UserMgrInTest,DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)682 TEST_F(UserMgrInTest,
683 DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)
684 {
685 const char* username = "user";
686 EXPECT_NO_THROW(
687 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
688 EXPECT_CALL(*this, executeUserClearFailRecords(testing::StrEq(username)))
689 .WillOnce(testing::Throw(
690 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
691 .WillOnce(testing::DoDefault());
692
693 EXPECT_THROW(
694 deleteUser(username),
695 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
696 EXPECT_NO_THROW(UserMgr::deleteUser(username));
697 }
698
TEST_F(UserMgrInTest,ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)699 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)
700 {
701 EXPECT_THROW(
702 throwForInvalidPrivilege("whatever"),
703 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
704 }
705
TEST_F(UserMgrInTest,ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)706 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)
707 {
708 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-admin"));
709 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-operator"));
710 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-user"));
711 }
712
TEST_F(UserMgrInTest,ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)713 TEST_F(UserMgrInTest, ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)
714 {
715 EXPECT_THROW(
716 throwForInvalidGroups({"whatever"}),
717 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
718 EXPECT_THROW(
719 throwForInvalidGroups({"web"}),
720 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
721 }
722
TEST_F(UserMgrInTest,ThrowForInvalidGroupsNoThrowWhenGroupIsValid)723 TEST_F(UserMgrInTest, ThrowForInvalidGroupsNoThrowWhenGroupIsValid)
724 {
725 EXPECT_NO_THROW(throwForInvalidGroups({"ipmi"}));
726 EXPECT_NO_THROW(throwForInvalidGroups({"ssh"}));
727 EXPECT_NO_THROW(throwForInvalidGroups({"redfish"}));
728 EXPECT_NO_THROW(throwForInvalidGroups({"hostconsole"}));
729 }
730
TEST_F(UserMgrInTest,RenameUserOnSuccess)731 TEST_F(UserMgrInTest, RenameUserOnSuccess)
732 {
733 std::string username = "user001";
734 EXPECT_NO_THROW(
735 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
736 std::string newUsername = "user002";
737
738 EXPECT_NO_THROW(UserMgr::renameUser(username, newUsername));
739
740 // old username doesn't exist
741 EXPECT_THROW(getUserInfo(username),
742 sdbusplus::xyz::openbmc_project::User::Common::Error::
743 UserNameDoesNotExist);
744
745 UserInfoMap userInfo = getUserInfo(newUsername);
746 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
747 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
748 testing::UnorderedElementsAre("redfish", "ssh"));
749 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
750
751 EXPECT_NO_THROW(UserMgr::deleteUser(newUsername));
752 }
753
TEST_F(UserMgrInTest,RenameUserThrowsInternalFailureIfExecuteUserModifyFails)754 TEST_F(UserMgrInTest, RenameUserThrowsInternalFailureIfExecuteUserModifyFails)
755 {
756 std::string username = "user001";
757 EXPECT_NO_THROW(
758 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
759 std::string newUsername = "user002";
760
761 EXPECT_CALL(*this, executeUserRename(testing::StrEq(username),
762 testing::StrEq(newUsername)))
763 .WillOnce(testing::Throw(
764 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
765 EXPECT_THROW(
766 UserMgr::renameUser(username, newUsername),
767 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
768
769 // The original user is unchanged
770 UserInfoMap userInfo = getUserInfo(username);
771 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
772 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
773 testing::UnorderedElementsAre("redfish", "ssh"));
774 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
775
776 EXPECT_NO_THROW(UserMgr::deleteUser(username));
777 }
778
TEST_F(UserMgrInTest,DefaultUserModifyFailedWithInternalFailure)779 TEST_F(UserMgrInTest, DefaultUserModifyFailedWithInternalFailure)
780 {
781 EXPECT_THROW(
782 UserMgr::executeUserRename("user0", "user1"),
783 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
784 EXPECT_THROW(
785 UserMgr::executeUserModify("user0", "ssh", true),
786 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
787 }
788
TEST_F(UserMgrInTest,UpdateGroupsAndPrivOnSuccess)789 TEST_F(UserMgrInTest, UpdateGroupsAndPrivOnSuccess)
790 {
791 std::string username = "user001";
792 EXPECT_NO_THROW(
793 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
794 EXPECT_NO_THROW(
795 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"));
796 UserInfoMap userInfo = getUserInfo(username);
797 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-admin");
798 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
799 testing::UnorderedElementsAre("ipmi", "ssh"));
800 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
801 EXPECT_NO_THROW(UserMgr::deleteUser(username));
802 }
803
TEST_F(UserMgrInTest,UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)804 TEST_F(UserMgrInTest,
805 UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)
806 {
807 std::string username = "user001";
808 EXPECT_NO_THROW(
809 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
810 EXPECT_CALL(*this, executeUserModify(testing::StrEq(username), testing::_,
811 testing::_))
812 .WillOnce(testing::Throw(
813 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
814 EXPECT_THROW(
815 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"),
816 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
817 EXPECT_NO_THROW(UserMgr::deleteUser(username));
818 }
819
TEST_F(UserMgrInTest,MinPasswordLengthReturnsIfValueIsTheSame)820 TEST_F(UserMgrInTest, MinPasswordLengthReturnsIfValueIsTheSame)
821 {
822 initializeAccountPolicy();
823 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
824 UserMgr::minPasswordLength(8);
825 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
826 }
827
TEST_F(UserMgrInTest,MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)828 TEST_F(UserMgrInTest,
829 MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)
830 {
831 initializeAccountPolicy();
832 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
833 EXPECT_THROW(
834 UserMgr::minPasswordLength(minPasswdLength - 1),
835 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
836 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
837 }
838
TEST_F(UserMgrInTest,MinPasswordLengthOnSuccess)839 TEST_F(UserMgrInTest, MinPasswordLengthOnSuccess)
840 {
841 initializeAccountPolicy();
842 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
843 UserMgr::minPasswordLength(16);
844 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 16);
845 }
846
TEST_F(UserMgrInTest,MinPasswordLengthOnFailure)847 TEST_F(UserMgrInTest, MinPasswordLengthOnFailure)
848 {
849 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
850 initializeAccountPolicy();
851 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
852 EXPECT_THROW(
853 UserMgr::minPasswordLength(16),
854 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
855 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
856 }
857
TEST_F(UserMgrInTest,RememberOldPasswordTimesReturnsIfValueIsTheSame)858 TEST_F(UserMgrInTest, RememberOldPasswordTimesReturnsIfValueIsTheSame)
859 {
860 initializeAccountPolicy();
861 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
862 UserMgr::rememberOldPasswordTimes(8);
863 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
864 UserMgr::rememberOldPasswordTimes(8);
865 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
866 }
867
TEST_F(UserMgrInTest,RememberOldPasswordTimesOnSuccess)868 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnSuccess)
869 {
870 initializeAccountPolicy();
871 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
872 UserMgr::rememberOldPasswordTimes(16);
873 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 16);
874 }
875
TEST_F(UserMgrInTest,RememberOldPasswordTimesOnFailure)876 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnFailure)
877 {
878 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
879 initializeAccountPolicy();
880 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
881 EXPECT_THROW(
882 UserMgr::rememberOldPasswordTimes(16),
883 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
884 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
885 }
886
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)887 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)
888 {
889 initializeAccountPolicy();
890 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
891 UserMgr::maxLoginAttemptBeforeLockout(2);
892 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
893 }
894
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutOnSuccess)895 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnSuccess)
896 {
897 initializeAccountPolicy();
898 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
899 UserMgr::maxLoginAttemptBeforeLockout(16);
900 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 16);
901 }
902
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutOnFailure)903 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnFailure)
904 {
905 initializeAccountPolicy();
906 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
907 EXPECT_THROW(
908 UserMgr::maxLoginAttemptBeforeLockout(16),
909 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
910 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
911 }
912
TEST_F(UserMgrInTest,AccountUnlockTimeoutReturnsIfValueIsTheSame)913 TEST_F(UserMgrInTest, AccountUnlockTimeoutReturnsIfValueIsTheSame)
914 {
915 initializeAccountPolicy();
916 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
917 UserMgr::accountUnlockTimeout(3);
918 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
919 }
920
TEST_F(UserMgrInTest,AccountUnlockTimeoutOnSuccess)921 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnSuccess)
922 {
923 initializeAccountPolicy();
924 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
925 UserMgr::accountUnlockTimeout(16);
926 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 16);
927 }
928
TEST_F(UserMgrInTest,AccountUnlockTimeoutOnFailure)929 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnFailure)
930 {
931 initializeAccountPolicy();
932 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
933 EXPECT_THROW(
934 UserMgr::accountUnlockTimeout(16),
935 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
936 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
937 }
938
TEST_F(UserMgrInTest,UserEnableOnSuccess)939 TEST_F(UserMgrInTest, UserEnableOnSuccess)
940 {
941 std::string username = "user001";
942 EXPECT_NO_THROW(
943 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
944 UserInfoMap userInfo = getUserInfo(username);
945 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
946
947 EXPECT_NO_THROW(userEnable(username, false));
948
949 userInfo = getUserInfo(username);
950 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), false);
951
952 EXPECT_NO_THROW(UserMgr::deleteUser(username));
953 }
954
TEST_F(UserMgrInTest,CreateDeleteUserSuccessForHostConsole)955 TEST_F(UserMgrInTest, CreateDeleteUserSuccessForHostConsole)
956 {
957 std::string username = "user001";
958 EXPECT_NO_THROW(
959 UserMgr::createUser(username, {"hostconsole"}, "priv-user", true));
960 EXPECT_NO_THROW(UserMgr::deleteUser(username));
961 EXPECT_NO_THROW(
962 UserMgr::createUser(username, {"hostconsole"}, "priv-admin", true));
963 EXPECT_NO_THROW(UserMgr::deleteUser(username));
964 EXPECT_NO_THROW(
965 UserMgr::createUser(username, {"hostconsole"}, "priv-operator", true));
966 EXPECT_NO_THROW(UserMgr::deleteUser(username));
967 }
968
TEST_F(UserMgrInTest,UserEnableThrowsInternalFailureIfExecuteUserModifyFail)969 TEST_F(UserMgrInTest, UserEnableThrowsInternalFailureIfExecuteUserModifyFail)
970 {
971 std::string username = "user001";
972 EXPECT_NO_THROW(
973 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
974 UserInfoMap userInfo = getUserInfo(username);
975 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
976
977 EXPECT_CALL(*this, executeUserModifyUserEnable(testing::StrEq(username),
978 testing::Eq(false)))
979 .WillOnce(testing::Throw(
980 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
981 EXPECT_THROW(
982 userEnable(username, false),
983 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
984
985 userInfo = getUserInfo(username);
986 // Stay unchanged
987 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
988
989 EXPECT_NO_THROW(UserMgr::deleteUser(username));
990 }
991
TEST_F(UserMgrInTest,UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)992 TEST_F(
993 UserMgrInTest,
994 UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)
995 {
996 EXPECT_FALSE(userLockedForFailedAttempt("whatever"));
997 }
998
TEST_F(UserMgrInTest,UserLockedForFailedAttemptZeroFailuresReturnsFalse)999 TEST_F(UserMgrInTest, UserLockedForFailedAttemptZeroFailuresReturnsFalse)
1000 {
1001 std::string username = "user001";
1002 initializeAccountPolicy();
1003 // Example output from BMC
1004 // root:~# faillock --user root
1005 // root:
1006 // When Type Source Valid
1007 std::vector<std::string> output = {"whatever",
1008 "When Type Source Valid"};
1009 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1010 .WillOnce(testing::Return(output));
1011
1012 EXPECT_FALSE(userLockedForFailedAttempt(username));
1013 }
1014
TEST_F(UserMgrInTest,UserLockedForFailedAttemptFailIfGetFailedAttemptFail)1015 TEST_F(UserMgrInTest, UserLockedForFailedAttemptFailIfGetFailedAttemptFail)
1016 {
1017 std::string username = "user001";
1018 initializeAccountPolicy();
1019 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1020 .WillOnce(testing::Throw(
1021 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1022
1023 EXPECT_THROW(
1024 userLockedForFailedAttempt(username),
1025 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1026 }
1027
TEST_F(UserMgrInTest,UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)1028 TEST_F(UserMgrInTest,
1029 UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)
1030 {
1031 std::string username = "user001";
1032 initializeAccountPolicy();
1033
1034 // Choose a date in the past.
1035 std::vector<std::string> output = {"whatever",
1036 "10/24/2002 00:00:00 type source V"};
1037 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1038 .WillOnce(testing::Return(output));
1039
1040 EXPECT_THROW(
1041 userLockedForFailedAttempt(username),
1042 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1043 }
1044
TEST_F(UserMgrInTest,UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)1045 TEST_F(UserMgrInTest,
1046 UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)
1047 {
1048 std::string username = "user001";
1049 initializeAccountPolicy();
1050
1051 // Choose a date in the past.
1052 std::vector<std::string> output = {"whatever",
1053 "2002-10-24 00:00:00 type source V"};
1054 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1055 .WillOnce(testing::Return(output));
1056
1057 EXPECT_EQ(userLockedForFailedAttempt(username), false);
1058 }
1059
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationOnSuccess)1060 TEST_F(UserMgrInTest, CheckAndThrowForDisallowedGroupCreationOnSuccess)
1061 {
1062 // Base Redfish Roles
1063 EXPECT_NO_THROW(
1064 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Administrator"));
1065 EXPECT_NO_THROW(
1066 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Operator"));
1067 EXPECT_NO_THROW(
1068 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_ReadOnly"));
1069 // Base Redfish Privileges
1070 EXPECT_NO_THROW(
1071 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_Login"));
1072 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1073 "openbmc_rfp_ConfigureManager"));
1074 EXPECT_NO_THROW(
1075 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureUsers"));
1076 EXPECT_NO_THROW(
1077 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureSelf"));
1078 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1079 "openbmc_rfp_ConfigureComponents"));
1080 // OEM Redfish Roles
1081 EXPECT_NO_THROW(
1082 checkAndThrowForDisallowedGroupCreation("openbmc_orfr_PowerService"));
1083 // OEM Redfish Privileges
1084 EXPECT_NO_THROW(
1085 checkAndThrowForDisallowedGroupCreation("openbmc_orfp_PowerService"));
1086 }
1087
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)1088 TEST_F(UserMgrInTest,
1089 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)
1090 {
1091 std::string groupName(maxSystemGroupNameLength + 1, 'A');
1092 EXPECT_THROW(
1093 checkAndThrowForDisallowedGroupCreation(groupName),
1094 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1095 }
1096
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)1097 TEST_F(
1098 UserMgrInTest,
1099 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)
1100 {
1101 EXPECT_THROW(
1102 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_?owerService"),
1103 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1104 EXPECT_THROW(
1105 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_-owerService"),
1106 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1107 }
1108
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)1109 TEST_F(
1110 UserMgrInTest,
1111 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)
1112 {
1113 EXPECT_THROW(
1114 checkAndThrowForDisallowedGroupCreation("google_rfp_"),
1115 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1116 EXPECT_THROW(
1117 checkAndThrowForDisallowedGroupCreation("com_rfp_"),
1118 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1119 }
1120
TEST_F(UserMgrInTest,CheckAndThrowForMaxGroupCountOnSuccess)1121 TEST_F(UserMgrInTest, CheckAndThrowForMaxGroupCountOnSuccess)
1122 {
1123 constexpr size_t predefGroupCount = 4;
1124
1125 EXPECT_THAT(allGroups().size(), predefGroupCount);
1126 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
1127 {
1128 std::string groupName = "openbmc_rfr_role";
1129 groupName += std::to_string(i);
1130 EXPECT_NO_THROW(createGroup(groupName));
1131 }
1132 EXPECT_THROW(
1133 createGroup("openbmc_rfr_AnotherRole"),
1134 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
1135 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
1136 {
1137 std::string groupName = "openbmc_rfr_role";
1138 groupName += std::to_string(i);
1139 EXPECT_NO_THROW(deleteGroup(groupName));
1140 }
1141 }
1142
TEST_F(UserMgrInTest,CheckAndThrowForGroupExist)1143 TEST_F(UserMgrInTest, CheckAndThrowForGroupExist)
1144 {
1145 std::string groupName = "openbmc_rfr_role";
1146 EXPECT_NO_THROW(createGroup(groupName));
1147 EXPECT_THROW(
1148 createGroup(groupName),
1149 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1150 EXPECT_NO_THROW(deleteGroup(groupName));
1151 }
1152
TEST_F(UserMgrInTest,ByDefaultAllGroupsArePredefinedGroups)1153 TEST_F(UserMgrInTest, ByDefaultAllGroupsArePredefinedGroups)
1154 {
1155 EXPECT_THAT(allGroups(), testing::UnorderedElementsAre(
1156 "redfish", "ipmi", "ssh", "hostconsole"));
1157 }
1158
TEST_F(UserMgrInTest,AddGroupThrowsIfPreDefinedGroupAdd)1159 TEST_F(UserMgrInTest, AddGroupThrowsIfPreDefinedGroupAdd)
1160 {
1161 EXPECT_THROW(
1162 createGroup("ipmi"),
1163 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1164 EXPECT_THROW(
1165 createGroup("redfish"),
1166 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1167 EXPECT_THROW(
1168 createGroup("ssh"),
1169 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1170 EXPECT_THROW(
1171 createGroup("hostconsole"),
1172 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1173 }
1174
TEST_F(UserMgrInTest,DeleteGroupThrowsIfGroupIsNotAllowedToChange)1175 TEST_F(UserMgrInTest, DeleteGroupThrowsIfGroupIsNotAllowedToChange)
1176 {
1177 EXPECT_THROW(
1178 deleteGroup("ipmi"),
1179 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1180 EXPECT_THROW(
1181 deleteGroup("redfish"),
1182 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1183 EXPECT_THROW(
1184 deleteGroup("ssh"),
1185 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1186 EXPECT_THROW(
1187 deleteGroup("hostconsole"),
1188 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1189 }
1190
TEST_F(UserMgrInTest,CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)1191 TEST_F(UserMgrInTest,
1192 CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)
1193 {
1194 EXPECT_CALL(*this, executeGroupCreation)
1195 .WillOnce(testing::Throw(
1196 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1197 EXPECT_THROW(
1198 createGroup("openbmc_rfr_role1"),
1199 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1200 }
1201
TEST_F(UserMgrInTest,DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)1202 TEST_F(UserMgrInTest,
1203 DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)
1204 {
1205 std::string groupName = "openbmc_rfr_role1";
1206 EXPECT_NO_THROW(UserMgr::createGroup(groupName));
1207 EXPECT_CALL(*this, executeGroupDeletion(testing::StrEq(groupName)))
1208 .WillOnce(testing::Throw(
1209 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
1210 .WillOnce(testing::DoDefault());
1211
1212 EXPECT_THROW(
1213 deleteGroup(groupName),
1214 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1215 EXPECT_NO_THROW(UserMgr::deleteGroup(groupName));
1216 }
1217
TEST_F(UserMgrInTest,CheckAndThrowForGroupNotExist)1218 TEST_F(UserMgrInTest, CheckAndThrowForGroupNotExist)
1219 {
1220 EXPECT_THROW(deleteGroup("whatever"),
1221 sdbusplus::xyz::openbmc_project::User::Common::Error::
1222 GroupNameDoesNotExist);
1223 }
1224
TEST(ReadAllGroupsOnSystemTest,OnlyReturnsPredefinedGroups)1225 TEST(ReadAllGroupsOnSystemTest, OnlyReturnsPredefinedGroups)
1226 {
1227 EXPECT_THAT(
1228 UserMgr::readAllGroupsOnSystem(),
1229 testing::UnorderedElementsAre("redfish", "ipmi", "ssh", "hostconsole"));
1230 }
1231
1232 } // namespace user
1233 } // namespace phosphor
1234