xref: /openbmc/phosphor-user-manager/test/user_mgr_test.cpp (revision 0e427be810a3233f23186cce599e8bf680ae3f62)
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